pi-cursor-sdk 0.1.44 → 0.1.45

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
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.1.45 - 2026-06-18
6
+
7
+ ### Fixed
8
+
9
+ - Classify Cursor SDK HTTP/2 `NGHTTP2_ENHANCE_YOUR_CALM` and stream-reset `ConnectError`s as retryable network errors so active-turn process errors do not hard-crash pi (#127).
10
+
5
11
  ## 0.1.44 - 2026-06-16
6
12
 
7
13
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-cursor-sdk",
3
- "version": "0.1.44",
3
+ "version": "0.1.45",
4
4
  "description": "pi provider extension backed by @cursor/sdk local agents",
5
5
  "author": "Mitch Fultz (https://github.com/fitchmultz)",
6
6
  "license": "MIT",
@@ -44,6 +44,35 @@ function getErrorStack(error: unknown, record: Record<string, unknown> | undefin
44
44
  return error instanceof Error ? error.stack ?? "" : getErrorStringField(record, "stack") ?? "";
45
45
  }
46
46
 
47
+ const CONNECT_ERROR_EVIDENCE_KEYS = ["name", "message", "rawMessage", "code", "syscall"] as const;
48
+
49
+ function getErrorEvidenceField(
50
+ value: unknown,
51
+ record: Record<string, unknown> | undefined,
52
+ key: (typeof CONNECT_ERROR_EVIDENCE_KEYS)[number],
53
+ ): string | undefined {
54
+ if (value instanceof Error && (key === "name" || key === "message")) return value[key] || undefined;
55
+ const field = record?.[key];
56
+ if (typeof field === "string") return field;
57
+ if (typeof field === "number") return String(field);
58
+ return undefined;
59
+ }
60
+
61
+ function collectConnectErrorEvidence(error: unknown, record: Record<string, unknown> | undefined): string {
62
+ const evidence: string[] = [];
63
+ let value = error;
64
+ let currentRecord = record;
65
+ for (let depth = 0; depth < 3 && currentRecord; depth += 1) {
66
+ for (const key of CONNECT_ERROR_EVIDENCE_KEYS) {
67
+ const field = getErrorEvidenceField(value, currentRecord, key)?.trim();
68
+ if (field) evidence.push(field);
69
+ }
70
+ value = currentRecord.cause;
71
+ currentRecord = asRecord(value);
72
+ }
73
+ return evidence.join("\n");
74
+ }
75
+
47
76
  function isConnectError(error: unknown, record: Record<string, unknown> | undefined): boolean {
48
77
  const name = error instanceof Error ? error.name : getErrorStringField(record, "name");
49
78
  return name === "ConnectError";
@@ -98,6 +127,7 @@ export function classifyCursorConnectError(error: unknown): CursorConnectErrorCl
98
127
  const cause = asRecord(record?.cause);
99
128
  const causeName = getErrorStringField(cause, "name");
100
129
  const stack = getErrorStack(error, record);
130
+ const evidence = collectConnectErrorEvidence(error, record);
101
131
 
102
132
  if (
103
133
  (code === 1 || code === "canceled") &&
@@ -109,7 +139,7 @@ export function classifyCursorConnectError(error: unknown): CursorConnectErrorCl
109
139
  return { kind: "abort", source: "cursor-sdk-stack" };
110
140
  }
111
141
 
112
- if (isUnauthenticatedConnectCode(code) || isLikelyAuthError(`${message}\n${rawMessage}`)) {
142
+ if (isUnauthenticatedConnectCode(code) || isLikelyAuthError(evidence)) {
113
143
  return { kind: "unauthenticated", source: getCursorConnectSource(error, record) };
114
144
  }
115
145
 
@@ -117,9 +147,7 @@ export function classifyCursorConnectError(error: unknown): CursorConnectErrorCl
117
147
  return { kind: "network", source: getCursorConnectSource(error, record) };
118
148
  }
119
149
 
120
- const causeCode = getErrorStringField(cause, "code");
121
- const causeSyscall = getErrorStringField(cause, "syscall");
122
- if (isLikelyNetworkTimeout(`${message}\n${rawMessage}\n${causeCode ?? ""}\n${causeSyscall ?? ""}`)) {
150
+ if (isLikelyNetworkTimeout(evidence)) {
123
151
  return { kind: "network", source: getCursorConnectSource(error, record) };
124
152
  }
125
153
 
@@ -136,8 +164,11 @@ export function isUnauthenticatedConnectError(error: unknown): boolean {
136
164
 
137
165
  function isLikelyNetworkTimeout(message: string): boolean {
138
166
  return (
139
- /\b(ETIMEDOUT|ECONNRESET|ECONNREFUSED|ENETUNREACH|EAI_AGAIN)\b/i.test(message) ||
167
+ /\b(ETIMEDOUT|ECONNRESET|ECONNREFUSED|ENETUNREACH|EAI_AGAIN|NGHTTP2_ENHANCE_YOUR_CALM|ERR_HTTP2_STREAM_ERROR|ERR_HTTP2_SESSION_ERROR)\b/i.test(
168
+ message,
169
+ ) ||
140
170
  /\bConnectError\b.*\b(unavailable|deadline|timeout|timed out)\b/i.test(message) ||
171
+ /\b(?:stream|session) closed with error code\b/i.test(message) ||
141
172
  /\bread ETIMEDOUT\b/i.test(message)
142
173
  );
143
174
  }