pi-cursor-sdk 0.1.20 → 0.1.21
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 +32 -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 +57 -17
- 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 +235 -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 +138 -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-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 +4 -10
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical Cursor tool presentation metadata.
|
|
3
|
+
* Names, labels, visibility, replay, lifecycle, web remapping, and alias normalization
|
|
4
|
+
* derive from this registry — do not duplicate tool lists in sibling modules.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
formatReplaySemSearchQuery,
|
|
9
|
+
readCursorReplaySummaryString,
|
|
10
|
+
summarizeReplayGenericActivity,
|
|
11
|
+
summarizeReplayMcp,
|
|
12
|
+
summarizeReplayPath,
|
|
13
|
+
summarizeReplayPlan,
|
|
14
|
+
summarizeReplayReadLints,
|
|
15
|
+
summarizeReplayRecordScreen,
|
|
16
|
+
summarizeReplayTask,
|
|
17
|
+
summarizeReplayTodoCount,
|
|
18
|
+
withActivitySummaryFallback,
|
|
19
|
+
type CursorReplayActivitySummaryOverride,
|
|
20
|
+
type CursorReplayGenerateImageSummaryArgs,
|
|
21
|
+
type CursorReplayPathSummaryArgs,
|
|
22
|
+
type CursorReplayPlanSummaryArgs,
|
|
23
|
+
type CursorReplayReadLintsSummaryArgs,
|
|
24
|
+
type CursorReplayRecordScreenSummaryArgs,
|
|
25
|
+
type CursorReplaySemSearchSummaryArgs,
|
|
26
|
+
type CursorReplaySummaryArgs,
|
|
27
|
+
type CursorReplayTaskSummaryArgs,
|
|
28
|
+
type CursorReplayTodoSummaryArgs,
|
|
29
|
+
type CursorReplayWebFetchSummaryArgs,
|
|
30
|
+
type CursorReplayWebSearchSummaryArgs,
|
|
31
|
+
} from "./cursor-replay-summary-args.js";
|
|
32
|
+
import {
|
|
33
|
+
buildCollapsedReplayDetailFields,
|
|
34
|
+
buildCreatePlanReplaySummaryArgs,
|
|
35
|
+
buildDeleteReplayDetailFields,
|
|
36
|
+
buildDeleteReplaySummaryArgs,
|
|
37
|
+
buildEmptyReplayDetailFields,
|
|
38
|
+
buildGenerateImageReplayDetailFields,
|
|
39
|
+
buildGenerateImageReplaySummaryArgs,
|
|
40
|
+
buildMcpReplaySummaryArgs,
|
|
41
|
+
buildReadLintsReplaySummaryArgs,
|
|
42
|
+
buildRecordScreenReplaySummaryArgs,
|
|
43
|
+
buildSemSearchReplaySummaryArgs,
|
|
44
|
+
buildTaskReplaySummaryArgs,
|
|
45
|
+
buildTodoReplaySummaryArgs,
|
|
46
|
+
buildWebFetchReplaySummaryArgs,
|
|
47
|
+
buildWebSearchReplaySummaryArgs,
|
|
48
|
+
type CursorReplayActivityBuildContext,
|
|
49
|
+
} from "./cursor-replay-activity-builders.js";
|
|
50
|
+
import { CURSOR_REPLAY_SOURCE_TOOL_NAMES, type CursorReplaySourceToolName } from "./cursor-replay-source-names.js";
|
|
51
|
+
import type {
|
|
52
|
+
CursorReplayActivityDetailFields,
|
|
53
|
+
CursorReplayGenerateImageDetailFields,
|
|
54
|
+
} from "./cursor-replay-tool-details.js";
|
|
55
|
+
|
|
56
|
+
export const CURSOR_REPLAY_ACTIVITY_TOOL_NAME = "cursor" as const;
|
|
57
|
+
|
|
58
|
+
export type CursorWebToolKind = "webSearch" | "webFetch";
|
|
59
|
+
|
|
60
|
+
export type CursorReplaySideEffectCategory = "file_mutations" | "real_tool_work";
|
|
61
|
+
|
|
62
|
+
export type CursorToolLifecycleLabelKind =
|
|
63
|
+
| "task"
|
|
64
|
+
| "shell"
|
|
65
|
+
| "mcp"
|
|
66
|
+
| "generateImage"
|
|
67
|
+
| "recordScreen"
|
|
68
|
+
| "semSearch"
|
|
69
|
+
| "webSearch"
|
|
70
|
+
| "webFetch"
|
|
71
|
+
| "createPlan"
|
|
72
|
+
| "updateTodos";
|
|
73
|
+
|
|
74
|
+
export type CursorReplayCallSummaryBuilder<T extends CursorReplayActivitySummaryOverride = CursorReplaySummaryArgs> = (
|
|
75
|
+
args: T | undefined,
|
|
76
|
+
) => string | undefined;
|
|
77
|
+
|
|
78
|
+
export interface CursorToolVisibilityPolicy {
|
|
79
|
+
incompleteTitle?: string;
|
|
80
|
+
lifecycleTitle?: string;
|
|
81
|
+
lifecycleEligible?: boolean;
|
|
82
|
+
fastLocalDiscovery?: boolean;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface CursorToolActivityReplaySpec<TArgs extends CursorReplaySummaryArgs = CursorReplaySummaryArgs> {
|
|
86
|
+
buildActivityArgs: (context: CursorReplayActivityBuildContext) => TArgs;
|
|
87
|
+
buildDetails: (context: CursorReplayActivityBuildContext, contentText: string) => CursorReplayActivityDetailFields;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface CursorToolGenerateImageReplaySpec {
|
|
91
|
+
buildActivityArgs: (context: CursorReplayActivityBuildContext) => CursorReplayGenerateImageSummaryArgs;
|
|
92
|
+
buildDetails: (context: CursorReplayActivityBuildContext, contentText: string) => CursorReplayGenerateImageDetailFields;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface CursorToolPresentationSpec {
|
|
96
|
+
normalizedName: CursorReplaySourceToolName;
|
|
97
|
+
/** Raw SDK/host names that resolve to this tool via {@link normalizeCursorToolName}. */
|
|
98
|
+
nameAliases?: readonly string[];
|
|
99
|
+
replayLegacyName?: string;
|
|
100
|
+
/** Human-readable SDK operation label for replay-only tool descriptions when it differs from {@link normalizedName}. */
|
|
101
|
+
replayOperationLabel?: string;
|
|
102
|
+
promptLabel: string;
|
|
103
|
+
displayLabel: string;
|
|
104
|
+
visibility: CursorToolVisibilityPolicy;
|
|
105
|
+
webKind?: CursorWebToolKind;
|
|
106
|
+
/** Regexes matched against lowercased trimmed tool names for {@link classifyCursorWebToolKind}. */
|
|
107
|
+
webNamePatterns?: readonly RegExp[];
|
|
108
|
+
lifecycleLabelKind?: CursorToolLifecycleLabelKind;
|
|
109
|
+
replayCallSummary?: CursorReplayCallSummaryBuilder;
|
|
110
|
+
/** Short label for replay-only tool definitions (for example `edit` for `cursor_edit`). */
|
|
111
|
+
replayWrapperLabel?: string;
|
|
112
|
+
/** Whether replay-only wrappers describe file mutations or other recorded tool work. */
|
|
113
|
+
replaySideEffectCategory?: CursorReplaySideEffectCategory;
|
|
114
|
+
activityReplay?: CursorToolActivityReplaySpec;
|
|
115
|
+
generateImageReplay?: CursorToolGenerateImageReplaySpec;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const WEB_SEARCH_NAME_PATTERN =
|
|
119
|
+
/^(?:web[-_ ]?search|search[-_ ]?web|websearch|browser[-_ ]?search|cursor[-_ ]?web[-_ ]?search)$/i;
|
|
120
|
+
const WEB_FETCH_NAME_PATTERN =
|
|
121
|
+
/^(?:web[-_ ]?fetch|fetch[-_ ]?web|webfetch|browser[-_ ]?fetch|fetch[-_ ]?url|cursor[-_ ]?web[-_ ]?fetch)$/i;
|
|
122
|
+
|
|
123
|
+
export const CURSOR_TOOL_PRESENTATION_SPECS = [
|
|
124
|
+
{
|
|
125
|
+
normalizedName: "read",
|
|
126
|
+
nameAliases: ["read_file"],
|
|
127
|
+
promptLabel: "read",
|
|
128
|
+
displayLabel: "read",
|
|
129
|
+
visibility: { incompleteTitle: "Cursor read", fastLocalDiscovery: true },
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
normalizedName: "grep",
|
|
133
|
+
nameAliases: ["grep_search", "search"],
|
|
134
|
+
promptLabel: "grep",
|
|
135
|
+
displayLabel: "grep",
|
|
136
|
+
visibility: { incompleteTitle: "Cursor grep", fastLocalDiscovery: true },
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
normalizedName: "glob",
|
|
140
|
+
nameAliases: ["file_search"],
|
|
141
|
+
promptLabel: "glob",
|
|
142
|
+
displayLabel: "glob",
|
|
143
|
+
visibility: { incompleteTitle: "Cursor find", fastLocalDiscovery: true },
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
normalizedName: "ls",
|
|
147
|
+
nameAliases: ["list_dir"],
|
|
148
|
+
promptLabel: "ls",
|
|
149
|
+
displayLabel: "ls",
|
|
150
|
+
visibility: { incompleteTitle: "Cursor ls", fastLocalDiscovery: true },
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
normalizedName: "shell",
|
|
154
|
+
nameAliases: ["run_terminal_cmd", "terminal", "bash"],
|
|
155
|
+
promptLabel: "shell",
|
|
156
|
+
displayLabel: "shell",
|
|
157
|
+
visibility: {
|
|
158
|
+
incompleteTitle: "Cursor shell",
|
|
159
|
+
lifecycleTitle: "Cursor shell",
|
|
160
|
+
lifecycleEligible: true,
|
|
161
|
+
},
|
|
162
|
+
lifecycleLabelKind: "shell",
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
normalizedName: "edit",
|
|
166
|
+
nameAliases: [
|
|
167
|
+
"strreplace",
|
|
168
|
+
"str_replace",
|
|
169
|
+
"str-replace",
|
|
170
|
+
"edit_file",
|
|
171
|
+
"editfile",
|
|
172
|
+
"edit_notebook",
|
|
173
|
+
"editnotebook",
|
|
174
|
+
"notebook_edit",
|
|
175
|
+
"notebookedit",
|
|
176
|
+
],
|
|
177
|
+
replayLegacyName: "cursor_edit",
|
|
178
|
+
promptLabel: "Cursor edit",
|
|
179
|
+
displayLabel: "Cursor edit",
|
|
180
|
+
visibility: {},
|
|
181
|
+
replayWrapperLabel: "edit",
|
|
182
|
+
replaySideEffectCategory: "file_mutations",
|
|
183
|
+
replayCallSummary: withActivitySummaryFallback(summarizeReplayPath),
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
normalizedName: "write",
|
|
187
|
+
nameAliases: ["write_file", "writefile"],
|
|
188
|
+
replayLegacyName: "cursor_write",
|
|
189
|
+
promptLabel: "Cursor write",
|
|
190
|
+
displayLabel: "Cursor write",
|
|
191
|
+
visibility: {},
|
|
192
|
+
replayWrapperLabel: "write",
|
|
193
|
+
replaySideEffectCategory: "file_mutations",
|
|
194
|
+
replayCallSummary: withActivitySummaryFallback(summarizeReplayPath),
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
normalizedName: "delete",
|
|
198
|
+
replayLegacyName: "cursor_delete",
|
|
199
|
+
promptLabel: "Cursor delete",
|
|
200
|
+
displayLabel: "Cursor delete",
|
|
201
|
+
visibility: {},
|
|
202
|
+
replayCallSummary: withActivitySummaryFallback(summarizeReplayPath),
|
|
203
|
+
activityReplay: {
|
|
204
|
+
buildActivityArgs: buildDeleteReplaySummaryArgs,
|
|
205
|
+
buildDetails: buildDeleteReplayDetailFields,
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
normalizedName: "readLints",
|
|
210
|
+
replayLegacyName: "cursor_read_lints",
|
|
211
|
+
promptLabel: "Cursor diagnostics",
|
|
212
|
+
displayLabel: "Cursor diagnostics",
|
|
213
|
+
visibility: {},
|
|
214
|
+
replayCallSummary: withActivitySummaryFallback(summarizeReplayReadLints),
|
|
215
|
+
activityReplay: {
|
|
216
|
+
buildActivityArgs: buildReadLintsReplaySummaryArgs,
|
|
217
|
+
buildDetails: buildEmptyReplayDetailFields,
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
normalizedName: "updateTodos",
|
|
222
|
+
replayLegacyName: "cursor_update_todos",
|
|
223
|
+
promptLabel: "Cursor todos",
|
|
224
|
+
displayLabel: "Cursor todos",
|
|
225
|
+
visibility: { lifecycleEligible: true },
|
|
226
|
+
lifecycleLabelKind: "updateTodos",
|
|
227
|
+
replayCallSummary: withActivitySummaryFallback(summarizeReplayTodoCount),
|
|
228
|
+
activityReplay: {
|
|
229
|
+
buildActivityArgs: ({ args, result }) => buildTodoReplaySummaryArgs(args, result),
|
|
230
|
+
buildDetails: buildEmptyReplayDetailFields,
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
normalizedName: "createPlan",
|
|
235
|
+
replayLegacyName: "cursor_create_plan",
|
|
236
|
+
promptLabel: "Cursor plan",
|
|
237
|
+
displayLabel: "Cursor plan",
|
|
238
|
+
visibility: { lifecycleEligible: true },
|
|
239
|
+
lifecycleLabelKind: "createPlan",
|
|
240
|
+
replayCallSummary: withActivitySummaryFallback(summarizeReplayPlan),
|
|
241
|
+
activityReplay: {
|
|
242
|
+
buildActivityArgs: buildCreatePlanReplaySummaryArgs,
|
|
243
|
+
buildDetails: buildEmptyReplayDetailFields,
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
normalizedName: "task",
|
|
248
|
+
replayLegacyName: "cursor_task",
|
|
249
|
+
promptLabel: "Cursor task",
|
|
250
|
+
displayLabel: "Cursor task",
|
|
251
|
+
visibility: { lifecycleEligible: true },
|
|
252
|
+
lifecycleLabelKind: "task",
|
|
253
|
+
replayCallSummary: withActivitySummaryFallback(summarizeReplayTask),
|
|
254
|
+
activityReplay: {
|
|
255
|
+
buildActivityArgs: buildTaskReplaySummaryArgs,
|
|
256
|
+
buildDetails: buildEmptyReplayDetailFields,
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
normalizedName: "generateImage",
|
|
261
|
+
replayLegacyName: "cursor_generate_image",
|
|
262
|
+
promptLabel: "Cursor image generation",
|
|
263
|
+
displayLabel: "Cursor image generation",
|
|
264
|
+
visibility: { lifecycleEligible: true },
|
|
265
|
+
lifecycleLabelKind: "generateImage",
|
|
266
|
+
replayCallSummary: withActivitySummaryFallback((args: CursorReplayGenerateImageSummaryArgs | undefined) =>
|
|
267
|
+
readCursorReplaySummaryString(args, "path") ?? readCursorReplaySummaryString(args, "prompt"),
|
|
268
|
+
),
|
|
269
|
+
generateImageReplay: {
|
|
270
|
+
buildActivityArgs: buildGenerateImageReplaySummaryArgs,
|
|
271
|
+
buildDetails: buildGenerateImageReplayDetailFields,
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
normalizedName: "mcp",
|
|
276
|
+
replayLegacyName: "cursor_mcp",
|
|
277
|
+
replayOperationLabel: "MCP",
|
|
278
|
+
promptLabel: "Cursor MCP",
|
|
279
|
+
displayLabel: "Cursor MCP",
|
|
280
|
+
visibility: { lifecycleEligible: true },
|
|
281
|
+
lifecycleLabelKind: "mcp",
|
|
282
|
+
replayCallSummary: withActivitySummaryFallback(summarizeReplayMcp),
|
|
283
|
+
activityReplay: {
|
|
284
|
+
buildActivityArgs: buildMcpReplaySummaryArgs,
|
|
285
|
+
buildDetails: buildEmptyReplayDetailFields,
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
normalizedName: "semSearch",
|
|
290
|
+
replayLegacyName: "cursor_sem_search",
|
|
291
|
+
promptLabel: "Cursor semantic search",
|
|
292
|
+
displayLabel: "Cursor semantic search",
|
|
293
|
+
visibility: { lifecycleEligible: true },
|
|
294
|
+
lifecycleLabelKind: "semSearch",
|
|
295
|
+
replayCallSummary: withActivitySummaryFallback(formatReplaySemSearchQuery),
|
|
296
|
+
activityReplay: {
|
|
297
|
+
buildActivityArgs: buildSemSearchReplaySummaryArgs,
|
|
298
|
+
buildDetails: buildEmptyReplayDetailFields,
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
normalizedName: "recordScreen",
|
|
303
|
+
replayLegacyName: "cursor_record_screen",
|
|
304
|
+
promptLabel: "Cursor screen recording",
|
|
305
|
+
displayLabel: "Cursor screen recording",
|
|
306
|
+
visibility: { lifecycleEligible: true },
|
|
307
|
+
lifecycleLabelKind: "recordScreen",
|
|
308
|
+
replayCallSummary: withActivitySummaryFallback(summarizeReplayRecordScreen),
|
|
309
|
+
activityReplay: {
|
|
310
|
+
buildActivityArgs: buildRecordScreenReplaySummaryArgs,
|
|
311
|
+
buildDetails: buildEmptyReplayDetailFields,
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
normalizedName: "webSearch",
|
|
316
|
+
nameAliases: ["websearch", "web_search", "web-search"],
|
|
317
|
+
replayLegacyName: "cursor_web_search",
|
|
318
|
+
replayOperationLabel: "web search",
|
|
319
|
+
promptLabel: "Cursor web search",
|
|
320
|
+
displayLabel: "Cursor web search",
|
|
321
|
+
visibility: { lifecycleEligible: true },
|
|
322
|
+
webKind: "webSearch",
|
|
323
|
+
webNamePatterns: [WEB_SEARCH_NAME_PATTERN],
|
|
324
|
+
lifecycleLabelKind: "webSearch",
|
|
325
|
+
replayCallSummary: withActivitySummaryFallback((args: CursorReplayWebSearchSummaryArgs | undefined) =>
|
|
326
|
+
readCursorReplaySummaryString(args, "query"),
|
|
327
|
+
),
|
|
328
|
+
activityReplay: {
|
|
329
|
+
buildActivityArgs: buildWebSearchReplaySummaryArgs,
|
|
330
|
+
buildDetails: buildCollapsedReplayDetailFields,
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
normalizedName: "webFetch",
|
|
335
|
+
nameAliases: ["webfetch", "web_fetch", "web-fetch"],
|
|
336
|
+
replayLegacyName: "cursor_web_fetch",
|
|
337
|
+
replayOperationLabel: "web fetch",
|
|
338
|
+
promptLabel: "Cursor web fetch",
|
|
339
|
+
displayLabel: "Cursor web fetch",
|
|
340
|
+
visibility: { lifecycleEligible: true },
|
|
341
|
+
webKind: "webFetch",
|
|
342
|
+
webNamePatterns: [WEB_FETCH_NAME_PATTERN],
|
|
343
|
+
lifecycleLabelKind: "webFetch",
|
|
344
|
+
replayCallSummary: withActivitySummaryFallback((args: CursorReplayWebFetchSummaryArgs | undefined) =>
|
|
345
|
+
readCursorReplaySummaryString(args, "url"),
|
|
346
|
+
),
|
|
347
|
+
activityReplay: {
|
|
348
|
+
buildActivityArgs: buildWebFetchReplaySummaryArgs,
|
|
349
|
+
buildDetails: buildCollapsedReplayDetailFields,
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
] as const satisfies readonly CursorToolPresentationSpec[];
|
|
353
|
+
|
|
354
|
+
type CursorToolPresentationSpecEntry = (typeof CURSOR_TOOL_PRESENTATION_SPECS)[number];
|
|
355
|
+
|
|
356
|
+
export type CursorNormalizedToolName = CursorReplaySourceToolName;
|
|
357
|
+
|
|
358
|
+
export type CursorReplayLegacyToolName = Extract<
|
|
359
|
+
CursorToolPresentationSpecEntry,
|
|
360
|
+
{ readonly replayLegacyName: string }
|
|
361
|
+
>["replayLegacyName"];
|
|
362
|
+
|
|
363
|
+
export type CursorReplayToolName = typeof CURSOR_REPLAY_ACTIVITY_TOOL_NAME | CursorReplayLegacyToolName;
|
|
364
|
+
|
|
365
|
+
type CursorToolPresentationSpecWithReplayLegacy = Extract<
|
|
366
|
+
CursorToolPresentationSpecEntry,
|
|
367
|
+
{ readonly replayLegacyName: string }
|
|
368
|
+
>;
|
|
369
|
+
|
|
370
|
+
const CURSOR_REPLAY_ACTIVITY_SIDE_EFFECT_CATEGORY: CursorReplaySideEffectCategory = "file_mutations";
|
|
371
|
+
|
|
372
|
+
function hasReplayLegacyName(spec: CursorToolPresentationSpecEntry): spec is CursorToolPresentationSpecWithReplayLegacy {
|
|
373
|
+
return "replayLegacyName" in spec;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
type ReplayActivityLabelKeysFromSpecs<Specs extends readonly CursorToolPresentationSpecEntry[]> = {
|
|
377
|
+
[K in Extract<Specs[number], { readonly replayLegacyName: string }>["normalizedName"]]: Extract<
|
|
378
|
+
Specs[number],
|
|
379
|
+
{ readonly replayLegacyName: string; normalizedName: K }
|
|
380
|
+
>["replayLegacyName"];
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
function buildReplayActivityLabelKeysByToolName<const Specs extends readonly CursorToolPresentationSpecEntry[]>(
|
|
384
|
+
specs: Specs,
|
|
385
|
+
): ReplayActivityLabelKeysFromSpecs<Specs> {
|
|
386
|
+
const labelKeys: Record<string, CursorReplayLegacyToolName> = {};
|
|
387
|
+
for (const spec of specs) {
|
|
388
|
+
if (!hasReplayLegacyName(spec)) continue;
|
|
389
|
+
labelKeys[spec.normalizedName] = spec.replayLegacyName;
|
|
390
|
+
}
|
|
391
|
+
return labelKeys as ReplayActivityLabelKeysFromSpecs<Specs>;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const CURSOR_REPLAY_SPECS = CURSOR_TOOL_PRESENTATION_SPECS.filter(hasReplayLegacyName);
|
|
395
|
+
|
|
396
|
+
/** Stable registration order for native replay tool wrappers (registry declaration order). */
|
|
397
|
+
export const CURSOR_REPLAY_LEGACY_TOOL_NAMES: readonly CursorReplayLegacyToolName[] = CURSOR_REPLAY_SPECS.map(
|
|
398
|
+
(spec) => spec.replayLegacyName,
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
export const CURSOR_REPLAY_ACTIVITY_LABEL_KEYS_BY_TOOL_NAME = buildReplayActivityLabelKeysByToolName(
|
|
402
|
+
CURSOR_TOOL_PRESENTATION_SPECS,
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
export type CursorReplayActivityToolName = keyof typeof CURSOR_REPLAY_ACTIVITY_LABEL_KEYS_BY_TOOL_NAME;
|
|
406
|
+
|
|
407
|
+
const SPECS_BY_NORMALIZED_NAME = new Map<string, CursorToolPresentationSpec>(
|
|
408
|
+
CURSOR_TOOL_PRESENTATION_SPECS.map((spec) => [spec.normalizedName, spec]),
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
const SPECS_BY_NORMALIZED_KEY = new Map<string, CursorToolPresentationSpec>(
|
|
412
|
+
CURSOR_TOOL_PRESENTATION_SPECS.map((spec) => [spec.normalizedName.toLowerCase(), spec]),
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
const SPECS_BY_REPLAY_LEGACY_NAME = new Map<CursorReplayLegacyToolName, CursorToolPresentationSpec>(
|
|
416
|
+
CURSOR_REPLAY_SPECS.map((spec) => [spec.replayLegacyName, spec]),
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
const ALIAS_TO_NORMALIZED_NAME = new Map<string, CursorNormalizedToolName>(
|
|
420
|
+
CURSOR_TOOL_PRESENTATION_SPECS.flatMap((spec) => {
|
|
421
|
+
const aliases = "nameAliases" in spec ? spec.nameAliases : undefined;
|
|
422
|
+
return (aliases ?? []).map((alias) => [alias.toLowerCase(), spec.normalizedName] as const);
|
|
423
|
+
}),
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
const WEB_KIND_BY_PATTERN = CURSOR_TOOL_PRESENTATION_SPECS.flatMap((spec) => {
|
|
427
|
+
if (!("webKind" in spec) || !("webNamePatterns" in spec)) return [];
|
|
428
|
+
const { webKind, webNamePatterns } = spec;
|
|
429
|
+
if (!webKind || !webNamePatterns) return [];
|
|
430
|
+
return webNamePatterns.map((pattern) => ({ pattern, webKind }));
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
export const CURSOR_KNOWN_NORMALIZED_TOOL_NAMES: readonly CursorNormalizedToolName[] = CURSOR_REPLAY_SOURCE_TOOL_NAMES;
|
|
434
|
+
|
|
435
|
+
export function getCursorToolPresentationSpec(
|
|
436
|
+
name: string,
|
|
437
|
+
): CursorToolPresentationSpec | undefined {
|
|
438
|
+
const trimmed = name.trim();
|
|
439
|
+
if (!trimmed) return undefined;
|
|
440
|
+
return (
|
|
441
|
+
SPECS_BY_NORMALIZED_NAME.get(trimmed) ??
|
|
442
|
+
SPECS_BY_NORMALIZED_KEY.get(trimmed.toLowerCase()) ??
|
|
443
|
+
(isCursorReplayLegacyToolName(trimmed) ? SPECS_BY_REPLAY_LEGACY_NAME.get(trimmed) : undefined)
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
export function normalizeCursorToolName(name: string): string {
|
|
448
|
+
const normalized = name.replace(/\s+/g, " ").trim();
|
|
449
|
+
if (!normalized) return "unknown";
|
|
450
|
+
const aliasTarget = ALIAS_TO_NORMALIZED_NAME.get(normalized.toLowerCase());
|
|
451
|
+
if (aliasTarget) return aliasTarget;
|
|
452
|
+
const spec = getCursorToolPresentationSpec(normalized);
|
|
453
|
+
if (spec) return spec.normalizedName;
|
|
454
|
+
return normalized;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export function classifyCursorWebToolKind(name: string | undefined): CursorWebToolKind | undefined {
|
|
458
|
+
if (!name) return undefined;
|
|
459
|
+
const normalized = name.replace(/\s+/g, " ").trim().toLowerCase();
|
|
460
|
+
for (const { pattern, webKind } of WEB_KIND_BY_PATTERN) {
|
|
461
|
+
if (pattern.test(normalized)) return webKind;
|
|
462
|
+
}
|
|
463
|
+
const spec = getCursorToolPresentationSpec(name);
|
|
464
|
+
return spec?.webKind;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const CURSOR_REPLAY_LEGACY_TOOL_NAME_SET: ReadonlySet<string> = new Set(CURSOR_REPLAY_LEGACY_TOOL_NAMES);
|
|
468
|
+
|
|
469
|
+
export function isCursorReplayLegacyToolName(toolName: string): toolName is CursorReplayLegacyToolName {
|
|
470
|
+
return CURSOR_REPLAY_LEGACY_TOOL_NAME_SET.has(toolName);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
export function isCursorReplayToolName(toolName: string): toolName is CursorReplayToolName {
|
|
474
|
+
return toolName === CURSOR_REPLAY_ACTIVITY_TOOL_NAME || isCursorReplayLegacyToolName(toolName);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
export function isExcludedFromCursorBridgeExposure(toolName: string): boolean {
|
|
478
|
+
return toolName === CURSOR_REPLAY_ACTIVITY_TOOL_NAME || isCursorReplayLegacyToolName(toolName);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
export function getCursorReplayWrapperLabel(toolName: CursorReplayToolName): string {
|
|
482
|
+
if (toolName === CURSOR_REPLAY_ACTIVITY_TOOL_NAME) return getCursorReplayDisplayLabel(toolName);
|
|
483
|
+
const spec = SPECS_BY_REPLAY_LEGACY_NAME.get(toolName);
|
|
484
|
+
return spec?.replayWrapperLabel ?? getCursorReplayDisplayLabel(toolName);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
export function getCursorReplaySideEffectCategory(toolName: CursorReplayToolName): CursorReplaySideEffectCategory {
|
|
488
|
+
if (toolName === CURSOR_REPLAY_ACTIVITY_TOOL_NAME) return CURSOR_REPLAY_ACTIVITY_SIDE_EFFECT_CATEGORY;
|
|
489
|
+
return SPECS_BY_REPLAY_LEGACY_NAME.get(toolName)?.replaySideEffectCategory ?? "real_tool_work";
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
export function getCursorReplaySideEffectDescription(toolName: CursorReplayToolName): string {
|
|
493
|
+
return getCursorReplaySideEffectCategory(toolName) === "file_mutations" ? "file mutations" : "real tool work";
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
export function getCursorReplayOperationLabel(toolName: CursorReplayLegacyToolName): string {
|
|
497
|
+
const spec = SPECS_BY_REPLAY_LEGACY_NAME.get(toolName);
|
|
498
|
+
return spec?.replayOperationLabel ?? spec?.normalizedName ?? toolName;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
export function getCursorReplayPromptLabel(toolName: string): string {
|
|
502
|
+
if (toolName === CURSOR_REPLAY_ACTIVITY_TOOL_NAME) return "Cursor activity";
|
|
503
|
+
if (isCursorReplayLegacyToolName(toolName)) {
|
|
504
|
+
const spec = SPECS_BY_REPLAY_LEGACY_NAME.get(toolName);
|
|
505
|
+
return spec?.promptLabel ?? toolName;
|
|
506
|
+
}
|
|
507
|
+
return toolName;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
export function getCursorReplayDisplayLabel(toolName: CursorReplayToolName): string {
|
|
511
|
+
if (toolName === CURSOR_REPLAY_ACTIVITY_TOOL_NAME) return "Cursor activity";
|
|
512
|
+
const spec = SPECS_BY_REPLAY_LEGACY_NAME.get(toolName);
|
|
513
|
+
return spec?.displayLabel ?? toolName;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
export function getCursorReplayActivityLabelKey(toolName: string): CursorReplayLegacyToolName | undefined {
|
|
517
|
+
const spec = getCursorToolPresentationSpec(toolName);
|
|
518
|
+
if (!spec?.replayLegacyName || !isCursorReplayLegacyToolName(spec.replayLegacyName)) return undefined;
|
|
519
|
+
return spec.replayLegacyName;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
export function getCursorReplayActivityTitle(toolName: string): string | undefined {
|
|
523
|
+
const spec = getCursorToolPresentationSpec(toolName);
|
|
524
|
+
if (!spec?.replayLegacyName) return undefined;
|
|
525
|
+
return spec.displayLabel;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function getCursorToolPresentationSpecByNormalizedKey(normalizedKey: string): CursorToolPresentationSpec | undefined {
|
|
529
|
+
return SPECS_BY_NORMALIZED_KEY.get(normalizedKey.toLowerCase());
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
export function getCursorToolVisibilityPolicy(normalizedKey: string): CursorToolVisibilityPolicy | undefined {
|
|
533
|
+
return getCursorToolPresentationSpecByNormalizedKey(normalizedKey)?.visibility;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
export function getCursorToolLifecycleLabelKind(normalizedKey: string): CursorToolLifecycleLabelKind | undefined {
|
|
537
|
+
return getCursorToolPresentationSpecByNormalizedKey(normalizedKey)?.lifecycleLabelKind;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
export function getCursorToolActivityReplaySpec(normalizedKey: string): CursorToolActivityReplaySpec | undefined {
|
|
541
|
+
return getCursorToolPresentationSpecByNormalizedKey(normalizedKey)?.activityReplay;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
export function getCursorToolGenerateImageReplaySpec(normalizedKey: string): CursorToolGenerateImageReplaySpec | undefined {
|
|
545
|
+
return getCursorToolPresentationSpecByNormalizedKey(normalizedKey)?.generateImageReplay;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
export function getCursorReplayCallSummary(
|
|
549
|
+
toolName: CursorReplayToolName,
|
|
550
|
+
args: CursorReplaySummaryArgs | undefined,
|
|
551
|
+
): string | undefined {
|
|
552
|
+
if (toolName === CURSOR_REPLAY_ACTIVITY_TOOL_NAME) {
|
|
553
|
+
return readCursorReplaySummaryString(args, "activitySummary") ?? summarizeReplayGenericActivity(args);
|
|
554
|
+
}
|
|
555
|
+
return SPECS_BY_REPLAY_LEGACY_NAME.get(toolName)?.replayCallSummary?.(args);
|
|
556
|
+
}
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
getToolName,
|
|
6
6
|
getToolResult,
|
|
7
7
|
normalizeResult,
|
|
8
|
-
normalizeToolName,
|
|
9
8
|
type CursorPiToolDisplay,
|
|
10
9
|
type TranscriptOptions,
|
|
11
10
|
} from "./cursor-transcript-utils.js";
|
|
11
|
+
import { normalizeCursorToolName as normalizeToolName } from "./cursor-tool-presentation-registry.js";
|
|
12
12
|
import {
|
|
13
13
|
buildCursorPiToolDisplayFromSpec,
|
|
14
14
|
formatCursorToolTranscriptFromSpec,
|
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
import { getCursorReplayActivityTitle } from "./cursor-tool-
|
|
2
|
-
import { getToolArgs, getToolName
|
|
1
|
+
import { getCursorReplayActivityTitle, getCursorToolVisibilityPolicy, normalizeCursorToolName as normalizeToolName } from "./cursor-tool-presentation-registry.js";
|
|
2
|
+
import { getToolArgs, getToolName } from "./cursor-transcript-utils.js";
|
|
3
3
|
import { resolveTranscriptToolName } from "./cursor-web-tool-activity.js";
|
|
4
4
|
|
|
5
|
-
interface CursorToolVisibilityConfig {
|
|
6
|
-
incompleteTitle?: string;
|
|
7
|
-
lifecycleTitle?: string;
|
|
8
|
-
lifecycleEligible?: boolean;
|
|
9
|
-
fastLocalDiscovery?: boolean;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
5
|
export interface CursorToolVisibility {
|
|
13
6
|
args: Record<string, unknown>;
|
|
14
7
|
displayName: string;
|
|
@@ -21,29 +14,12 @@ export interface CursorToolVisibility {
|
|
|
21
14
|
fastLocalDiscovery: boolean;
|
|
22
15
|
}
|
|
23
16
|
|
|
24
|
-
const CURSOR_TOOL_VISIBILITY_BY_NAME: Record<string, CursorToolVisibilityConfig> = {
|
|
25
|
-
read: { incompleteTitle: "Cursor read", fastLocalDiscovery: true },
|
|
26
|
-
grep: { incompleteTitle: "Cursor grep", fastLocalDiscovery: true },
|
|
27
|
-
glob: { incompleteTitle: "Cursor find", fastLocalDiscovery: true },
|
|
28
|
-
ls: { incompleteTitle: "Cursor ls", fastLocalDiscovery: true },
|
|
29
|
-
shell: { incompleteTitle: "Cursor shell", lifecycleTitle: "Cursor shell", lifecycleEligible: true },
|
|
30
|
-
task: { lifecycleEligible: true },
|
|
31
|
-
mcp: { lifecycleEligible: true },
|
|
32
|
-
generateimage: { lifecycleEligible: true },
|
|
33
|
-
recordscreen: { lifecycleEligible: true },
|
|
34
|
-
semsearch: { lifecycleEligible: true },
|
|
35
|
-
websearch: { lifecycleEligible: true },
|
|
36
|
-
webfetch: { lifecycleEligible: true },
|
|
37
|
-
createplan: { lifecycleEligible: true },
|
|
38
|
-
updatetodos: { lifecycleEligible: true },
|
|
39
|
-
};
|
|
40
|
-
|
|
41
17
|
export function classifyCursorToolVisibility(toolCall: unknown): CursorToolVisibility {
|
|
42
18
|
const args = getToolArgs(toolCall);
|
|
43
19
|
const displayName = resolveTranscriptToolName(getToolName(toolCall), args);
|
|
44
20
|
const normalizedName = normalizeToolName(displayName);
|
|
45
21
|
const normalizedKey = normalizedName.toLowerCase();
|
|
46
|
-
const config =
|
|
22
|
+
const config = getCursorToolVisibilityPolicy(normalizedKey);
|
|
47
23
|
const replayActivityTitle = getCursorReplayActivityTitle(normalizedName);
|
|
48
24
|
return {
|
|
49
25
|
args,
|