pi-cursor-sdk 0.1.20 → 0.1.22
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 +38 -0
- package/README.md +49 -9
- package/docs/cursor-dogfood-checklist.md +57 -0
- package/docs/cursor-live-smoke-checklist.md +115 -9
- package/docs/cursor-model-ux-spec.md +58 -18
- package/docs/cursor-native-tool-replay.md +15 -7
- package/docs/cursor-native-tool-visual-audit.md +104 -59
- package/docs/cursor-testing-lessons.md +8 -3
- package/docs/cursor-tool-surfaces.md +69 -0
- package/package.json +34 -10
- package/scripts/debug-provider-events.d.mts +59 -0
- package/scripts/debug-provider-events.mjs +70 -175
- package/scripts/debug-sdk-events.d.mts +90 -0
- package/scripts/debug-sdk-events.mjs +36 -98
- package/scripts/fixtures/plan-strip-shim/index.ts +12 -0
- package/scripts/isolated-cursor-smoke.sh +264 -102
- package/scripts/lib/cursor-child-process.d.mts +10 -0
- package/scripts/lib/cursor-child-process.mjs +50 -0
- package/scripts/lib/cursor-cli-args.d.mts +63 -0
- package/scripts/lib/cursor-cli-args.mjs +129 -0
- package/scripts/lib/cursor-script-fail.d.mts +1 -0
- package/scripts/lib/cursor-script-fail.mjs +13 -0
- package/scripts/lib/cursor-sdk-output-filter.d.mts +5 -0
- package/scripts/lib/cursor-smoke-env.d.mts +38 -0
- package/scripts/lib/cursor-smoke-env.mjs +81 -0
- package/scripts/lib/cursor-smoke-shell.sh +174 -0
- package/scripts/lib/cursor-visual-render.d.mts +15 -0
- package/scripts/lib/cursor-visual-render.mjs +131 -0
- package/scripts/probe-mcp-coldstart.mjs +20 -38
- package/scripts/refresh-cursor-model-snapshots.mjs +29 -65
- package/scripts/steering-rpc-smoke.mjs +170 -65
- package/scripts/tmux-live-smoke.sh +152 -98
- package/scripts/visual-tui-smoke.mjs +659 -0
- package/shared/cursor-sdk-event-debug-env.d.mts +12 -0
- package/shared/cursor-sdk-event-debug-env.mjs +13 -0
- package/shared/cursor-sensitive-text.d.mts +1 -0
- package/{scripts/lib/cursor-probe-utils.mjs → shared/cursor-sensitive-text.mjs} +1 -13
- package/shared/cursor-setting-sources.d.mts +5 -0
- package/shared/cursor-setting-sources.mjs +22 -0
- package/src/context.ts +21 -12
- package/src/cursor-bridge-contract.ts +1 -3
- package/src/cursor-incomplete-tool-visibility.ts +22 -5
- package/src/cursor-native-tool-display-registration.ts +63 -27
- package/src/cursor-native-tool-display-replay.ts +246 -144
- package/src/cursor-native-tool-display-state.ts +2 -0
- package/src/cursor-native-tool-display-tools.ts +149 -41
- package/src/cursor-provider-live-run-drain.ts +1 -52
- package/src/cursor-provider-run-finalizer.ts +237 -0
- package/src/cursor-provider-run-outcome.ts +149 -0
- package/src/cursor-provider-turn-api-key.ts +8 -0
- package/src/cursor-provider-turn-coordinator.ts +98 -446
- package/src/cursor-provider-turn-display-router.ts +216 -0
- package/src/cursor-provider-turn-emit.ts +59 -0
- package/src/cursor-provider-turn-finalize.ts +119 -0
- package/src/cursor-provider-turn-lifecycle-emitter.ts +97 -0
- package/src/cursor-provider-turn-message-offset.ts +15 -0
- package/src/cursor-provider-turn-prepare.ts +216 -0
- package/src/cursor-provider-turn-runner.ts +140 -0
- package/src/cursor-provider-turn-sdk-normalizer.ts +88 -0
- package/src/cursor-provider-turn-send.ts +103 -0
- package/src/cursor-provider-turn-shell-output.ts +107 -0
- package/src/cursor-provider-turn-tool-ledger.ts +126 -0
- package/src/cursor-provider-turn-types.ts +87 -0
- package/src/cursor-provider.ts +16 -504
- package/src/cursor-replay-activity-builders.ts +276 -0
- package/src/cursor-replay-source-names.ts +33 -0
- package/src/cursor-replay-summary-args.ts +191 -0
- package/src/cursor-replay-tool-details.ts +464 -0
- package/src/cursor-run-final-text.ts +56 -0
- package/src/cursor-sdk-abort-error-guard.ts +4 -0
- package/src/cursor-sdk-event-debug-constants.ts +14 -5
- package/src/cursor-sdk-event-debug.ts +2 -1
- package/src/cursor-sensitive-text.ts +3 -36
- package/src/cursor-session-agent.ts +3 -1
- package/src/cursor-session-compaction-prep.ts +19 -0
- package/src/cursor-setting-sources.ts +7 -10
- package/src/cursor-state.ts +232 -28
- package/src/cursor-tool-lifecycle.ts +9 -8
- package/src/cursor-tool-manifest.ts +41 -0
- package/src/cursor-tool-names.ts +18 -106
- package/src/cursor-tool-presentation-registry.ts +556 -0
- package/src/cursor-tool-transcript.ts +1 -1
- package/src/cursor-tool-visibility.ts +3 -27
- package/src/cursor-transcript-tool-formatters.ts +0 -59
- package/src/cursor-transcript-tool-specs.ts +158 -233
- package/src/cursor-transcript-utils.ts +0 -44
- package/src/cursor-web-tool-activity.ts +10 -60
- package/src/cursor-web-tool-args.ts +39 -0
- package/src/index.ts +8 -10
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function scrubSensitiveText(text: string, apiKey?: string): string;
|
|
@@ -1,21 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
/** Canonical secret/bridge scrubbing (parity-tested by provider runtime and maintainer scripts). */
|
|
2
2
|
|
|
3
3
|
function escapeRegExp(value) {
|
|
4
4
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
export function resolveCursorSettingSources(raw) {
|
|
8
|
-
const trimmed = raw?.trim();
|
|
9
|
-
if (!trimmed) return ["all"];
|
|
10
|
-
const normalized = trimmed.toLowerCase();
|
|
11
|
-
if (["0", "false", "off", "none", "omit", "disabled"].includes(normalized)) return undefined;
|
|
12
|
-
if (["1", "true", "on", "all"].includes(normalized)) return ["all"];
|
|
13
|
-
return trimmed
|
|
14
|
-
.split(",")
|
|
15
|
-
.map((entry) => entry.trim())
|
|
16
|
-
.filter(Boolean);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
7
|
const BRIDGE_ENDPOINT_ROOT = "/cursor-pi-tool-bridge";
|
|
20
8
|
const BRIDGE_ENDPOINT_TOKEN_PATTERN = "[^/\\s\"'<>]+";
|
|
21
9
|
const BRIDGE_LOOPBACK_HOST_PATTERN = "127\\.0\\.0\\.1(?::\\d+)?";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const CURSOR_SETTING_SOURCES_ENV: "PI_CURSOR_SETTING_SOURCES";
|
|
2
|
+
|
|
3
|
+
export declare function resolveCursorSettingSources(raw?: string): string[] | undefined;
|
|
4
|
+
|
|
5
|
+
export declare function serializeCursorSettingSources(settingSources: string[] | undefined): string;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Canonical Cursor settingSources parsing (parity-tested by provider runtime and maintainer scripts). */
|
|
2
|
+
export const CURSOR_SETTING_SOURCES_ENV = "PI_CURSOR_SETTING_SOURCES";
|
|
3
|
+
|
|
4
|
+
export function resolveCursorSettingSources(raw) {
|
|
5
|
+
const trimmed = raw?.trim();
|
|
6
|
+
if (!trimmed) return ["all"];
|
|
7
|
+
const normalized = trimmed.toLowerCase();
|
|
8
|
+
if (["0", "false", "off", "none", "omit", "disabled"].includes(normalized)) return undefined;
|
|
9
|
+
if (["1", "true", "on", "all"].includes(normalized)) return ["all"];
|
|
10
|
+
const sources = trimmed
|
|
11
|
+
.split(",")
|
|
12
|
+
.map((entry) => entry.trim())
|
|
13
|
+
.filter(Boolean);
|
|
14
|
+
if (sources.length === 0) return undefined;
|
|
15
|
+
return sources;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Serialize parsed settingSources for PI_CURSOR_SETTING_SOURCES (undefined => explicit none). */
|
|
19
|
+
export function serializeCursorSettingSources(settingSources) {
|
|
20
|
+
if (settingSources === undefined || settingSources.length === 0) return "none";
|
|
21
|
+
return settingSources.join(",");
|
|
22
|
+
}
|
package/src/context.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import type { Context, Message, ToolCall } from "@earendil-works/pi-ai";
|
|
3
3
|
import { convertToLlm } from "@earendil-works/pi-coding-agent";
|
|
4
4
|
import type { SDKImage } from "@cursor/sdk";
|
|
5
|
-
import { getCursorPiBridgeContractText } from "./cursor-bridge-contract.js";
|
|
6
5
|
import { getCursorReplayPromptLabel } from "./cursor-tool-names.js";
|
|
7
6
|
|
|
8
7
|
export interface CursorPrompt {
|
|
@@ -14,6 +13,8 @@ export interface CursorPromptOptions {
|
|
|
14
13
|
maxInputTokens?: number;
|
|
15
14
|
charsPerToken?: number;
|
|
16
15
|
imageTokenEstimate?: number;
|
|
16
|
+
/** Compact callable-surface summary; included on bootstrap prompts when set. */
|
|
17
|
+
toolManifest?: string;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
export const CURSOR_APPROX_CHARS_PER_TOKEN = 4;
|
|
@@ -21,20 +22,25 @@ export const CURSOR_IMAGE_TOKEN_ESTIMATE = 1200;
|
|
|
21
22
|
const SECTION_SEPARATOR = "\n\n";
|
|
22
23
|
|
|
23
24
|
export function getCursorToolTailGuardText(): string {
|
|
24
|
-
return
|
|
25
|
+
return [
|
|
26
|
+
"Shell: use an explicit `cd` to the repo path when running project commands; session cwd may not match paths in tool args.",
|
|
27
|
+
"Tool boundary reminder: If a tool is needed, call an available Cursor SDK/MCP tool. Never print a tool card (for example Tool call/Shell/command) as assistant text.",
|
|
28
|
+
].join("\n");
|
|
25
29
|
}
|
|
26
30
|
|
|
27
|
-
function getCursorToolBoundaryText(): string {
|
|
28
|
-
|
|
31
|
+
function getCursorToolBoundaryText(options: { hasToolManifest?: boolean } = {}): string {
|
|
32
|
+
const lines = [
|
|
29
33
|
"Cursor SDK tool boundary:",
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
"
|
|
34
|
+
"Call only tools exposed by Cursor SDK in this run. Pi tool names, replay labels, and transcript names are context only—not callable.",
|
|
35
|
+
"Bridged pi tools: call pi__* MCP names when exposed, not the pi card name in history. Replay activity is display-only.",
|
|
36
|
+
"Do not claim pi-side or WebSearch/WebFetch tools unless Cursor executes an equivalent tool.",
|
|
33
37
|
"Use pi__cursor_ask_question for material choices if exposed.",
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
"Images: only the latest user message's images are sent as bytes; ask to reattach or describe prior images.",
|
|
39
|
+
];
|
|
40
|
+
if (options.hasToolManifest) {
|
|
41
|
+
lines.push("See callable tool surfaces block below.");
|
|
42
|
+
}
|
|
43
|
+
return lines.join("\n");
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
function getCursorBootstrapTailSections(): string[] {
|
|
@@ -370,7 +376,10 @@ export function buildCursorIncrementalPrompt(context: Context, options: CursorPr
|
|
|
370
376
|
}
|
|
371
377
|
|
|
372
378
|
export function buildCursorPrompt(context: Context, options: CursorPromptOptions = {}): CursorPrompt {
|
|
373
|
-
const sectionsBeforeMessages: string[] = [getCursorToolBoundaryText()];
|
|
379
|
+
const sectionsBeforeMessages: string[] = [getCursorToolBoundaryText({ hasToolManifest: Boolean(options.toolManifest) })];
|
|
380
|
+
if (options.toolManifest) {
|
|
381
|
+
sectionsBeforeMessages.push(options.toolManifest);
|
|
382
|
+
}
|
|
374
383
|
|
|
375
384
|
if (context.systemPrompt) {
|
|
376
385
|
sectionsBeforeMessages.push(`System instructions from pi:\n${sanitizeSystemPromptForCursor(context.systemPrompt)}`);
|
|
@@ -20,8 +20,6 @@ export function buildCursorPiBridgeMcpToolDescription(options: {
|
|
|
20
20
|
}): string {
|
|
21
21
|
return [
|
|
22
22
|
options.piToolDescription,
|
|
23
|
-
|
|
24
|
-
getCursorPiBridgeContractText(),
|
|
25
|
-
`This run exposes real pi tool ${options.piToolName} as Cursor MCP tool ${options.mcpToolName}.`,
|
|
23
|
+
`Call MCP name ${options.mcpToolName} (pi tool: ${options.piToolName}). Full tool-surface rules are in the session bootstrap prompt.`,
|
|
26
24
|
].join("\n");
|
|
27
25
|
}
|
|
@@ -5,6 +5,11 @@ import {
|
|
|
5
5
|
DISCARDED_INCOMPLETE_TOOL_CALL_REASON,
|
|
6
6
|
type DiscardedIncompleteStartedToolCallReason,
|
|
7
7
|
} from "./cursor-sdk-event-debug.js";
|
|
8
|
+
import {
|
|
9
|
+
assembleCursorReplayActivityDetails,
|
|
10
|
+
parseCursorReplayToolDetails,
|
|
11
|
+
resolveIncompleteReplayActivitySourceToolName,
|
|
12
|
+
} from "./cursor-replay-tool-details.js";
|
|
8
13
|
import { truncateArg, type CursorPiToolDisplay } from "./cursor-transcript-utils.js";
|
|
9
14
|
import { classifyCursorToolVisibility } from "./cursor-tool-visibility.js";
|
|
10
15
|
|
|
@@ -87,6 +92,14 @@ export function buildIncompleteCursorToolDisplay(
|
|
|
87
92
|
const headline = `${activityTitle} did not complete`;
|
|
88
93
|
const reasonText = scrubSensitiveText(formatIncompleteCursorToolReasonText(reason), options.apiKey);
|
|
89
94
|
const contentText = `${headline}\n${reasonText}`;
|
|
95
|
+
const details = assembleCursorReplayActivityDetails(
|
|
96
|
+
resolveIncompleteReplayActivitySourceToolName(visibility.normalizedName),
|
|
97
|
+
headline,
|
|
98
|
+
{ summary: reasonText, expandedText: contentText },
|
|
99
|
+
contentText,
|
|
100
|
+
true,
|
|
101
|
+
reasonText,
|
|
102
|
+
);
|
|
90
103
|
return {
|
|
91
104
|
toolName: CURSOR_REPLAY_ACTIVITY_TOOL_NAME,
|
|
92
105
|
args: {
|
|
@@ -97,17 +110,21 @@ export function buildIncompleteCursorToolDisplay(
|
|
|
97
110
|
},
|
|
98
111
|
result: {
|
|
99
112
|
content: [{ type: "text", text: contentText }],
|
|
100
|
-
details
|
|
101
|
-
cursorToolName: visibility.normalizedName,
|
|
102
|
-
title: headline,
|
|
103
|
-
summary: reasonText,
|
|
104
|
-
},
|
|
113
|
+
details,
|
|
105
114
|
},
|
|
106
115
|
isError: true,
|
|
107
116
|
};
|
|
108
117
|
}
|
|
109
118
|
|
|
110
119
|
export function formatIncompleteCursorToolTrace(display: CursorPiToolDisplay): string {
|
|
120
|
+
const parsed = parseCursorReplayToolDetails(display.result.details);
|
|
121
|
+
if (parsed?.variant === "activity") {
|
|
122
|
+
const summary =
|
|
123
|
+
parsed.summary?.trim() ||
|
|
124
|
+
(typeof display.args.activitySummary === "string" && display.args.activitySummary.trim()) ||
|
|
125
|
+
formatIncompleteCursorToolReasonText(DISCARDED_INCOMPLETE_TOOL_CALL_REASON);
|
|
126
|
+
return `${truncateCursorDisplayLine(parsed.title)}: ${truncateCursorDisplayLine(summary)}\n`;
|
|
127
|
+
}
|
|
111
128
|
const details = display.result.details;
|
|
112
129
|
const detailRecord = details && typeof details === "object" ? (details as Record<string, unknown>) : undefined;
|
|
113
130
|
const argsRecord = display.args;
|
|
@@ -13,12 +13,19 @@ import {
|
|
|
13
13
|
NATIVE_CURSOR_TOOL_DISPLAY_ENV,
|
|
14
14
|
readBooleanEnv,
|
|
15
15
|
registeredNativeToolNames,
|
|
16
|
+
skippedNativeToolNames,
|
|
16
17
|
} from "./cursor-native-tool-display-state.js";
|
|
17
18
|
import { isCursorReplayToolName } from "./cursor-tool-names.js";
|
|
18
19
|
|
|
19
|
-
const
|
|
20
|
+
export const CURSOR_CORE_PI_REPLAY_TOOL_NAMES = ["read", "bash", "edit", "write"] as const;
|
|
21
|
+
const CORE_PI_TOOL_NAMES = new Set<string>(CURSOR_CORE_PI_REPLAY_TOOL_NAMES);
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
function isCursorCorePiReplayToolName(toolName: string): toolName is (typeof CURSOR_CORE_PI_REPLAY_TOOL_NAMES)[number] {
|
|
24
|
+
return CORE_PI_TOOL_NAMES.has(toolName);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
type CursorNativeToolActivationApi = Pick<ExtensionAPI, "getActiveTools" | "setActiveTools">;
|
|
28
|
+
type CursorNativeToolRegistryApi = CursorNativeToolActivationApi & Pick<ExtensionAPI, "getAllTools" | "registerTool">;
|
|
22
29
|
|
|
23
30
|
export interface CursorNativeToolDisplayExtensionApi extends CursorNativeToolRegistryApi {
|
|
24
31
|
on(event: "session_start", handler: ExtensionHandler<SessionStartEvent>): void;
|
|
@@ -34,7 +41,40 @@ function hasNonBuiltinTool(pi: Pick<ExtensionAPI, "getAllTools">, toolName: Nati
|
|
|
34
41
|
|
|
35
42
|
type NativeRegistrationContext = { hasUI: boolean; ui: Pick<ExtensionContext["ui"], "notify">; model?: ExtensionContext["model"] };
|
|
36
43
|
|
|
37
|
-
|
|
44
|
+
function registerNativeCursorToolsFromSet(
|
|
45
|
+
pi: CursorNativeToolRegistryApi,
|
|
46
|
+
toolNames: readonly NativeCursorToolName[],
|
|
47
|
+
): NativeCursorToolName[] {
|
|
48
|
+
const newlySkippedToolNames: NativeCursorToolName[] = [];
|
|
49
|
+
for (const toolName of toolNames) {
|
|
50
|
+
if (registeredNativeToolNames.has(toolName) || skippedNativeToolNames.has(toolName)) continue;
|
|
51
|
+
if (hasNonBuiltinTool(pi, toolName)) {
|
|
52
|
+
skippedNativeToolNames.add(toolName);
|
|
53
|
+
newlySkippedToolNames.push(toolName);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
registerNativeCursorTool(pi, toolName);
|
|
57
|
+
registeredNativeToolNames.add(toolName);
|
|
58
|
+
}
|
|
59
|
+
return newlySkippedToolNames;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function notifySkippedNativeCursorToolsIfNeeded(ctx: NativeRegistrationContext, skippedToolNames: readonly NativeCursorToolName[]): void {
|
|
63
|
+
if (skippedToolNames.length === 0 || readBooleanEnv(NATIVE_CURSOR_TOOL_DISPLAY_ENV) !== true || !ctx.hasUI) return;
|
|
64
|
+
ctx.ui.notify(
|
|
65
|
+
`Cursor native tool replay skipped for ${skippedToolNames.join(", ")} because another extension already provides ${skippedToolNames.length === 1 ? "that tool" : "those tools"}. Cursor will use scrubbed activity transcripts for skipped tools.`,
|
|
66
|
+
"warning",
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function hasAttemptedNativeCursorToolRegistration(): boolean {
|
|
71
|
+
return registeredNativeToolNames.size > 0 || skippedNativeToolNames.size > 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function syncRegisteredNativeCursorToolsForModel(
|
|
75
|
+
pi: CursorNativeToolActivationApi,
|
|
76
|
+
model: ExtensionContext["model"],
|
|
77
|
+
): void {
|
|
38
78
|
if (registeredNativeToolNames.size === 0) return;
|
|
39
79
|
const activeToolNames = new Set(pi.getActiveTools());
|
|
40
80
|
let changed = false;
|
|
@@ -47,7 +87,7 @@ export function syncRegisteredNativeCursorToolsForModel(pi: Pick<ExtensionAPI, "
|
|
|
47
87
|
}
|
|
48
88
|
} else {
|
|
49
89
|
for (const toolName of registeredNativeToolNames) {
|
|
50
|
-
if (
|
|
90
|
+
if (isCursorCorePiReplayToolName(toolName)) continue;
|
|
51
91
|
if (!activeToolNames.delete(toolName)) continue;
|
|
52
92
|
changed = true;
|
|
53
93
|
}
|
|
@@ -55,45 +95,41 @@ export function syncRegisteredNativeCursorToolsForModel(pi: Pick<ExtensionAPI, "
|
|
|
55
95
|
if (changed) pi.setActiveTools([...activeToolNames]);
|
|
56
96
|
}
|
|
57
97
|
|
|
58
|
-
function
|
|
98
|
+
function ensureNativeCursorToolsRegisteredForModel(pi: CursorNativeToolRegistryApi, ctx: NativeRegistrationContext): void {
|
|
59
99
|
if (!isCursorNativeToolRegistrationRequested()) {
|
|
60
100
|
registeredNativeToolNames.clear();
|
|
101
|
+
skippedNativeToolNames.clear();
|
|
61
102
|
return;
|
|
62
103
|
}
|
|
104
|
+
if (!isCursorModel(ctx.model) || hasAttemptedNativeCursorToolRegistration()) return;
|
|
63
105
|
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
registerNativeCursorTool(pi, toolName);
|
|
72
|
-
registeredNativeToolNames.add(toolName);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
syncRegisteredNativeCursorToolsForModel(pi, ctx.model);
|
|
106
|
+
const nonCoreToolNames = NATIVE_CURSOR_TOOL_NAMES.filter((toolName) => !isCursorCorePiReplayToolName(toolName));
|
|
107
|
+
const skippedToolNames = [
|
|
108
|
+
...registerNativeCursorToolsFromSet(pi, nonCoreToolNames),
|
|
109
|
+
...registerNativeCursorToolsFromSet(pi, CURSOR_CORE_PI_REPLAY_TOOL_NAMES),
|
|
110
|
+
];
|
|
111
|
+
notifySkippedNativeCursorToolsIfNeeded(ctx, skippedToolNames);
|
|
112
|
+
}
|
|
76
113
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
"warning",
|
|
81
|
-
);
|
|
114
|
+
function ensureThenSyncNativeCursorToolsForModel(pi: CursorNativeToolRegistryApi, ctx: NativeRegistrationContext): void {
|
|
115
|
+
if (isCursorModel(ctx.model) && !hasAttemptedNativeCursorToolRegistration()) {
|
|
116
|
+
ensureNativeCursorToolsRegisteredForModel(pi, ctx);
|
|
82
117
|
}
|
|
118
|
+
syncRegisteredNativeCursorToolsForModel(pi, ctx.model);
|
|
83
119
|
}
|
|
84
120
|
|
|
85
121
|
export function registerCursorNativeToolDisplay(pi: CursorNativeToolDisplayExtensionApi): void {
|
|
86
122
|
pi.on("session_start", (_event, ctx) => {
|
|
87
|
-
|
|
123
|
+
ensureThenSyncNativeCursorToolsForModel(pi, ctx);
|
|
88
124
|
});
|
|
89
125
|
pi.on("before_agent_start", (_event, ctx) => {
|
|
90
|
-
|
|
126
|
+
ensureThenSyncNativeCursorToolsForModel(pi, ctx);
|
|
91
127
|
});
|
|
92
128
|
pi.on("turn_start", (_event, ctx) => {
|
|
93
|
-
|
|
129
|
+
ensureThenSyncNativeCursorToolsForModel(pi, ctx);
|
|
94
130
|
});
|
|
95
|
-
pi.on("model_select", (event) => {
|
|
96
|
-
|
|
131
|
+
pi.on("model_select", (event, ctx) => {
|
|
132
|
+
ensureThenSyncNativeCursorToolsForModel(pi, { ...ctx, model: event.model });
|
|
97
133
|
});
|
|
98
134
|
}
|
|
99
135
|
|