@emmaneugene/pi-cursor-sdk 0.3.7 → 0.4.1
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 +22 -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-extension-factory-guard.js +31 -0
- package/dist/cursor-pi-tool-bridge-server.js +3 -0
- package/dist/cursor-pi-tool-bridge.js +5 -0
- 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/dist/index.js +65 -49
- package/docs/cursor-dogfood-checklist.md +4 -4
- package/docs/cursor-live-smoke-checklist.md +24 -24
- 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 +10 -10
- package/docs/cursor-testing-lessons.md +38 -16
- package/docs/cursor-tool-surfaces.md +2 -4
- package/docs/platform-smoke-implementation.md +5 -5
- package/docs/platform-smoke.md +28 -73
- package/node_modules/cross-spawn/node_modules/which/CHANGELOG.md +166 -0
- package/package.json +3 -17
- package/platform-smoke.config.mjs +2 -1
- package/scripts/lib/cursor-visual-render.mjs +12 -2
- 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/scripts/visual-tui-smoke-self-test.mjs +9 -33
- package/scripts/visual-tui-smoke.mjs +54 -11
- 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-extension-factory-guard.ts +57 -0
- package/src/cursor-pi-tool-bridge-server.ts +4 -0
- package/src/cursor-pi-tool-bridge.ts +5 -0
- 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/src/index.ts +70 -49
- 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/src/cursor-skill-tool.ts
CHANGED
|
@@ -9,11 +9,9 @@ import type {
|
|
|
9
9
|
} from "@earendil-works/pi-coding-agent";
|
|
10
10
|
import { Type } from "typebox";
|
|
11
11
|
import { arePiToolsDisabled } from "./cursor-active-tools.js";
|
|
12
|
-
import type { CursorRuntime } from "./cursor-config.js";
|
|
13
12
|
import { isCursorModel } from "./cursor-model.js";
|
|
14
13
|
import { registerCursorModelLifecycle, type CursorModelLifecycleExtensionApi } from "./cursor-model-lifecycle.js";
|
|
15
14
|
import { resolveCursorPiToolBridgeEnabled } from "./cursor-pi-tool-bridge-env.js";
|
|
16
|
-
import { resolveEffectiveCursorConfigForContext } from "./cursor-runtime-state.js";
|
|
17
15
|
|
|
18
16
|
export const CURSOR_ACTIVATE_SKILL_TOOL_NAME = "cursor_activate_skill";
|
|
19
17
|
export const CURSOR_ACTIVATE_SKILL_MCP_NAME = "pi__cursor_activate_skill";
|
|
@@ -59,24 +57,16 @@ function getAvailableSkillNames(): string[] {
|
|
|
59
57
|
return [...currentSkillsByName.keys()].sort();
|
|
60
58
|
}
|
|
61
59
|
|
|
62
|
-
function
|
|
63
|
-
|
|
64
|
-
ctx: Pick<ExtensionContext, "cwd"> & Partial<Pick<ExtensionContext, "isProjectTrusted">>,
|
|
65
|
-
): CursorRuntime {
|
|
66
|
-
return cursorModel ? resolveEffectiveCursorConfigForContext(ctx).runtime.value : "local";
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function shouldExposeSkillTool(model: ExtensionContext["model"], runtime: CursorRuntime): boolean {
|
|
70
|
-
return runtime === "local" && isCursorModel(model) && resolveCursorPiToolBridgeEnabled() && currentSkillsByName.size > 0;
|
|
60
|
+
function shouldExposeSkillTool(model: ExtensionContext["model"]): boolean {
|
|
61
|
+
return isCursorModel(model) && resolveCursorPiToolBridgeEnabled() && currentSkillsByName.size > 0;
|
|
71
62
|
}
|
|
72
63
|
|
|
73
64
|
function syncCursorSkillToolForModel(
|
|
74
65
|
pi: Pick<ExtensionAPI, "getActiveTools" | "setActiveTools">,
|
|
75
66
|
model: ExtensionContext["model"],
|
|
76
|
-
runtime: CursorRuntime,
|
|
77
67
|
): void {
|
|
78
68
|
const activeToolNames = new Set(pi.getActiveTools());
|
|
79
|
-
const shouldBeActive = !arePiToolsDisabled(pi) && shouldExposeSkillTool(model
|
|
69
|
+
const shouldBeActive = !arePiToolsDisabled(pi) && shouldExposeSkillTool(model);
|
|
80
70
|
const alreadyActive = activeToolNames.has(CURSOR_ACTIVATE_SKILL_TOOL_NAME);
|
|
81
71
|
if (shouldBeActive === alreadyActive) return;
|
|
82
72
|
if (shouldBeActive) {
|
|
@@ -114,10 +104,8 @@ export function resolveCursorSkillSystemPrompt(
|
|
|
114
104
|
systemPrompt: string,
|
|
115
105
|
model: ExtensionContext["model"],
|
|
116
106
|
systemPromptOptions?: BuildSystemPromptOptions,
|
|
117
|
-
runtime: CursorRuntime = "local",
|
|
118
107
|
): string {
|
|
119
108
|
if (!isCursorModel(model)) return systemPrompt;
|
|
120
|
-
if (runtime === "cloud") return systemPrompt.replace(AVAILABLE_SKILLS_SECTION_PATTERN, "");
|
|
121
109
|
const skills = getVisibleSkills(systemPromptOptions?.skills);
|
|
122
110
|
if (skills.length === 0) return systemPrompt;
|
|
123
111
|
const replacement = formatCursorSkillsForPrompt(skills);
|
|
@@ -231,9 +219,9 @@ export function registerCursorSkillTool(pi: CursorSkillToolExtensionApi): void {
|
|
|
231
219
|
},
|
|
232
220
|
});
|
|
233
221
|
|
|
234
|
-
const clearSkillsAndSync = (model: ExtensionContext["model"]
|
|
222
|
+
const clearSkillsAndSync = (model: ExtensionContext["model"]): void => {
|
|
235
223
|
setCurrentSkills([]);
|
|
236
|
-
syncCursorSkillToolForModel(pi, model
|
|
224
|
+
syncCursorSkillToolForModel(pi, model);
|
|
237
225
|
};
|
|
238
226
|
|
|
239
227
|
registerCursorModelLifecycle(pi, {
|
|
@@ -244,21 +232,17 @@ export function registerCursorSkillTool(pi: CursorSkillToolExtensionApi): void {
|
|
|
244
232
|
clearSkillsAndSync(event.model);
|
|
245
233
|
},
|
|
246
234
|
turnStart: (_event, ctx) => {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
if (!cursorModel || runtime === "cloud") setCurrentSkills([]);
|
|
250
|
-
syncCursorSkillToolForModel(pi, ctx.model, runtime);
|
|
235
|
+
if (!isCursorModel(ctx.model)) setCurrentSkills([]);
|
|
236
|
+
syncCursorSkillToolForModel(pi, ctx.model);
|
|
251
237
|
},
|
|
252
238
|
beforeAgentStart: (event, ctx) => {
|
|
253
|
-
|
|
254
|
-
const runtime = resolveEffectiveRuntimeForSkillLifecycle(cursorModel, ctx);
|
|
255
|
-
if (cursorModel && runtime === "local") {
|
|
239
|
+
if (isCursorModel(ctx.model)) {
|
|
256
240
|
setCurrentSkills(event.systemPromptOptions?.skills);
|
|
257
241
|
} else {
|
|
258
242
|
setCurrentSkills([]);
|
|
259
243
|
}
|
|
260
|
-
syncCursorSkillToolForModel(pi, ctx.model
|
|
261
|
-
const resolved = resolveCursorSkillSystemPrompt(event.systemPrompt, ctx.model, event.systemPromptOptions
|
|
244
|
+
syncCursorSkillToolForModel(pi, ctx.model);
|
|
245
|
+
const resolved = resolveCursorSkillSystemPrompt(event.systemPrompt, ctx.model, event.systemPromptOptions);
|
|
262
246
|
if (resolved === event.systemPrompt) return undefined;
|
|
263
247
|
return { systemPrompt: resolved };
|
|
264
248
|
},
|
package/src/cursor-state.ts
CHANGED
|
@@ -42,16 +42,14 @@ import {
|
|
|
42
42
|
} from "./cursor-config.js";
|
|
43
43
|
import {
|
|
44
44
|
consumeCursorLocalForceOverride,
|
|
45
|
-
CURSOR_RUNTIME_ENTRY_TYPE,
|
|
46
45
|
formatCursorStatus,
|
|
47
46
|
getCursorCliConfig,
|
|
48
47
|
getCursorSessionConfig,
|
|
49
|
-
|
|
48
|
+
registerCursorLocalRuntimeFlags,
|
|
50
49
|
resetCursorRuntimeStateForTests,
|
|
51
50
|
resolveCursorStatusRuntime,
|
|
52
51
|
resolveEffectiveCursorConfigForContext,
|
|
53
52
|
restoreCursorCliState,
|
|
54
|
-
restoreSessionCursorRuntimeState,
|
|
55
53
|
type CursorRuntimeStateExtensionApi,
|
|
56
54
|
} from "./cursor-runtime-state.js";
|
|
57
55
|
|
|
@@ -178,7 +176,6 @@ function restoreSessionCursorMode(branch: readonly SessionEntry[]): void {
|
|
|
178
176
|
|
|
179
177
|
function restoreSessionCursorPreferences(ctx: { sessionManager: Pick<ExtensionContext["sessionManager"], "getBranch"> }): void {
|
|
180
178
|
const branch = ctx.sessionManager.getBranch();
|
|
181
|
-
restoreSessionCursorRuntimeState(branch);
|
|
182
179
|
restoreSessionFastPreferences(branch);
|
|
183
180
|
restoreSessionCursorMode(branch);
|
|
184
181
|
restoreSessionCursorHttp1(branch);
|
|
@@ -266,14 +263,13 @@ function updateCursorStatus(ctx: CursorStatusContext & Pick<ExtensionContext, "m
|
|
|
266
263
|
const modeResolution = resolveCursorAgentMode();
|
|
267
264
|
const mode = modeResolution.kind === "invalid" ? "invalid" : modeResolution.mode;
|
|
268
265
|
if (resolution.kind === "invalid") {
|
|
269
|
-
ctx.ui.setStatus("cursor", formatCursorStatus("invalid"
|
|
266
|
+
ctx.ui.setStatus("cursor", formatCursorStatus(undefined, "invalid"));
|
|
270
267
|
return;
|
|
271
268
|
}
|
|
272
|
-
const
|
|
273
|
-
const fast = runtime === "cloud" ? undefined : metadata?.supportsFast ? getEffectiveFast(model.id) : undefined;
|
|
269
|
+
const fast = metadata?.supportsFast ? getEffectiveFast(model.id) : undefined;
|
|
274
270
|
ctx.ui.setStatus(
|
|
275
271
|
"cursor",
|
|
276
|
-
formatCursorStatus(
|
|
272
|
+
formatCursorStatus(fast, mode, resolution.useHttp1ForAgent.value),
|
|
277
273
|
);
|
|
278
274
|
}
|
|
279
275
|
|
|
@@ -432,7 +428,7 @@ export function getEffectiveFastForModelId(modelId: string): boolean | undefined
|
|
|
432
428
|
}
|
|
433
429
|
|
|
434
430
|
export function registerCursorRuntimeControls(pi: CursorRuntimeControlsExtensionApi): void {
|
|
435
|
-
|
|
431
|
+
registerCursorLocalRuntimeFlags(pi);
|
|
436
432
|
|
|
437
433
|
pi.registerFlag("cursor-fast", {
|
|
438
434
|
description: "Force Cursor fast mode for this run when the selected Cursor model supports it",
|
|
@@ -673,7 +669,6 @@ export const __testUtils = {
|
|
|
673
669
|
FAST_ENTRY_TYPE,
|
|
674
670
|
MODE_ENTRY_TYPE,
|
|
675
671
|
CURSOR_HTTP1_ENTRY_TYPE,
|
|
676
|
-
RUNTIME_ENTRY_TYPE: CURSOR_RUNTIME_ENTRY_TYPE,
|
|
677
672
|
DEFAULT_CURSOR_AGENT_MODE,
|
|
678
673
|
getConfigPath,
|
|
679
674
|
loadGlobalFastPreferences,
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
type CursorPromptOptions,
|
|
8
8
|
} from "./context.js";
|
|
9
9
|
import { asRecord, getNumber } from "./cursor-record-utils.js";
|
|
10
|
-
import type { CursorRuntime } from "./cursor-config.js";
|
|
11
10
|
|
|
12
11
|
export interface CursorUsagePromptOptions extends CursorPromptOptions {
|
|
13
12
|
maxInputTokens: number;
|
|
@@ -110,7 +109,6 @@ export function isCursorSdkUsageSafeForPiMessage(turnUsage: CursorSdkTurnUsage,
|
|
|
110
109
|
}
|
|
111
110
|
|
|
112
111
|
export interface CursorSdkUsageApplyOptions {
|
|
113
|
-
runtime: CursorRuntime;
|
|
114
112
|
turn?: CursorSdkTurnUsage;
|
|
115
113
|
billed?: CursorSdkTurnUsage;
|
|
116
114
|
}
|
|
@@ -209,7 +207,7 @@ export function applyCursorUsage(
|
|
|
209
207
|
sdkUsage?: CursorSdkUsageApplyOptions,
|
|
210
208
|
): void {
|
|
211
209
|
const billed = sdkUsage?.billed;
|
|
212
|
-
const localTurn = sdkUsage?.
|
|
210
|
+
const localTurn = sdkUsage?.turn;
|
|
213
211
|
if (billed && isCursorSdkUsagePartitionSafe(billed, model)) {
|
|
214
212
|
applyCursorSdkUsage(partial, billed);
|
|
215
213
|
applyResolvedCursorOccupancy(partial, model, context, localTurn);
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,11 @@ import { registerCursorAgentsContextDedup } from "./cursor-agents-context-regist
|
|
|
16
16
|
import { registerCursorOverflowNormalization } from "./cursor-provider-overflow.js";
|
|
17
17
|
import { registerCursorSdkSessionProcessErrorGuard } from "./cursor-sdk-process-error-guard.js";
|
|
18
18
|
import { prepareCursorSessionForCompaction } from "./cursor-session-compaction-prep.js";
|
|
19
|
+
import {
|
|
20
|
+
claimCursorExtensionFactory,
|
|
21
|
+
registerCursorExtensionFactoryRelease,
|
|
22
|
+
releaseCursorExtensionFactory,
|
|
23
|
+
} from "./cursor-extension-factory-guard.js";
|
|
19
24
|
|
|
20
25
|
type CursorExtensionApi =
|
|
21
26
|
& Pick<ExtensionAPI, "registerProvider" | "registerCommand" | "on">
|
|
@@ -31,7 +36,8 @@ type CursorExtensionApi =
|
|
|
31
36
|
& Parameters<typeof registerCursorFallbackIssueWarning>[0]
|
|
32
37
|
& Parameters<typeof registerCursorAgentsContextDedup>[0]
|
|
33
38
|
& Parameters<typeof registerCursorOverflowNormalization>[0]
|
|
34
|
-
& Parameters<typeof registerCursorSdkSessionProcessErrorGuard>[0]
|
|
39
|
+
& Parameters<typeof registerCursorSdkSessionProcessErrorGuard>[0]
|
|
40
|
+
& Parameters<typeof registerCursorExtensionFactoryRelease>[0];
|
|
35
41
|
|
|
36
42
|
function createCursorProviderConfig(models: ProviderModelConfig[]): ProviderConfig {
|
|
37
43
|
return {
|
|
@@ -49,55 +55,70 @@ function registerCursorProvider(pi: Pick<ExtensionAPI, "registerProvider">, mode
|
|
|
49
55
|
}
|
|
50
56
|
|
|
51
57
|
export default async function (pi: CursorExtensionApi) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
registerCursorSessionAgentLineage(pi);
|
|
55
|
-
registerCursorSessionAgentLifecycle(pi);
|
|
56
|
-
registerCursorSessionAgentResume(pi);
|
|
57
|
-
pi.on("session_before_compact", async () => {
|
|
58
|
-
await prepareCursorSessionForCompaction();
|
|
59
|
-
});
|
|
60
|
-
registerCursorRuntimeControls(pi);
|
|
61
|
-
registerCursorNativeToolDisplay(pi);
|
|
62
|
-
registerCursorQuestionTool(pi);
|
|
63
|
-
registerCursorSkillTool(pi);
|
|
64
|
-
registerCursorPiToolBridge(pi);
|
|
65
|
-
registerCursorAgentsContextDedup(pi);
|
|
66
|
-
registerCursorOverflowNormalization(pi);
|
|
67
|
-
let fallbackIssue: CursorModelFallbackIssue | undefined;
|
|
68
|
-
const models = await discoverModels({
|
|
69
|
-
onFallback: (issue) => {
|
|
70
|
-
fallbackIssue = issue;
|
|
71
|
-
},
|
|
72
|
-
});
|
|
58
|
+
const factoryClaim = claimCursorExtensionFactory();
|
|
59
|
+
if (factoryClaim.kind === "nested") return;
|
|
73
60
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
61
|
+
try {
|
|
62
|
+
// Discover first. A discovery failure must not leave process-global
|
|
63
|
+
// registrars from a discarded extension load.
|
|
64
|
+
let fallbackIssue: CursorModelFallbackIssue | undefined;
|
|
65
|
+
const models = await discoverModels({
|
|
66
|
+
onFallback: (issue) => {
|
|
67
|
+
fallbackIssue = issue;
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Session cwd must register before other session_start listeners that depend on it.
|
|
72
|
+
registerCursorSessionScope(pi);
|
|
73
|
+
registerCursorSessionAgentLineage(pi);
|
|
74
|
+
registerCursorSessionAgentLifecycle(pi);
|
|
75
|
+
registerCursorSessionAgentResume(pi);
|
|
76
|
+
pi.on("session_before_compact", async () => {
|
|
77
|
+
await prepareCursorSessionForCompaction();
|
|
78
|
+
});
|
|
79
|
+
registerCursorRuntimeControls(pi);
|
|
80
|
+
registerCursorNativeToolDisplay(pi);
|
|
81
|
+
registerCursorQuestionTool(pi);
|
|
82
|
+
registerCursorSkillTool(pi);
|
|
83
|
+
registerCursorPiToolBridge(pi);
|
|
84
|
+
registerCursorAgentsContextDedup(pi);
|
|
85
|
+
registerCursorOverflowNormalization(pi);
|
|
77
86
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
let refreshFallbackIssue: CursorModelFallbackIssue | undefined;
|
|
82
|
-
const apiKey = resolveCursorApiKey(await ctx.modelRegistry.getApiKeyForProvider("cursor"));
|
|
83
|
-
const refreshedModels = await discoverModels({
|
|
84
|
-
apiKey,
|
|
85
|
-
forceRefresh: true,
|
|
86
|
-
onFallback: (issue) => {
|
|
87
|
-
refreshFallbackIssue = issue;
|
|
88
|
-
},
|
|
89
|
-
});
|
|
90
|
-
registerCursorProvider(pi, refreshedModels);
|
|
91
|
-
if (!ctx.hasUI) return;
|
|
92
|
-
if (refreshFallbackIssue) {
|
|
93
|
-
ctx.ui.notify(`Cursor model catalog refresh did not use a live catalog: ${refreshFallbackIssue.message}`, "warning");
|
|
94
|
-
} else {
|
|
95
|
-
ctx.ui.notify(`Cursor model catalog refreshed with ${refreshedModels.length} model${refreshedModels.length === 1 ? "" : "s"}.`, "info");
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
|
-
});
|
|
87
|
+
if (fallbackIssue) {
|
|
88
|
+
registerCursorFallbackIssueWarning(pi, fallbackIssue);
|
|
89
|
+
}
|
|
99
90
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
91
|
+
pi.registerCommand("cursor-refresh-models", {
|
|
92
|
+
description: "Refresh the live Cursor model catalog without restarting pi",
|
|
93
|
+
handler: async (_args, ctx) => {
|
|
94
|
+
let refreshFallbackIssue: CursorModelFallbackIssue | undefined;
|
|
95
|
+
const apiKey = resolveCursorApiKey(await ctx.modelRegistry.getApiKeyForProvider("cursor"));
|
|
96
|
+
const refreshedModels = await discoverModels({
|
|
97
|
+
apiKey,
|
|
98
|
+
forceRefresh: true,
|
|
99
|
+
onFallback: (issue) => {
|
|
100
|
+
refreshFallbackIssue = issue;
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
registerCursorProvider(pi, refreshedModels);
|
|
104
|
+
if (!ctx.hasUI) return;
|
|
105
|
+
if (refreshFallbackIssue) {
|
|
106
|
+
ctx.ui.notify(`Cursor model catalog refresh did not use a live catalog: ${refreshFallbackIssue.message}`, "warning");
|
|
107
|
+
} else {
|
|
108
|
+
ctx.ui.notify(`Cursor model catalog refreshed with ${refreshedModels.length} model${refreshedModels.length === 1 ? "" : "s"}.`, "info");
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
registerCursorProvider(pi, models);
|
|
114
|
+
// Keep the process error guard near the end so earlier Cursor cleanup
|
|
115
|
+
// remains protected during session shutdown.
|
|
116
|
+
registerCursorSdkSessionProcessErrorGuard(pi);
|
|
117
|
+
// Register last so ownership remains protected until all other Cursor
|
|
118
|
+
// session_shutdown handlers finish.
|
|
119
|
+
registerCursorExtensionFactoryRelease(pi, factoryClaim);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
releaseCursorExtensionFactory(factoryClaim.token);
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
103
124
|
}
|