pi-cursor-sdk 0.1.28 → 0.1.29
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 +19 -0
- package/README.md +38 -35
- package/docs/crabbox-platform-testing-lessons.md +508 -0
- package/docs/cursor-dogfood-checklist.md +4 -3
- package/docs/cursor-live-smoke-checklist.md +22 -20
- package/docs/cursor-model-ux-spec.md +12 -12
- package/docs/cursor-native-tool-replay.md +10 -10
- package/docs/cursor-native-tool-visual-audit.md +9 -7
- package/docs/cursor-testing-lessons.md +20 -15
- package/docs/cursor-tool-surfaces.md +3 -3
- package/docs/platform-smoke.md +994 -0
- package/package.json +32 -3
- package/platform-smoke.config.mjs +21 -0
- package/scripts/debug-provider-events.mjs +10 -3
- package/scripts/debug-sdk-events.mjs +10 -2
- package/scripts/isolated-cursor-smoke.sh +4 -4
- package/scripts/lib/cursor-visual-render.mjs +1 -0
- package/scripts/platform-smoke/artifacts.mjs +124 -0
- package/scripts/platform-smoke/assertions.mjs +101 -0
- package/scripts/platform-smoke/card-detect.mjs +96 -0
- package/scripts/platform-smoke/crabbox-runner.mjs +215 -0
- package/scripts/platform-smoke/doctor.mjs +446 -0
- package/scripts/platform-smoke/jsonl-text.mjs +31 -0
- package/scripts/platform-smoke/live-suite-runner.mjs +677 -0
- package/scripts/platform-smoke/platform-build-windows.ps1 +187 -0
- package/scripts/platform-smoke/pty-capture.mjs +131 -0
- package/scripts/platform-smoke/render-ansi.mjs +65 -0
- package/scripts/platform-smoke/scenarios.mjs +186 -0
- package/scripts/platform-smoke/targets.mjs +900 -0
- package/scripts/platform-smoke/visual-evidence.mjs +139 -0
- package/scripts/platform-smoke.mjs +193 -0
- package/scripts/probe-mcp-coldstart.mjs +8 -1
- package/scripts/steering-rpc-smoke.mjs +1 -1
- package/scripts/tmux-live-smoke.sh +3 -3
- package/scripts/visual-tui-smoke.mjs +1 -1
- package/src/cursor-pi-tool-bridge-abort.ts +1 -0
- package/src/cursor-pi-tool-bridge-diagnostics.ts +12 -1
- package/src/cursor-pi-tool-bridge.ts +46 -1
- package/src/cursor-provider-turn-lifecycle-emitter.ts +65 -8
- package/src/cursor-provider-turn-tool-ledger.ts +2 -3
- package/src/cursor-run-final-text.ts +11 -1
- package/src/cursor-state.ts +38 -19
- package/src/cursor-tool-lifecycle.ts +1 -1
- package/src/cursor-tool-manifest.ts +1 -1
- package/src/cursor-transcript-utils.ts +7 -3
package/src/cursor-state.ts
CHANGED
|
@@ -29,7 +29,8 @@ export type CursorAgentMode = AgentModeOption;
|
|
|
29
29
|
const DEFAULT_CURSOR_AGENT_MODE: AgentModeOption = "agent";
|
|
30
30
|
|
|
31
31
|
interface CursorFastEntryData {
|
|
32
|
-
|
|
32
|
+
modelId?: string;
|
|
33
|
+
baseModelId?: string;
|
|
33
34
|
fast: boolean;
|
|
34
35
|
}
|
|
35
36
|
|
|
@@ -71,7 +72,11 @@ export function parseCursorAgentMode(raw: unknown): AgentModeOption | undefined
|
|
|
71
72
|
function isCursorFastEntryData(value: unknown): value is CursorFastEntryData {
|
|
72
73
|
if (!value || typeof value !== "object") return false;
|
|
73
74
|
const data = value as Record<string, unknown>;
|
|
74
|
-
return typeof data.baseModelId === "string" && typeof data.fast === "boolean";
|
|
75
|
+
return (typeof data.modelId === "string" || typeof data.baseModelId === "string") && typeof data.fast === "boolean";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function getCursorFastEntryModelId(data: CursorFastEntryData): string {
|
|
79
|
+
return data.modelId ?? data.baseModelId ?? "";
|
|
75
80
|
}
|
|
76
81
|
|
|
77
82
|
function isCursorModeEntryData(value: unknown): value is CursorModeEntryData {
|
|
@@ -113,7 +118,8 @@ function restoreSessionFastPreferences(ctx: { sessionManager: Pick<ExtensionCont
|
|
|
113
118
|
for (const entry of ctx.sessionManager.getBranch()) {
|
|
114
119
|
if (entry.type !== "custom" || entry.customType !== FAST_ENTRY_TYPE) continue;
|
|
115
120
|
if (isCursorFastEntryData(entry.data)) {
|
|
116
|
-
|
|
121
|
+
const modelId = getCursorFastEntryModelId(entry.data);
|
|
122
|
+
if (modelId) sessionFastPreferences.set(modelId, entry.data.fast);
|
|
117
123
|
}
|
|
118
124
|
}
|
|
119
125
|
}
|
|
@@ -128,12 +134,26 @@ function restoreSessionCursorMode(ctx: { sessionManager: Pick<ExtensionContext["
|
|
|
128
134
|
}
|
|
129
135
|
}
|
|
130
136
|
|
|
131
|
-
function
|
|
137
|
+
function getFastPreferenceModelId(metadata: NonNullable<ReturnType<typeof getCursorModelMetadata>>): string {
|
|
138
|
+
return metadata.selectionModelId || metadata.baseModelId;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function getStoredFastPreference(metadata: NonNullable<ReturnType<typeof getCursorModelMetadata>>): boolean | undefined {
|
|
142
|
+
const preferenceModelId = getFastPreferenceModelId(metadata);
|
|
143
|
+
return (
|
|
144
|
+
sessionFastPreferences.get(preferenceModelId) ??
|
|
145
|
+
(preferenceModelId !== metadata.baseModelId ? sessionFastPreferences.get(metadata.baseModelId) : undefined) ??
|
|
146
|
+
globalFastPreferences.get(preferenceModelId) ??
|
|
147
|
+
(preferenceModelId !== metadata.baseModelId ? globalFastPreferences.get(metadata.baseModelId) : undefined)
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function getEffectiveFast(modelId: string): boolean | undefined {
|
|
132
152
|
const metadata = getCursorModelMetadata(modelId);
|
|
133
153
|
if (!metadata?.supportsFast) return undefined;
|
|
134
154
|
if (cliForceNoFast) return false;
|
|
135
155
|
if (cliForceFast) return true;
|
|
136
|
-
return
|
|
156
|
+
return getStoredFastPreference(metadata) ?? metadata.defaultFast;
|
|
137
157
|
}
|
|
138
158
|
|
|
139
159
|
function formatInvalidCursorMode(raw: string): string {
|
|
@@ -168,7 +188,7 @@ function updateCursorStatus(ctx: Pick<ExtensionContext, "model" | "ui">, model =
|
|
|
168
188
|
return;
|
|
169
189
|
}
|
|
170
190
|
const metadata = getCursorModelMetadata(model.id);
|
|
171
|
-
const fast = metadata?.supportsFast ? getEffectiveFast(
|
|
191
|
+
const fast = metadata?.supportsFast ? getEffectiveFast(model.id) : undefined;
|
|
172
192
|
ctx.ui.setStatus("cursor", formatCursorStatus(fast));
|
|
173
193
|
}
|
|
174
194
|
|
|
@@ -186,19 +206,19 @@ function restoreMapValue(map: Map<string, boolean>, key: string, previous: boole
|
|
|
186
206
|
}
|
|
187
207
|
}
|
|
188
208
|
|
|
189
|
-
function persistFastPreference(pi: Pick<ExtensionAPI, "appendEntry">,
|
|
190
|
-
const previousSession = sessionFastPreferences.get(
|
|
191
|
-
const previousGlobal = globalFastPreferences.get(
|
|
209
|
+
function persistFastPreference(pi: Pick<ExtensionAPI, "appendEntry">, modelId: string, fast: boolean): void {
|
|
210
|
+
const previousSession = sessionFastPreferences.get(modelId);
|
|
211
|
+
const previousGlobal = globalFastPreferences.get(modelId);
|
|
192
212
|
let savedGlobal = false;
|
|
193
|
-
sessionFastPreferences.set(
|
|
194
|
-
globalFastPreferences.set(
|
|
213
|
+
sessionFastPreferences.set(modelId, fast);
|
|
214
|
+
globalFastPreferences.set(modelId, fast);
|
|
195
215
|
try {
|
|
196
216
|
saveGlobalFastPreferences();
|
|
197
217
|
savedGlobal = true;
|
|
198
|
-
pi.appendEntry<CursorFastEntryData>(FAST_ENTRY_TYPE, {
|
|
218
|
+
pi.appendEntry<CursorFastEntryData>(FAST_ENTRY_TYPE, { modelId, fast });
|
|
199
219
|
} catch (error) {
|
|
200
|
-
restoreMapValue(sessionFastPreferences,
|
|
201
|
-
restoreMapValue(globalFastPreferences,
|
|
220
|
+
restoreMapValue(sessionFastPreferences, modelId, previousSession);
|
|
221
|
+
restoreMapValue(globalFastPreferences, modelId, previousGlobal);
|
|
202
222
|
if (savedGlobal) {
|
|
203
223
|
try {
|
|
204
224
|
saveGlobalFastPreferences();
|
|
@@ -285,9 +305,7 @@ function emitCursorToolsDebugReport(
|
|
|
285
305
|
}
|
|
286
306
|
|
|
287
307
|
export function getEffectiveFastForModelId(modelId: string): boolean | undefined {
|
|
288
|
-
|
|
289
|
-
if (!metadata) return undefined;
|
|
290
|
-
return getEffectiveFast(metadata.baseModelId, modelId);
|
|
308
|
+
return getEffectiveFast(modelId);
|
|
291
309
|
}
|
|
292
310
|
|
|
293
311
|
export function registerCursorRuntimeControls(pi: CursorRuntimeControlsExtensionApi): void {
|
|
@@ -327,10 +345,11 @@ export function registerCursorRuntimeControls(pi: CursorRuntimeControlsExtension
|
|
|
327
345
|
return;
|
|
328
346
|
}
|
|
329
347
|
|
|
330
|
-
const
|
|
348
|
+
const preferenceModelId = getFastPreferenceModelId(metadata);
|
|
349
|
+
const current = getEffectiveFast(metadata.piModelId) ?? false;
|
|
331
350
|
const next = !current;
|
|
332
351
|
try {
|
|
333
|
-
persistFastPreference(pi,
|
|
352
|
+
persistFastPreference(pi, preferenceModelId, next);
|
|
334
353
|
} catch (error) {
|
|
335
354
|
updateCursorStatus(ctx);
|
|
336
355
|
ctx.ui.notify(`Failed to save Cursor fast preference: ${error instanceof Error ? error.message : String(error)}`, "error");
|
|
@@ -45,7 +45,7 @@ export function buildCursorToolLifecycleLabel(toolCall: unknown, apiKey?: string
|
|
|
45
45
|
return scrubLifecycleDetail(getString(args, "description"), apiKey) ?? "task";
|
|
46
46
|
}
|
|
47
47
|
case "shell": {
|
|
48
|
-
return "
|
|
48
|
+
return scrubLifecycleDetail(getString(args, "command") ?? getString(args, "cmd"), apiKey);
|
|
49
49
|
}
|
|
50
50
|
case "mcp": {
|
|
51
51
|
return scrubLifecycleDetail(getString(args, "toolName"), apiKey) ?? "mcp";
|
|
@@ -4,7 +4,7 @@ import type { CursorPiToolBridgeSnapshot } from "./cursor-pi-tool-bridge-types.j
|
|
|
4
4
|
export const CURSOR_TOOL_MANIFEST_ENV = "PI_CURSOR_TOOL_MANIFEST";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Representative @cursor/sdk@1.0.
|
|
7
|
+
* Representative @cursor/sdk@1.0.17 local-agent ToolType values; actual exposure can vary by run.
|
|
8
8
|
* See docs/cursor-native-tool-replay.md#sdk-tooltype-replay-matrix.
|
|
9
9
|
*/
|
|
10
10
|
export const CURSOR_HOST_TOOL_MANIFEST_SUMMARY =
|
|
@@ -145,14 +145,18 @@ export function formatError(error: unknown): string {
|
|
|
145
145
|
return text ? `Error: ${text}` : "Error";
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
function normalizeDisplaySeparators(path: string): string {
|
|
149
|
+
return path.replace(/\\/g, "/");
|
|
150
|
+
}
|
|
151
|
+
|
|
148
152
|
export function formatDisplayPath(path: string, cwd = process.cwd()): string {
|
|
149
153
|
const trimmed = path.trim();
|
|
150
154
|
if (!trimmed) return trimmed;
|
|
151
|
-
if (!isAbsolute(trimmed)) return trimmed;
|
|
155
|
+
if (!isAbsolute(trimmed)) return normalizeDisplaySeparators(trimmed);
|
|
152
156
|
const relativePath = relative(cwd, trimmed);
|
|
153
157
|
if (!relativePath || relativePath === "") return ".";
|
|
154
|
-
if (relativePath.startsWith("..") || isAbsolute(relativePath)) return trimmed;
|
|
155
|
-
return relativePath;
|
|
158
|
+
if (relativePath.startsWith("..") || isAbsolute(relativePath)) return normalizeDisplaySeparators(trimmed);
|
|
159
|
+
return normalizeDisplaySeparators(relativePath);
|
|
156
160
|
}
|
|
157
161
|
|
|
158
162
|
export function formatDiffPath(path: string, cwd = process.cwd()): string {
|