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 +6 -0
- package/package.json +1 -1
- package/src/cursor-provider-errors.ts +36 -5
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
|
@@ -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(
|
|
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
|
-
|
|
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(
|
|
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
|
}
|