@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
package/dist/cursor-config.js
CHANGED
|
@@ -5,19 +5,6 @@ import { CONFIG_DIR_NAME, getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
|
5
5
|
import { parseOptionalEnvBoolean } from "./cursor-env-boolean.js";
|
|
6
6
|
import { asRecord } from "./cursor-record-utils.js";
|
|
7
7
|
export const CURSOR_SDK_CONFIG_FILE = "cursor-sdk.json";
|
|
8
|
-
export const CURSOR_RUNTIME_ENV = "PI_CURSOR_RUNTIME";
|
|
9
|
-
export const CURSOR_CLOUD_REPO_ENV = "PI_CURSOR_CLOUD_REPO";
|
|
10
|
-
export const CURSOR_CLOUD_BRANCH_ENV = "PI_CURSOR_CLOUD_BRANCH";
|
|
11
|
-
export const CURSOR_CLOUD_CONTEXT_ENV = "PI_CURSOR_CLOUD_CONTEXT";
|
|
12
|
-
export const CURSOR_CLOUD_DIRECT_PUSH_ENV = "PI_CURSOR_CLOUD_DIRECT_PUSH";
|
|
13
|
-
export const CURSOR_CLOUD_AUTO_CREATE_PR_ENV = "PI_CURSOR_CLOUD_AUTO_CREATE_PR";
|
|
14
|
-
export const CURSOR_CLOUD_SKIP_REVIEWER_REQUEST_ENV = "PI_CURSOR_CLOUD_SKIP_REVIEWER_REQUEST";
|
|
15
|
-
export const CURSOR_CLOUD_ALLOW_LOCAL_STATE_ENV = "PI_CURSOR_CLOUD_ALLOW_LOCAL_STATE";
|
|
16
|
-
export const CURSOR_CLOUD_ENV_ENV = "PI_CURSOR_CLOUD_ENV";
|
|
17
|
-
export const CURSOR_CLOUD_ENV_FROM_FILES_ENV = "PI_CURSOR_CLOUD_ENV_FROM_FILES";
|
|
18
|
-
export const CURSOR_CLOUD_ENV_TYPE_ENV = "PI_CURSOR_CLOUD_ENV_TYPE";
|
|
19
|
-
export const CURSOR_CLOUD_ENV_NAME_ENV = "PI_CURSOR_CLOUD_ENV_NAME";
|
|
20
|
-
export const CURSOR_CLOUD_ACK_ENV = "PI_CURSOR_CLOUD_ACK";
|
|
21
8
|
export const CURSOR_AUTO_REVIEW_ENV = "PI_CURSOR_AUTO_REVIEW";
|
|
22
9
|
export const CURSOR_SANDBOX_ENV = "PI_CURSOR_SANDBOX";
|
|
23
10
|
export const CURSOR_LOCAL_FORCE_ENV = "PI_CURSOR_LOCAL_FORCE";
|
|
@@ -32,28 +19,6 @@ const TRUST_LEVELS = {
|
|
|
32
19
|
"model-alias": "model-catalog",
|
|
33
20
|
builtin: "builtin",
|
|
34
21
|
};
|
|
35
|
-
const BUILT_IN_CURSOR_CONFIG = {
|
|
36
|
-
runtime: "local",
|
|
37
|
-
cloud: {
|
|
38
|
-
repo: "",
|
|
39
|
-
branch: "",
|
|
40
|
-
contextHandoff: "fresh",
|
|
41
|
-
directPush: false,
|
|
42
|
-
autoCreatePR: false,
|
|
43
|
-
skipReviewerRequest: false,
|
|
44
|
-
allowLocalState: false,
|
|
45
|
-
envNames: [],
|
|
46
|
-
envFromFiles: false,
|
|
47
|
-
environment: {},
|
|
48
|
-
acknowledged: false,
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
export function isCursorRuntime(value) {
|
|
52
|
-
return value === "local" || value === "cloud";
|
|
53
|
-
}
|
|
54
|
-
export function isCursorCloudContextHandoff(value) {
|
|
55
|
-
return value === "never" || value === "fresh" || value === "bootstrap";
|
|
56
|
-
}
|
|
57
22
|
function validateExplicitValue(raw, name, isValid, validValues) {
|
|
58
23
|
const value = raw?.trim();
|
|
59
24
|
if (!value)
|
|
@@ -62,100 +27,27 @@ function validateExplicitValue(raw, name, isValid, validValues) {
|
|
|
62
27
|
throw new Error(`Invalid ${name} "${value}". Use ${validValues}.`);
|
|
63
28
|
return value;
|
|
64
29
|
}
|
|
65
|
-
export function isCursorCloudEnvironmentType(value) {
|
|
66
|
-
return value === "cloud" || value === "pool" || value === "machine";
|
|
67
|
-
}
|
|
68
30
|
function parseNonEmptyString(value) {
|
|
69
31
|
if (typeof value !== "string")
|
|
70
32
|
return undefined;
|
|
71
33
|
const trimmed = value.trim();
|
|
72
34
|
return trimmed ? trimmed : undefined;
|
|
73
35
|
}
|
|
74
|
-
function isAllowedEnvName(value) {
|
|
75
|
-
return typeof value === "string" && /^[A-Za-z_][A-Za-z0-9_]*$/.test(value) && !value.startsWith("CURSOR_");
|
|
76
|
-
}
|
|
77
36
|
function parseToolNames(value) {
|
|
78
37
|
if (!Array.isArray(value))
|
|
79
38
|
return undefined;
|
|
80
39
|
const parsed = [...new Set(value.map((name) => (typeof name === "string" ? name.trim() : "")).filter((name) => name.length > 0))];
|
|
81
40
|
return parsed.length > 0 ? parsed : undefined;
|
|
82
41
|
}
|
|
83
|
-
function parseEnvNames(value) {
|
|
84
|
-
const names = Array.isArray(value)
|
|
85
|
-
? value
|
|
86
|
-
: typeof value === "string"
|
|
87
|
-
? value.split(",")
|
|
88
|
-
: undefined;
|
|
89
|
-
if (!names)
|
|
90
|
-
return undefined;
|
|
91
|
-
const parsed = [...new Set(names.map((name) => (typeof name === "string" ? name.trim() : "")).filter(isAllowedEnvName))];
|
|
92
|
-
return parsed.length > 0 || (Array.isArray(value) && value.length === 0) ? parsed : undefined;
|
|
93
|
-
}
|
|
94
|
-
export function parseExplicitCursorCloudEnvNames(value, name) {
|
|
95
|
-
const request = parseNonEmptyString(value);
|
|
96
|
-
if (!request)
|
|
97
|
-
return undefined;
|
|
98
|
-
const parsed = parseEnvNames(request);
|
|
99
|
-
if (!parsed?.length)
|
|
100
|
-
throw new Error(`Invalid ${name}: no valid environment variable names were requested.`);
|
|
101
|
-
return parsed;
|
|
102
|
-
}
|
|
103
|
-
function parseCloudEnvironment(value) {
|
|
104
|
-
const environment = asRecord(value);
|
|
105
|
-
if (!environment)
|
|
106
|
-
return undefined;
|
|
107
|
-
const parsed = {};
|
|
108
|
-
const rawType = parseNonEmptyString(environment.type);
|
|
109
|
-
const name = parseNonEmptyString(environment.name);
|
|
110
|
-
if (rawType)
|
|
111
|
-
parsed.type = rawType;
|
|
112
|
-
if (name)
|
|
113
|
-
parsed.name = name;
|
|
114
|
-
return Object.keys(parsed).length > 0 ? parsed : undefined;
|
|
115
|
-
}
|
|
116
42
|
export function parseCursorSdkConfig(value) {
|
|
117
43
|
const record = asRecord(value);
|
|
118
44
|
if (!record)
|
|
119
45
|
return undefined;
|
|
120
46
|
const config = {};
|
|
121
|
-
if (isCursorRuntime(record.runtime))
|
|
122
|
-
config.runtime = record.runtime;
|
|
123
47
|
const fastDefaults = asRecord(record.fastDefaults);
|
|
124
48
|
if (fastDefaults) {
|
|
125
49
|
config.fastDefaults = Object.fromEntries(Object.entries(fastDefaults).filter((entry) => typeof entry[1] === "boolean"));
|
|
126
50
|
}
|
|
127
|
-
const cloud = asRecord(record.cloud);
|
|
128
|
-
if (cloud) {
|
|
129
|
-
const parsedCloud = {};
|
|
130
|
-
const repo = parseNonEmptyString(cloud.repo);
|
|
131
|
-
const branch = parseNonEmptyString(cloud.branch);
|
|
132
|
-
const envNames = parseEnvNames(cloud.envNames);
|
|
133
|
-
const environment = parseCloudEnvironment(cloud.environment);
|
|
134
|
-
if (repo)
|
|
135
|
-
parsedCloud.repo = repo;
|
|
136
|
-
if (branch)
|
|
137
|
-
parsedCloud.branch = branch;
|
|
138
|
-
if (isCursorCloudContextHandoff(cloud.contextHandoff))
|
|
139
|
-
parsedCloud.contextHandoff = cloud.contextHandoff;
|
|
140
|
-
if (typeof cloud.directPush === "boolean")
|
|
141
|
-
parsedCloud.directPush = cloud.directPush;
|
|
142
|
-
if (typeof cloud.autoCreatePR === "boolean")
|
|
143
|
-
parsedCloud.autoCreatePR = cloud.autoCreatePR;
|
|
144
|
-
if (typeof cloud.skipReviewerRequest === "boolean")
|
|
145
|
-
parsedCloud.skipReviewerRequest = cloud.skipReviewerRequest;
|
|
146
|
-
if (typeof cloud.allowLocalState === "boolean")
|
|
147
|
-
parsedCloud.allowLocalState = cloud.allowLocalState;
|
|
148
|
-
if (envNames)
|
|
149
|
-
parsedCloud.envNames = envNames;
|
|
150
|
-
if (typeof cloud.envFromFiles === "boolean")
|
|
151
|
-
parsedCloud.envFromFiles = cloud.envFromFiles;
|
|
152
|
-
if (environment)
|
|
153
|
-
parsedCloud.environment = environment;
|
|
154
|
-
if (typeof cloud.acknowledged === "boolean")
|
|
155
|
-
parsedCloud.acknowledged = cloud.acknowledged;
|
|
156
|
-
if (Object.keys(parsedCloud).length > 0)
|
|
157
|
-
config.cloud = parsedCloud;
|
|
158
|
-
}
|
|
159
51
|
const local = asRecord(record.local);
|
|
160
52
|
if (local) {
|
|
161
53
|
const parsedLocal = {};
|
|
@@ -321,15 +213,11 @@ export function mergeCursorSdkConfig(base, patch) {
|
|
|
321
213
|
return mergeCursorSdkConfigForUpdate({ ...base }, patch);
|
|
322
214
|
}
|
|
323
215
|
export function mergeCursorSdkConfigForUpdate(base, patch) {
|
|
324
|
-
const baseCloud = asRecord(base.cloud);
|
|
325
216
|
const baseLocal = asRecord(base.local);
|
|
326
217
|
const baseSandboxOptions = asRecord(baseLocal?.sandboxOptions);
|
|
327
218
|
return {
|
|
328
219
|
...base,
|
|
329
220
|
...patch,
|
|
330
|
-
...(baseCloud || patch.cloud
|
|
331
|
-
? { cloud: { ...baseCloud, ...patch.cloud } }
|
|
332
|
-
: {}),
|
|
333
221
|
...(baseLocal || patch.local
|
|
334
222
|
? {
|
|
335
223
|
local: {
|
|
@@ -352,8 +240,8 @@ export function withCursorFastDefaults(config, fastDefaults) {
|
|
|
352
240
|
fastDefaults: Object.fromEntries([...fastDefaults.entries()].sort(([a], [b]) => a.localeCompare(b))),
|
|
353
241
|
};
|
|
354
242
|
}
|
|
355
|
-
function resolved(source, value
|
|
356
|
-
return { value, source, trustLevel: TRUST_LEVELS[source]
|
|
243
|
+
function resolved(source, value) {
|
|
244
|
+
return { value, source, trustLevel: TRUST_LEVELS[source] };
|
|
357
245
|
}
|
|
358
246
|
function valueFrom(source, value) {
|
|
359
247
|
return value === undefined ? undefined : resolved(source, value);
|
|
@@ -364,40 +252,6 @@ function resolveOrdinary(layers) {
|
|
|
364
252
|
throw new Error("Cursor config resolver missing built-in default");
|
|
365
253
|
return match;
|
|
366
254
|
}
|
|
367
|
-
// One cap engine for every safety-capped field. `cap` receives the candidate cap layer's raw value and the
|
|
368
|
-
// resolved base setting; it returns the value to use once capped, or undefined to mean "don't cap". CLI is
|
|
369
|
-
// always uncapped (one-shot, explicit operator intent).
|
|
370
|
-
function resolveWithCap(baseLayers, capLayer, cap) {
|
|
371
|
-
const cli = baseLayers[0];
|
|
372
|
-
if (cli)
|
|
373
|
-
return cli;
|
|
374
|
-
const base = resolveOrdinary(baseLayers.slice(1));
|
|
375
|
-
if (!capLayer)
|
|
376
|
-
return base;
|
|
377
|
-
const cappedValue = cap(capLayer.value, base);
|
|
378
|
-
if (cappedValue === undefined)
|
|
379
|
-
return base;
|
|
380
|
-
return resolved(capLayer.source, cappedValue, {
|
|
381
|
-
source: capLayer.source,
|
|
382
|
-
trustLevel: capLayer.trustLevel,
|
|
383
|
-
value: cappedValue,
|
|
384
|
-
cappedSource: base.source,
|
|
385
|
-
cappedValue: base.value,
|
|
386
|
-
reason: "safer-source",
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
|
-
function scalarRiskCap(risk) {
|
|
390
|
-
return (candidate, base) => (risk(candidate) < risk(base.value) ? candidate : undefined);
|
|
391
|
-
}
|
|
392
|
-
function envNamesCap(candidate, base) {
|
|
393
|
-
if (base.source === "user")
|
|
394
|
-
return undefined;
|
|
395
|
-
const allowed = new Set(candidate);
|
|
396
|
-
const filtered = base.value.filter((name) => allowed.has(name));
|
|
397
|
-
return filtered.length === base.value.length ? undefined : filtered;
|
|
398
|
-
}
|
|
399
|
-
const RUNTIME_ORDER = ["cli", "environment", "session", "project", "user", "builtin"];
|
|
400
|
-
const CLOUD_ORDER = ["cli", "environment", "session", "user", "builtin"];
|
|
401
255
|
const LOCAL_ORDER = ["cli", "environment", "project", "user", "builtin"];
|
|
402
256
|
const LOCAL_FORCE_ORDER = ["cli", "environment", "builtin"];
|
|
403
257
|
const HTTP1_ORDER = ["session", "environment", "user", "builtin"];
|
|
@@ -408,56 +262,8 @@ function buildFieldLayers(order, values) {
|
|
|
408
262
|
function resolveOrdinaryField(order, values) {
|
|
409
263
|
return resolveOrdinary(buildFieldLayers(order, values));
|
|
410
264
|
}
|
|
411
|
-
function resolveSafetyField(order, values, risk) {
|
|
412
|
-
return resolveWithCap(buildFieldLayers(order, values), valueFrom("user", values.user), scalarRiskCap(risk));
|
|
413
|
-
}
|
|
414
|
-
function resolveEnvNamesSafetyField(order, values) {
|
|
415
|
-
return resolveWithCap(buildFieldLayers(order, values), valueFrom("user", values.user), envNamesCap);
|
|
416
|
-
}
|
|
417
265
|
export function cursorSdkConfigFromEnv(env = process.env) {
|
|
418
266
|
const config = {};
|
|
419
|
-
const runtime = validateExplicitValue(env[CURSOR_RUNTIME_ENV], CURSOR_RUNTIME_ENV, isCursorRuntime, '"local" or "cloud"');
|
|
420
|
-
if (runtime)
|
|
421
|
-
config.runtime = runtime;
|
|
422
|
-
const repo = parseNonEmptyString(env[CURSOR_CLOUD_REPO_ENV]);
|
|
423
|
-
const branch = parseNonEmptyString(env[CURSOR_CLOUD_BRANCH_ENV]);
|
|
424
|
-
const contextHandoff = validateExplicitValue(env[CURSOR_CLOUD_CONTEXT_ENV], CURSOR_CLOUD_CONTEXT_ENV, isCursorCloudContextHandoff, '"never", "fresh", or "bootstrap"');
|
|
425
|
-
const directPush = parseOptionalEnvBoolean(env[CURSOR_CLOUD_DIRECT_PUSH_ENV]);
|
|
426
|
-
const autoCreatePR = parseOptionalEnvBoolean(env[CURSOR_CLOUD_AUTO_CREATE_PR_ENV]);
|
|
427
|
-
const skipReviewerRequest = parseOptionalEnvBoolean(env[CURSOR_CLOUD_SKIP_REVIEWER_REQUEST_ENV]);
|
|
428
|
-
const allowLocalState = parseOptionalEnvBoolean(env[CURSOR_CLOUD_ALLOW_LOCAL_STATE_ENV]);
|
|
429
|
-
const envNames = parseExplicitCursorCloudEnvNames(env[CURSOR_CLOUD_ENV_ENV], CURSOR_CLOUD_ENV_ENV);
|
|
430
|
-
const envFromFiles = parseOptionalEnvBoolean(env[CURSOR_CLOUD_ENV_FROM_FILES_ENV]);
|
|
431
|
-
const environment = parseCloudEnvironment({
|
|
432
|
-
type: env[CURSOR_CLOUD_ENV_TYPE_ENV],
|
|
433
|
-
name: env[CURSOR_CLOUD_ENV_NAME_ENV],
|
|
434
|
-
});
|
|
435
|
-
const acknowledged = parseOptionalEnvBoolean(env[CURSOR_CLOUD_ACK_ENV]);
|
|
436
|
-
if (repo !== undefined ||
|
|
437
|
-
branch !== undefined ||
|
|
438
|
-
isCursorCloudContextHandoff(contextHandoff) ||
|
|
439
|
-
directPush !== undefined ||
|
|
440
|
-
autoCreatePR !== undefined ||
|
|
441
|
-
skipReviewerRequest !== undefined ||
|
|
442
|
-
allowLocalState !== undefined ||
|
|
443
|
-
envNames !== undefined ||
|
|
444
|
-
envFromFiles !== undefined ||
|
|
445
|
-
environment !== undefined ||
|
|
446
|
-
acknowledged !== undefined) {
|
|
447
|
-
config.cloud = {
|
|
448
|
-
...(repo !== undefined ? { repo } : {}),
|
|
449
|
-
...(branch !== undefined ? { branch } : {}),
|
|
450
|
-
...(isCursorCloudContextHandoff(contextHandoff) ? { contextHandoff } : {}),
|
|
451
|
-
...(directPush !== undefined ? { directPush } : {}),
|
|
452
|
-
...(autoCreatePR !== undefined ? { autoCreatePR } : {}),
|
|
453
|
-
...(skipReviewerRequest !== undefined ? { skipReviewerRequest } : {}),
|
|
454
|
-
...(allowLocalState !== undefined ? { allowLocalState } : {}),
|
|
455
|
-
...(envNames !== undefined ? { envNames } : {}),
|
|
456
|
-
...(envFromFiles !== undefined ? { envFromFiles } : {}),
|
|
457
|
-
...(environment !== undefined ? { environment } : {}),
|
|
458
|
-
...(acknowledged !== undefined ? { acknowledged } : {}),
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
267
|
const autoReview = parseOptionalEnvBoolean(env[CURSOR_AUTO_REVIEW_ENV]);
|
|
462
268
|
const sandbox = parseOptionalEnvBoolean(env[CURSOR_SANDBOX_ENV]);
|
|
463
269
|
const force = parseOptionalEnvBoolean(env[CURSOR_LOCAL_FORCE_ENV]);
|
|
@@ -475,106 +281,12 @@ export function cursorSdkConfigFromEnv(env = process.env) {
|
|
|
475
281
|
return config;
|
|
476
282
|
}
|
|
477
283
|
export function resolveCursorSdkConfig(options = {}) {
|
|
478
|
-
const cliRuntime = validateExplicitValue(options.cli?.runtime, "--cursor-runtime", isCursorRuntime, '"local" or "cloud"');
|
|
479
|
-
const cliContextHandoff = validateExplicitValue(options.cli?.cloud?.contextHandoff, "--cursor-cloud-context", isCursorCloudContextHandoff, '"never", "fresh", or "bootstrap"');
|
|
480
284
|
const env = cursorSdkConfigFromEnv(options.env);
|
|
481
|
-
const builtIn = {
|
|
482
|
-
...BUILT_IN_CURSOR_CONFIG,
|
|
483
|
-
...options.builtIn,
|
|
484
|
-
cloud: { ...BUILT_IN_CURSOR_CONFIG.cloud, ...options.builtIn?.cloud },
|
|
485
|
-
};
|
|
486
285
|
const cli = options.cli;
|
|
487
286
|
const session = options.session;
|
|
488
287
|
const project = options.project;
|
|
489
288
|
const user = options.user;
|
|
490
289
|
return {
|
|
491
|
-
runtime: resolveSafetyField(RUNTIME_ORDER, {
|
|
492
|
-
cli: cliRuntime,
|
|
493
|
-
environment: env.runtime,
|
|
494
|
-
session: session?.runtime,
|
|
495
|
-
project: project?.runtime,
|
|
496
|
-
user: user?.runtime,
|
|
497
|
-
builtin: builtIn.runtime,
|
|
498
|
-
}, (value) => (value === "cloud" ? 1 : 0)),
|
|
499
|
-
cloud: {
|
|
500
|
-
repo: resolveOrdinaryField(CLOUD_ORDER, {
|
|
501
|
-
cli: cli?.cloud?.repo,
|
|
502
|
-
environment: env.cloud?.repo,
|
|
503
|
-
session: session?.cloud?.repo,
|
|
504
|
-
user: user?.cloud?.repo,
|
|
505
|
-
builtin: undefined,
|
|
506
|
-
}),
|
|
507
|
-
branch: resolveOrdinaryField(CLOUD_ORDER, {
|
|
508
|
-
cli: cli?.cloud?.branch,
|
|
509
|
-
environment: env.cloud?.branch,
|
|
510
|
-
session: session?.cloud?.branch,
|
|
511
|
-
user: user?.cloud?.branch,
|
|
512
|
-
builtin: undefined,
|
|
513
|
-
}),
|
|
514
|
-
contextHandoff: resolveSafetyField(CLOUD_ORDER, {
|
|
515
|
-
cli: cliContextHandoff,
|
|
516
|
-
environment: env.cloud?.contextHandoff,
|
|
517
|
-
session: session?.cloud?.contextHandoff,
|
|
518
|
-
user: user?.cloud?.contextHandoff,
|
|
519
|
-
builtin: builtIn.cloud.contextHandoff,
|
|
520
|
-
}, (value) => ({ never: 0, fresh: 1, bootstrap: 2 })[value]),
|
|
521
|
-
directPush: resolveSafetyField(CLOUD_ORDER, {
|
|
522
|
-
cli: cli?.cloud?.directPush,
|
|
523
|
-
environment: env.cloud?.directPush,
|
|
524
|
-
session: session?.cloud?.directPush,
|
|
525
|
-
user: user?.cloud?.directPush,
|
|
526
|
-
builtin: builtIn.cloud.directPush,
|
|
527
|
-
}, (value) => (value ? 1 : 0)),
|
|
528
|
-
autoCreatePR: resolveSafetyField(CLOUD_ORDER, {
|
|
529
|
-
cli: cli?.cloud?.autoCreatePR,
|
|
530
|
-
environment: env.cloud?.autoCreatePR,
|
|
531
|
-
session: session?.cloud?.autoCreatePR,
|
|
532
|
-
user: user?.cloud?.autoCreatePR,
|
|
533
|
-
builtin: builtIn.cloud.autoCreatePR,
|
|
534
|
-
}, (value) => (value ? 1 : 0)),
|
|
535
|
-
skipReviewerRequest: resolveSafetyField(CLOUD_ORDER, {
|
|
536
|
-
cli: cli?.cloud?.skipReviewerRequest,
|
|
537
|
-
environment: env.cloud?.skipReviewerRequest,
|
|
538
|
-
session: session?.cloud?.skipReviewerRequest,
|
|
539
|
-
user: user?.cloud?.skipReviewerRequest,
|
|
540
|
-
builtin: builtIn.cloud.skipReviewerRequest,
|
|
541
|
-
}, (value) => (value ? 1 : 0)),
|
|
542
|
-
allowLocalState: resolveSafetyField(CLOUD_ORDER, {
|
|
543
|
-
cli: cli?.cloud?.allowLocalState,
|
|
544
|
-
environment: env.cloud?.allowLocalState,
|
|
545
|
-
session: session?.cloud?.allowLocalState,
|
|
546
|
-
user: user?.cloud?.allowLocalState,
|
|
547
|
-
builtin: builtIn.cloud.allowLocalState,
|
|
548
|
-
}, (value) => (value ? 1 : 0)),
|
|
549
|
-
envNames: resolveEnvNamesSafetyField(CLOUD_ORDER, {
|
|
550
|
-
cli: cli?.cloud?.envNames,
|
|
551
|
-
environment: env.cloud?.envNames,
|
|
552
|
-
session: session?.cloud?.envNames,
|
|
553
|
-
user: user?.cloud?.envNames,
|
|
554
|
-
builtin: builtIn.cloud.envNames,
|
|
555
|
-
}),
|
|
556
|
-
envFromFiles: resolveSafetyField(CLOUD_ORDER, {
|
|
557
|
-
cli: cli?.cloud?.envFromFiles,
|
|
558
|
-
environment: env.cloud?.envFromFiles,
|
|
559
|
-
session: session?.cloud?.envFromFiles,
|
|
560
|
-
user: user?.cloud?.envFromFiles,
|
|
561
|
-
builtin: builtIn.cloud.envFromFiles,
|
|
562
|
-
}, (value) => (value ? 1 : 0)),
|
|
563
|
-
environment: resolveOrdinaryField(CLOUD_ORDER, {
|
|
564
|
-
cli: cli?.cloud?.environment,
|
|
565
|
-
environment: env.cloud?.environment,
|
|
566
|
-
session: session?.cloud?.environment,
|
|
567
|
-
user: user?.cloud?.environment,
|
|
568
|
-
builtin: undefined,
|
|
569
|
-
}),
|
|
570
|
-
acknowledged: resolveOrdinaryField(CLOUD_ORDER, {
|
|
571
|
-
cli: cli?.cloud?.acknowledged,
|
|
572
|
-
environment: env.cloud?.acknowledged,
|
|
573
|
-
session: session?.cloud?.acknowledged,
|
|
574
|
-
user: user?.cloud?.acknowledged,
|
|
575
|
-
builtin: builtIn.cloud.acknowledged,
|
|
576
|
-
}),
|
|
577
|
-
},
|
|
578
290
|
local: {
|
|
579
291
|
autoReview: resolveOrdinaryField(LOCAL_ORDER, {
|
|
580
292
|
cli: cli?.local?.autoReview,
|
|
@@ -3,7 +3,6 @@ import { scrubSensitiveText } from "./cursor-sensitive-text.js";
|
|
|
3
3
|
export const MISSING_CURSOR_API_KEY_MESSAGE = "Cursor SDK runs require a Cursor SDK API key. Cursor Agent CLI/Desktop login is not reused. Run /login -> Use an API key -> Cursor, set CURSOR_API_KEY before starting pi, or restart pi with --api-key.";
|
|
4
4
|
const GENERIC_CURSOR_SDK_ERROR_MESSAGE = "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.";
|
|
5
5
|
const AUTH_CURSOR_SDK_ERROR_MESSAGE = "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.";
|
|
6
|
-
const CLOUD_AUTH_CURSOR_SDK_ERROR_MESSAGE = "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.";
|
|
7
6
|
// Keep "Network error" aligned with pi's agent-level retry classifier.
|
|
8
7
|
const NETWORK_CURSOR_SDK_ERROR_MESSAGE = "Network error: Cursor SDK request failed during network or service I/O. Check your connection; pi will retry automatically when auto-retry is enabled.";
|
|
9
8
|
// Keep this phrase aligned with pi's agent-level retry classifier (`provider.?returned.?error`).
|
|
@@ -29,53 +28,6 @@ function getErrorStringField(record, key) {
|
|
|
29
28
|
function getErrorName(error, record) {
|
|
30
29
|
return error instanceof Error ? error.name : getErrorStringField(record, "name");
|
|
31
30
|
}
|
|
32
|
-
function scrubHttpsHelpUrl(helpUrl, apiKey) {
|
|
33
|
-
if (!helpUrl)
|
|
34
|
-
return undefined;
|
|
35
|
-
try {
|
|
36
|
-
const url = new URL(helpUrl);
|
|
37
|
-
if (url.protocol !== "https:")
|
|
38
|
-
return undefined;
|
|
39
|
-
url.username = "";
|
|
40
|
-
url.password = "";
|
|
41
|
-
url.pathname = url.pathname
|
|
42
|
-
.split("/")
|
|
43
|
-
.map((segment) => {
|
|
44
|
-
const decoded = decodeURIComponent(segment);
|
|
45
|
-
const scrubbed = scrubSensitiveText(decoded, apiKey);
|
|
46
|
-
return scrubbed === decoded ? segment : encodeURIComponent(scrubbed);
|
|
47
|
-
})
|
|
48
|
-
.join("/");
|
|
49
|
-
const scrubbedParams = new URLSearchParams();
|
|
50
|
-
for (const [name, value] of url.searchParams) {
|
|
51
|
-
const scrubbedName = scrubSensitiveText(name, apiKey);
|
|
52
|
-
const scrubbedPair = scrubSensitiveText(`${name}=${value}`, apiKey);
|
|
53
|
-
scrubbedParams.append(scrubbedName, scrubbedPair === `${name}=${value}` ? value : "[redacted]");
|
|
54
|
-
}
|
|
55
|
-
url.search = scrubbedParams.toString();
|
|
56
|
-
if (url.hash) {
|
|
57
|
-
const decoded = decodeURIComponent(url.hash.slice(1));
|
|
58
|
-
const scrubbed = scrubSensitiveText(decoded, apiKey);
|
|
59
|
-
if (scrubbed !== decoded)
|
|
60
|
-
url.hash = encodeURIComponent(scrubbed);
|
|
61
|
-
}
|
|
62
|
-
return scrubSensitiveText(url.href, apiKey).trim() || undefined;
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
return undefined;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
function formatIntegrationNotConnectedError(error, record, scrubbedMessage, apiKey) {
|
|
69
|
-
if (getErrorName(error, record) !== "IntegrationNotConnectedError")
|
|
70
|
-
return undefined;
|
|
71
|
-
const provider = scrubSensitiveText(getErrorStringField(record, "provider") ?? "", apiKey).trim();
|
|
72
|
-
if (!provider)
|
|
73
|
-
return undefined;
|
|
74
|
-
const message = scrubbedMessage || "Cursor Cloud integration is not connected.";
|
|
75
|
-
const punctuation = /[.!?]$/.test(message) ? "" : ".";
|
|
76
|
-
const helpUrl = scrubHttpsHelpUrl(getErrorStringField(record, "helpUrl"), apiKey);
|
|
77
|
-
return `${message}${punctuation} Connect the ${provider} integration${helpUrl ? `: ${helpUrl}` : "."}`;
|
|
78
|
-
}
|
|
79
31
|
function getErrorStack(error, record) {
|
|
80
32
|
return error instanceof Error ? error.stack ?? "" : getErrorStringField(record, "stack") ?? "";
|
|
81
33
|
}
|
|
@@ -284,22 +236,15 @@ export function resolveCursorSdkAbortCause(options) {
|
|
|
284
236
|
return "live_run_disposed";
|
|
285
237
|
return "unknown";
|
|
286
238
|
}
|
|
287
|
-
export function sanitizeCursorProviderError(error, apiKey
|
|
239
|
+
export function sanitizeCursorProviderError(error, apiKey) {
|
|
288
240
|
const record = asRecord(error);
|
|
289
241
|
const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
|
|
290
242
|
if (message === MISSING_CURSOR_API_KEY_MESSAGE)
|
|
291
243
|
return MISSING_CURSOR_API_KEY_MESSAGE;
|
|
292
244
|
const scrubbed = scrubSensitiveText(message, apiKey).trim();
|
|
293
|
-
const integrationMessage = runtimeTarget === "cloud"
|
|
294
|
-
? formatIntegrationNotConnectedError(error, record, scrubbed, apiKey)
|
|
295
|
-
: undefined;
|
|
296
|
-
if (integrationMessage)
|
|
297
|
-
return integrationMessage;
|
|
298
245
|
const connectClassification = classifyCursorConnectError(error);
|
|
299
|
-
if (
|
|
300
|
-
|
|
301
|
-
isLikelyAuthError(scrubbed)) {
|
|
302
|
-
return runtimeTarget === "cloud" ? CLOUD_AUTH_CURSOR_SDK_ERROR_MESSAGE : AUTH_CURSOR_SDK_ERROR_MESSAGE;
|
|
246
|
+
if (connectClassification?.kind === "unauthenticated" || isLikelyAuthError(scrubbed)) {
|
|
247
|
+
return AUTH_CURSOR_SDK_ERROR_MESSAGE;
|
|
303
248
|
}
|
|
304
249
|
if (connectClassification?.kind === "network" || isCursorSdkConnectionStalledError(error) || isLikelyNetworkTimeout(scrubbed))
|
|
305
250
|
return NETWORK_CURSOR_SDK_ERROR_MESSAGE;
|
|
@@ -141,7 +141,6 @@ function emitCursorNativeToolUseTurn(stream, partial, model, context, run, toolR
|
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
applyCursorUsage(partial, model, context, cursorLiveRuns.takeTurnInputTokens(run, toolResultInputTokens), {
|
|
144
|
-
runtime: "local",
|
|
145
144
|
turn: cursorLiveRuns.takeSdkTurnUsage(run),
|
|
146
145
|
});
|
|
147
146
|
partial.stopReason = "toolUse";
|
|
@@ -177,7 +176,6 @@ function emitCursorBridgeToolUseTurn(stream, partial, model, context, run, toolR
|
|
|
177
176
|
stream.push({ type: "toolcall_end", contentIndex, toolCall: block, partial });
|
|
178
177
|
}
|
|
179
178
|
applyCursorUsage(partial, model, context, cursorLiveRuns.takeTurnInputTokens(run, toolResultInputTokens), {
|
|
180
|
-
runtime: "local",
|
|
181
179
|
turn: cursorLiveRuns.takeSdkTurnUsage(run),
|
|
182
180
|
});
|
|
183
181
|
partial.stopReason = "toolUse";
|
|
@@ -293,7 +291,6 @@ export async function drainCursorLiveRunTurn(stream, partial, model, context, ru
|
|
|
293
291
|
await emitTextDeltas(stream, partial, splitTextIntoReplayDeltas(finalText));
|
|
294
292
|
}
|
|
295
293
|
applyCursorUsage(partial, model, context, cursorLiveRuns.takeTurnInputTokens(run, toolResultInputTokens), {
|
|
296
|
-
runtime: "local",
|
|
297
294
|
turn: cursorLiveRuns.takeSdkTurnUsage(run),
|
|
298
295
|
billed: run.billedTurnUsage,
|
|
299
296
|
});
|
|
@@ -58,7 +58,7 @@ export class CursorRunFinalizer {
|
|
|
58
58
|
.catch((error) => {
|
|
59
59
|
this.safeCleanup(() => discardIncompleteTools({ status: "error" }));
|
|
60
60
|
if (!liveRun.disposed) {
|
|
61
|
-
cursorLiveRuns.markError(liveRun, sanitizeCursorProviderError(error, this.params.resolvedApiKey() ?? runnerParams.options?.apiKey
|
|
61
|
+
cursorLiveRuns.markError(liveRun, sanitizeCursorProviderError(error, this.params.resolvedApiKey() ?? runnerParams.options?.apiKey));
|
|
62
62
|
}
|
|
63
63
|
this.safeCleanup(() => sdkEventDebug?.recordWaitResult({ status: "error", error: String(error) }));
|
|
64
64
|
this.safeCleanup(() => sdkEventDebug?.recordError("run_wait", error));
|
|
@@ -72,7 +72,7 @@ export class CursorRunFinalizer {
|
|
|
72
72
|
if (this.terminalApplied)
|
|
73
73
|
return;
|
|
74
74
|
if (event.kind === "direct") {
|
|
75
|
-
await this.applyDirectOutcome(event.prepared, event.outcome
|
|
75
|
+
await this.applyDirectOutcome(event.prepared, event.outcome);
|
|
76
76
|
this.terminalApplied = true;
|
|
77
77
|
return;
|
|
78
78
|
}
|
|
@@ -99,7 +99,7 @@ export class CursorRunFinalizer {
|
|
|
99
99
|
await this.finalizeSdkEventDebugBestEffort();
|
|
100
100
|
this.safeCleanup(() => this.params.sdkProcessErrorGuard.dispose());
|
|
101
101
|
}
|
|
102
|
-
async applyDirectOutcome(prepared, outcome
|
|
102
|
+
async applyDirectOutcome(prepared, outcome) {
|
|
103
103
|
const { stream, partial, model, context } = this.params.runnerParams;
|
|
104
104
|
prepared.runtime.turnCoordinator.closeTraceBlock();
|
|
105
105
|
switch (classifyCursorRunEmission(outcome)) {
|
|
@@ -115,14 +115,11 @@ export class CursorRunFinalizer {
|
|
|
115
115
|
prepared.lifecycle.commitSend(context, prepared.meta.bootstrap);
|
|
116
116
|
prepared.runtime.turnCoordinator.flushText(outcome.kind === "finished" && hasUsableText(outcome.finalText) ? [outcome.finalText] : []);
|
|
117
117
|
applyCursorUsage(partial, model, context, prepared.meta.promptInputTokens, {
|
|
118
|
-
runtime: prepared.runtimeTarget,
|
|
119
118
|
turn: prepared.runtime.turnCoordinator.lastSdkTurnUsage,
|
|
120
119
|
billed: prepared.runtime.billedTurnUsage,
|
|
121
120
|
});
|
|
122
121
|
if (prepared.meta.resumeNotice)
|
|
123
122
|
emitDisplayOnlyTraceBlock(stream, partial, prepared.meta.resumeNotice);
|
|
124
|
-
if (displayOnlyTraceBlock)
|
|
125
|
-
emitDisplayOnlyTraceBlock(stream, partial, displayOnlyTraceBlock);
|
|
126
123
|
stream.push({ type: "done", reason: "stop", message: partial });
|
|
127
124
|
break;
|
|
128
125
|
}
|
|
@@ -145,7 +142,7 @@ export class CursorRunFinalizer {
|
|
|
145
142
|
this.pushTerminalError(this.params.runnerParams.partial, "aborted", this.abortMessage());
|
|
146
143
|
}
|
|
147
144
|
else {
|
|
148
|
-
this.pushTerminalError(this.params.runnerParams.partial, "error", sanitizeCursorProviderError(error, this.params.resolvedApiKey() ?? this.params.runnerParams.options?.apiKey
|
|
145
|
+
this.pushTerminalError(this.params.runnerParams.partial, "error", sanitizeCursorProviderError(error, this.params.resolvedApiKey() ?? this.params.runnerParams.options?.apiKey));
|
|
149
146
|
}
|
|
150
147
|
}
|
|
151
148
|
pushTerminalError(partial, reason, message) {
|
|
@@ -42,7 +42,7 @@ export function resolveCursorRunOutcome(params) {
|
|
|
42
42
|
status: "error",
|
|
43
43
|
assistantTextProduced: false,
|
|
44
44
|
}),
|
|
45
|
-
errorMessage: sanitizeCursorProviderError(failureDetail, params.resolvedApiKey ?? params.optionsApiKey
|
|
45
|
+
errorMessage: sanitizeCursorProviderError(failureDetail, params.resolvedApiKey ?? params.optionsApiKey),
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
48
|
const assistantTextProduced = hasCursorAssistantText(waitResult.result, params.textDeltas, params.planTextCandidate);
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { loadCursorTranscriptWebToolCallsAfterOffset } from "./cursor-agent-message-web-tools.js";
|
|
2
|
-
import { collectCursorCloudRunReport, formatCursorCloudRunReport, } from "./cursor-cloud-reporting.js";
|
|
3
|
-
import { recordCursorCloudLifecycleRun } from "./cursor-cloud-lifecycle.js";
|
|
4
2
|
import { getCheckpointContextWindow, saveCachedContextWindow } from "./context-window-cache.js";
|
|
5
|
-
import { scrubSensitiveText } from "./cursor-sensitive-text.js";
|
|
6
3
|
import { isCursorRunFinishedSuccessfully, resolveCursorRunOutcome, } from "./cursor-provider-run-outcome.js";
|
|
7
4
|
import { loadCursorSdk } from "./cursor-sdk-runtime.js";
|
|
8
5
|
import { attachCursorSdkBilledTurnUsage } from "./cursor-sdk-billed-usage.js";
|
|
@@ -39,7 +36,6 @@ export function buildCursorRunOutcomeFromWait(params) {
|
|
|
39
36
|
runErrorFallback: params.runErrorFallback,
|
|
40
37
|
resolvedApiKey: params.resolvedApiKey,
|
|
41
38
|
optionsApiKey: params.optionsApiKey,
|
|
42
|
-
runtimeTarget: prepared.runtimeTarget,
|
|
43
39
|
});
|
|
44
40
|
}
|
|
45
41
|
async function replayCursorTranscriptWebToolCalls(agentId, cwd, messageOffset, turnStore, turnCoordinator, sdkEventDebug) {
|
|
@@ -63,20 +59,8 @@ async function replayCursorTranscriptWebToolCalls(agentId, cwd, messageOffset, t
|
|
|
63
59
|
sdkEventDebug?.recordError("cursor_transcript_web_tools", error);
|
|
64
60
|
}
|
|
65
61
|
}
|
|
66
|
-
function scrubCursorCloudReportingError(error, apiKey) {
|
|
67
|
-
return new Error(scrubSensitiveText(error instanceof Error ? error.message : String(error), apiKey));
|
|
68
|
-
}
|
|
69
|
-
function recordCursorCloudReportingError(sdkEventDebug, error, apiKey) {
|
|
70
|
-
try {
|
|
71
|
-
sdkEventDebug?.recordError("cloud_run_report", scrubCursorCloudReportingError(error, apiKey));
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
// Debug reporting must never affect provider execution.
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
62
|
/** Single wait/finalize path for SDK runs: wait, debug capture, transcript replay, incomplete tools, artifacts, context cache. */
|
|
78
63
|
export async function awaitFinalizeCursorRunOutcome(params) {
|
|
79
|
-
const apiKey = params.resolvedApiKey ?? params.optionsApiKey;
|
|
80
64
|
const waitResult = params.waitResult ?? (await params.run.wait());
|
|
81
65
|
const outcome = buildCursorRunOutcomeFromWait({
|
|
82
66
|
waitResult,
|
|
@@ -90,54 +74,18 @@ export async function awaitFinalizeCursorRunOutcome(params) {
|
|
|
90
74
|
const billed = await attachCursorSdkBilledTurnUsage({
|
|
91
75
|
agent: params.prepared.agent,
|
|
92
76
|
agentId: params.run.agentId,
|
|
93
|
-
runtime: params.prepared.runtimeTarget,
|
|
94
|
-
runId: params.run.id,
|
|
95
77
|
});
|
|
96
78
|
params.prepared.runtime.billedTurnUsage = billed.turn;
|
|
97
79
|
if (params.prepared.runtime.liveRun) {
|
|
98
80
|
params.prepared.runtime.liveRun.billedTurnUsage = billed.turn;
|
|
99
81
|
}
|
|
100
|
-
let displayOnlyTraceBlock;
|
|
101
|
-
if (params.prepared.runtimeTarget === "cloud" && isCursorRunFinishedSuccessfully(outcome)) {
|
|
102
|
-
let report = { agentId: params.run.agentId, runId: params.run.id, branches: [] };
|
|
103
|
-
try {
|
|
104
|
-
report = await collectCursorCloudRunReport({
|
|
105
|
-
agent: params.prepared.agent,
|
|
106
|
-
run: params.run,
|
|
107
|
-
waitResult,
|
|
108
|
-
apiKey,
|
|
109
|
-
agentUsage: billed.agentUsage,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
catch (error) {
|
|
113
|
-
recordCursorCloudReportingError(params.sdkEventDebug, error, apiKey);
|
|
114
|
-
}
|
|
115
|
-
try {
|
|
116
|
-
recordCursorCloudLifecycleRun(report, { apiKey });
|
|
117
|
-
}
|
|
118
|
-
catch (error) {
|
|
119
|
-
recordCursorCloudReportingError(params.sdkEventDebug, error, apiKey);
|
|
120
|
-
}
|
|
121
|
-
try {
|
|
122
|
-
params.sdkEventDebug?.recordProviderEvent("cloud_run_report", report);
|
|
123
|
-
}
|
|
124
|
-
catch (error) {
|
|
125
|
-
recordCursorCloudReportingError(params.sdkEventDebug, error, apiKey);
|
|
126
|
-
}
|
|
127
|
-
try {
|
|
128
|
-
displayOnlyTraceBlock = formatCursorCloudRunReport(report, { apiKey });
|
|
129
|
-
}
|
|
130
|
-
catch (error) {
|
|
131
|
-
recordCursorCloudReportingError(params.sdkEventDebug, error, apiKey);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
82
|
try {
|
|
135
83
|
params.sdkEventDebug?.recordWaitResult(waitResult);
|
|
136
84
|
}
|
|
137
85
|
catch {
|
|
138
86
|
// Debug reporting must never affect provider execution.
|
|
139
87
|
}
|
|
140
|
-
if (
|
|
88
|
+
if (isCursorRunFinishedSuccessfully(outcome)) {
|
|
141
89
|
await replayCursorTranscriptWebToolCalls(params.run.agentId, params.prepared.cwd, params.cursorAgentMessageOffset, params.prepared.sessionAgentLease.store, params.prepared.runtime.turnCoordinator, params.sdkEventDebug);
|
|
142
90
|
}
|
|
143
91
|
params.prepared.runtime.turnCoordinator.discardIncompleteStartedToolCalls(outcome.incompleteTools);
|
|
@@ -147,8 +95,8 @@ export async function awaitFinalizeCursorRunOutcome(params) {
|
|
|
147
95
|
catch {
|
|
148
96
|
// Debug artifact failures must never affect provider execution.
|
|
149
97
|
}
|
|
150
|
-
if (params.
|
|
98
|
+
if (params.cacheContextWindow !== false) {
|
|
151
99
|
await cacheSdkContextWindow(params.contextWindowAgentId ?? params.run.agentId, params.modelId, params.prepared.cwd, params.prepared.sessionAgentLease.store);
|
|
152
100
|
}
|
|
153
|
-
return { outcome
|
|
101
|
+
return { outcome };
|
|
154
102
|
}
|