pi-cursor-sdk 0.1.60 → 0.1.61
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 +27 -0
- package/README.md +123 -9
- package/docs/cursor-model-ux-spec.md +19 -11
- package/docs/cursor-native-tool-replay.md +4 -2
- package/docs/cursor-tool-surfaces.md +7 -1
- package/docs/platform-smoke.md +51 -20
- package/package.json +13 -2
- package/platform-smoke.config.mjs +1 -0
- package/scripts/cloud-runtime-smoke.d.mts +40 -1
- package/scripts/cloud-runtime-smoke.mjs +444 -325
- package/scripts/lib/cloud-smoke-artifacts.d.mts +16 -0
- package/scripts/lib/cloud-smoke-artifacts.mjs +94 -0
- package/scripts/lib/cloud-smoke-cleanup-evidence.d.mts +209 -0
- package/scripts/lib/cloud-smoke-cleanup-evidence.mjs +585 -0
- package/scripts/lib/cloud-smoke-github.d.mts +78 -0
- package/scripts/lib/cloud-smoke-github.mjs +331 -0
- package/scripts/lib/cloud-smoke-pi-runner.d.mts +42 -0
- package/scripts/lib/cloud-smoke-pi-runner.mjs +214 -0
- package/scripts/lib/cloud-smoke-shutdown.d.mts +67 -0
- package/scripts/lib/cloud-smoke-shutdown.mjs +133 -0
- package/scripts/lib/local-resume-smoke-harness.mjs +2 -0
- package/scripts/local-resume-cleanup-smoke.mjs +11 -2
- package/scripts/platform-smoke/card-detect.mjs +1 -0
- package/scripts/platform-smoke/scenarios.d.mts +22 -0
- package/scripts/platform-smoke/scenarios.mjs +17 -0
- package/scripts/platform-smoke/targets.mjs +1 -0
- package/src/cursor-agent-message-web-tools.ts +14 -6
- package/src/cursor-cloud-local-state.ts +536 -0
- package/src/cursor-cloud-options.ts +46 -70
- package/src/cursor-config.ts +160 -14
- package/src/cursor-http1.ts +65 -0
- package/src/cursor-live-run-coordinator.ts +8 -1
- package/src/cursor-pi-tool-bridge-abort.ts +10 -3
- package/src/cursor-pi-tool-bridge-constants.ts +6 -0
- package/src/cursor-pi-tool-bridge-env.ts +9 -0
- package/src/cursor-pi-tool-bridge-run.ts +27 -5
- package/src/cursor-pi-tool-bridge.ts +11 -2
- package/src/cursor-provider-errors.ts +72 -2
- package/src/cursor-provider-live-run-drain.ts +2 -1
- package/src/cursor-provider-run-finalizer.ts +8 -2
- package/src/cursor-provider-run-outcome.ts +7 -1
- package/src/cursor-provider-turn-finalize.ts +23 -4
- package/src/cursor-provider-turn-prepare.ts +17 -3
- package/src/cursor-provider-turn-runner.ts +5 -0
- package/src/cursor-provider-turn-send.ts +1 -1
- package/src/cursor-question-tool.ts +8 -0
- package/src/cursor-ripgrep-path.ts +32 -0
- package/src/cursor-runtime-state.ts +119 -100
- package/src/cursor-sdk-process-error-guard.ts +19 -0
- package/src/cursor-session-agent-cleanup.ts +66 -15
- package/src/cursor-session-agent-lifecycle.ts +9 -4
- package/src/cursor-session-agent-resume.ts +50 -7
- package/src/cursor-session-agent.ts +106 -67
- package/src/cursor-session-scope.ts +22 -2
- package/src/cursor-session-store.ts +155 -0
- package/src/cursor-state.ts +162 -21
package/src/cursor-state.ts
CHANGED
|
@@ -6,6 +6,14 @@ import {
|
|
|
6
6
|
resolveCursorToolManifestEnabled,
|
|
7
7
|
} from "./cursor-tool-manifest.js";
|
|
8
8
|
import { runCursorSessionAgentCleanupCommand } from "./cursor-session-agent-cleanup.js";
|
|
9
|
+
import {
|
|
10
|
+
CURSOR_HTTP1_ENTRY_TYPE,
|
|
11
|
+
getStoredCursorHttp1Enabled,
|
|
12
|
+
isCursorHttp1EntryData,
|
|
13
|
+
setCursorHttp1GlobalPreferenceAuthoritative,
|
|
14
|
+
setStoredCursorHttp1Enabled,
|
|
15
|
+
type CursorHttp1EntryData,
|
|
16
|
+
} from "./cursor-http1.js";
|
|
9
17
|
import {
|
|
10
18
|
buildCursorPiToolBridgeSnapshot,
|
|
11
19
|
CURSOR_PI_TOOL_BRIDGE_ENV,
|
|
@@ -26,10 +34,9 @@ import {
|
|
|
26
34
|
cursorFastDefaultsFromConfig,
|
|
27
35
|
getCursorSdkUserConfigPath,
|
|
28
36
|
loadCursorSdkUserConfig,
|
|
37
|
+
mergeCursorSdkConfigForUpdate,
|
|
29
38
|
resolveCursorFastDefault,
|
|
30
|
-
|
|
31
|
-
withCursorFastDefaults,
|
|
32
|
-
type CursorSdkConfig,
|
|
39
|
+
updateCursorSdkConfig,
|
|
33
40
|
} from "./cursor-config.js";
|
|
34
41
|
import {
|
|
35
42
|
consumeCursorLocalForceOverride,
|
|
@@ -79,6 +86,7 @@ type CursorCliModeState =
|
|
|
79
86
|
| { kind: "invalid"; raw: string; message: string };
|
|
80
87
|
|
|
81
88
|
const sessionFastPreferences = new Map<string, boolean>();
|
|
89
|
+
const authoritativeGlobalFastPreferenceIds = new Set<string>();
|
|
82
90
|
let globalFastPreferences = new Map<string, boolean>();
|
|
83
91
|
let cliForceFast = false;
|
|
84
92
|
let cliForceNoFast = false;
|
|
@@ -118,9 +126,30 @@ function loadGlobalFastPreferences(): Map<string, boolean> {
|
|
|
118
126
|
return cursorFastDefaultsFromConfig(loadCursorSdkUserConfig());
|
|
119
127
|
}
|
|
120
128
|
|
|
121
|
-
function
|
|
122
|
-
|
|
123
|
-
|
|
129
|
+
function saveGlobalFastPreference(modelId: string, fast: boolean): void {
|
|
130
|
+
updateCursorSdkConfig(
|
|
131
|
+
getConfigPath(),
|
|
132
|
+
(current) => {
|
|
133
|
+
const fastDefaults = { ...asRecord(current.fastDefaults), [modelId]: fast };
|
|
134
|
+
return {
|
|
135
|
+
...current,
|
|
136
|
+
fastDefaults: Object.fromEntries(
|
|
137
|
+
Object.entries(fastDefaults).sort(([a], [b]) => a.localeCompare(b)),
|
|
138
|
+
),
|
|
139
|
+
};
|
|
140
|
+
},
|
|
141
|
+
{ newFileMode: 0o600 },
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function saveGlobalCursorHttp1Enabled(enabled: boolean): void {
|
|
146
|
+
updateCursorSdkConfig(
|
|
147
|
+
getConfigPath(),
|
|
148
|
+
(current) => mergeCursorSdkConfigForUpdate(current, {
|
|
149
|
+
local: { useHttp1ForAgent: enabled },
|
|
150
|
+
}),
|
|
151
|
+
{ newFileMode: 0o600 },
|
|
152
|
+
);
|
|
124
153
|
}
|
|
125
154
|
|
|
126
155
|
function restoreSessionFastPreferences(branch: readonly SessionEntry[]): void {
|
|
@@ -149,6 +178,17 @@ function restoreSessionCursorPreferences(ctx: { sessionManager: Pick<ExtensionCo
|
|
|
149
178
|
restoreSessionCursorRuntimeState(branch);
|
|
150
179
|
restoreSessionFastPreferences(branch);
|
|
151
180
|
restoreSessionCursorMode(branch);
|
|
181
|
+
restoreSessionCursorHttp1(branch);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function restoreSessionCursorHttp1(branch: readonly SessionEntry[]): void {
|
|
185
|
+
setStoredCursorHttp1Enabled(undefined);
|
|
186
|
+
for (const entry of branch) {
|
|
187
|
+
if (entry.type !== "custom" || entry.customType !== CURSOR_HTTP1_ENTRY_TYPE) continue;
|
|
188
|
+
if (isCursorHttp1EntryData(entry.data)) {
|
|
189
|
+
setStoredCursorHttp1Enabled(entry.data.enabled);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
152
192
|
}
|
|
153
193
|
|
|
154
194
|
function getFastPreferenceModelId(metadata: NonNullable<ReturnType<typeof getCursorModelMetadata>>): string {
|
|
@@ -174,7 +214,9 @@ function getEffectiveFast(modelId: string): boolean | undefined {
|
|
|
174
214
|
cliForceNoFast,
|
|
175
215
|
cliForceFast,
|
|
176
216
|
aliasOverride: metadata.fastOverride,
|
|
177
|
-
sessionValue:
|
|
217
|
+
sessionValue: authoritativeGlobalFastPreferenceIds.has(getFastPreferenceModelId(metadata))
|
|
218
|
+
? undefined
|
|
219
|
+
: getMapFastPreference(sessionFastPreferences, metadata),
|
|
178
220
|
userValue: getMapFastPreference(globalFastPreferences, metadata),
|
|
179
221
|
modelDefault: metadata.defaultFast,
|
|
180
222
|
}).value;
|
|
@@ -226,7 +268,10 @@ function updateCursorStatus(ctx: CursorStatusContext & Pick<ExtensionContext, "m
|
|
|
226
268
|
}
|
|
227
269
|
const runtime = resolution.runtime.value;
|
|
228
270
|
const fast = runtime === "cloud" ? undefined : metadata?.supportsFast ? getEffectiveFast(model.id) : undefined;
|
|
229
|
-
ctx.ui.setStatus(
|
|
271
|
+
ctx.ui.setStatus(
|
|
272
|
+
"cursor",
|
|
273
|
+
formatCursorStatus(runtime, fast, mode, resolution.useHttp1ForAgent.value),
|
|
274
|
+
);
|
|
230
275
|
}
|
|
231
276
|
|
|
232
277
|
function getCurrentCursorMetadata(ctx: Pick<ExtensionContext, "model">) {
|
|
@@ -243,28 +288,30 @@ function restoreMapValue(map: Map<string, boolean>, key: string, previous: boole
|
|
|
243
288
|
}
|
|
244
289
|
}
|
|
245
290
|
|
|
246
|
-
function persistFastPreference(
|
|
291
|
+
function persistFastPreference(
|
|
292
|
+
pi: Pick<ExtensionAPI, "appendEntry">,
|
|
293
|
+
modelId: string,
|
|
294
|
+
fast: boolean,
|
|
295
|
+
): unknown | undefined {
|
|
247
296
|
const previousSession = sessionFastPreferences.get(modelId);
|
|
248
297
|
const previousGlobal = globalFastPreferences.get(modelId);
|
|
249
|
-
let savedGlobal = false;
|
|
250
298
|
sessionFastPreferences.set(modelId, fast);
|
|
251
299
|
globalFastPreferences.set(modelId, fast);
|
|
252
300
|
try {
|
|
253
|
-
|
|
254
|
-
savedGlobal = true;
|
|
255
|
-
pi.appendEntry<CursorFastEntryData>(FAST_ENTRY_TYPE, { modelId, fast });
|
|
301
|
+
saveGlobalFastPreference(modelId, fast);
|
|
256
302
|
} catch (error) {
|
|
257
303
|
restoreMapValue(sessionFastPreferences, modelId, previousSession);
|
|
258
304
|
restoreMapValue(globalFastPreferences, modelId, previousGlobal);
|
|
259
|
-
if (savedGlobal) {
|
|
260
|
-
try {
|
|
261
|
-
saveGlobalFastPreferences();
|
|
262
|
-
} catch {
|
|
263
|
-
// Preserve the original append failure reported to the user.
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
305
|
throw error;
|
|
267
306
|
}
|
|
307
|
+
try {
|
|
308
|
+
pi.appendEntry<CursorFastEntryData>(FAST_ENTRY_TYPE, { modelId, fast });
|
|
309
|
+
authoritativeGlobalFastPreferenceIds.delete(modelId);
|
|
310
|
+
return undefined;
|
|
311
|
+
} catch (error) {
|
|
312
|
+
authoritativeGlobalFastPreferenceIds.add(modelId);
|
|
313
|
+
return error;
|
|
314
|
+
}
|
|
268
315
|
}
|
|
269
316
|
|
|
270
317
|
function persistCursorModePreference(pi: Pick<ExtensionAPI, "appendEntry">, mode: AgentModeOption): void {
|
|
@@ -278,6 +325,28 @@ function persistCursorModePreference(pi: Pick<ExtensionAPI, "appendEntry">, mode
|
|
|
278
325
|
}
|
|
279
326
|
}
|
|
280
327
|
|
|
328
|
+
function persistCursorHttp1Preference(
|
|
329
|
+
pi: Pick<ExtensionAPI, "appendEntry">,
|
|
330
|
+
enabled: boolean,
|
|
331
|
+
): unknown | undefined {
|
|
332
|
+
const previousSession = getStoredCursorHttp1Enabled();
|
|
333
|
+
setStoredCursorHttp1Enabled(enabled);
|
|
334
|
+
try {
|
|
335
|
+
saveGlobalCursorHttp1Enabled(enabled);
|
|
336
|
+
} catch (error) {
|
|
337
|
+
setStoredCursorHttp1Enabled(previousSession);
|
|
338
|
+
throw error;
|
|
339
|
+
}
|
|
340
|
+
try {
|
|
341
|
+
pi.appendEntry<CursorHttp1EntryData>(CURSOR_HTTP1_ENTRY_TYPE, { enabled });
|
|
342
|
+
setCursorHttp1GlobalPreferenceAuthoritative(false);
|
|
343
|
+
return undefined;
|
|
344
|
+
} catch (error) {
|
|
345
|
+
setCursorHttp1GlobalPreferenceAuthoritative(true);
|
|
346
|
+
return error;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
281
350
|
function restoreCliCursorMode(raw: boolean | string | undefined): void {
|
|
282
351
|
cliCursorModeState = { kind: "unset" };
|
|
283
352
|
if (raw === undefined || raw === "" || raw === false) return;
|
|
@@ -399,14 +468,22 @@ export function registerCursorRuntimeControls(pi: CursorRuntimeControlsExtension
|
|
|
399
468
|
const preferenceModelId = getFastPreferenceModelId(metadata);
|
|
400
469
|
const current = getEffectiveFast(metadata.piModelId) ?? false;
|
|
401
470
|
const next = !current;
|
|
471
|
+
let appendError: unknown;
|
|
402
472
|
try {
|
|
403
|
-
persistFastPreference(pi, preferenceModelId, next);
|
|
473
|
+
appendError = persistFastPreference(pi, preferenceModelId, next);
|
|
404
474
|
} catch (error) {
|
|
405
475
|
updateCursorStatus(ctx);
|
|
406
476
|
ctx.ui.notify(`Failed to save Cursor fast preference: ${error instanceof Error ? error.message : String(error)}`, "error");
|
|
407
477
|
return;
|
|
408
478
|
}
|
|
409
479
|
updateCursorStatus(ctx);
|
|
480
|
+
if (appendError !== undefined) {
|
|
481
|
+
ctx.ui.notify(
|
|
482
|
+
`Cursor fast ${next ? "enabled" : "disabled"} was saved globally, but persisting the session entry failed: ${appendError instanceof Error ? appendError.message : String(appendError)}`,
|
|
483
|
+
"error",
|
|
484
|
+
);
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
410
487
|
ctx.ui.notify(`Cursor fast ${next ? "enabled" : "disabled"}`, "info");
|
|
411
488
|
},
|
|
412
489
|
});
|
|
@@ -418,6 +495,64 @@ export function registerCursorRuntimeControls(pi: CursorRuntimeControlsExtension
|
|
|
418
495
|
},
|
|
419
496
|
});
|
|
420
497
|
|
|
498
|
+
pi.registerCommand("cursor-http", {
|
|
499
|
+
description: "Toggle Cursor SDK HTTP/1.1/SSE transport compatibility mode",
|
|
500
|
+
handler: async (args, ctx) => {
|
|
501
|
+
const usage = "Usage: /cursor-http [on|off|toggle]";
|
|
502
|
+
const normalized = args.trim().toLowerCase();
|
|
503
|
+
const resolution = resolveCursorStatusRuntime(ctx);
|
|
504
|
+
if (resolution.kind === "invalid") {
|
|
505
|
+
ctx.ui.notify(resolution.message, "error");
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
const setting = resolution.useHttp1ForAgent;
|
|
509
|
+
if (!normalized) {
|
|
510
|
+
ctx.ui.notify(
|
|
511
|
+
`Cursor HTTP/1.1/SSE transport is ${setting.value ? "enabled" : "disabled"} (source: ${setting.source}). ${usage}`,
|
|
512
|
+
"info",
|
|
513
|
+
);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
const next = normalized === "on"
|
|
517
|
+
? true
|
|
518
|
+
: normalized === "off"
|
|
519
|
+
? false
|
|
520
|
+
: normalized === "toggle"
|
|
521
|
+
? !setting.value
|
|
522
|
+
: undefined;
|
|
523
|
+
if (next === undefined) {
|
|
524
|
+
ctx.ui.notify(
|
|
525
|
+
`Invalid Cursor HTTP transport mode "${args.trim()}". ${usage}`,
|
|
526
|
+
"error",
|
|
527
|
+
);
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
let appendError: unknown;
|
|
531
|
+
try {
|
|
532
|
+
appendError = persistCursorHttp1Preference(pi, next);
|
|
533
|
+
} catch (error) {
|
|
534
|
+
updateCursorStatus(ctx);
|
|
535
|
+
ctx.ui.notify(
|
|
536
|
+
`Failed to save Cursor HTTP/1.1 preference: ${error instanceof Error ? error.message : String(error)}`,
|
|
537
|
+
"error",
|
|
538
|
+
);
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
updateCursorStatus(ctx);
|
|
542
|
+
if (appendError !== undefined) {
|
|
543
|
+
ctx.ui.notify(
|
|
544
|
+
`Cursor HTTP/1.1 preference was saved globally, but persisting the session entry failed: ${appendError instanceof Error ? appendError.message : String(appendError)}`,
|
|
545
|
+
"error",
|
|
546
|
+
);
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
ctx.ui.notify(
|
|
550
|
+
`Cursor HTTP/1.1/SSE transport ${next ? "enabled" : "disabled"}`,
|
|
551
|
+
"info",
|
|
552
|
+
);
|
|
553
|
+
},
|
|
554
|
+
});
|
|
555
|
+
|
|
421
556
|
pi.registerCommand("cursor-local-resume-cleanup", {
|
|
422
557
|
description: "Dry-run or delete recorded superseded local Cursor SDK agents",
|
|
423
558
|
handler: async (args, ctx) => {
|
|
@@ -495,6 +630,8 @@ export function registerCursorRuntimeControls(pi: CursorRuntimeControlsExtension
|
|
|
495
630
|
|
|
496
631
|
registerCursorModelLifecycle(pi, {
|
|
497
632
|
sessionStart: (_event, ctx) => {
|
|
633
|
+
authoritativeGlobalFastPreferenceIds.clear();
|
|
634
|
+
setCursorHttp1GlobalPreferenceAuthoritative(false);
|
|
498
635
|
globalFastPreferences = loadGlobalFastPreferences();
|
|
499
636
|
cliForceFast = pi.getFlag("cursor-fast") === true;
|
|
500
637
|
cliForceNoFast = pi.getFlag("cursor-no-fast") === true;
|
|
@@ -511,14 +648,18 @@ export function registerCursorRuntimeControls(pi: CursorRuntimeControlsExtension
|
|
|
511
648
|
|
|
512
649
|
function resetCursorModeStateForTests(): void {
|
|
513
650
|
sessionCursorAgentMode = undefined;
|
|
651
|
+
setCursorHttp1GlobalPreferenceAuthoritative(false);
|
|
652
|
+
setStoredCursorHttp1Enabled(undefined);
|
|
514
653
|
cliCursorModeState = { kind: "unset" };
|
|
515
654
|
resetCursorRuntimeStateForTests();
|
|
516
655
|
invalidCursorModeNotifiedSessionScopeKeys.clear();
|
|
656
|
+
authoritativeGlobalFastPreferenceIds.clear();
|
|
517
657
|
}
|
|
518
658
|
|
|
519
659
|
export const __testUtils = {
|
|
520
660
|
FAST_ENTRY_TYPE,
|
|
521
661
|
MODE_ENTRY_TYPE,
|
|
662
|
+
CURSOR_HTTP1_ENTRY_TYPE,
|
|
522
663
|
RUNTIME_ENTRY_TYPE: CURSOR_RUNTIME_ENTRY_TYPE,
|
|
523
664
|
DEFAULT_CURSOR_AGENT_MODE,
|
|
524
665
|
getConfigPath,
|