@bifrost-ai/engine-cursor 0.1.1-build.1783540132209

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.
@@ -0,0 +1,27 @@
1
+ import { McpServerConfig, SettingSource } from "@cursor/sdk";
2
+ import { Engine, EngineContext, EngineResult } from "@bifrost-ai/engine";
3
+
4
+ //#region src/cursor-engine.d.ts
5
+ type CursorEngineConfig = {
6
+ apiKey?: string;
7
+ model?: string;
8
+ settingSources?: SettingSource[];
9
+ mode?: "agent" | "plan";
10
+ executionTimeoutMs?: number;
11
+ };
12
+ type McpToolkitConstructor = (context: EngineContext) => McpServerConfig;
13
+ declare class CursorEngine implements Engine {
14
+ private readonly config;
15
+ private toolkits;
16
+ constructor(config?: CursorEngineConfig);
17
+ registerToolkit(name: string, toolkit: McpServerConfig | McpToolkitConstructor): void;
18
+ private resolveApiKey;
19
+ private resolveModel;
20
+ private resolveMcpServers;
21
+ private streamRun;
22
+ private withExecutionTimeout;
23
+ private mapFinishedResult;
24
+ execute(context: EngineContext, sessionId?: string): Promise<EngineResult>;
25
+ }
26
+ //#endregion
27
+ export { CursorEngine, type CursorEngineConfig, type McpToolkitConstructor };
package/dist/index.mjs ADDED
@@ -0,0 +1,619 @@
1
+ import { Agent, CursorAgentError } from "@cursor/sdk";
2
+ import createDebug from "debug";
3
+ //#region src/prompt.ts
4
+ const promptSection = (name, body) => `<${name}>${body}</${name}>`;
5
+ const buildPrompt = (options) => {
6
+ const { agent, instructions } = options;
7
+ return [promptSection("AgentDefinition", agent.promptBody), promptSection("FeatureDefinition", instructions)].join("\n");
8
+ };
9
+ //#endregion
10
+ //#region src/pricing.ts
11
+ const catalog = {
12
+ source: "https://cursor.com/docs/models-and-pricing",
13
+ unit: "usd_per_million_tokens",
14
+ auto: {
15
+ "inputAndCacheWrite": 1.25,
16
+ "output": 6,
17
+ "cacheRead": .25
18
+ },
19
+ models: [
20
+ {
21
+ "name": "Claude 4 Sonnet",
22
+ "ids": ["claude-4-sonnet", "claude-4-sonnet-thinking"],
23
+ "provider": "Anthropic",
24
+ "input": 3,
25
+ "cacheWrite": 3.75,
26
+ "cacheRead": .3,
27
+ "output": 15
28
+ },
29
+ {
30
+ "name": "Claude 4 Sonnet 1M",
31
+ "ids": ["claude-4-sonnet-1m"],
32
+ "provider": "Anthropic",
33
+ "input": 6,
34
+ "cacheWrite": 7.5,
35
+ "cacheRead": .6,
36
+ "output": 22.5
37
+ },
38
+ {
39
+ "name": "Claude 4.5 Haiku",
40
+ "ids": ["claude-4-5-haiku", "claude-4.5-haiku"],
41
+ "provider": "Anthropic",
42
+ "input": 1,
43
+ "cacheWrite": 1.25,
44
+ "cacheRead": .1,
45
+ "output": 5
46
+ },
47
+ {
48
+ "name": "Claude 4.5 Opus",
49
+ "ids": ["claude-4-5-opus", "claude-4.5-opus"],
50
+ "provider": "Anthropic",
51
+ "input": 5,
52
+ "cacheWrite": 6.25,
53
+ "cacheRead": .5,
54
+ "output": 25
55
+ },
56
+ {
57
+ "name": "Claude 4.5 Sonnet",
58
+ "ids": ["claude-4-5-sonnet", "claude-4.5-sonnet"],
59
+ "provider": "Anthropic",
60
+ "input": 3,
61
+ "cacheWrite": 3.75,
62
+ "cacheRead": .3,
63
+ "output": 15
64
+ },
65
+ {
66
+ "name": "Claude 4.6 Opus",
67
+ "ids": ["claude-4-6-opus", "claude-4.6-opus"],
68
+ "provider": "Anthropic",
69
+ "input": 5,
70
+ "cacheWrite": 6.25,
71
+ "cacheRead": .5,
72
+ "output": 25
73
+ },
74
+ {
75
+ "name": "Claude 4.6 Sonnet",
76
+ "ids": ["claude-4-6-sonnet", "claude-4.6-sonnet"],
77
+ "provider": "Anthropic",
78
+ "input": 3,
79
+ "cacheWrite": 3.75,
80
+ "cacheRead": .3,
81
+ "output": 15
82
+ },
83
+ {
84
+ "name": "Claude 4.7 Opus",
85
+ "ids": ["claude-4-7-opus", "claude-4.7-opus"],
86
+ "provider": "Anthropic",
87
+ "input": 5,
88
+ "cacheWrite": 6.25,
89
+ "cacheRead": .5,
90
+ "output": 25
91
+ },
92
+ {
93
+ "name": "Claude Fable 5",
94
+ "ids": ["claude-fable-5"],
95
+ "provider": "Anthropic",
96
+ "input": 10,
97
+ "cacheWrite": 12.5,
98
+ "cacheRead": 1,
99
+ "output": 50
100
+ },
101
+ {
102
+ "name": "Claude Opus 4.7 (fast mode)",
103
+ "ids": ["claude-opus-4-7-fast", "claude-opus-4.7-fast"],
104
+ "provider": "Anthropic",
105
+ "input": 30,
106
+ "cacheWrite": 37.5,
107
+ "cacheRead": 3,
108
+ "output": 150
109
+ },
110
+ {
111
+ "name": "Claude Opus 4.8",
112
+ "ids": [
113
+ "claude-opus-4-8",
114
+ "claude-opus-4.8",
115
+ "claude-opus-4-8-fast"
116
+ ],
117
+ "provider": "Anthropic",
118
+ "input": 5,
119
+ "cacheWrite": 6.25,
120
+ "cacheRead": .5,
121
+ "output": 25
122
+ },
123
+ {
124
+ "name": "Claude Sonnet 5",
125
+ "ids": ["claude-sonnet-5"],
126
+ "provider": "Anthropic",
127
+ "input": 3,
128
+ "cacheWrite": 3.75,
129
+ "cacheRead": .3,
130
+ "output": 15
131
+ },
132
+ {
133
+ "name": "Composer 1",
134
+ "ids": ["composer-1"],
135
+ "provider": "Cursor",
136
+ "input": 1.25,
137
+ "cacheRead": .125,
138
+ "output": 10
139
+ },
140
+ {
141
+ "name": "Composer 1.5",
142
+ "ids": ["composer-1.5"],
143
+ "provider": "Cursor",
144
+ "input": 3.5,
145
+ "cacheRead": .35,
146
+ "output": 17.5
147
+ },
148
+ {
149
+ "name": "Composer 2",
150
+ "ids": ["composer-2", "composer-2-fast"],
151
+ "provider": "Cursor",
152
+ "input": .5,
153
+ "cacheRead": .2,
154
+ "output": 2.5
155
+ },
156
+ {
157
+ "name": "Composer 2.5",
158
+ "ids": ["composer-2.5"],
159
+ "provider": "Cursor",
160
+ "input": .5,
161
+ "cacheRead": .2,
162
+ "output": 2.5
163
+ },
164
+ {
165
+ "name": "Composer 2.5 (Fast)",
166
+ "ids": ["composer-2.5-fast"],
167
+ "provider": "Cursor",
168
+ "input": 3,
169
+ "cacheRead": .5,
170
+ "output": 15
171
+ },
172
+ {
173
+ "name": "Gemini 2.5 Flash",
174
+ "ids": ["gemini-2.5-flash"],
175
+ "provider": "Google",
176
+ "input": .3,
177
+ "cacheRead": .03,
178
+ "output": 2.5
179
+ },
180
+ {
181
+ "name": "Gemini 3 Flash",
182
+ "ids": ["gemini-3-flash"],
183
+ "provider": "Google",
184
+ "input": .5,
185
+ "cacheRead": .05,
186
+ "output": 3
187
+ },
188
+ {
189
+ "name": "Gemini 3 Pro",
190
+ "ids": ["gemini-3-pro", "gemini-3-pro-image-preview"],
191
+ "provider": "Google",
192
+ "input": 2,
193
+ "cacheRead": .2,
194
+ "output": 12
195
+ },
196
+ {
197
+ "name": "Gemini 3.1 Pro",
198
+ "ids": ["gemini-3.1-pro"],
199
+ "provider": "Google",
200
+ "input": 2,
201
+ "cacheRead": .2,
202
+ "output": 12
203
+ },
204
+ {
205
+ "name": "Gemini 3.5 Flash",
206
+ "ids": ["gemini-3.5-flash"],
207
+ "provider": "Google",
208
+ "input": 1.5,
209
+ "cacheRead": .15,
210
+ "output": 9
211
+ },
212
+ {
213
+ "name": "GLM 5.2",
214
+ "ids": ["glm-5.2"],
215
+ "provider": "Z.ai",
216
+ "input": 1.4,
217
+ "cacheRead": .26,
218
+ "output": 4.4
219
+ },
220
+ {
221
+ "name": "GPT-5",
222
+ "ids": ["gpt-5", "gpt-5-high"],
223
+ "provider": "OpenAI",
224
+ "input": 1.25,
225
+ "cacheRead": .125,
226
+ "output": 10
227
+ },
228
+ {
229
+ "name": "GPT-5 Fast",
230
+ "ids": [
231
+ "gpt-5-fast",
232
+ "gpt-5-high-fast",
233
+ "gpt-5-low-fast"
234
+ ],
235
+ "provider": "OpenAI",
236
+ "input": 2.5,
237
+ "cacheRead": .25,
238
+ "output": 20
239
+ },
240
+ {
241
+ "name": "GPT-5 Mini",
242
+ "ids": ["gpt-5-mini"],
243
+ "provider": "OpenAI",
244
+ "input": .25,
245
+ "cacheRead": .025,
246
+ "output": 2
247
+ },
248
+ {
249
+ "name": "GPT-5-Codex",
250
+ "ids": ["gpt-5-codex"],
251
+ "provider": "OpenAI",
252
+ "input": 1.25,
253
+ "cacheRead": .125,
254
+ "output": 10
255
+ },
256
+ {
257
+ "name": "GPT-5.1 Codex",
258
+ "ids": ["gpt-5.1-codex"],
259
+ "provider": "OpenAI",
260
+ "input": 1.25,
261
+ "cacheRead": .125,
262
+ "output": 10
263
+ },
264
+ {
265
+ "name": "GPT-5.1 Codex Max",
266
+ "ids": ["gpt-5.1-codex-max"],
267
+ "provider": "OpenAI",
268
+ "input": 1.25,
269
+ "cacheRead": .125,
270
+ "output": 10
271
+ },
272
+ {
273
+ "name": "GPT-5.1 Codex Mini",
274
+ "ids": ["gpt-5.1-codex-mini"],
275
+ "provider": "OpenAI",
276
+ "input": .25,
277
+ "cacheRead": .025,
278
+ "output": 2
279
+ },
280
+ {
281
+ "name": "GPT-5.2",
282
+ "ids": ["gpt-5.2", "gpt-5.2-high"],
283
+ "provider": "OpenAI",
284
+ "input": 1.75,
285
+ "cacheRead": .175,
286
+ "output": 14
287
+ },
288
+ {
289
+ "name": "GPT-5.2 Codex",
290
+ "ids": ["gpt-5.2-codex"],
291
+ "provider": "OpenAI",
292
+ "input": 1.75,
293
+ "cacheRead": .175,
294
+ "output": 14
295
+ },
296
+ {
297
+ "name": "GPT-5.3 Codex",
298
+ "ids": ["gpt-5.3-codex", "gpt-5.3-codex-high"],
299
+ "provider": "OpenAI",
300
+ "input": 1.75,
301
+ "cacheRead": .175,
302
+ "output": 14
303
+ },
304
+ {
305
+ "name": "GPT-5.4",
306
+ "ids": ["gpt-5.4", "gpt-5.4-fast"],
307
+ "provider": "OpenAI",
308
+ "input": 2.5,
309
+ "cacheRead": .25,
310
+ "output": 15
311
+ },
312
+ {
313
+ "name": "GPT-5.4 Mini",
314
+ "ids": ["gpt-5.4-mini"],
315
+ "provider": "OpenAI",
316
+ "input": .75,
317
+ "cacheRead": .075,
318
+ "output": 4.5
319
+ },
320
+ {
321
+ "name": "GPT-5.4 Nano",
322
+ "ids": ["gpt-5.4-nano"],
323
+ "provider": "OpenAI",
324
+ "input": .2,
325
+ "cacheRead": .02,
326
+ "output": 1.25
327
+ },
328
+ {
329
+ "name": "GPT-5.5",
330
+ "ids": ["gpt-5.5", "gpt-5.5-fast"],
331
+ "provider": "OpenAI",
332
+ "input": 5,
333
+ "cacheRead": .5,
334
+ "output": 30
335
+ },
336
+ {
337
+ "name": "Grok 4.20",
338
+ "ids": ["grok-4.20"],
339
+ "provider": "xAI",
340
+ "input": 2,
341
+ "cacheRead": .2,
342
+ "output": 6
343
+ },
344
+ {
345
+ "name": "Grok 4.3",
346
+ "ids": ["grok-4.3"],
347
+ "provider": "xAI",
348
+ "input": 1.25,
349
+ "cacheRead": .2,
350
+ "output": 2.5
351
+ },
352
+ {
353
+ "name": "Grok Build 0.1",
354
+ "ids": ["grok-build-0.1"],
355
+ "provider": "xAI",
356
+ "input": 1,
357
+ "cacheRead": .2,
358
+ "output": 2
359
+ },
360
+ {
361
+ "name": "Kimi K2.7 Code",
362
+ "ids": ["kimi-k2.7-code", "kimi-k2-7-code"],
363
+ "provider": "Moonshot",
364
+ "input": .95,
365
+ "cacheRead": .19,
366
+ "output": 4
367
+ }
368
+ ]
369
+ };
370
+ const TOKENS_PER_MILLION = 1e6;
371
+ const normalizeModelId = (modelId) => modelId.trim().toLowerCase().replaceAll("_", "-");
372
+ const ratesById = new Map(catalog.models.flatMap((model) => model.ids.map((id) => [normalizeModelId(id), {
373
+ input: model.input,
374
+ cacheWrite: model.cacheWrite,
375
+ cacheRead: model.cacheRead,
376
+ output: model.output
377
+ }])));
378
+ const resolveModelRates = (modelId) => {
379
+ if (!modelId) return;
380
+ const normalized = normalizeModelId(modelId);
381
+ if (normalized === "auto") return {
382
+ input: catalog.auto.inputAndCacheWrite,
383
+ cacheWrite: catalog.auto.inputAndCacheWrite,
384
+ cacheRead: catalog.auto.cacheRead,
385
+ output: catalog.auto.output
386
+ };
387
+ const exact = ratesById.get(normalized);
388
+ if (exact) return exact;
389
+ let bestMatchId;
390
+ let bestRates;
391
+ for (const [id, rates] of ratesById) if (normalized.startsWith(id)) {
392
+ if (!bestMatchId || id.length > bestMatchId.length) {
393
+ bestMatchId = id;
394
+ bestRates = rates;
395
+ }
396
+ }
397
+ return bestRates;
398
+ };
399
+ const calculateUsageCostUsd = (modelId, usage) => {
400
+ const rates = resolveModelRates(modelId);
401
+ if (!rates) return 0;
402
+ const cacheWriteRate = rates.cacheWrite ?? rates.input;
403
+ const cacheReadRate = rates.cacheRead ?? 0;
404
+ return (usage.inputTokens * rates.input + usage.cacheWriteTokens * cacheWriteRate + usage.cacheReadTokens * cacheReadRate + usage.outputTokens * rates.output) / TOKENS_PER_MILLION;
405
+ };
406
+ //#endregion
407
+ //#region src/stats.ts
408
+ const mapRunResultToStats = (result, numTurns) => {
409
+ const usage = result.usage;
410
+ const tokenUsage = {
411
+ inputTokens: usage?.inputTokens ?? 0,
412
+ outputTokens: usage?.outputTokens ?? 0,
413
+ cacheReadTokens: usage?.cacheReadTokens ?? 0,
414
+ cacheWriteTokens: usage?.cacheWriteTokens ?? 0
415
+ };
416
+ return {
417
+ durationMs: result.durationMs ?? 0,
418
+ inputTokens: tokenUsage.inputTokens,
419
+ outputTokens: tokenUsage.outputTokens,
420
+ cacheReadTokens: tokenUsage.cacheReadTokens,
421
+ cacheCreationTokens: tokenUsage.cacheWriteTokens,
422
+ totalCostUsd: calculateUsageCostUsd(result.modelId, tokenUsage),
423
+ numTurns
424
+ };
425
+ };
426
+ //#endregion
427
+ //#region src/stream-preview.ts
428
+ const formatToolInput = (input) => {
429
+ if (!input || typeof input !== "object") return String(input ?? "");
430
+ return Object.entries(input).slice(0, 3).map(([key, val]) => `${key}=${String(val)}`).join(", ");
431
+ };
432
+ const extractAssistantPreview = (message) => {
433
+ if (message.type !== "assistant") return null;
434
+ const content = message.message.content;
435
+ const parts = [];
436
+ for (const block of content) if (block.type === "text" && block.text) parts.push(block.text.replace(/\n/g, " "));
437
+ else if (block.type === "tool_use" && block.name) {
438
+ const args = formatToolInput(block.input);
439
+ parts.push(`ToolCall(${block.name}${args ? `, ${args}` : ""})`);
440
+ }
441
+ return parts.length > 0 ? parts.join(" | ") : null;
442
+ };
443
+ const getMessagePreview = (message) => {
444
+ if (message.type === "assistant") return extractAssistantPreview(message) ?? "";
445
+ if (message.type === "thinking") return message.text.replace(/\n/g, " ");
446
+ if (message.type === "tool_call") return `ToolCall(${message.name}, ${message.status})`;
447
+ if (message.type === "user") {
448
+ const parts = [];
449
+ for (const block of message.message.content) if (block.type === "text" && block.text) parts.push(block.text.replace(/\n/g, " "));
450
+ return parts.join(" | ");
451
+ }
452
+ return "";
453
+ };
454
+ //#endregion
455
+ //#region src/cursor-engine.ts
456
+ const debug = createDebug("bifrost:engine:cursor");
457
+ const DEFAULT_MODEL = "composer-2.5";
458
+ const DEFAULT_EXECUTION_TIMEOUT_MS = 1800 * 1e3;
459
+ const mcpServerNamePattern = /^mcp__([^_]+(?:_[^_]+)*)__/;
460
+ var ExecutionTimeoutError = class extends Error {
461
+ timeoutMs;
462
+ constructor(timeoutMs) {
463
+ super(`Execution timed out after ${timeoutMs}ms`);
464
+ this.timeoutMs = timeoutMs;
465
+ this.name = "ExecutionTimeoutError";
466
+ }
467
+ };
468
+ var CursorEngine = class {
469
+ config;
470
+ toolkits = /* @__PURE__ */ new Map();
471
+ constructor(config = {}) {
472
+ this.config = config;
473
+ }
474
+ registerToolkit(name, toolkit) {
475
+ this.toolkits.set(name, toolkit);
476
+ }
477
+ resolveApiKey() {
478
+ return this.config.apiKey ?? process.env.CURSOR_API_KEY;
479
+ }
480
+ resolveModel(agentModel) {
481
+ return { id: agentModel ?? this.config.model ?? DEFAULT_MODEL };
482
+ }
483
+ resolveMcpServers(tools, context) {
484
+ const bareToolNames = [...new Set(tools.map((tool) => typeof tool === "string" ? tool.replace(/\(.*\)$/, "") : tool.name))];
485
+ const activeServerNames = new Set(bareToolNames.map((toolName) => mcpServerNamePattern.exec(toolName)?.[1]).filter((serverName) => serverName !== null && serverName !== void 0));
486
+ if (activeServerNames.size === 0) return;
487
+ debug("creating tools workingDir=%s", context.workingDir);
488
+ const mcpServers = {};
489
+ for (const name of activeServerNames) {
490
+ const entry = this.toolkits.get(name);
491
+ if (entry !== void 0) mcpServers[name] = typeof entry === "function" ? entry(context) : entry;
492
+ }
493
+ debug("mcp tools created count=%s", Object.keys(mcpServers).length);
494
+ return Object.keys(mcpServers).length > 0 ? mcpServers : void 0;
495
+ }
496
+ async streamRun(run) {
497
+ let lastMessage = null;
498
+ let numTurns = 0;
499
+ for await (const message of run.stream()) {
500
+ const preview = getMessagePreview(message);
501
+ debug("message type=%s preview=%s", message.type, preview ? `"${preview}..."` : "-");
502
+ if (message.type === "usage") numTurns += 1;
503
+ if (message.type === "assistant") {
504
+ if (preview) lastMessage = preview;
505
+ }
506
+ }
507
+ return {
508
+ lastMessage,
509
+ numTurns: numTurns > 0 ? numTurns : 1
510
+ };
511
+ }
512
+ async withExecutionTimeout(run, timeoutMs, operation) {
513
+ let timer;
514
+ try {
515
+ return await Promise.race([operation(), new Promise((_, reject) => {
516
+ timer = setTimeout(() => {
517
+ reject(new ExecutionTimeoutError(timeoutMs));
518
+ }, timeoutMs);
519
+ })]);
520
+ } catch (error) {
521
+ if (error instanceof ExecutionTimeoutError) await run.cancel().catch(() => void 0);
522
+ throw error;
523
+ } finally {
524
+ if (timer !== void 0) clearTimeout(timer);
525
+ }
526
+ }
527
+ mapFinishedResult(result, agentId, lastMessage, numTurns, modelId) {
528
+ const stats = mapRunResultToStats({
529
+ durationMs: result.durationMs,
530
+ usage: result.usage,
531
+ modelId: result.model?.id ?? modelId
532
+ }, numTurns);
533
+ return {
534
+ success: true,
535
+ skipFulfill: false,
536
+ lastMessage: result.result ?? lastMessage ?? "No response from Cursor",
537
+ stats,
538
+ sessionId: agentId
539
+ };
540
+ }
541
+ async execute(context, sessionId) {
542
+ const { agent, instructions, workingDir } = context;
543
+ const apiKey = this.resolveApiKey();
544
+ if (!apiKey) return {
545
+ success: false,
546
+ skipFulfill: false,
547
+ lastMessage: "Missing Cursor API key (set CURSOR_API_KEY or pass apiKey in config)",
548
+ stats: null
549
+ };
550
+ const prompt = sessionId ? instructions : buildPrompt({
551
+ agent,
552
+ instructions
553
+ });
554
+ const model = this.resolveModel(agent.model);
555
+ const mcpServers = this.resolveMcpServers(agent.tools, context);
556
+ const settingSources = this.config.settingSources ?? [];
557
+ const executionTimeoutMs = this.config.executionTimeoutMs ?? DEFAULT_EXECUTION_TIMEOUT_MS;
558
+ debug("execute workingDir=%s sessionId=%s", workingDir, sessionId ?? "none");
559
+ debug("prompt: %s", prompt);
560
+ try {
561
+ const agentHandle = sessionId ? await this.withExecutionTimeout({ cancel: async () => void 0 }, executionTimeoutMs, () => Agent.resume(sessionId, {
562
+ apiKey,
563
+ model,
564
+ local: {
565
+ cwd: workingDir,
566
+ settingSources
567
+ },
568
+ ...mcpServers && { mcpServers }
569
+ })) : await this.withExecutionTimeout({ cancel: async () => void 0 }, executionTimeoutMs, () => Agent.create({
570
+ apiKey,
571
+ model,
572
+ local: {
573
+ cwd: workingDir,
574
+ settingSources
575
+ },
576
+ ...mcpServers && { mcpServers },
577
+ ...this.config.mode && { mode: this.config.mode }
578
+ }));
579
+ const run = await this.withExecutionTimeout({ cancel: async () => void 0 }, executionTimeoutMs, () => agentHandle.send(prompt));
580
+ debug("run started id=%s requestId=%s", run.id, run.requestId ?? "-");
581
+ const { lastMessage, numTurns } = await this.withExecutionTimeout(run, executionTimeoutMs, () => this.streamRun(run));
582
+ const result = await this.withExecutionTimeout(run, executionTimeoutMs, () => run.wait());
583
+ if (result.status === "error" || result.status === "cancelled") return {
584
+ success: false,
585
+ skipFulfill: false,
586
+ lastMessage: result.result ?? result.status,
587
+ stats: mapRunResultToStats({
588
+ durationMs: result.durationMs,
589
+ usage: result.usage,
590
+ modelId: result.model?.id ?? model.id
591
+ }, numTurns),
592
+ sessionId: agentHandle.agentId
593
+ };
594
+ return this.mapFinishedResult(result, agentHandle.agentId, lastMessage, numTurns, model.id);
595
+ } catch (error) {
596
+ debug("error: %o", error);
597
+ if (error instanceof ExecutionTimeoutError) return {
598
+ success: false,
599
+ skipFulfill: false,
600
+ lastMessage: error.message,
601
+ stats: null
602
+ };
603
+ if (error instanceof CursorAgentError) return {
604
+ success: false,
605
+ skipFulfill: false,
606
+ lastMessage: error.message,
607
+ stats: null
608
+ };
609
+ return {
610
+ success: false,
611
+ skipFulfill: false,
612
+ lastMessage: error instanceof Error ? error.message : String(error),
613
+ stats: null
614
+ };
615
+ }
616
+ }
617
+ };
618
+ //#endregion
619
+ export { CursorEngine };
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@bifrost-ai/engine-cursor",
3
+ "version": "0.1.1-build.1783540132209",
4
+ "description": "Cursor SDK engine for Bifrost orchestrator v2",
5
+ "license": "MIT",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "type": "module",
10
+ "exports": {
11
+ ".": "./dist/index.mjs",
12
+ "./package.json": "./package.json"
13
+ },
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "dependencies": {
18
+ "@bifrost-ai/engine": "0.1.1-build.1783540132209",
19
+ "@cursor/sdk": "^1.0.22",
20
+ "debug": "^4.4.0"
21
+ },
22
+ "devDependencies": {
23
+ "@types/debug": "^4.1.12",
24
+ "@types/node": "^25.6.2",
25
+ "@typescript/native-preview": "latest",
26
+ "bumpp": "^11.1.0",
27
+ "typescript": "^6.0.3",
28
+ "vite-plus": "^0.2.0",
29
+ "vitest-gwt": "^4.1.0"
30
+ },
31
+ "scripts": {
32
+ "build": "vp pack",
33
+ "dev": "vp pack --watch",
34
+ "test": "vp test",
35
+ "check": "vp check"
36
+ }
37
+ }