@emmaneugene/pi-cursor-sdk 0.3.7 → 0.4.0
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 +16 -0
- package/README.md +99 -126
- package/dist/cursor-agents-context-registration.js +1 -3
- package/dist/cursor-agents-context.js +2 -2
- package/dist/cursor-config.js +2 -290
- package/dist/cursor-provider-errors.js +3 -58
- package/dist/cursor-provider-live-run-drain.js +0 -3
- package/dist/cursor-provider-run-finalizer.js +4 -7
- package/dist/cursor-provider-run-outcome.js +1 -1
- package/dist/cursor-provider-turn-finalize.js +3 -55
- package/dist/cursor-provider-turn-prepare.js +8 -144
- package/dist/cursor-provider-turn-runner.js +9 -23
- package/dist/cursor-provider-turn-send.js +8 -35
- package/dist/cursor-runtime-state.js +6 -268
- package/dist/cursor-sdk-billed-usage.js +3 -18
- package/dist/cursor-sdk-platform-package.js +88 -0
- package/dist/cursor-session-agent.js +18 -14
- package/dist/cursor-skill-tool.js +12 -22
- package/dist/cursor-state.js +5 -8
- package/dist/cursor-usage-accounting.js +1 -1
- package/docs/cursor-dogfood-checklist.md +4 -4
- package/docs/cursor-live-smoke-checklist.md +23 -23
- package/docs/cursor-model-ux-spec.md +27 -30
- package/docs/cursor-native-tool-replay.md +4 -4
- package/docs/cursor-native-tool-visual-audit.md +7 -7
- package/docs/cursor-testing-lessons.md +23 -16
- package/docs/cursor-tool-surfaces.md +2 -4
- package/docs/platform-smoke-implementation.md +5 -5
- package/docs/platform-smoke.md +27 -72
- package/package.json +3 -17
- package/platform-smoke.config.mjs +2 -1
- package/scripts/lib/local-resume-smoke-harness.mjs +0 -18
- package/scripts/platform-smoke/card-detect.mjs +1 -1
- package/scripts/platform-smoke/local-resume-runner.mjs +1 -1
- package/scripts/platform-smoke/scenarios.mjs +1 -1
- package/scripts/platform-smoke/targets.mjs +14 -5
- package/src/cursor-agents-context-registration.ts +0 -5
- package/src/cursor-agents-context.ts +1 -3
- package/src/cursor-config.ts +8 -379
- package/src/cursor-provider-errors.ts +2 -62
- package/src/cursor-provider-live-run-drain.ts +0 -3
- package/src/cursor-provider-run-finalizer.ts +4 -12
- package/src/cursor-provider-run-outcome.ts +0 -3
- package/src/cursor-provider-turn-finalize.ts +3 -61
- package/src/cursor-provider-turn-prepare.ts +8 -165
- package/src/cursor-provider-turn-runner.ts +15 -31
- package/src/cursor-provider-turn-send.ts +7 -38
- package/src/cursor-provider-turn-types.ts +9 -30
- package/src/cursor-runtime-state.ts +6 -345
- package/src/cursor-sdk-billed-usage.ts +3 -24
- package/src/cursor-sdk-platform-package.ts +106 -0
- package/src/cursor-session-agent.ts +16 -12
- package/src/cursor-skill-tool.ts +10 -26
- package/src/cursor-state.ts +5 -10
- package/src/cursor-usage-accounting.ts +1 -3
- package/dist/cursor-cloud-lifecycle.js +0 -650
- package/dist/cursor-cloud-local-state.js +0 -460
- package/dist/cursor-cloud-options.js +0 -145
- package/dist/cursor-cloud-reporting.js +0 -222
- package/dist/cursor-ripgrep-path.js +0 -27
- package/scripts/cloud-runtime-smoke.d.mts +0 -42
- package/scripts/cloud-runtime-smoke.mjs +0 -623
- package/scripts/lib/cloud-smoke-artifacts.d.mts +0 -16
- package/scripts/lib/cloud-smoke-artifacts.mjs +0 -94
- package/scripts/lib/cloud-smoke-cleanup-evidence.d.mts +0 -209
- package/scripts/lib/cloud-smoke-cleanup-evidence.mjs +0 -585
- package/scripts/lib/cloud-smoke-github.d.mts +0 -78
- package/scripts/lib/cloud-smoke-github.mjs +0 -331
- package/scripts/lib/cloud-smoke-pi-runner.d.mts +0 -42
- package/scripts/lib/cloud-smoke-pi-runner.mjs +0 -214
- package/scripts/lib/cloud-smoke-shutdown.d.mts +0 -67
- package/scripts/lib/cloud-smoke-shutdown.mjs +0 -133
- package/shared/cursor-cloud-lifecycle-constants.d.mts +0 -3
- package/shared/cursor-cloud-lifecycle-constants.mjs +0 -7
- package/src/cursor-cloud-lifecycle.ts +0 -733
- package/src/cursor-cloud-local-state.ts +0 -536
- package/src/cursor-cloud-options.ts +0 -182
- package/src/cursor-cloud-reporting.ts +0 -267
- package/src/cursor-ripgrep-path.ts +0 -32
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
resolveCursorSettingSources,
|
|
12
12
|
} from "./cursor-setting-sources.js";
|
|
13
13
|
import type { SettingSource } from "@cursor/sdk";
|
|
14
|
-
import type { CursorRuntime } from "./cursor-config.js";
|
|
15
14
|
export const CURSOR_PRESERVE_PI_AGENTS_MD_ENV = "PI_CURSOR_PRESERVE_PI_AGENTS_MD";
|
|
16
15
|
|
|
17
16
|
/** Opening tag prefix pi `buildSystemPrompt()` uses for each context file (path attribute only). */
|
|
@@ -152,9 +151,8 @@ export function resolveCursorFacingSystemPrompt(
|
|
|
152
151
|
systemPromptOptions?: BuildSystemPromptOptions,
|
|
153
152
|
settingSourcesRaw?: string,
|
|
154
153
|
agentDir?: string,
|
|
155
|
-
runtime: CursorRuntime = "local",
|
|
156
154
|
): string {
|
|
157
|
-
if (
|
|
155
|
+
if (!systemPromptOptions) return systemPrompt;
|
|
158
156
|
const contextFiles = systemPromptOptions.contextFiles ?? [];
|
|
159
157
|
const settingSources =
|
|
160
158
|
settingSourcesRaw === undefined
|
package/src/cursor-config.ts
CHANGED
|
@@ -18,19 +18,6 @@ import { asRecord } from "./cursor-record-utils.js";
|
|
|
18
18
|
|
|
19
19
|
export const CURSOR_SDK_CONFIG_FILE = "cursor-sdk.json";
|
|
20
20
|
|
|
21
|
-
export const CURSOR_RUNTIME_ENV = "PI_CURSOR_RUNTIME";
|
|
22
|
-
export const CURSOR_CLOUD_REPO_ENV = "PI_CURSOR_CLOUD_REPO";
|
|
23
|
-
export const CURSOR_CLOUD_BRANCH_ENV = "PI_CURSOR_CLOUD_BRANCH";
|
|
24
|
-
export const CURSOR_CLOUD_CONTEXT_ENV = "PI_CURSOR_CLOUD_CONTEXT";
|
|
25
|
-
export const CURSOR_CLOUD_DIRECT_PUSH_ENV = "PI_CURSOR_CLOUD_DIRECT_PUSH";
|
|
26
|
-
export const CURSOR_CLOUD_AUTO_CREATE_PR_ENV = "PI_CURSOR_CLOUD_AUTO_CREATE_PR";
|
|
27
|
-
export const CURSOR_CLOUD_SKIP_REVIEWER_REQUEST_ENV = "PI_CURSOR_CLOUD_SKIP_REVIEWER_REQUEST";
|
|
28
|
-
export const CURSOR_CLOUD_ALLOW_LOCAL_STATE_ENV = "PI_CURSOR_CLOUD_ALLOW_LOCAL_STATE";
|
|
29
|
-
export const CURSOR_CLOUD_ENV_ENV = "PI_CURSOR_CLOUD_ENV";
|
|
30
|
-
export const CURSOR_CLOUD_ENV_FROM_FILES_ENV = "PI_CURSOR_CLOUD_ENV_FROM_FILES";
|
|
31
|
-
export const CURSOR_CLOUD_ENV_TYPE_ENV = "PI_CURSOR_CLOUD_ENV_TYPE";
|
|
32
|
-
export const CURSOR_CLOUD_ENV_NAME_ENV = "PI_CURSOR_CLOUD_ENV_NAME";
|
|
33
|
-
export const CURSOR_CLOUD_ACK_ENV = "PI_CURSOR_CLOUD_ACK";
|
|
34
21
|
export const CURSOR_AUTO_REVIEW_ENV = "PI_CURSOR_AUTO_REVIEW";
|
|
35
22
|
export const CURSOR_SANDBOX_ENV = "PI_CURSOR_SANDBOX";
|
|
36
23
|
export const CURSOR_LOCAL_FORCE_ENV = "PI_CURSOR_LOCAL_FORCE";
|
|
@@ -39,31 +26,9 @@ export const CURSOR_HTTP1_ENV = "PI_CURSOR_HTTP_1_1";
|
|
|
39
26
|
|
|
40
27
|
export type CursorConfigSource = "cli" | "environment" | "project" | "user" | "session" | "model-alias" | "builtin";
|
|
41
28
|
export type CursorConfigTrustLevel = "one-shot" | "environment" | "trusted-project" | "user" | "session" | "model-catalog" | "builtin";
|
|
42
|
-
export type CursorRuntime = "local" | "cloud";
|
|
43
|
-
export type CursorCloudContextHandoff = "never" | "fresh" | "bootstrap";
|
|
44
|
-
export type CursorCloudEnvironmentType = "cloud" | "pool" | "machine";
|
|
45
|
-
|
|
46
|
-
export interface CursorCloudEnvironmentConfig {
|
|
47
|
-
type?: CursorCloudEnvironmentType | string;
|
|
48
|
-
name?: string;
|
|
49
|
-
}
|
|
50
29
|
|
|
51
30
|
export interface CursorSdkConfig {
|
|
52
31
|
fastDefaults?: Record<string, boolean>;
|
|
53
|
-
runtime?: CursorRuntime;
|
|
54
|
-
cloud?: {
|
|
55
|
-
repo?: string;
|
|
56
|
-
branch?: string;
|
|
57
|
-
contextHandoff?: CursorCloudContextHandoff;
|
|
58
|
-
directPush?: boolean;
|
|
59
|
-
autoCreatePR?: boolean;
|
|
60
|
-
skipReviewerRequest?: boolean;
|
|
61
|
-
allowLocalState?: boolean;
|
|
62
|
-
envNames?: string[];
|
|
63
|
-
envFromFiles?: boolean;
|
|
64
|
-
environment?: CursorCloudEnvironmentConfig;
|
|
65
|
-
acknowledged?: boolean;
|
|
66
|
-
};
|
|
67
32
|
local?: {
|
|
68
33
|
autoReview?: boolean;
|
|
69
34
|
sandbox?: boolean;
|
|
@@ -80,37 +45,13 @@ export interface CursorSdkConfig {
|
|
|
80
45
|
};
|
|
81
46
|
}
|
|
82
47
|
|
|
83
|
-
export interface CursorSafetyCap<T> {
|
|
84
|
-
source: CursorConfigSource;
|
|
85
|
-
trustLevel: CursorConfigTrustLevel;
|
|
86
|
-
value: T;
|
|
87
|
-
cappedSource: CursorConfigSource;
|
|
88
|
-
cappedValue: T;
|
|
89
|
-
reason: "safer-source";
|
|
90
|
-
}
|
|
91
|
-
|
|
92
48
|
export interface CursorResolvedSetting<T> {
|
|
93
49
|
value: T;
|
|
94
50
|
source: CursorConfigSource;
|
|
95
51
|
trustLevel: CursorConfigTrustLevel;
|
|
96
|
-
cappedBy?: CursorSafetyCap<T>;
|
|
97
52
|
}
|
|
98
53
|
|
|
99
54
|
export interface CursorResolvedSdkConfig {
|
|
100
|
-
runtime: CursorResolvedSetting<CursorRuntime>;
|
|
101
|
-
cloud: {
|
|
102
|
-
repo: CursorResolvedSetting<string | undefined>;
|
|
103
|
-
branch: CursorResolvedSetting<string | undefined>;
|
|
104
|
-
contextHandoff: CursorResolvedSetting<CursorCloudContextHandoff>;
|
|
105
|
-
directPush: CursorResolvedSetting<boolean>;
|
|
106
|
-
autoCreatePR: CursorResolvedSetting<boolean>;
|
|
107
|
-
skipReviewerRequest: CursorResolvedSetting<boolean>;
|
|
108
|
-
allowLocalState: CursorResolvedSetting<boolean>;
|
|
109
|
-
envNames: CursorResolvedSetting<string[]>;
|
|
110
|
-
envFromFiles: CursorResolvedSetting<boolean>;
|
|
111
|
-
environment: CursorResolvedSetting<CursorCloudEnvironmentConfig | undefined>;
|
|
112
|
-
acknowledged: CursorResolvedSetting<boolean>;
|
|
113
|
-
};
|
|
114
55
|
local: {
|
|
115
56
|
autoReview: CursorResolvedSetting<boolean>;
|
|
116
57
|
sandboxEnabled: CursorResolvedSetting<boolean>;
|
|
@@ -123,9 +64,9 @@ export interface CursorResolvedSdkConfig {
|
|
|
123
64
|
};
|
|
124
65
|
}
|
|
125
66
|
|
|
126
|
-
// Widens string-literal-union fields
|
|
127
|
-
//
|
|
128
|
-
//
|
|
67
|
+
// Widens string-literal-union fields to raw `string` so CLI callers can pass unvalidated input through to
|
|
68
|
+
// validateExplicitValue, while keeping every other field's shape linked to CursorSdkConfig so new fields
|
|
69
|
+
// don't need a manually maintained parallel type.
|
|
129
70
|
type WidenLiterals<T> = T extends string
|
|
130
71
|
? string
|
|
131
72
|
: T extends readonly (infer U)[]
|
|
@@ -142,7 +83,6 @@ export interface ResolveCursorSdkConfigOptions {
|
|
|
142
83
|
session?: CursorSdkConfig;
|
|
143
84
|
project?: CursorSdkConfig;
|
|
144
85
|
user?: CursorSdkConfig;
|
|
145
|
-
builtIn?: CursorSdkConfig;
|
|
146
86
|
}
|
|
147
87
|
|
|
148
88
|
export interface LoadCursorSdkConfigOptions {
|
|
@@ -161,33 +101,6 @@ const TRUST_LEVELS: Record<CursorConfigSource, CursorConfigTrustLevel> = {
|
|
|
161
101
|
builtin: "builtin",
|
|
162
102
|
};
|
|
163
103
|
|
|
164
|
-
const BUILT_IN_CURSOR_CONFIG: Required<Pick<CursorSdkConfig, "runtime">> & {
|
|
165
|
-
cloud: Required<NonNullable<CursorSdkConfig["cloud"]>>;
|
|
166
|
-
} = {
|
|
167
|
-
runtime: "local",
|
|
168
|
-
cloud: {
|
|
169
|
-
repo: "",
|
|
170
|
-
branch: "",
|
|
171
|
-
contextHandoff: "fresh",
|
|
172
|
-
directPush: false,
|
|
173
|
-
autoCreatePR: false,
|
|
174
|
-
skipReviewerRequest: false,
|
|
175
|
-
allowLocalState: false,
|
|
176
|
-
envNames: [],
|
|
177
|
-
envFromFiles: false,
|
|
178
|
-
environment: {},
|
|
179
|
-
acknowledged: false,
|
|
180
|
-
},
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
export function isCursorRuntime(value: unknown): value is CursorRuntime {
|
|
184
|
-
return value === "local" || value === "cloud";
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export function isCursorCloudContextHandoff(value: unknown): value is CursorCloudContextHandoff {
|
|
188
|
-
return value === "never" || value === "fresh" || value === "bootstrap";
|
|
189
|
-
}
|
|
190
|
-
|
|
191
104
|
function validateExplicitValue<T extends string>(
|
|
192
105
|
raw: string | undefined,
|
|
193
106
|
name: string,
|
|
@@ -200,62 +113,23 @@ function validateExplicitValue<T extends string>(
|
|
|
200
113
|
return value;
|
|
201
114
|
}
|
|
202
115
|
|
|
203
|
-
export function isCursorCloudEnvironmentType(value: unknown): value is CursorCloudEnvironmentType {
|
|
204
|
-
return value === "cloud" || value === "pool" || value === "machine";
|
|
205
|
-
}
|
|
206
|
-
|
|
207
116
|
function parseNonEmptyString(value: unknown): string | undefined {
|
|
208
117
|
if (typeof value !== "string") return undefined;
|
|
209
118
|
const trimmed = value.trim();
|
|
210
119
|
return trimmed ? trimmed : undefined;
|
|
211
120
|
}
|
|
212
121
|
|
|
213
|
-
function isAllowedEnvName(value: unknown): value is string {
|
|
214
|
-
return typeof value === "string" && /^[A-Za-z_][A-Za-z0-9_]*$/.test(value) && !value.startsWith("CURSOR_");
|
|
215
|
-
}
|
|
216
|
-
|
|
217
122
|
function parseToolNames(value: unknown): string[] | undefined {
|
|
218
123
|
if (!Array.isArray(value)) return undefined;
|
|
219
124
|
const parsed = [...new Set(value.map((name) => (typeof name === "string" ? name.trim() : "")).filter((name) => name.length > 0))];
|
|
220
125
|
return parsed.length > 0 ? parsed : undefined;
|
|
221
126
|
}
|
|
222
|
-
function parseEnvNames(value: unknown): string[] | undefined {
|
|
223
|
-
const names = Array.isArray(value)
|
|
224
|
-
? value
|
|
225
|
-
: typeof value === "string"
|
|
226
|
-
? value.split(",")
|
|
227
|
-
: undefined;
|
|
228
|
-
if (!names) return undefined;
|
|
229
|
-
const parsed = [...new Set(names.map((name) => (typeof name === "string" ? name.trim() : "")).filter(isAllowedEnvName))];
|
|
230
|
-
return parsed.length > 0 || (Array.isArray(value) && value.length === 0) ? parsed : undefined;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
export function parseExplicitCursorCloudEnvNames(value: string | undefined, name: string): string[] | undefined {
|
|
234
|
-
const request = parseNonEmptyString(value);
|
|
235
|
-
if (!request) return undefined;
|
|
236
|
-
const parsed = parseEnvNames(request);
|
|
237
|
-
if (!parsed?.length) throw new Error(`Invalid ${name}: no valid environment variable names were requested.`);
|
|
238
|
-
return parsed;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
function parseCloudEnvironment(value: unknown): CursorCloudEnvironmentConfig | undefined {
|
|
242
|
-
const environment = asRecord(value);
|
|
243
|
-
if (!environment) return undefined;
|
|
244
|
-
const parsed: CursorCloudEnvironmentConfig = {};
|
|
245
|
-
const rawType = parseNonEmptyString(environment.type);
|
|
246
|
-
const name = parseNonEmptyString(environment.name);
|
|
247
|
-
if (rawType) parsed.type = rawType;
|
|
248
|
-
if (name) parsed.name = name;
|
|
249
|
-
return Object.keys(parsed).length > 0 ? parsed : undefined;
|
|
250
|
-
}
|
|
251
127
|
|
|
252
128
|
export function parseCursorSdkConfig(value: unknown): CursorSdkConfig | undefined {
|
|
253
129
|
const record = asRecord(value);
|
|
254
130
|
if (!record) return undefined;
|
|
255
131
|
const config: CursorSdkConfig = {};
|
|
256
132
|
|
|
257
|
-
if (isCursorRuntime(record.runtime)) config.runtime = record.runtime;
|
|
258
|
-
|
|
259
133
|
const fastDefaults = asRecord(record.fastDefaults);
|
|
260
134
|
if (fastDefaults) {
|
|
261
135
|
config.fastDefaults = Object.fromEntries(
|
|
@@ -263,27 +137,6 @@ export function parseCursorSdkConfig(value: unknown): CursorSdkConfig | undefine
|
|
|
263
137
|
);
|
|
264
138
|
}
|
|
265
139
|
|
|
266
|
-
const cloud = asRecord(record.cloud);
|
|
267
|
-
if (cloud) {
|
|
268
|
-
const parsedCloud: NonNullable<CursorSdkConfig["cloud"]> = {};
|
|
269
|
-
const repo = parseNonEmptyString(cloud.repo);
|
|
270
|
-
const branch = parseNonEmptyString(cloud.branch);
|
|
271
|
-
const envNames = parseEnvNames(cloud.envNames);
|
|
272
|
-
const environment = parseCloudEnvironment(cloud.environment);
|
|
273
|
-
if (repo) parsedCloud.repo = repo;
|
|
274
|
-
if (branch) parsedCloud.branch = branch;
|
|
275
|
-
if (isCursorCloudContextHandoff(cloud.contextHandoff)) parsedCloud.contextHandoff = cloud.contextHandoff;
|
|
276
|
-
if (typeof cloud.directPush === "boolean") parsedCloud.directPush = cloud.directPush;
|
|
277
|
-
if (typeof cloud.autoCreatePR === "boolean") parsedCloud.autoCreatePR = cloud.autoCreatePR;
|
|
278
|
-
if (typeof cloud.skipReviewerRequest === "boolean") parsedCloud.skipReviewerRequest = cloud.skipReviewerRequest;
|
|
279
|
-
if (typeof cloud.allowLocalState === "boolean") parsedCloud.allowLocalState = cloud.allowLocalState;
|
|
280
|
-
if (envNames) parsedCloud.envNames = envNames;
|
|
281
|
-
if (typeof cloud.envFromFiles === "boolean") parsedCloud.envFromFiles = cloud.envFromFiles;
|
|
282
|
-
if (environment) parsedCloud.environment = environment;
|
|
283
|
-
if (typeof cloud.acknowledged === "boolean") parsedCloud.acknowledged = cloud.acknowledged;
|
|
284
|
-
if (Object.keys(parsedCloud).length > 0) config.cloud = parsedCloud;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
140
|
const local = asRecord(record.local);
|
|
288
141
|
if (local) {
|
|
289
142
|
const parsedLocal: NonNullable<CursorSdkConfig["local"]> = {};
|
|
@@ -453,15 +306,11 @@ export function mergeCursorSdkConfigForUpdate(
|
|
|
453
306
|
base: Record<string, unknown>,
|
|
454
307
|
patch: CursorSdkConfig,
|
|
455
308
|
): Record<string, unknown> {
|
|
456
|
-
const baseCloud = asRecord(base.cloud);
|
|
457
309
|
const baseLocal = asRecord(base.local);
|
|
458
310
|
const baseSandboxOptions = asRecord(baseLocal?.sandboxOptions);
|
|
459
311
|
return {
|
|
460
312
|
...base,
|
|
461
313
|
...patch,
|
|
462
|
-
...(baseCloud || patch.cloud
|
|
463
|
-
? { cloud: { ...baseCloud, ...patch.cloud } }
|
|
464
|
-
: {}),
|
|
465
314
|
...(baseLocal || patch.local
|
|
466
315
|
? {
|
|
467
316
|
local: {
|
|
@@ -490,8 +339,8 @@ export function withCursorFastDefaults<T extends object>(
|
|
|
490
339
|
};
|
|
491
340
|
}
|
|
492
341
|
|
|
493
|
-
function resolved<T>(source: CursorConfigSource, value: T
|
|
494
|
-
return { value, source, trustLevel: TRUST_LEVELS[source]
|
|
342
|
+
function resolved<T>(source: CursorConfigSource, value: T): CursorResolvedSetting<T> {
|
|
343
|
+
return { value, source, trustLevel: TRUST_LEVELS[source] };
|
|
495
344
|
}
|
|
496
345
|
|
|
497
346
|
function valueFrom<T>(source: CursorConfigSource, value: T | undefined): CursorResolvedSetting<T> | undefined {
|
|
@@ -504,50 +353,13 @@ function resolveOrdinary<T>(layers: Array<CursorResolvedSetting<T> | undefined>)
|
|
|
504
353
|
return match;
|
|
505
354
|
}
|
|
506
355
|
|
|
507
|
-
// One cap engine for every safety-capped field. `cap` receives the candidate cap layer's raw value and the
|
|
508
|
-
// resolved base setting; it returns the value to use once capped, or undefined to mean "don't cap". CLI is
|
|
509
|
-
// always uncapped (one-shot, explicit operator intent).
|
|
510
|
-
function resolveWithCap<T>(
|
|
511
|
-
baseLayers: Array<CursorResolvedSetting<T> | undefined>,
|
|
512
|
-
capLayer: CursorResolvedSetting<T> | undefined,
|
|
513
|
-
cap: (candidate: T, base: CursorResolvedSetting<T>) => T | undefined,
|
|
514
|
-
): CursorResolvedSetting<T> {
|
|
515
|
-
const cli = baseLayers[0];
|
|
516
|
-
if (cli) return cli;
|
|
517
|
-
const base = resolveOrdinary(baseLayers.slice(1));
|
|
518
|
-
if (!capLayer) return base;
|
|
519
|
-
const cappedValue = cap(capLayer.value, base);
|
|
520
|
-
if (cappedValue === undefined) return base;
|
|
521
|
-
return resolved(capLayer.source, cappedValue, {
|
|
522
|
-
source: capLayer.source,
|
|
523
|
-
trustLevel: capLayer.trustLevel,
|
|
524
|
-
value: cappedValue,
|
|
525
|
-
cappedSource: base.source,
|
|
526
|
-
cappedValue: base.value,
|
|
527
|
-
reason: "safer-source",
|
|
528
|
-
});
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
function scalarRiskCap<T>(risk: (value: T) => number): (candidate: T, base: CursorResolvedSetting<T>) => T | undefined {
|
|
532
|
-
return (candidate, base) => (risk(candidate) < risk(base.value) ? candidate : undefined);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
function envNamesCap(candidate: string[], base: CursorResolvedSetting<string[]>): string[] | undefined {
|
|
536
|
-
if (base.source === "user") return undefined;
|
|
537
|
-
const allowed = new Set(candidate);
|
|
538
|
-
const filtered = base.value.filter((name) => allowed.has(name));
|
|
539
|
-
return filtered.length === base.value.length ? undefined : filtered;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
356
|
// Field/layer resolver table: each field declares the ordered list of sources it participates in (its
|
|
543
|
-
// precedence), plus its per-layer values. Sources omitted from a field's order (e.g.
|
|
544
|
-
// "
|
|
545
|
-
//
|
|
357
|
+
// precedence), plus its per-layer values. Sources omitted from a field's order (e.g. local fields skip
|
|
358
|
+
// "session", force skips project/user/session) are the field-specific omissions the review asked to keep
|
|
359
|
+
// explicit; test/cursor-config.test.ts asserts each one.
|
|
546
360
|
type CursorFieldSource = Exclude<CursorConfigSource, "model-alias">;
|
|
547
361
|
type CursorFieldValues<T> = Partial<Record<CursorFieldSource, T>>;
|
|
548
362
|
|
|
549
|
-
const RUNTIME_ORDER: CursorFieldSource[] = ["cli", "environment", "session", "project", "user", "builtin"];
|
|
550
|
-
const CLOUD_ORDER: CursorFieldSource[] = ["cli", "environment", "session", "user", "builtin"];
|
|
551
363
|
const LOCAL_ORDER: CursorFieldSource[] = ["cli", "environment", "project", "user", "builtin"];
|
|
552
364
|
const LOCAL_FORCE_ORDER: CursorFieldSource[] = ["cli", "environment", "builtin"];
|
|
553
365
|
const HTTP1_ORDER: CursorFieldSource[] = ["session", "environment", "user", "builtin"];
|
|
@@ -561,64 +373,8 @@ function resolveOrdinaryField<T>(order: CursorFieldSource[], values: CursorField
|
|
|
561
373
|
return resolveOrdinary(buildFieldLayers(order, values));
|
|
562
374
|
}
|
|
563
375
|
|
|
564
|
-
function resolveSafetyField<T>(order: CursorFieldSource[], values: CursorFieldValues<T>, risk: (value: T) => number): CursorResolvedSetting<T> {
|
|
565
|
-
return resolveWithCap(buildFieldLayers(order, values), valueFrom("user", values.user), scalarRiskCap(risk));
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
function resolveEnvNamesSafetyField(order: CursorFieldSource[], values: CursorFieldValues<string[]>): CursorResolvedSetting<string[]> {
|
|
569
|
-
return resolveWithCap(buildFieldLayers(order, values), valueFrom("user", values.user), envNamesCap);
|
|
570
|
-
}
|
|
571
|
-
|
|
572
376
|
export function cursorSdkConfigFromEnv(env: Record<string, string | undefined> = process.env): CursorSdkConfig {
|
|
573
377
|
const config: CursorSdkConfig = {};
|
|
574
|
-
const runtime = validateExplicitValue(env[CURSOR_RUNTIME_ENV], CURSOR_RUNTIME_ENV, isCursorRuntime, '"local" or "cloud"');
|
|
575
|
-
if (runtime) config.runtime = runtime;
|
|
576
|
-
const repo = parseNonEmptyString(env[CURSOR_CLOUD_REPO_ENV]);
|
|
577
|
-
const branch = parseNonEmptyString(env[CURSOR_CLOUD_BRANCH_ENV]);
|
|
578
|
-
const contextHandoff = validateExplicitValue(
|
|
579
|
-
env[CURSOR_CLOUD_CONTEXT_ENV],
|
|
580
|
-
CURSOR_CLOUD_CONTEXT_ENV,
|
|
581
|
-
isCursorCloudContextHandoff,
|
|
582
|
-
'"never", "fresh", or "bootstrap"',
|
|
583
|
-
);
|
|
584
|
-
const directPush = parseOptionalEnvBoolean(env[CURSOR_CLOUD_DIRECT_PUSH_ENV]);
|
|
585
|
-
const autoCreatePR = parseOptionalEnvBoolean(env[CURSOR_CLOUD_AUTO_CREATE_PR_ENV]);
|
|
586
|
-
const skipReviewerRequest = parseOptionalEnvBoolean(env[CURSOR_CLOUD_SKIP_REVIEWER_REQUEST_ENV]);
|
|
587
|
-
const allowLocalState = parseOptionalEnvBoolean(env[CURSOR_CLOUD_ALLOW_LOCAL_STATE_ENV]);
|
|
588
|
-
const envNames = parseExplicitCursorCloudEnvNames(env[CURSOR_CLOUD_ENV_ENV], CURSOR_CLOUD_ENV_ENV);
|
|
589
|
-
const envFromFiles = parseOptionalEnvBoolean(env[CURSOR_CLOUD_ENV_FROM_FILES_ENV]);
|
|
590
|
-
const environment = parseCloudEnvironment({
|
|
591
|
-
type: env[CURSOR_CLOUD_ENV_TYPE_ENV],
|
|
592
|
-
name: env[CURSOR_CLOUD_ENV_NAME_ENV],
|
|
593
|
-
});
|
|
594
|
-
const acknowledged = parseOptionalEnvBoolean(env[CURSOR_CLOUD_ACK_ENV]);
|
|
595
|
-
if (
|
|
596
|
-
repo !== undefined ||
|
|
597
|
-
branch !== undefined ||
|
|
598
|
-
isCursorCloudContextHandoff(contextHandoff) ||
|
|
599
|
-
directPush !== undefined ||
|
|
600
|
-
autoCreatePR !== undefined ||
|
|
601
|
-
skipReviewerRequest !== undefined ||
|
|
602
|
-
allowLocalState !== undefined ||
|
|
603
|
-
envNames !== undefined ||
|
|
604
|
-
envFromFiles !== undefined ||
|
|
605
|
-
environment !== undefined ||
|
|
606
|
-
acknowledged !== undefined
|
|
607
|
-
) {
|
|
608
|
-
config.cloud = {
|
|
609
|
-
...(repo !== undefined ? { repo } : {}),
|
|
610
|
-
...(branch !== undefined ? { branch } : {}),
|
|
611
|
-
...(isCursorCloudContextHandoff(contextHandoff) ? { contextHandoff } : {}),
|
|
612
|
-
...(directPush !== undefined ? { directPush } : {}),
|
|
613
|
-
...(autoCreatePR !== undefined ? { autoCreatePR } : {}),
|
|
614
|
-
...(skipReviewerRequest !== undefined ? { skipReviewerRequest } : {}),
|
|
615
|
-
...(allowLocalState !== undefined ? { allowLocalState } : {}),
|
|
616
|
-
...(envNames !== undefined ? { envNames } : {}),
|
|
617
|
-
...(envFromFiles !== undefined ? { envFromFiles } : {}),
|
|
618
|
-
...(environment !== undefined ? { environment } : {}),
|
|
619
|
-
...(acknowledged !== undefined ? { acknowledged } : {}),
|
|
620
|
-
};
|
|
621
|
-
}
|
|
622
378
|
const autoReview = parseOptionalEnvBoolean(env[CURSOR_AUTO_REVIEW_ENV]);
|
|
623
379
|
const sandbox = parseOptionalEnvBoolean(env[CURSOR_SANDBOX_ENV]);
|
|
624
380
|
const force = parseOptionalEnvBoolean(env[CURSOR_LOCAL_FORCE_ENV]);
|
|
@@ -637,139 +393,12 @@ export function cursorSdkConfigFromEnv(env: Record<string, string | undefined> =
|
|
|
637
393
|
}
|
|
638
394
|
|
|
639
395
|
export function resolveCursorSdkConfig(options: ResolveCursorSdkConfigOptions = {}): CursorResolvedSdkConfig {
|
|
640
|
-
const cliRuntime = validateExplicitValue(options.cli?.runtime, "--cursor-runtime", isCursorRuntime, '"local" or "cloud"');
|
|
641
|
-
const cliContextHandoff = validateExplicitValue(
|
|
642
|
-
options.cli?.cloud?.contextHandoff,
|
|
643
|
-
"--cursor-cloud-context",
|
|
644
|
-
isCursorCloudContextHandoff,
|
|
645
|
-
'"never", "fresh", or "bootstrap"',
|
|
646
|
-
);
|
|
647
396
|
const env = cursorSdkConfigFromEnv(options.env);
|
|
648
|
-
const builtIn = {
|
|
649
|
-
...BUILT_IN_CURSOR_CONFIG,
|
|
650
|
-
...options.builtIn,
|
|
651
|
-
cloud: { ...BUILT_IN_CURSOR_CONFIG.cloud, ...options.builtIn?.cloud },
|
|
652
|
-
};
|
|
653
397
|
const cli = options.cli;
|
|
654
398
|
const session = options.session;
|
|
655
399
|
const project = options.project;
|
|
656
400
|
const user = options.user;
|
|
657
401
|
return {
|
|
658
|
-
runtime: resolveSafetyField(
|
|
659
|
-
RUNTIME_ORDER,
|
|
660
|
-
{
|
|
661
|
-
cli: cliRuntime,
|
|
662
|
-
environment: env.runtime,
|
|
663
|
-
session: session?.runtime,
|
|
664
|
-
project: project?.runtime,
|
|
665
|
-
user: user?.runtime,
|
|
666
|
-
builtin: builtIn.runtime,
|
|
667
|
-
},
|
|
668
|
-
(value) => (value === "cloud" ? 1 : 0),
|
|
669
|
-
),
|
|
670
|
-
cloud: {
|
|
671
|
-
repo: resolveOrdinaryField(CLOUD_ORDER, {
|
|
672
|
-
cli: cli?.cloud?.repo,
|
|
673
|
-
environment: env.cloud?.repo,
|
|
674
|
-
session: session?.cloud?.repo,
|
|
675
|
-
user: user?.cloud?.repo,
|
|
676
|
-
builtin: undefined,
|
|
677
|
-
}),
|
|
678
|
-
branch: resolveOrdinaryField(CLOUD_ORDER, {
|
|
679
|
-
cli: cli?.cloud?.branch,
|
|
680
|
-
environment: env.cloud?.branch,
|
|
681
|
-
session: session?.cloud?.branch,
|
|
682
|
-
user: user?.cloud?.branch,
|
|
683
|
-
builtin: undefined,
|
|
684
|
-
}),
|
|
685
|
-
contextHandoff: resolveSafetyField(
|
|
686
|
-
CLOUD_ORDER,
|
|
687
|
-
{
|
|
688
|
-
cli: cliContextHandoff,
|
|
689
|
-
environment: env.cloud?.contextHandoff,
|
|
690
|
-
session: session?.cloud?.contextHandoff,
|
|
691
|
-
user: user?.cloud?.contextHandoff,
|
|
692
|
-
builtin: builtIn.cloud.contextHandoff,
|
|
693
|
-
},
|
|
694
|
-
(value) => ({ never: 0, fresh: 1, bootstrap: 2 })[value],
|
|
695
|
-
),
|
|
696
|
-
directPush: resolveSafetyField(
|
|
697
|
-
CLOUD_ORDER,
|
|
698
|
-
{
|
|
699
|
-
cli: cli?.cloud?.directPush,
|
|
700
|
-
environment: env.cloud?.directPush,
|
|
701
|
-
session: session?.cloud?.directPush,
|
|
702
|
-
user: user?.cloud?.directPush,
|
|
703
|
-
builtin: builtIn.cloud.directPush,
|
|
704
|
-
},
|
|
705
|
-
(value) => (value ? 1 : 0),
|
|
706
|
-
),
|
|
707
|
-
autoCreatePR: resolveSafetyField(
|
|
708
|
-
CLOUD_ORDER,
|
|
709
|
-
{
|
|
710
|
-
cli: cli?.cloud?.autoCreatePR,
|
|
711
|
-
environment: env.cloud?.autoCreatePR,
|
|
712
|
-
session: session?.cloud?.autoCreatePR,
|
|
713
|
-
user: user?.cloud?.autoCreatePR,
|
|
714
|
-
builtin: builtIn.cloud.autoCreatePR,
|
|
715
|
-
},
|
|
716
|
-
(value) => (value ? 1 : 0),
|
|
717
|
-
),
|
|
718
|
-
skipReviewerRequest: resolveSafetyField(
|
|
719
|
-
CLOUD_ORDER,
|
|
720
|
-
{
|
|
721
|
-
cli: cli?.cloud?.skipReviewerRequest,
|
|
722
|
-
environment: env.cloud?.skipReviewerRequest,
|
|
723
|
-
session: session?.cloud?.skipReviewerRequest,
|
|
724
|
-
user: user?.cloud?.skipReviewerRequest,
|
|
725
|
-
builtin: builtIn.cloud.skipReviewerRequest,
|
|
726
|
-
},
|
|
727
|
-
(value) => (value ? 1 : 0),
|
|
728
|
-
),
|
|
729
|
-
allowLocalState: resolveSafetyField(
|
|
730
|
-
CLOUD_ORDER,
|
|
731
|
-
{
|
|
732
|
-
cli: cli?.cloud?.allowLocalState,
|
|
733
|
-
environment: env.cloud?.allowLocalState,
|
|
734
|
-
session: session?.cloud?.allowLocalState,
|
|
735
|
-
user: user?.cloud?.allowLocalState,
|
|
736
|
-
builtin: builtIn.cloud.allowLocalState,
|
|
737
|
-
},
|
|
738
|
-
(value) => (value ? 1 : 0),
|
|
739
|
-
),
|
|
740
|
-
envNames: resolveEnvNamesSafetyField(CLOUD_ORDER, {
|
|
741
|
-
cli: cli?.cloud?.envNames,
|
|
742
|
-
environment: env.cloud?.envNames,
|
|
743
|
-
session: session?.cloud?.envNames,
|
|
744
|
-
user: user?.cloud?.envNames,
|
|
745
|
-
builtin: builtIn.cloud.envNames,
|
|
746
|
-
}),
|
|
747
|
-
envFromFiles: resolveSafetyField(
|
|
748
|
-
CLOUD_ORDER,
|
|
749
|
-
{
|
|
750
|
-
cli: cli?.cloud?.envFromFiles,
|
|
751
|
-
environment: env.cloud?.envFromFiles,
|
|
752
|
-
session: session?.cloud?.envFromFiles,
|
|
753
|
-
user: user?.cloud?.envFromFiles,
|
|
754
|
-
builtin: builtIn.cloud.envFromFiles,
|
|
755
|
-
},
|
|
756
|
-
(value) => (value ? 1 : 0),
|
|
757
|
-
),
|
|
758
|
-
environment: resolveOrdinaryField(CLOUD_ORDER, {
|
|
759
|
-
cli: cli?.cloud?.environment,
|
|
760
|
-
environment: env.cloud?.environment,
|
|
761
|
-
session: session?.cloud?.environment,
|
|
762
|
-
user: user?.cloud?.environment,
|
|
763
|
-
builtin: undefined,
|
|
764
|
-
}),
|
|
765
|
-
acknowledged: resolveOrdinaryField(CLOUD_ORDER, {
|
|
766
|
-
cli: cli?.cloud?.acknowledged,
|
|
767
|
-
environment: env.cloud?.acknowledged,
|
|
768
|
-
session: session?.cloud?.acknowledged,
|
|
769
|
-
user: user?.cloud?.acknowledged,
|
|
770
|
-
builtin: builtIn.cloud.acknowledged,
|
|
771
|
-
}),
|
|
772
|
-
},
|
|
773
402
|
local: {
|
|
774
403
|
autoReview: resolveOrdinaryField(LOCAL_ORDER, {
|
|
775
404
|
cli: cli?.local?.autoReview,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { RunError, RunResult } from "@cursor/sdk";
|
|
2
|
-
import type { CursorRuntime } from "./cursor-config.js";
|
|
3
2
|
import { asRecord } from "./cursor-record-utils.js";
|
|
4
3
|
import { scrubSensitiveText } from "./cursor-sensitive-text.js";
|
|
5
4
|
|
|
@@ -9,8 +8,6 @@ const GENERIC_CURSOR_SDK_ERROR_MESSAGE =
|
|
|
9
8
|
"Cursor SDK request failed. The Cursor SDK API key may be missing, invalid, or unauthorized. Cursor Agent CLI/Desktop login is not reused. Run /login -> Use an API key -> Cursor, verify CURSOR_API_KEY, or pass --api-key, then retry.";
|
|
10
9
|
const AUTH_CURSOR_SDK_ERROR_MESSAGE =
|
|
11
10
|
"Cursor SDK request failed because the Cursor SDK API key may be invalid or unauthorized. Cursor Agent CLI/Desktop login is not reused. Run /login -> Use an API key -> Cursor, verify CURSOR_API_KEY, or pass --api-key, then retry.";
|
|
12
|
-
const CLOUD_AUTH_CURSOR_SDK_ERROR_MESSAGE =
|
|
13
|
-
"Cursor Cloud Agents request failed because Cloud API authentication rejected the API key. Use a user API key from Cursor Dashboard -> API Keys or a service account API key from Team settings; Team Admin API keys are not supported as Cursor Cloud Agents credentials. Configure the key with /login -> Use an API key -> Cursor, CURSOR_API_KEY, or --api-key, then retry.";
|
|
14
11
|
// Keep "Network error" aligned with pi's agent-level retry classifier.
|
|
15
12
|
const NETWORK_CURSOR_SDK_ERROR_MESSAGE =
|
|
16
13
|
"Network error: Cursor SDK request failed during network or service I/O. Check your connection; pi will retry automatically when auto-retry is enabled.";
|
|
@@ -47,54 +44,6 @@ function getErrorName(error: unknown, record: Record<string, unknown> | undefine
|
|
|
47
44
|
return error instanceof Error ? error.name : getErrorStringField(record, "name");
|
|
48
45
|
}
|
|
49
46
|
|
|
50
|
-
function scrubHttpsHelpUrl(helpUrl: string | undefined, apiKey: string | undefined): string | undefined {
|
|
51
|
-
if (!helpUrl) return undefined;
|
|
52
|
-
try {
|
|
53
|
-
const url = new URL(helpUrl);
|
|
54
|
-
if (url.protocol !== "https:") return undefined;
|
|
55
|
-
url.username = "";
|
|
56
|
-
url.password = "";
|
|
57
|
-
url.pathname = url.pathname
|
|
58
|
-
.split("/")
|
|
59
|
-
.map((segment) => {
|
|
60
|
-
const decoded = decodeURIComponent(segment);
|
|
61
|
-
const scrubbed = scrubSensitiveText(decoded, apiKey);
|
|
62
|
-
return scrubbed === decoded ? segment : encodeURIComponent(scrubbed);
|
|
63
|
-
})
|
|
64
|
-
.join("/");
|
|
65
|
-
const scrubbedParams = new URLSearchParams();
|
|
66
|
-
for (const [name, value] of url.searchParams) {
|
|
67
|
-
const scrubbedName = scrubSensitiveText(name, apiKey);
|
|
68
|
-
const scrubbedPair = scrubSensitiveText(`${name}=${value}`, apiKey);
|
|
69
|
-
scrubbedParams.append(scrubbedName, scrubbedPair === `${name}=${value}` ? value : "[redacted]");
|
|
70
|
-
}
|
|
71
|
-
url.search = scrubbedParams.toString();
|
|
72
|
-
if (url.hash) {
|
|
73
|
-
const decoded = decodeURIComponent(url.hash.slice(1));
|
|
74
|
-
const scrubbed = scrubSensitiveText(decoded, apiKey);
|
|
75
|
-
if (scrubbed !== decoded) url.hash = encodeURIComponent(scrubbed);
|
|
76
|
-
}
|
|
77
|
-
return scrubSensitiveText(url.href, apiKey).trim() || undefined;
|
|
78
|
-
} catch {
|
|
79
|
-
return undefined;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function formatIntegrationNotConnectedError(
|
|
84
|
-
error: unknown,
|
|
85
|
-
record: Record<string, unknown> | undefined,
|
|
86
|
-
scrubbedMessage: string,
|
|
87
|
-
apiKey: string | undefined,
|
|
88
|
-
): string | undefined {
|
|
89
|
-
if (getErrorName(error, record) !== "IntegrationNotConnectedError") return undefined;
|
|
90
|
-
const provider = scrubSensitiveText(getErrorStringField(record, "provider") ?? "", apiKey).trim();
|
|
91
|
-
if (!provider) return undefined;
|
|
92
|
-
const message = scrubbedMessage || "Cursor Cloud integration is not connected.";
|
|
93
|
-
const punctuation = /[.!?]$/.test(message) ? "" : ".";
|
|
94
|
-
const helpUrl = scrubHttpsHelpUrl(getErrorStringField(record, "helpUrl"), apiKey);
|
|
95
|
-
return `${message}${punctuation} Connect the ${provider} integration${helpUrl ? `: ${helpUrl}` : "."}`;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
47
|
function getErrorStack(error: unknown, record: Record<string, unknown> | undefined): string {
|
|
99
48
|
return error instanceof Error ? error.stack ?? "" : getErrorStringField(record, "stack") ?? "";
|
|
100
49
|
}
|
|
@@ -352,23 +301,14 @@ export function resolveCursorSdkAbortCause(options: {
|
|
|
352
301
|
export function sanitizeCursorProviderError(
|
|
353
302
|
error: unknown,
|
|
354
303
|
apiKey?: string,
|
|
355
|
-
runtimeTarget?: CursorRuntime,
|
|
356
304
|
): string {
|
|
357
305
|
const record = asRecord(error);
|
|
358
306
|
const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
|
|
359
307
|
if (message === MISSING_CURSOR_API_KEY_MESSAGE) return MISSING_CURSOR_API_KEY_MESSAGE;
|
|
360
308
|
const scrubbed = scrubSensitiveText(message, apiKey).trim();
|
|
361
|
-
const integrationMessage = runtimeTarget === "cloud"
|
|
362
|
-
? formatIntegrationNotConnectedError(error, record, scrubbed, apiKey)
|
|
363
|
-
: undefined;
|
|
364
|
-
if (integrationMessage) return integrationMessage;
|
|
365
309
|
const connectClassification = classifyCursorConnectError(error);
|
|
366
|
-
if (
|
|
367
|
-
|
|
368
|
-
connectClassification?.kind === "unauthenticated" ||
|
|
369
|
-
isLikelyAuthError(scrubbed)
|
|
370
|
-
) {
|
|
371
|
-
return runtimeTarget === "cloud" ? CLOUD_AUTH_CURSOR_SDK_ERROR_MESSAGE : AUTH_CURSOR_SDK_ERROR_MESSAGE;
|
|
310
|
+
if (connectClassification?.kind === "unauthenticated" || isLikelyAuthError(scrubbed)) {
|
|
311
|
+
return AUTH_CURSOR_SDK_ERROR_MESSAGE;
|
|
372
312
|
}
|
|
373
313
|
if (connectClassification?.kind === "network" || isCursorSdkConnectionStalledError(error) || isLikelyNetworkTimeout(scrubbed)) return NETWORK_CURSOR_SDK_ERROR_MESSAGE;
|
|
374
314
|
if (isGenericCursorRunFailureMessage(scrubbed)) return RETRYABLE_CURSOR_RUN_FAILURE_PREFIX;
|
|
@@ -196,7 +196,6 @@ function emitCursorNativeToolUseTurn(
|
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
applyCursorUsage(partial, model, context, cursorLiveRuns.takeTurnInputTokens(run, toolResultInputTokens), {
|
|
199
|
-
runtime: "local",
|
|
200
199
|
turn: cursorLiveRuns.takeSdkTurnUsage(run),
|
|
201
200
|
});
|
|
202
201
|
partial.stopReason = "toolUse";
|
|
@@ -244,7 +243,6 @@ function emitCursorBridgeToolUseTurn(
|
|
|
244
243
|
if (block.type === "toolCall") stream.push({ type: "toolcall_end", contentIndex, toolCall: block, partial });
|
|
245
244
|
}
|
|
246
245
|
applyCursorUsage(partial, model, context, cursorLiveRuns.takeTurnInputTokens(run, toolResultInputTokens), {
|
|
247
|
-
runtime: "local",
|
|
248
246
|
turn: cursorLiveRuns.takeSdkTurnUsage(run),
|
|
249
247
|
});
|
|
250
248
|
partial.stopReason = "toolUse";
|
|
@@ -380,7 +378,6 @@ export async function drainCursorLiveRunTurn(
|
|
|
380
378
|
await emitTextDeltas(stream, partial, splitTextIntoReplayDeltas(finalText));
|
|
381
379
|
}
|
|
382
380
|
applyCursorUsage(partial, model, context, cursorLiveRuns.takeTurnInputTokens(run, toolResultInputTokens), {
|
|
383
|
-
runtime: "local",
|
|
384
381
|
turn: cursorLiveRuns.takeSdkTurnUsage(run),
|
|
385
382
|
billed: run.billedTurnUsage,
|
|
386
383
|
});
|