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,464 @@
|
|
|
1
|
+
import { isCursorReplayActivitySourceName, type CursorReplayActivitySourceName } from "./cursor-replay-source-names.js";
|
|
2
|
+
|
|
3
|
+
/** Replay detail variants keyed by replay card disposition, not SDK source tool alone. */
|
|
4
|
+
export type CursorReplayToolDetailsVariant =
|
|
5
|
+
| "nativeEdit"
|
|
6
|
+
| "nativeWrite"
|
|
7
|
+
| "activity"
|
|
8
|
+
| "generateImage"
|
|
9
|
+
| "genericFallback";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Sentinel source tool name for activity cards whose SDK name is not a known registry entry.
|
|
13
|
+
* Display identity lives in `title` and replay args.
|
|
14
|
+
*/
|
|
15
|
+
export const CURSOR_REPLAY_UNREGISTERED_ACTIVITY_TOOL_NAME = "unregisteredActivity" as const;
|
|
16
|
+
|
|
17
|
+
/** SDK source tool names carried on neutral activity replay cards. */
|
|
18
|
+
export type CursorReplayActivitySourceToolName =
|
|
19
|
+
| CursorReplayActivitySourceName
|
|
20
|
+
| typeof CURSOR_REPLAY_UNREGISTERED_ACTIVITY_TOOL_NAME;
|
|
21
|
+
|
|
22
|
+
declare const cursorReplayUnknownSourceToolNameBrand: unique symbol;
|
|
23
|
+
|
|
24
|
+
/** Opaque unknown/future Cursor tool names on generic-fallback replay cards. */
|
|
25
|
+
export type CursorReplayUnknownSourceToolName = string & {
|
|
26
|
+
readonly [cursorReplayUnknownSourceToolNameBrand]: unique symbol;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export interface CursorReplayNativeEditDetails {
|
|
30
|
+
variant: "nativeEdit";
|
|
31
|
+
path?: string;
|
|
32
|
+
linesAdded?: number;
|
|
33
|
+
linesRemoved?: number;
|
|
34
|
+
diffString?: string;
|
|
35
|
+
diff?: string;
|
|
36
|
+
firstChangedLine?: number;
|
|
37
|
+
summary?: string;
|
|
38
|
+
expandedText?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface CursorReplayNativeWriteDetails {
|
|
42
|
+
variant: "nativeWrite";
|
|
43
|
+
path?: string;
|
|
44
|
+
linesCreated?: number;
|
|
45
|
+
fileSize?: number;
|
|
46
|
+
fileContentAfterWrite?: string;
|
|
47
|
+
expandedText?: string;
|
|
48
|
+
summary?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface CursorReplayGenerateImageDetails {
|
|
52
|
+
variant: "generateImage";
|
|
53
|
+
imagePath?: string;
|
|
54
|
+
imageDisplayPath?: string;
|
|
55
|
+
imageMimeType?: string;
|
|
56
|
+
summary?: string;
|
|
57
|
+
expandedText?: string;
|
|
58
|
+
/** Legacy parsed title retained on older payloads; display always uses `Cursor generateImage`. */
|
|
59
|
+
title?: string;
|
|
60
|
+
collapseDetailsByDefault?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Neutral Cursor activity cards and unknown-tool fallbacks with a display title. */
|
|
64
|
+
export interface CursorReplayActivityDetails {
|
|
65
|
+
variant: "activity";
|
|
66
|
+
sourceToolName: CursorReplayActivitySourceToolName;
|
|
67
|
+
title: string;
|
|
68
|
+
summary?: string;
|
|
69
|
+
expandedText?: string;
|
|
70
|
+
collapseDetailsByDefault?: boolean;
|
|
71
|
+
path?: string;
|
|
72
|
+
fileSize?: number;
|
|
73
|
+
/** Structured unified diff for edit (and similar) activity cards; drives canonical colored diff rendering. */
|
|
74
|
+
diffString?: string;
|
|
75
|
+
diff?: string;
|
|
76
|
+
linesAdded?: number;
|
|
77
|
+
linesRemoved?: number;
|
|
78
|
+
/** Optional post-write content for write activity fallbacks (mirrors nativeWrite). */
|
|
79
|
+
fileContentAfterWrite?: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Parsed replay details without a display title (legacy or malformed payloads). */
|
|
83
|
+
export interface CursorReplayGenericFallbackDetails {
|
|
84
|
+
variant: "genericFallback";
|
|
85
|
+
sourceToolName: CursorReplayUnknownSourceToolName;
|
|
86
|
+
summary?: string;
|
|
87
|
+
expandedText?: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export type CursorReplayToolDetails =
|
|
91
|
+
| CursorReplayNativeEditDetails
|
|
92
|
+
| CursorReplayNativeWriteDetails
|
|
93
|
+
| CursorReplayGenerateImageDetails
|
|
94
|
+
| CursorReplayActivityDetails
|
|
95
|
+
| CursorReplayGenericFallbackDetails;
|
|
96
|
+
|
|
97
|
+
/** @deprecated Use {@link CursorReplayNativeEditDetails}. */
|
|
98
|
+
export type CursorReplayEditDetails = CursorReplayNativeEditDetails;
|
|
99
|
+
|
|
100
|
+
/** @deprecated Use {@link CursorReplayNativeWriteDetails}. */
|
|
101
|
+
export type CursorReplayWriteDetails = CursorReplayNativeWriteDetails;
|
|
102
|
+
|
|
103
|
+
/** @deprecated Use {@link CursorReplayActivityDetails}. */
|
|
104
|
+
export type CursorReplayTitledActivityDetails = CursorReplayActivityDetails;
|
|
105
|
+
|
|
106
|
+
/** @deprecated Use {@link CursorReplayActivitySourceToolName}. */
|
|
107
|
+
export type CursorReplayActivityCursorToolName = CursorReplayActivitySourceToolName;
|
|
108
|
+
|
|
109
|
+
/** @deprecated Use {@link CursorReplayUnknownSourceToolName}. */
|
|
110
|
+
export type CursorReplayUnknownCursorToolName = CursorReplayUnknownSourceToolName;
|
|
111
|
+
|
|
112
|
+
export type CursorReplayActivityDetailFields = Pick<
|
|
113
|
+
CursorReplayActivityDetails,
|
|
114
|
+
| "summary"
|
|
115
|
+
| "expandedText"
|
|
116
|
+
| "collapseDetailsByDefault"
|
|
117
|
+
| "path"
|
|
118
|
+
| "fileSize"
|
|
119
|
+
| "diffString"
|
|
120
|
+
| "diff"
|
|
121
|
+
| "linesAdded"
|
|
122
|
+
| "linesRemoved"
|
|
123
|
+
| "fileContentAfterWrite"
|
|
124
|
+
>;
|
|
125
|
+
|
|
126
|
+
export type CursorReplayGenerateImageDetailFields = Pick<
|
|
127
|
+
CursorReplayGenerateImageDetails,
|
|
128
|
+
"summary" | "expandedText" | "imagePath" | "imageDisplayPath" | "imageMimeType"
|
|
129
|
+
>;
|
|
130
|
+
|
|
131
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
132
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function readOptionalString(record: Record<string, unknown>, key: string): string | undefined {
|
|
136
|
+
const value = record[key];
|
|
137
|
+
return typeof value === "string" ? value : undefined;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function readOptionalNumber(record: Record<string, unknown>, key: string): number | undefined {
|
|
141
|
+
const value = record[key];
|
|
142
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function readOptionalBoolean(record: Record<string, unknown>, key: string): boolean | undefined {
|
|
146
|
+
const value = record[key];
|
|
147
|
+
return typeof value === "boolean" ? value : undefined;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function readCurrentSourceToolName(record: Record<string, unknown>): string | undefined {
|
|
151
|
+
const sourceToolName = readOptionalString(record, "sourceToolName");
|
|
152
|
+
return sourceToolName?.trim() ? sourceToolName.trim() : undefined;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function readLegacySourceToolName(record: Record<string, unknown>): string | undefined {
|
|
156
|
+
const sourceToolName = readCurrentSourceToolName(record);
|
|
157
|
+
if (sourceToolName) return sourceToolName;
|
|
158
|
+
const cursorToolName = readOptionalString(record, "cursorToolName");
|
|
159
|
+
return cursorToolName?.trim() ? cursorToolName.trim() : undefined;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function readLegacyVariant(record: Record<string, unknown>): string | undefined {
|
|
163
|
+
const variant = readOptionalString(record, "variant");
|
|
164
|
+
return variant?.trim() ? variant.trim() : undefined;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function parseCursorReplayNativeEditDetails(record: Record<string, unknown>): CursorReplayNativeEditDetails {
|
|
168
|
+
return {
|
|
169
|
+
variant: "nativeEdit",
|
|
170
|
+
path: readOptionalString(record, "path"),
|
|
171
|
+
linesAdded: readOptionalNumber(record, "linesAdded"),
|
|
172
|
+
linesRemoved: readOptionalNumber(record, "linesRemoved"),
|
|
173
|
+
diffString: readOptionalString(record, "diffString"),
|
|
174
|
+
diff: readOptionalString(record, "diff"),
|
|
175
|
+
firstChangedLine: readOptionalNumber(record, "firstChangedLine"),
|
|
176
|
+
summary: readOptionalString(record, "summary"),
|
|
177
|
+
expandedText: readOptionalString(record, "expandedText"),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function parseCursorReplayNativeWriteDetails(record: Record<string, unknown>): CursorReplayNativeWriteDetails {
|
|
182
|
+
return {
|
|
183
|
+
variant: "nativeWrite",
|
|
184
|
+
path: readOptionalString(record, "path"),
|
|
185
|
+
linesCreated: readOptionalNumber(record, "linesCreated"),
|
|
186
|
+
fileSize: readOptionalNumber(record, "fileSize"),
|
|
187
|
+
fileContentAfterWrite: readOptionalString(record, "fileContentAfterWrite"),
|
|
188
|
+
expandedText: readOptionalString(record, "expandedText"),
|
|
189
|
+
summary: readOptionalString(record, "summary"),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function parseCursorReplayGenerateImageDetails(record: Record<string, unknown>): CursorReplayGenerateImageDetails {
|
|
194
|
+
const title = readOptionalString(record, "title");
|
|
195
|
+
const collapseDetailsByDefault = readOptionalBoolean(record, "collapseDetailsByDefault");
|
|
196
|
+
return {
|
|
197
|
+
variant: "generateImage",
|
|
198
|
+
imagePath: readOptionalString(record, "imagePath"),
|
|
199
|
+
imageDisplayPath: readOptionalString(record, "imageDisplayPath"),
|
|
200
|
+
imageMimeType: readOptionalString(record, "imageMimeType"),
|
|
201
|
+
summary: readOptionalString(record, "summary"),
|
|
202
|
+
expandedText: readOptionalString(record, "expandedText"),
|
|
203
|
+
...(title !== undefined ? { title } : {}),
|
|
204
|
+
...(collapseDetailsByDefault !== undefined ? { collapseDetailsByDefault } : {}),
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function parseCursorReplayActivityDetails(
|
|
209
|
+
record: Record<string, unknown>,
|
|
210
|
+
sourceToolName: CursorReplayActivitySourceToolName,
|
|
211
|
+
title: string,
|
|
212
|
+
): CursorReplayActivityDetails {
|
|
213
|
+
return {
|
|
214
|
+
variant: "activity",
|
|
215
|
+
sourceToolName,
|
|
216
|
+
title,
|
|
217
|
+
summary: readOptionalString(record, "summary"),
|
|
218
|
+
expandedText: readOptionalString(record, "expandedText"),
|
|
219
|
+
collapseDetailsByDefault: readOptionalBoolean(record, "collapseDetailsByDefault"),
|
|
220
|
+
path: readOptionalString(record, "path"),
|
|
221
|
+
fileSize: readOptionalNumber(record, "fileSize"),
|
|
222
|
+
diffString: readOptionalString(record, "diffString"),
|
|
223
|
+
diff: readOptionalString(record, "diff"),
|
|
224
|
+
linesAdded: readOptionalNumber(record, "linesAdded"),
|
|
225
|
+
linesRemoved: readOptionalNumber(record, "linesRemoved"),
|
|
226
|
+
fileContentAfterWrite: readOptionalString(record, "fileContentAfterWrite"),
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function brandCursorReplayUnknownSourceToolName(sourceToolName: string): CursorReplayUnknownSourceToolName {
|
|
231
|
+
return sourceToolName as CursorReplayUnknownSourceToolName;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function parseCursorReplayGenericFallbackDetails(
|
|
235
|
+
record: Record<string, unknown>,
|
|
236
|
+
sourceToolName: string,
|
|
237
|
+
): CursorReplayGenericFallbackDetails {
|
|
238
|
+
return {
|
|
239
|
+
variant: "genericFallback",
|
|
240
|
+
sourceToolName: brandCursorReplayUnknownSourceToolName(sourceToolName),
|
|
241
|
+
summary: readOptionalString(record, "summary"),
|
|
242
|
+
expandedText: readOptionalString(record, "expandedText"),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function isCursorReplayActivitySourceToolName(name: string): name is CursorReplayActivitySourceToolName {
|
|
247
|
+
if (name === CURSOR_REPLAY_UNREGISTERED_ACTIVITY_TOOL_NAME) return true;
|
|
248
|
+
if (name === "generateImage") return false;
|
|
249
|
+
return isCursorReplayActivitySourceName(name);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function resolveParseActivitySourceToolName(sourceToolName: string): CursorReplayActivitySourceToolName {
|
|
253
|
+
return isCursorReplayActivitySourceToolName(sourceToolName)
|
|
254
|
+
? sourceToolName
|
|
255
|
+
: CURSOR_REPLAY_UNREGISTERED_ACTIVITY_TOOL_NAME;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** Maps incomplete or non-activity replay source names onto activity-card source tool names. */
|
|
259
|
+
export function resolveIncompleteReplayActivitySourceToolName(
|
|
260
|
+
sourceToolName: string,
|
|
261
|
+
): CursorReplayActivitySourceToolName {
|
|
262
|
+
if (sourceToolName === "generateImage") return CURSOR_REPLAY_UNREGISTERED_ACTIVITY_TOOL_NAME;
|
|
263
|
+
return resolveParseActivitySourceToolName(sourceToolName);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function hasNativeEditChanges(record: Record<string, unknown>): boolean {
|
|
267
|
+
return Boolean(
|
|
268
|
+
readOptionalString(record, "diffString")?.trim()
|
|
269
|
+
|| readOptionalString(record, "diff")?.trim()
|
|
270
|
+
|| readOptionalNumber(record, "linesAdded")
|
|
271
|
+
|| readOptionalNumber(record, "linesRemoved"),
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function parseLegacyEditDetails(record: Record<string, unknown>): CursorReplayToolDetails {
|
|
276
|
+
const title = readOptionalString(record, "title")?.trim();
|
|
277
|
+
if (title) {
|
|
278
|
+
return parseCursorReplayActivityDetails(record, resolveParseActivitySourceToolName("edit"), title);
|
|
279
|
+
}
|
|
280
|
+
return parseCursorReplayNativeEditDetails(record);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function parseLegacyWriteDetails(record: Record<string, unknown>): CursorReplayToolDetails {
|
|
284
|
+
const title = readOptionalString(record, "title")?.trim();
|
|
285
|
+
if (title) {
|
|
286
|
+
return parseCursorReplayActivityDetails(record, resolveParseActivitySourceToolName("write"), title);
|
|
287
|
+
}
|
|
288
|
+
return parseCursorReplayNativeWriteDetails(record);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
type CursorReplayVariantParser = (record: Record<string, unknown>) => CursorReplayToolDetails | undefined;
|
|
292
|
+
|
|
293
|
+
function parseActivityVariantDetails(
|
|
294
|
+
record: Record<string, unknown>,
|
|
295
|
+
readSourceToolName: (record: Record<string, unknown>) => string | undefined,
|
|
296
|
+
): CursorReplayActivityDetails | undefined {
|
|
297
|
+
const title = readOptionalString(record, "title")?.trim();
|
|
298
|
+
if (!title) return undefined;
|
|
299
|
+
return parseCursorReplayActivityDetails(
|
|
300
|
+
record,
|
|
301
|
+
resolveParseActivitySourceToolName(readSourceToolName(record) ?? CURSOR_REPLAY_UNREGISTERED_ACTIVITY_TOOL_NAME),
|
|
302
|
+
title,
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const CURRENT_REPLAY_VARIANT_PARSERS: Readonly<Record<CursorReplayToolDetailsVariant, CursorReplayVariantParser>> = {
|
|
307
|
+
nativeEdit: parseCursorReplayNativeEditDetails,
|
|
308
|
+
nativeWrite: parseCursorReplayNativeWriteDetails,
|
|
309
|
+
generateImage: parseCursorReplayGenerateImageDetails,
|
|
310
|
+
activity: (record) => {
|
|
311
|
+
if (!readCurrentSourceToolName(record) && readOptionalString(record, "cursorToolName")?.trim()) return undefined;
|
|
312
|
+
return parseActivityVariantDetails(record, readCurrentSourceToolName);
|
|
313
|
+
},
|
|
314
|
+
genericFallback: (record) => parseCursorReplayGenericFallbackDetails(record, readCurrentSourceToolName(record) ?? "tool"),
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
const LEGACY_REPLAY_VARIANT_UPGRADERS: Readonly<Record<string, CursorReplayVariantParser>> = {
|
|
318
|
+
edit: parseLegacyEditDetails,
|
|
319
|
+
write: parseLegacyWriteDetails,
|
|
320
|
+
titledActivity: (record) => parseActivityVariantDetails(record, readLegacySourceToolName),
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
export function parseStrictCurrentCursorReplayToolDetails(value: unknown): CursorReplayToolDetails | undefined {
|
|
324
|
+
if (!isRecord(value)) return undefined;
|
|
325
|
+
const variant = readLegacyVariant(value);
|
|
326
|
+
if (!variant) return undefined;
|
|
327
|
+
return CURRENT_REPLAY_VARIANT_PARSERS[variant as CursorReplayToolDetailsVariant]?.(value);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export function upgradeLegacyCursorReplayToolDetails(value: unknown): CursorReplayToolDetails | undefined {
|
|
331
|
+
if (!isRecord(value)) return undefined;
|
|
332
|
+
const explicitVariant = readLegacyVariant(value);
|
|
333
|
+
if (explicitVariant) {
|
|
334
|
+
return LEGACY_REPLAY_VARIANT_UPGRADERS[explicitVariant]?.(value);
|
|
335
|
+
}
|
|
336
|
+
const sourceToolName = readLegacySourceToolName(value);
|
|
337
|
+
if (sourceToolName === "edit") return parseLegacyEditDetails(value);
|
|
338
|
+
if (sourceToolName === "write") return parseLegacyWriteDetails(value);
|
|
339
|
+
if (sourceToolName === "generateImage") return parseCursorReplayGenerateImageDetails(value);
|
|
340
|
+
const title = readOptionalString(value, "title")?.trim();
|
|
341
|
+
if (title) {
|
|
342
|
+
return parseCursorReplayActivityDetails(
|
|
343
|
+
value,
|
|
344
|
+
resolveParseActivitySourceToolName(sourceToolName ?? CURSOR_REPLAY_UNREGISTERED_ACTIVITY_TOOL_NAME),
|
|
345
|
+
title,
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
if (sourceToolName === undefined && hasNativeEditChanges(value)) {
|
|
349
|
+
return parseCursorReplayNativeEditDetails(value);
|
|
350
|
+
}
|
|
351
|
+
return undefined;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
export function parseCursorReplayToolDetails(value: unknown): CursorReplayToolDetails | undefined {
|
|
355
|
+
return parseStrictCurrentCursorReplayToolDetails(value) ?? upgradeLegacyCursorReplayToolDetails(value);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/** @deprecated Prefer {@link parseCursorReplayToolDetails} for validated narrowing. */
|
|
359
|
+
export const asCursorReplayToolDetails = parseCursorReplayToolDetails;
|
|
360
|
+
|
|
361
|
+
export function buildCursorReplayNativeEditDetails(
|
|
362
|
+
fields: Omit<CursorReplayNativeEditDetails, "variant">,
|
|
363
|
+
): CursorReplayNativeEditDetails {
|
|
364
|
+
return { variant: "nativeEdit", ...fields };
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/** @deprecated Prefer {@link buildCursorReplayNativeEditDetails}. */
|
|
368
|
+
export const buildCursorReplayEditDetails = buildCursorReplayNativeEditDetails;
|
|
369
|
+
|
|
370
|
+
export function buildCursorReplayNativeWriteDetails(
|
|
371
|
+
fields: Omit<CursorReplayNativeWriteDetails, "variant">,
|
|
372
|
+
): CursorReplayNativeWriteDetails {
|
|
373
|
+
return { variant: "nativeWrite", ...fields };
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/** @deprecated Prefer {@link buildCursorReplayNativeWriteDetails}. */
|
|
377
|
+
export const buildCursorReplayWriteDetails = buildCursorReplayNativeWriteDetails;
|
|
378
|
+
|
|
379
|
+
export function assembleCursorReplayActivityDetails(
|
|
380
|
+
sourceToolName: CursorReplayActivitySourceToolName,
|
|
381
|
+
title: string,
|
|
382
|
+
fields: CursorReplayActivityDetailFields,
|
|
383
|
+
contentText: string,
|
|
384
|
+
isError: boolean,
|
|
385
|
+
activitySummary: string | undefined,
|
|
386
|
+
): CursorReplayActivityDetails {
|
|
387
|
+
const summary = isError ? fields.summary : (fields.summary ?? activitySummary);
|
|
388
|
+
return {
|
|
389
|
+
variant: "activity",
|
|
390
|
+
sourceToolName,
|
|
391
|
+
title,
|
|
392
|
+
summary,
|
|
393
|
+
expandedText: fields.expandedText ?? contentText,
|
|
394
|
+
...(fields.collapseDetailsByDefault !== undefined ? { collapseDetailsByDefault: fields.collapseDetailsByDefault } : {}),
|
|
395
|
+
...(fields.path !== undefined ? { path: fields.path } : {}),
|
|
396
|
+
...(fields.fileSize !== undefined ? { fileSize: fields.fileSize } : {}),
|
|
397
|
+
...(fields.diffString !== undefined ? { diffString: fields.diffString } : {}),
|
|
398
|
+
...(fields.diff !== undefined ? { diff: fields.diff } : {}),
|
|
399
|
+
...(fields.linesAdded !== undefined ? { linesAdded: fields.linesAdded } : {}),
|
|
400
|
+
...(fields.linesRemoved !== undefined ? { linesRemoved: fields.linesRemoved } : {}),
|
|
401
|
+
...(fields.fileContentAfterWrite !== undefined ? { fileContentAfterWrite: fields.fileContentAfterWrite } : {}),
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/** @deprecated Prefer {@link assembleCursorReplayActivityDetails}. */
|
|
406
|
+
export const assembleCursorReplayTitledActivityDetails = assembleCursorReplayActivityDetails;
|
|
407
|
+
|
|
408
|
+
export const CURSOR_REPLAY_GENERATE_IMAGE_RESULT_TITLE = "Cursor generateImage" as const;
|
|
409
|
+
|
|
410
|
+
export function assembleCursorReplayGenerateImageDetails(
|
|
411
|
+
fields: CursorReplayGenerateImageDetailFields,
|
|
412
|
+
contentText: string,
|
|
413
|
+
isError: boolean,
|
|
414
|
+
activitySummary: string | undefined,
|
|
415
|
+
): CursorReplayGenerateImageDetails {
|
|
416
|
+
const summary = isError ? fields.summary : (fields.summary ?? activitySummary);
|
|
417
|
+
return {
|
|
418
|
+
variant: "generateImage",
|
|
419
|
+
imagePath: fields.imagePath,
|
|
420
|
+
imageDisplayPath: fields.imageDisplayPath,
|
|
421
|
+
imageMimeType: fields.imageMimeType,
|
|
422
|
+
summary,
|
|
423
|
+
expandedText: fields.expandedText ?? contentText,
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export function isCursorReplayNativeEditDetails(
|
|
428
|
+
details: CursorReplayToolDetails,
|
|
429
|
+
): details is CursorReplayNativeEditDetails {
|
|
430
|
+
return details.variant === "nativeEdit";
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/** @deprecated Prefer {@link isCursorReplayNativeEditDetails}. */
|
|
434
|
+
export const isCursorReplayEditDetails = isCursorReplayNativeEditDetails;
|
|
435
|
+
|
|
436
|
+
export function isCursorReplayNativeWriteDetails(
|
|
437
|
+
details: CursorReplayToolDetails,
|
|
438
|
+
): details is CursorReplayNativeWriteDetails {
|
|
439
|
+
return details.variant === "nativeWrite";
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/** @deprecated Prefer {@link isCursorReplayNativeWriteDetails}. */
|
|
443
|
+
export const isCursorReplayWriteDetails = isCursorReplayNativeWriteDetails;
|
|
444
|
+
|
|
445
|
+
export function isCursorReplayGenerateImageDetails(
|
|
446
|
+
details: CursorReplayToolDetails,
|
|
447
|
+
): details is CursorReplayGenerateImageDetails {
|
|
448
|
+
return details.variant === "generateImage";
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
export function isCursorReplayActivityDetails(
|
|
452
|
+
details: CursorReplayToolDetails,
|
|
453
|
+
): details is CursorReplayActivityDetails {
|
|
454
|
+
return details.variant === "activity";
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/** @deprecated Prefer {@link isCursorReplayActivityDetails}. */
|
|
458
|
+
export const isCursorReplayTitledActivityDetails = isCursorReplayActivityDetails;
|
|
459
|
+
|
|
460
|
+
export function isCursorReplayGenericFallbackDetails(
|
|
461
|
+
details: CursorReplayToolDetails,
|
|
462
|
+
): details is CursorReplayGenericFallbackDetails {
|
|
463
|
+
return details.variant === "genericFallback";
|
|
464
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { hasUsableText } from "./cursor-record-utils.js";
|
|
2
|
+
|
|
3
|
+
function isCursorTextBoundary(text: string, index: number): boolean {
|
|
4
|
+
if (index <= 0 || index >= text.length) return true;
|
|
5
|
+
const before = text[index - 1];
|
|
6
|
+
const after = text[index];
|
|
7
|
+
return !/[\p{L}\p{N}_]/u.test(before) || !/[\p{L}\p{N}_]/u.test(after);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function trimAlreadyEmittedCursorText(text: string, emittedText: string, options?: { allowPartialPrefix?: boolean }): string {
|
|
11
|
+
if (!text || !emittedText) return text;
|
|
12
|
+
if (text === emittedText) return "";
|
|
13
|
+
if (text.startsWith(emittedText) && (options?.allowPartialPrefix || isCursorTextBoundary(text, emittedText.length))) {
|
|
14
|
+
return text.slice(emittedText.length);
|
|
15
|
+
}
|
|
16
|
+
if (emittedText.endsWith(text) && isCursorTextBoundary(emittedText, emittedText.length - text.length)) return "";
|
|
17
|
+
const trimmedText = text.trim();
|
|
18
|
+
const trimmedEmittedText = emittedText.trim();
|
|
19
|
+
if (trimmedText === trimmedEmittedText) return "";
|
|
20
|
+
if (trimmedText && trimmedEmittedText.endsWith(trimmedText)) {
|
|
21
|
+
const suffixStart = trimmedEmittedText.length - trimmedText.length;
|
|
22
|
+
if (isCursorTextBoundary(trimmedEmittedText, suffixStart)) return "";
|
|
23
|
+
}
|
|
24
|
+
return text;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function trimCurrentTurnAlreadyEmittedCursorText(
|
|
28
|
+
text: string,
|
|
29
|
+
currentTurnEmittedText: string,
|
|
30
|
+
emittedText = currentTurnEmittedText,
|
|
31
|
+
): string {
|
|
32
|
+
if (!currentTurnEmittedText) return trimAlreadyEmittedCursorText(text, emittedText);
|
|
33
|
+
const currentTurnTrimmedText = trimAlreadyEmittedCursorText(text, currentTurnEmittedText, { allowPartialPrefix: true });
|
|
34
|
+
if (currentTurnTrimmedText !== text) return currentTurnTrimmedText;
|
|
35
|
+
if (emittedText.endsWith(currentTurnEmittedText)) {
|
|
36
|
+
const emittedTextTrimmedText = trimAlreadyEmittedCursorText(text, emittedText, { allowPartialPrefix: true });
|
|
37
|
+
if (emittedTextTrimmedText !== text) return emittedTextTrimmedText;
|
|
38
|
+
}
|
|
39
|
+
return trimAlreadyEmittedCursorText(text, emittedText);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function selectCursorFinalText(
|
|
43
|
+
resultText: unknown,
|
|
44
|
+
textDeltas: readonly string[],
|
|
45
|
+
emittedText: string,
|
|
46
|
+
fallbackText?: string,
|
|
47
|
+
options?: { allowPartialPrefix?: boolean },
|
|
48
|
+
): string {
|
|
49
|
+
const candidates = [typeof resultText === "string" ? resultText : undefined, fallbackText, textDeltas.join("")];
|
|
50
|
+
for (const candidate of candidates) {
|
|
51
|
+
if (!hasUsableText(candidate)) continue;
|
|
52
|
+
const trimmedCandidate = trimAlreadyEmittedCursorText(candidate, emittedText, options);
|
|
53
|
+
if (hasUsableText(trimmedCandidate)) return trimmedCandidate;
|
|
54
|
+
}
|
|
55
|
+
return "";
|
|
56
|
+
}
|
|
@@ -88,6 +88,10 @@ function uninstallProcessEmitPatchIfIdle(): void {
|
|
|
88
88
|
originalProcessEmit = undefined;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
export const __testUtils = {
|
|
92
|
+
activeSuppressionCount: (): number => activeSuppressions.size,
|
|
93
|
+
};
|
|
94
|
+
|
|
91
95
|
export function installCursorSdkAbortErrorSuppression(): CursorSdkAbortErrorSuppression {
|
|
92
96
|
installProcessEmitPatch();
|
|
93
97
|
const token: CursorSdkAbortErrorSuppressionToken = { suppress: false };
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
|
+
import {
|
|
3
|
+
CURSOR_SDK_EVENT_DEBUG_DIR_ENV,
|
|
4
|
+
CURSOR_SDK_EVENT_DEBUG_ENV,
|
|
5
|
+
CURSOR_SDK_EVENT_DEBUG_RUN_DIR_ENV,
|
|
6
|
+
CURSOR_SDK_EVENT_DEBUG_SESSION_DIR_ENV,
|
|
7
|
+
CURSOR_SDK_EVENT_DEBUG_STDERR_ENV,
|
|
8
|
+
} from "../shared/cursor-sdk-event-debug-env.mjs";
|
|
2
9
|
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
export {
|
|
11
|
+
CURSOR_SDK_EVENT_DEBUG_DIR_ENV,
|
|
12
|
+
CURSOR_SDK_EVENT_DEBUG_ENV,
|
|
13
|
+
CURSOR_SDK_EVENT_DEBUG_RUN_DIR_ENV,
|
|
14
|
+
CURSOR_SDK_EVENT_DEBUG_SESSION_DIR_ENV,
|
|
15
|
+
CURSOR_SDK_EVENT_DEBUG_STDERR_ENV,
|
|
16
|
+
};
|
|
8
17
|
export const CURSOR_SDK_EVENT_DEBUG_LOG_PREFIX = "[pi-cursor-sdk:sdk-events]";
|
|
9
18
|
|
|
10
19
|
export const SESSION_MANIFEST = "session.json";
|
|
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { copyFileSync, existsSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import type { AssistantMessageEventStream } from "@earendil-works/pi-ai";
|
|
5
|
-
import type { InteractionUpdate } from "@cursor/sdk";
|
|
5
|
+
import type { AgentModeOption, InteractionUpdate } from "@cursor/sdk";
|
|
6
6
|
import type { CursorPiToolBridgeDiagnosticEvent } from "./cursor-pi-tool-bridge-diagnostics.js";
|
|
7
7
|
import { serializeCursorPiToolBridgeDiagnostic } from "./cursor-pi-tool-bridge-diagnostics.js";
|
|
8
8
|
import type { CursorPiBridgeToolRequest } from "./cursor-pi-tool-bridge-types.js";
|
|
@@ -72,6 +72,7 @@ export interface CursorSdkEventDebugSendMeta {
|
|
|
72
72
|
bridgeEnabled: boolean;
|
|
73
73
|
nativeReplayId: string;
|
|
74
74
|
promptInputTokens: number;
|
|
75
|
+
agentMode: AgentModeOption;
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
export interface CursorSdkEventDebugRunMeta {
|
|
@@ -1,42 +1,9 @@
|
|
|
1
1
|
import type { CursorPiToolDisplay } from "./cursor-transcript-utils.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
const BRIDGE_ENDPOINT_ROOT = "/cursor-pi-tool-bridge";
|
|
8
|
-
const BRIDGE_ENDPOINT_TOKEN_PATTERN = "[^/\\s\"'<>]+";
|
|
9
|
-
const BRIDGE_LOOPBACK_HOST_PATTERN = "127\\.0\\.0\\.1(?::\\d+)?";
|
|
10
|
-
const BRIDGE_ENDPOINT_PATH_PATTERN = `${escapeRegExp(BRIDGE_ENDPOINT_ROOT)}/${BRIDGE_ENDPOINT_TOKEN_PATTERN}/mcp`;
|
|
11
|
-
|
|
12
|
-
function scrubBridgeEndpointMaterial(text: string): string {
|
|
13
|
-
return text
|
|
14
|
-
.replace(
|
|
15
|
-
new RegExp(`https?://${BRIDGE_LOOPBACK_HOST_PATTERN}${BRIDGE_ENDPOINT_PATH_PATTERN}`, "gi"),
|
|
16
|
-
"[redacted-bridge-endpoint]",
|
|
17
|
-
)
|
|
18
|
-
.replace(
|
|
19
|
-
new RegExp(`${BRIDGE_LOOPBACK_HOST_PATTERN}${BRIDGE_ENDPOINT_PATH_PATTERN}`, "gi"),
|
|
20
|
-
"[redacted-bridge-endpoint]",
|
|
21
|
-
)
|
|
22
|
-
.replace(new RegExp(BRIDGE_ENDPOINT_PATH_PATTERN, "gi"), "[redacted-bridge-endpoint]");
|
|
23
|
-
}
|
|
2
|
+
/** Provider-facing wrapper; canonical scrubbing lives in shared/cursor-sensitive-text.mjs. */
|
|
3
|
+
import { scrubSensitiveText as scrubSensitiveTextJs } from "../shared/cursor-sensitive-text.mjs";
|
|
24
4
|
|
|
25
5
|
export function scrubSensitiveText(text: string, apiKey?: string): string {
|
|
26
|
-
|
|
27
|
-
const trimmedKey = apiKey?.trim();
|
|
28
|
-
if (trimmedKey) {
|
|
29
|
-
scrubbed = scrubbed.replace(new RegExp(escapeRegExp(trimmedKey), "g"), "[redacted]");
|
|
30
|
-
}
|
|
31
|
-
return scrubBridgeEndpointMaterial(
|
|
32
|
-
scrubbed
|
|
33
|
-
.replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [redacted]")
|
|
34
|
-
.replace(/((?:^|[\s,{])cookie["']?\s*[:=]\s*["']?)[^\n]+/gi, "$1[redacted]")
|
|
35
|
-
.replace(
|
|
36
|
-
/((?:authorization|api[_-]?key|apiKey|token|session(?:[_-]?id)?)["']?\s*[:=]\s*["']?)[^"'\s,;}]+/gi,
|
|
37
|
-
"$1[redacted]",
|
|
38
|
-
),
|
|
39
|
-
);
|
|
6
|
+
return scrubSensitiveTextJs(text, apiKey);
|
|
40
7
|
}
|
|
41
8
|
|
|
42
9
|
function scrubDisplayValue(value: unknown, apiKey?: string): unknown {
|
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
} from "@earendil-works/pi-coding-agent";
|
|
8
8
|
import { createHash } from "node:crypto";
|
|
9
9
|
import { Agent } from "@cursor/sdk";
|
|
10
|
-
import type { ModelSelection, SDKAgent, SettingSource } from "@cursor/sdk";
|
|
10
|
+
import type { AgentModeOption, ModelSelection, SDKAgent, SettingSource } from "@cursor/sdk";
|
|
11
11
|
import type { Context } from "@earendil-works/pi-ai";
|
|
12
12
|
import {
|
|
13
13
|
getRegisteredCursorPiToolBridge,
|
|
@@ -103,6 +103,7 @@ function rethrowSupersededWhenReplacedByDifferentPoolKey(scopeKey: string, poolK
|
|
|
103
103
|
|
|
104
104
|
interface SessionCursorAgentCreateParams {
|
|
105
105
|
apiKey: string;
|
|
106
|
+
agentMode: AgentModeOption;
|
|
106
107
|
cwd: string;
|
|
107
108
|
modelSelection: ModelSelection;
|
|
108
109
|
settingSources?: SettingSource[];
|
|
@@ -382,6 +383,7 @@ async function createSessionAgentEntry(
|
|
|
382
383
|
agent = await createAgent({
|
|
383
384
|
apiKey: params.apiKey,
|
|
384
385
|
model: params.modelSelection,
|
|
386
|
+
mode: params.agentMode,
|
|
385
387
|
local: params.settingSources ? { cwd: params.cwd, settingSources: params.settingSources } : { cwd: params.cwd },
|
|
386
388
|
...(bridgeRun?.mcpServers ? { mcpServers: bridgeRun.mcpServers } : {}),
|
|
387
389
|
});
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import type { SettingSource } from "@cursor/sdk";
|
|
2
|
+
/** Provider-facing wrapper; canonical parsing lives in shared/cursor-setting-sources.mjs. */
|
|
3
|
+
import {
|
|
4
|
+
CURSOR_SETTING_SOURCES_ENV as CURSOR_SETTING_SOURCES_ENV_JS,
|
|
5
|
+
resolveCursorSettingSources as resolveCursorSettingSourcesJs,
|
|
6
|
+
} from "../shared/cursor-setting-sources.mjs";
|
|
2
7
|
|
|
3
|
-
export const CURSOR_SETTING_SOURCES_ENV =
|
|
8
|
+
export const CURSOR_SETTING_SOURCES_ENV = CURSOR_SETTING_SOURCES_ENV_JS;
|
|
4
9
|
|
|
5
10
|
export function resolveCursorSettingSources(raw?: string): SettingSource[] | undefined {
|
|
6
|
-
|
|
7
|
-
if (!trimmed) return ["all"];
|
|
8
|
-
const normalized = trimmed.toLowerCase();
|
|
9
|
-
if (["0", "false", "off", "none", "omit", "disabled"].includes(normalized)) return undefined;
|
|
10
|
-
if (["1", "true", "on", "all"].includes(normalized)) return ["all"];
|
|
11
|
-
return trimmed
|
|
12
|
-
.split(",")
|
|
13
|
-
.map((entry) => entry.trim())
|
|
14
|
-
.filter((entry): entry is SettingSource => Boolean(entry));
|
|
11
|
+
return resolveCursorSettingSourcesJs(raw) as SettingSource[] | undefined;
|
|
15
12
|
}
|
|
16
13
|
|
|
17
14
|
export function getEffectiveCursorSettingSources(raw: string | undefined = process.env[CURSOR_SETTING_SOURCES_ENV]): SettingSource[] | undefined {
|