@stablekernel/opencode-cursor 0.1.0-rc.1 → 0.1.0
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 +23 -11
- package/README.md +60 -19
- package/dist/{chunk-YYO6O43T.js → chunk-D4YQ7ZEM.js} +135 -18
- package/dist/chunk-D4YQ7ZEM.js.map +1 -0
- package/dist/plugin/index.js +34 -17
- package/dist/plugin/index.js.map +1 -1
- package/dist/provider/index.d.ts +8 -7
- package/dist/provider/index.js +202 -47
- package/dist/provider/index.js.map +1 -1
- package/package.json +5 -1
- package/dist/chunk-YYO6O43T.js.map +0 -1
package/dist/provider/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
resolveControls,
|
|
4
4
|
resolveCursorApiKey,
|
|
5
5
|
streamAgentTurn
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-D4YQ7ZEM.js";
|
|
7
7
|
|
|
8
8
|
// src/provider/index.ts
|
|
9
9
|
import { NoSuchModelError } from "@ai-sdk/provider";
|
|
@@ -93,8 +93,14 @@ function latestUserMessage(prompt) {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
// src/provider/stream-map.ts
|
|
96
|
-
var FINISH_STOP = {
|
|
97
|
-
|
|
96
|
+
var FINISH_STOP = {
|
|
97
|
+
unified: "stop",
|
|
98
|
+
raw: void 0
|
|
99
|
+
};
|
|
100
|
+
var FINISH_ERROR = {
|
|
101
|
+
unified: "error",
|
|
102
|
+
raw: void 0
|
|
103
|
+
};
|
|
98
104
|
function safeJsonString(input) {
|
|
99
105
|
try {
|
|
100
106
|
return typeof input === "string" ? input : JSON.stringify(input ?? {});
|
|
@@ -105,7 +111,7 @@ function safeJsonString(input) {
|
|
|
105
111
|
function blockToolName(name) {
|
|
106
112
|
return `cursor_${name.replace(/[^A-Za-z0-9_-]/g, "_")}`;
|
|
107
113
|
}
|
|
108
|
-
function
|
|
114
|
+
function toolCallObj(id, name, input) {
|
|
109
115
|
return {
|
|
110
116
|
type: "tool-call",
|
|
111
117
|
toolCallId: id,
|
|
@@ -115,7 +121,7 @@ function toolCallPart(id, name, input) {
|
|
|
115
121
|
dynamic: true
|
|
116
122
|
};
|
|
117
123
|
}
|
|
118
|
-
function
|
|
124
|
+
function toolResultObj(id, name, result, isError) {
|
|
119
125
|
return {
|
|
120
126
|
type: "tool-result",
|
|
121
127
|
toolCallId: id,
|
|
@@ -126,29 +132,112 @@ function toolResultPart(id, name, result, isError) {
|
|
|
126
132
|
dynamic: true
|
|
127
133
|
};
|
|
128
134
|
}
|
|
129
|
-
|
|
135
|
+
var EDIT_TOOL_NAME = "edit";
|
|
136
|
+
function isRecord(v) {
|
|
137
|
+
return typeof v === "object" && v !== null;
|
|
138
|
+
}
|
|
139
|
+
function editFilePath(input) {
|
|
140
|
+
return isRecord(input) && typeof input["path"] === "string" ? input["path"] : "";
|
|
141
|
+
}
|
|
142
|
+
function editDiffString(result) {
|
|
143
|
+
if (!isRecord(result) || result["status"] !== "success") return null;
|
|
144
|
+
const value = result["value"];
|
|
145
|
+
if (!isRecord(value)) return null;
|
|
146
|
+
const diff = value["diffString"];
|
|
147
|
+
return typeof diff === "string" && diff.length > 0 ? diff : null;
|
|
148
|
+
}
|
|
149
|
+
function reconstructEditStrings(diff) {
|
|
150
|
+
const oldLines = [];
|
|
151
|
+
const newLines = [];
|
|
152
|
+
for (const line of diff.split("\n")) {
|
|
153
|
+
if (line.startsWith("---") || line.startsWith("+++") || line.startsWith("@@") || line.startsWith("Index:") || line.startsWith("===")) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (line.startsWith("-")) oldLines.push(line.slice(1));
|
|
157
|
+
else if (line.startsWith("+")) newLines.push(line.slice(1));
|
|
158
|
+
}
|
|
159
|
+
return { oldString: oldLines.join("\n"), newString: newLines.join("\n") };
|
|
160
|
+
}
|
|
161
|
+
function editCallFields(id, filePath, diff) {
|
|
162
|
+
const { oldString, newString } = reconstructEditStrings(diff);
|
|
130
163
|
return {
|
|
131
164
|
type: "tool-call",
|
|
132
165
|
toolCallId: id,
|
|
133
|
-
toolName:
|
|
134
|
-
input: safeJsonString(
|
|
166
|
+
toolName: EDIT_TOOL_NAME,
|
|
167
|
+
input: safeJsonString({ filePath, oldString, newString }),
|
|
135
168
|
providerExecuted: true,
|
|
136
169
|
dynamic: true
|
|
137
170
|
};
|
|
138
171
|
}
|
|
139
|
-
function
|
|
172
|
+
function editResultFields(id, filePath, diff, result) {
|
|
173
|
+
const value = isRecord(result) ? result["value"] : void 0;
|
|
174
|
+
const added = isRecord(value) && typeof value["linesAdded"] === "number" ? value["linesAdded"] : void 0;
|
|
175
|
+
const removed = isRecord(value) && typeof value["linesRemoved"] === "number" ? value["linesRemoved"] : void 0;
|
|
176
|
+
const counts = added !== void 0 || removed !== void 0 ? ` (+${added ?? 0}/-${removed ?? 0})` : "";
|
|
140
177
|
return {
|
|
141
178
|
type: "tool-result",
|
|
142
179
|
toolCallId: id,
|
|
143
|
-
toolName:
|
|
144
|
-
result:
|
|
145
|
-
|
|
180
|
+
toolName: EDIT_TOOL_NAME,
|
|
181
|
+
result: {
|
|
182
|
+
title: filePath,
|
|
183
|
+
metadata: { diff, diagnostics: {} },
|
|
184
|
+
output: `Edit applied${counts}.`
|
|
185
|
+
},
|
|
186
|
+
isError: false,
|
|
146
187
|
providerExecuted: true,
|
|
147
188
|
dynamic: true
|
|
148
189
|
};
|
|
149
190
|
}
|
|
191
|
+
function newBlockToolState() {
|
|
192
|
+
return { openToolCalls: /* @__PURE__ */ new Map(), pendingEdits: /* @__PURE__ */ new Map() };
|
|
193
|
+
}
|
|
194
|
+
function blockToolCallParts(id, name, input, state) {
|
|
195
|
+
if (name === EDIT_TOOL_NAME) {
|
|
196
|
+
state.pendingEdits.set(id, editFilePath(input));
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
199
|
+
state.openToolCalls.set(id, name);
|
|
200
|
+
return [toolCallObj(id, name, input)];
|
|
201
|
+
}
|
|
202
|
+
function blockToolResultParts(id, name, result, isError, state) {
|
|
203
|
+
if (state.pendingEdits.has(id)) {
|
|
204
|
+
const filePath = state.pendingEdits.get(id);
|
|
205
|
+
state.pendingEdits.delete(id);
|
|
206
|
+
const diff = isError ? null : editDiffString(result);
|
|
207
|
+
if (diff && filePath) {
|
|
208
|
+
return [
|
|
209
|
+
editCallFields(id, filePath, diff),
|
|
210
|
+
editResultFields(id, filePath, diff, result)
|
|
211
|
+
];
|
|
212
|
+
}
|
|
213
|
+
return [
|
|
214
|
+
toolCallObj(id, EDIT_TOOL_NAME, { path: filePath }),
|
|
215
|
+
toolResultObj(id, EDIT_TOOL_NAME, result, isError)
|
|
216
|
+
];
|
|
217
|
+
}
|
|
218
|
+
state.openToolCalls.delete(id);
|
|
219
|
+
return [toolResultObj(id, name, result, isError)];
|
|
220
|
+
}
|
|
221
|
+
function blockDanglingParts(state) {
|
|
222
|
+
const parts = [];
|
|
223
|
+
for (const [id, name] of state.openToolCalls) {
|
|
224
|
+
parts.push(toolResultObj(id, name, DANGLING_TOOL_RESULT, true));
|
|
225
|
+
}
|
|
226
|
+
state.openToolCalls.clear();
|
|
227
|
+
for (const [id, filePath] of state.pendingEdits) {
|
|
228
|
+
parts.push(toolCallObj(id, EDIT_TOOL_NAME, { path: filePath }));
|
|
229
|
+
parts.push(toolResultObj(id, EDIT_TOOL_NAME, DANGLING_TOOL_RESULT, true));
|
|
230
|
+
}
|
|
231
|
+
state.pendingEdits.clear();
|
|
232
|
+
return parts;
|
|
233
|
+
}
|
|
150
234
|
var EMPTY_USAGE = {
|
|
151
|
-
inputTokens: {
|
|
235
|
+
inputTokens: {
|
|
236
|
+
total: void 0,
|
|
237
|
+
noCache: void 0,
|
|
238
|
+
cacheRead: void 0,
|
|
239
|
+
cacheWrite: void 0
|
|
240
|
+
},
|
|
152
241
|
outputTokens: { total: void 0, text: void 0, reasoning: void 0 }
|
|
153
242
|
};
|
|
154
243
|
function mapUsage(usage) {
|
|
@@ -159,14 +248,19 @@ function mapUsage(usage) {
|
|
|
159
248
|
cacheRead: usage.cacheReadTokens,
|
|
160
249
|
cacheWrite: usage.cacheWriteTokens
|
|
161
250
|
},
|
|
162
|
-
outputTokens: {
|
|
251
|
+
outputTokens: {
|
|
252
|
+
total: usage.outputTokens,
|
|
253
|
+
text: void 0,
|
|
254
|
+
reasoning: void 0
|
|
255
|
+
}
|
|
163
256
|
};
|
|
164
257
|
}
|
|
165
258
|
function formatToolCall(name, input) {
|
|
166
259
|
let arg = "";
|
|
167
260
|
try {
|
|
168
261
|
const s = typeof input === "string" ? input : JSON.stringify(input);
|
|
169
|
-
if (s && s !== "{}" && s !== '""')
|
|
262
|
+
if (s && s !== "{}" && s !== '""')
|
|
263
|
+
arg = ` ${s.length > 120 ? `${s.slice(0, 120)}\u2026` : s}`;
|
|
170
264
|
} catch {
|
|
171
265
|
}
|
|
172
266
|
return `[tool] ${name}${arg}`;
|
|
@@ -175,21 +269,21 @@ var DANGLING_TOOL_RESULT = {
|
|
|
175
269
|
status: "error",
|
|
176
270
|
error: "Cursor run ended before this tool call completed."
|
|
177
271
|
};
|
|
178
|
-
function cursorEventsToStream(events, toolDisplay = "
|
|
272
|
+
function cursorEventsToStream(events, toolDisplay = "blocks") {
|
|
179
273
|
return new ReadableStream({
|
|
180
274
|
async start(controller) {
|
|
181
275
|
controller.enqueue({ type: "stream-start", warnings: [] });
|
|
182
276
|
let textId;
|
|
277
|
+
let textCount = 0;
|
|
183
278
|
let reasoningId;
|
|
184
279
|
let reasoningCount = 0;
|
|
185
280
|
let usage;
|
|
186
281
|
let streamedText = false;
|
|
187
|
-
const
|
|
282
|
+
const toolState = newBlockToolState();
|
|
188
283
|
const closeDanglingToolCalls = () => {
|
|
189
|
-
for (const
|
|
190
|
-
controller.enqueue(
|
|
284
|
+
for (const part of blockDanglingParts(toolState)) {
|
|
285
|
+
controller.enqueue(part);
|
|
191
286
|
}
|
|
192
|
-
openToolCalls.clear();
|
|
193
287
|
};
|
|
194
288
|
const closeReasoning = () => {
|
|
195
289
|
if (reasoningId) {
|
|
@@ -197,15 +291,22 @@ function cursorEventsToStream(events, toolDisplay = "reasoning") {
|
|
|
197
291
|
reasoningId = void 0;
|
|
198
292
|
}
|
|
199
293
|
};
|
|
294
|
+
const closeText = () => {
|
|
295
|
+
if (textId) {
|
|
296
|
+
controller.enqueue({ type: "text-end", id: textId });
|
|
297
|
+
textId = void 0;
|
|
298
|
+
}
|
|
299
|
+
};
|
|
200
300
|
const ensureText = () => {
|
|
201
301
|
closeReasoning();
|
|
202
302
|
if (!textId) {
|
|
203
|
-
textId =
|
|
303
|
+
textId = `text-${textCount++}`;
|
|
204
304
|
controller.enqueue({ type: "text-start", id: textId });
|
|
205
305
|
}
|
|
206
306
|
return textId;
|
|
207
307
|
};
|
|
208
308
|
const ensureReasoning = () => {
|
|
309
|
+
closeText();
|
|
209
310
|
if (!reasoningId) {
|
|
210
311
|
reasoningId = `reasoning-${reasoningCount++}`;
|
|
211
312
|
controller.enqueue({ type: "reasoning-start", id: reasoningId });
|
|
@@ -213,22 +314,36 @@ function cursorEventsToStream(events, toolDisplay = "reasoning") {
|
|
|
213
314
|
return reasoningId;
|
|
214
315
|
};
|
|
215
316
|
const reasoningLine = (text) => {
|
|
216
|
-
controller.enqueue({
|
|
317
|
+
controller.enqueue({
|
|
318
|
+
type: "reasoning-delta",
|
|
319
|
+
id: ensureReasoning(),
|
|
320
|
+
delta: text
|
|
321
|
+
});
|
|
217
322
|
};
|
|
218
323
|
try {
|
|
219
324
|
for await (const event of events) {
|
|
220
325
|
switch (event.type) {
|
|
221
326
|
case "text-delta":
|
|
222
327
|
streamedText = true;
|
|
223
|
-
controller.enqueue({
|
|
328
|
+
controller.enqueue({
|
|
329
|
+
type: "text-delta",
|
|
330
|
+
id: ensureText(),
|
|
331
|
+
delta: event.text
|
|
332
|
+
});
|
|
224
333
|
break;
|
|
225
334
|
case "reasoning-delta":
|
|
226
335
|
reasoningLine(event.text);
|
|
227
336
|
break;
|
|
228
337
|
case "tool-call":
|
|
229
338
|
if (toolDisplay === "blocks") {
|
|
230
|
-
|
|
231
|
-
|
|
339
|
+
for (const part of blockToolCallParts(
|
|
340
|
+
event.id,
|
|
341
|
+
event.name,
|
|
342
|
+
event.input,
|
|
343
|
+
toolState
|
|
344
|
+
)) {
|
|
345
|
+
controller.enqueue(part);
|
|
346
|
+
}
|
|
232
347
|
} else {
|
|
233
348
|
reasoningLine(`
|
|
234
349
|
${formatToolCall(event.name, event.input)}
|
|
@@ -237,10 +352,15 @@ ${formatToolCall(event.name, event.input)}
|
|
|
237
352
|
break;
|
|
238
353
|
case "tool-result":
|
|
239
354
|
if (toolDisplay === "blocks") {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
355
|
+
for (const part of blockToolResultParts(
|
|
356
|
+
event.id,
|
|
357
|
+
event.name,
|
|
358
|
+
event.result,
|
|
359
|
+
event.isError,
|
|
360
|
+
toolState
|
|
361
|
+
)) {
|
|
362
|
+
controller.enqueue(part);
|
|
363
|
+
}
|
|
244
364
|
} else if (event.isError) {
|
|
245
365
|
reasoningLine(`[tool] ${event.name} failed
|
|
246
366
|
`);
|
|
@@ -251,31 +371,43 @@ ${formatToolCall(event.name, event.input)}
|
|
|
251
371
|
break;
|
|
252
372
|
case "finish":
|
|
253
373
|
if (!streamedText && event.text) {
|
|
254
|
-
controller.enqueue({
|
|
374
|
+
controller.enqueue({
|
|
375
|
+
type: "text-delta",
|
|
376
|
+
id: ensureText(),
|
|
377
|
+
delta: event.text
|
|
378
|
+
});
|
|
255
379
|
}
|
|
256
380
|
break;
|
|
257
381
|
}
|
|
258
382
|
}
|
|
259
383
|
closeDanglingToolCalls();
|
|
260
384
|
closeReasoning();
|
|
261
|
-
|
|
262
|
-
controller.enqueue({
|
|
385
|
+
closeText();
|
|
386
|
+
controller.enqueue({
|
|
387
|
+
type: "finish",
|
|
388
|
+
usage: usage ?? EMPTY_USAGE,
|
|
389
|
+
finishReason: FINISH_STOP
|
|
390
|
+
});
|
|
263
391
|
controller.close();
|
|
264
392
|
} catch (err) {
|
|
265
393
|
controller.enqueue({ type: "error", error: err });
|
|
266
394
|
closeDanglingToolCalls();
|
|
267
395
|
closeReasoning();
|
|
268
|
-
|
|
269
|
-
controller.enqueue({
|
|
396
|
+
closeText();
|
|
397
|
+
controller.enqueue({
|
|
398
|
+
type: "finish",
|
|
399
|
+
usage: usage ?? EMPTY_USAGE,
|
|
400
|
+
finishReason: FINISH_ERROR
|
|
401
|
+
});
|
|
270
402
|
controller.close();
|
|
271
403
|
}
|
|
272
404
|
}
|
|
273
405
|
});
|
|
274
406
|
}
|
|
275
|
-
async function cursorEventsToContent(events, toolDisplay = "
|
|
407
|
+
async function cursorEventsToContent(events, toolDisplay = "blocks") {
|
|
276
408
|
const content = [];
|
|
277
409
|
const toolParts = [];
|
|
278
|
-
const
|
|
410
|
+
const toolState = newBlockToolState();
|
|
279
411
|
let text = "";
|
|
280
412
|
let reasoning = "";
|
|
281
413
|
let usage = EMPTY_USAGE;
|
|
@@ -291,8 +423,14 @@ async function cursorEventsToContent(events, toolDisplay = "reasoning") {
|
|
|
291
423
|
break;
|
|
292
424
|
case "tool-call":
|
|
293
425
|
if (toolDisplay === "blocks") {
|
|
294
|
-
|
|
295
|
-
|
|
426
|
+
for (const part of blockToolCallParts(
|
|
427
|
+
event.id,
|
|
428
|
+
event.name,
|
|
429
|
+
event.input,
|
|
430
|
+
toolState
|
|
431
|
+
)) {
|
|
432
|
+
toolParts.push(part);
|
|
433
|
+
}
|
|
296
434
|
} else {
|
|
297
435
|
reasoning += `
|
|
298
436
|
${formatToolCall(event.name, event.input)}
|
|
@@ -301,8 +439,15 @@ ${formatToolCall(event.name, event.input)}
|
|
|
301
439
|
break;
|
|
302
440
|
case "tool-result":
|
|
303
441
|
if (toolDisplay === "blocks") {
|
|
304
|
-
|
|
305
|
-
|
|
442
|
+
for (const part of blockToolResultParts(
|
|
443
|
+
event.id,
|
|
444
|
+
event.name,
|
|
445
|
+
event.result,
|
|
446
|
+
event.isError,
|
|
447
|
+
toolState
|
|
448
|
+
)) {
|
|
449
|
+
toolParts.push(part);
|
|
450
|
+
}
|
|
306
451
|
} else if (event.isError) {
|
|
307
452
|
reasoning += `[tool] ${event.name} failed
|
|
308
453
|
`;
|
|
@@ -319,10 +464,9 @@ ${formatToolCall(event.name, event.input)}
|
|
|
319
464
|
} catch {
|
|
320
465
|
finishReason = FINISH_ERROR;
|
|
321
466
|
}
|
|
322
|
-
for (const
|
|
323
|
-
toolParts.push(
|
|
467
|
+
for (const part of blockDanglingParts(toolState)) {
|
|
468
|
+
toolParts.push(part);
|
|
324
469
|
}
|
|
325
|
-
openToolCalls.clear();
|
|
326
470
|
if (reasoning) content.push({ type: "reasoning", text: reasoning });
|
|
327
471
|
content.push(...toolParts);
|
|
328
472
|
if (text) content.push({ type: "text", text });
|
|
@@ -377,16 +521,27 @@ var CursorLanguageModel = class {
|
|
|
377
521
|
});
|
|
378
522
|
const message = acquired.resumed ? latestUserMessage(options.prompt) ?? promptToCursorMessage(options.prompt) : promptToCursorMessage(options.prompt);
|
|
379
523
|
try {
|
|
380
|
-
yield* streamAgentTurn(acquired.agent, message, {
|
|
524
|
+
yield* streamAgentTurn(acquired.agent, message, {
|
|
525
|
+
mode,
|
|
526
|
+
abortSignal: options.abortSignal
|
|
527
|
+
});
|
|
381
528
|
} finally {
|
|
382
529
|
acquired.release();
|
|
383
530
|
}
|
|
384
531
|
}
|
|
385
532
|
async doStream(options) {
|
|
386
|
-
return {
|
|
533
|
+
return {
|
|
534
|
+
stream: cursorEventsToStream(
|
|
535
|
+
this.agentRun(options),
|
|
536
|
+
this.config.toolDisplay
|
|
537
|
+
)
|
|
538
|
+
};
|
|
387
539
|
}
|
|
388
540
|
async doGenerate(options) {
|
|
389
|
-
const result = await cursorEventsToContent(
|
|
541
|
+
const result = await cursorEventsToContent(
|
|
542
|
+
this.agentRun(options),
|
|
543
|
+
this.config.toolDisplay
|
|
544
|
+
);
|
|
390
545
|
return { ...result, warnings: [] };
|
|
391
546
|
}
|
|
392
547
|
};
|
|
@@ -405,7 +560,7 @@ function createCursor(options = {}) {
|
|
|
405
560
|
...options.sandbox !== void 0 ? { sandbox: options.sandbox } : {},
|
|
406
561
|
...options.agents ? { agents: options.agents } : {},
|
|
407
562
|
...options.session !== void 0 ? { session: options.session } : {},
|
|
408
|
-
|
|
563
|
+
toolDisplay: options.toolDisplay ?? "blocks"
|
|
409
564
|
};
|
|
410
565
|
const notImplemented = (kind, modelId) => {
|
|
411
566
|
throw new NoSuchModelError({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/provider/index.ts","../../src/provider/language-model.ts","../../src/provider/message-map.ts","../../src/provider/stream-map.ts"],"sourcesContent":["import type { EmbeddingModelV3, ImageModelV3, ProviderV3 } from \"@ai-sdk/provider\";\nimport { NoSuchModelError } from \"@ai-sdk/provider\";\nimport type { AgentDefinition, AgentModeOption, McpServerConfig, SettingSource } from \"@cursor/sdk\";\nimport { resolveCursorApiKey } from \"../api-key.js\";\nimport { CursorLanguageModel, type CursorModelConfig } from \"./language-model.js\";\nimport type { ToolDisplay } from \"./stream-map.js\";\n\nexport interface CursorProviderOptions {\n /**\n * Cursor API key. opencode passes this from the provider's resolved auth /\n * options. When omitted, falls back to the CURSOR_API_KEY environment\n * variable at call time.\n */\n apiKey?: string;\n /** Provider id, supplied by opencode as `name`. Defaults to \"cursor\". */\n name?: string;\n /** Working directory for the local Cursor agent. Defaults to process.cwd(). */\n cwd?: string;\n /** Default conversation mode: \"agent\" (default) or \"plan\". Overridable per-request. */\n mode?: AgentModeOption;\n /** Default Cursor model params (id -> value), e.g. { thinking: \"high\" }. */\n params?: Record<string, string>;\n /**\n * MCP servers to make available to the Cursor agent, keyed by name. The\n * plugin's `config` hook populates this by translating opencode's configured\n * `config.mcp` servers, so the agent can use the same MCP servers (e.g.\n * Serena) that opencode does.\n */\n mcpServers?: Record<string, McpServerConfig>;\n /**\n * Cursor settings layers to load from the local filesystem (\"project\",\n * \"user\", \"all\", ...). Enables the agent to pick up your Cursor skills,\n * rules, and `.cursor/mcp.json` servers.\n */\n settingSources?: SettingSource[];\n /** Run the agent's tools inside Cursor's sandbox. */\n sandbox?: boolean;\n /** Cursor subagent definitions (`{ description, prompt, model?, mcpServers? }`). */\n agents?: Record<string, AgentDefinition>;\n /**\n * Reuse one Cursor agent per opencode session (resume across turns instead of\n * creating a fresh agent each turn). Off by default.\n */\n session?: boolean;\n /**\n * How Cursor's internal tool activity (shell/read/edit/mcp/…) is surfaced:\n * - `\"reasoning\"` (default): compact reasoning lines (works on every host).\n * - `\"blocks\"`: structured provider-executed `tool-call`/`tool-result` parts\n * so opencode renders proper tool blocks. Opt-in; requires a V3-native host.\n */\n toolDisplay?: ToolDisplay;\n}\n\n/**\n * Cursor provider for the Vercel AI SDK (V3), backed by the official\n * `@cursor/sdk` local agent runtime.\n *\n * opencode loads this package by its `npm` provider config, finds the export\n * whose name starts with `create`, calls it with `{ name, apiKey, ...options }`,\n * and then calls `.languageModel(modelId)`.\n */\nexport function createCursor(options: CursorProviderOptions = {}): ProviderV3 {\n const mcpServers =\n options.mcpServers && Object.keys(options.mcpServers).length > 0 ? options.mcpServers : undefined;\n const config: CursorModelConfig = {\n providerName: options.name ?? \"cursor\",\n apiKey: resolveCursorApiKey(options.apiKey),\n cwd: options.cwd ?? process.cwd(),\n mode: options.mode ?? \"agent\",\n ...(options.params ? { params: options.params } : {}),\n ...(mcpServers ? { mcpServers } : {}),\n ...(options.settingSources ? { settingSources: options.settingSources } : {}),\n ...(options.sandbox !== undefined ? { sandbox: options.sandbox } : {}),\n ...(options.agents ? { agents: options.agents } : {}),\n ...(options.session !== undefined ? { session: options.session } : {}),\n ...(options.toolDisplay ? { toolDisplay: options.toolDisplay } : {}),\n };\n\n const notImplemented = (kind: string, modelId: string): never => {\n throw new NoSuchModelError({\n modelId,\n modelType: kind as \"languageModel\",\n message: `The Cursor provider does not support ${kind} models.`,\n });\n };\n\n return {\n specificationVersion: \"v3\",\n languageModel: (modelId: string) => new CursorLanguageModel(modelId, config),\n embeddingModel: (modelId: string): EmbeddingModelV3 =>\n notImplemented(\"embeddingModel\", modelId),\n imageModel: (modelId: string): ImageModelV3 => notImplemented(\"imageModel\", modelId),\n };\n}\n","import type {\n LanguageModelV3,\n LanguageModelV3CallOptions,\n LanguageModelV3Content,\n LanguageModelV3FinishReason,\n LanguageModelV3StreamPart,\n LanguageModelV3Usage,\n} from \"@ai-sdk/provider\";\nimport { LoadAPIKeyError } from \"@ai-sdk/provider\";\nimport type {\n AgentDefinition,\n McpServerConfig,\n SettingSource,\n AgentModeOption,\n} from \"@cursor/sdk\";\nimport { resolveCursorApiKey } from \"../api-key.js\";\nimport { latestUserMessage, promptToCursorMessage } from \"./message-map.js\";\nimport { streamAgentTurn, type CursorEvent } from \"./agent-events.js\";\nimport { cursorEventsToContent, cursorEventsToStream, type ToolDisplay } from \"./stream-map.js\";\nimport { resolveControls } from \"./controls.js\";\nimport { acquireAgent } from \"./session-pool.js\";\n\nexport interface CursorModelConfig {\n /** Provider id used for logging and the providerOptions key (e.g. \"cursor\"). */\n providerName: string;\n /** Explicit API key; re-resolved against the env at call time when absent. */\n apiKey?: string;\n /** Working directory the local Cursor agent operates in. */\n cwd: string;\n /** Default conversation mode; overridable per-request via providerOptions. */\n mode: AgentModeOption;\n /** Default Cursor model params (id -> value); overridable per-request. */\n params?: Record<string, string>;\n /** MCP servers forwarded to the Cursor agent (e.g. opencode's Serena). */\n mcpServers?: Record<string, McpServerConfig>;\n /** Cursor settings layers to load from disk (skills, rules, .cursor/mcp.json). */\n settingSources?: SettingSource[];\n /** Run the agent's tools inside Cursor's sandbox. */\n sandbox?: boolean;\n /** Cursor subagent definitions made available to the agent. */\n agents?: Record<string, AgentDefinition>;\n /**\n * Reuse one Cursor agent per opencode session (resume across turns, sending\n * only the new message). Off by default; the default per-turn-fresh path\n * re-sends the full transcript and is robust to opencode's non-chat calls.\n */\n session?: boolean;\n /**\n * How Cursor's internal tool activity is surfaced (see {@link ToolDisplay}).\n * Defaults to `\"reasoning\"`.\n */\n toolDisplay?: ToolDisplay;\n}\n\n/**\n * A Vercel AI SDK `LanguageModelV3` backed by a local Cursor agent. opencode\n * loads this via the provider factory and calls `doStream` / `doGenerate`.\n * The event→stream translation lives in stream-map.ts so it can be unit tested\n * without a live agent.\n */\nexport class CursorLanguageModel implements LanguageModelV3 {\n readonly specificationVersion = \"v3\" as const;\n readonly modelId: string;\n readonly provider: string;\n // Images are passed inline as base64 data, so no URLs are fetched natively.\n readonly supportedUrls: Record<string, RegExp[]> = {};\n\n constructor(\n modelId: string,\n private readonly config: CursorModelConfig,\n ) {\n this.modelId = modelId;\n this.provider = config.providerName;\n }\n\n private requireApiKey(): string {\n const apiKey = resolveCursorApiKey(this.config.apiKey);\n if (!apiKey) {\n throw new LoadAPIKeyError({\n message:\n \"Cursor API key missing. Run `opencode auth login` and choose Cursor, or set CURSOR_API_KEY.\",\n });\n }\n return apiKey;\n }\n\n private async *agentRun(options: LanguageModelV3CallOptions): AsyncGenerator<CursorEvent> {\n // opencode delivers per-request controls (merged model options + selected\n // variant) under providerOptions keyed by our provider id. The session id is\n // injected there by the plugin's chat.params hook.\n const providerOptions = options.providerOptions?.[this.provider] as\n | Record<string, unknown>\n | undefined;\n const { mode, modelSelection } = resolveControls(\n this.modelId,\n { mode: this.config.mode, params: this.config.params },\n providerOptions,\n );\n const sessionID =\n typeof providerOptions?.[\"sessionID\"] === \"string\"\n ? (providerOptions[\"sessionID\"] as string)\n : undefined;\n const useSession = this.config.session === true && Boolean(sessionID);\n // Power users can resume a specific Cursor agent via\n // `providerOptions.cursor.agentId`; it takes precedence over session pooling.\n const explicitAgentId =\n typeof providerOptions?.[\"agentId\"] === \"string\"\n ? (providerOptions[\"agentId\"] as string)\n : undefined;\n\n const acquired = await acquireAgent({\n apiKey: this.requireApiKey(),\n modelSelection,\n mode,\n cwd: this.config.cwd,\n ...(this.config.settingSources ? { settingSources: this.config.settingSources } : {}),\n ...(this.config.sandbox !== undefined ? { sandbox: this.config.sandbox } : {}),\n ...(this.config.mcpServers ? { mcpServers: this.config.mcpServers } : {}),\n ...(this.config.agents ? { agents: this.config.agents } : {}),\n ...(useSession ? { name: `opencode/${sessionID!.slice(-8)}` } : {}),\n ...(explicitAgentId ? { agentId: explicitAgentId } : {}),\n sessionID,\n session: useSession,\n });\n\n // A resumed agent already remembers the prior conversation, so send only the\n // new turn; otherwise send the full transcript.\n const message = acquired.resumed\n ? (latestUserMessage(options.prompt) ?? promptToCursorMessage(options.prompt))\n : promptToCursorMessage(options.prompt);\n\n try {\n yield* streamAgentTurn(acquired.agent, message, { mode, abortSignal: options.abortSignal });\n } finally {\n acquired.release();\n }\n }\n\n async doStream(options: LanguageModelV3CallOptions): Promise<{\n stream: ReadableStream<LanguageModelV3StreamPart>;\n }> {\n return { stream: cursorEventsToStream(this.agentRun(options), this.config.toolDisplay) };\n }\n\n async doGenerate(options: LanguageModelV3CallOptions): Promise<{\n content: Array<LanguageModelV3Content>;\n finishReason: LanguageModelV3FinishReason;\n usage: LanguageModelV3Usage;\n warnings: Array<never>;\n }> {\n const result = await cursorEventsToContent(this.agentRun(options), this.config.toolDisplay);\n return { ...result, warnings: [] };\n }\n}\n","import type { LanguageModelV3Prompt } from \"@ai-sdk/provider\";\nimport type { SDKImage, SDKUserMessage } from \"@cursor/sdk\";\n\n/**\n * Convert an AI-SDK prompt (the full conversation opencode sends on every call)\n * into a single Cursor `SDKUserMessage`.\n *\n * The Cursor agent keeps its own per-agent conversation memory, but opencode\n * re-sends the whole history each turn. To stay correct without double-counting\n * context, we create a fresh agent per turn (see language-model.ts) and flatten\n * the entire prompt into one transcript message. Images from the final user\n * turn are attached natively so multimodal models can see them.\n */\nexport function promptToCursorMessage(prompt: LanguageModelV3Prompt): SDKUserMessage {\n const lines: string[] = [];\n const images: SDKImage[] = [];\n\n prompt.forEach((message, index) => {\n const isLast = index === prompt.length - 1;\n switch (message.role) {\n case \"system\":\n lines.push(`# System\\n${message.content}`);\n break;\n case \"user\": {\n const text: string[] = [];\n for (const part of message.content) {\n if (part.type === \"text\") text.push(part.text);\n else if (part.type === \"file\" && part.mediaType.startsWith(\"image/\")) {\n const image = fileToImage(part.data, part.mediaType);\n // Only attach images natively for the final user turn; earlier ones\n // are referenced by transcript order.\n if (isLast && image) images.push(image);\n text.push(\"[image attached]\");\n }\n }\n lines.push(`# User\\n${text.join(\"\\n\")}`);\n break;\n }\n case \"assistant\": {\n const text: string[] = [];\n for (const part of message.content) {\n if (part.type === \"text\") text.push(part.text);\n else if (part.type === \"reasoning\") text.push(`(thinking) ${part.text}`);\n else if (part.type === \"tool-call\") text.push(`[called ${part.toolName}(${part.input})]`);\n else if (part.type === \"tool-result\") text.push(`[result of ${part.toolName}]`);\n }\n lines.push(`# Assistant\\n${text.join(\"\\n\")}`);\n break;\n }\n case \"tool\": {\n for (const part of message.content) {\n if (part.type === \"tool-result\") {\n lines.push(`# Tool result (${part.toolName})\\n${JSON.stringify(part.output)}`);\n }\n }\n break;\n }\n }\n });\n\n const out: SDKUserMessage = { text: lines.join(\"\\n\\n\") };\n if (images.length > 0) out.images = images;\n return out;\n}\n\nfunction fileToImage(\n data: string | Uint8Array | URL,\n mediaType: string,\n): SDKImage | undefined {\n if (data instanceof URL) return { url: data.toString() };\n if (typeof data === \"string\") {\n // Either a URL or already-base64 encoded data.\n if (/^https?:\\/\\//i.test(data)) return { url: data };\n return { data, mimeType: mediaType };\n }\n if (data instanceof Uint8Array) {\n return { data: Buffer.from(data).toString(\"base64\"), mimeType: mediaType };\n }\n return undefined;\n}\n\n/**\n * Extract only the final user turn as a Cursor message. Used when resuming a\n * pooled agent that already remembers the prior conversation, so we send just\n * the new message instead of the whole transcript. Returns `undefined` if the\n * last message isn't a user turn (caller should fall back to the full transcript).\n */\nexport function latestUserMessage(prompt: LanguageModelV3Prompt): SDKUserMessage | undefined {\n const last = prompt[prompt.length - 1];\n if (!last || last.role !== \"user\") return undefined;\n\n const text: string[] = [];\n const images: SDKImage[] = [];\n for (const part of last.content) {\n if (part.type === \"text\") text.push(part.text);\n else if (part.type === \"file\" && part.mediaType.startsWith(\"image/\")) {\n const image = fileToImage(part.data, part.mediaType);\n if (image) images.push(image);\n text.push(\"[image attached]\");\n }\n }\n\n const out: SDKUserMessage = { text: text.join(\"\\n\") };\n if (images.length > 0) out.images = images;\n return out;\n}\n\n","import type {\n LanguageModelV3Content,\n LanguageModelV3FinishReason,\n LanguageModelV3StreamPart,\n LanguageModelV3Usage,\n} from \"@ai-sdk/provider\";\nimport type { CursorEvent, CursorUsage } from \"./agent-events.js\";\n\n/**\n * How Cursor's internal tool activity (shell/read/edit/mcp/…) is surfaced to\n * opencode:\n * - `\"reasoning\"` (default): rendered as compact reasoning lines. Robust on\n * every host — no tool-call parts cross the execution boundary.\n * - `\"blocks\"`: emitted as provider-executed AI-SDK `tool-call`/`tool-result`\n * parts so opencode renders structured tool blocks. The parts must carry\n * BOTH `providerExecuted: true` AND `dynamic: true` — ai's `parseToolCall`\n * (v6, `doParseToolCall`) only exempts that combination from registered-tool\n * validation; without `dynamic` an unknown name raises `NoSuchToolError`,\n * which opencode's `experimental_repairToolCall` rewrites into its \"invalid\"\n * tool. Names are also prefixed (`cursor_…`) so they can never collide with\n * a tool opencode has registered (`read`, `grep`, `task`, …) — a colliding\n * name is validated against that tool's input schema instead of being\n * treated as dynamic.\n */\nexport type ToolDisplay = \"reasoning\" | \"blocks\";\n\nconst FINISH_STOP: LanguageModelV3FinishReason = { unified: \"stop\", raw: undefined };\nconst FINISH_ERROR: LanguageModelV3FinishReason = { unified: \"error\", raw: undefined };\n\nfunction safeJsonString(input: unknown): string {\n try {\n return typeof input === \"string\" ? input : JSON.stringify(input ?? {});\n } catch {\n return \"{}\";\n }\n}\n\n/**\n * Tool name as it crosses into opencode in \"blocks\" mode. Prefixed so it can\n * never collide with a tool opencode has registered, and sanitized because MCP\n * names contain `/` (e.g. `serena/find_symbol` → `cursor_serena_find_symbol`).\n */\nfunction blockToolName(name: string): string {\n return `cursor_${name.replace(/[^A-Za-z0-9_-]/g, \"_\")}`;\n}\n\n/**\n * Build a provider-executed dynamic `tool-call` stream part (V3). `input` is a\n * stringified JSON object per the spec.\n */\nfunction toolCallPart(id: string, name: string, input: unknown): LanguageModelV3StreamPart {\n return {\n type: \"tool-call\",\n toolCallId: id,\n toolName: blockToolName(name),\n input: safeJsonString(input),\n providerExecuted: true,\n dynamic: true,\n } as LanguageModelV3StreamPart;\n}\n\n/**\n * Build a provider-executed dynamic `tool-result` stream part. Per the V3 spec\n * (and ai v6's `runToolsTransformation`, which reads `chunk.result` /\n * `chunk.isError`) the payload goes in `result`; `result` is typed\n * `NonNullable<JSONValue>` so a missing Cursor result is coalesced to `null`\n * and cast.\n */\nfunction toolResultPart(\n id: string,\n name: string,\n result: unknown,\n isError: boolean,\n): LanguageModelV3StreamPart {\n return {\n type: \"tool-result\",\n toolCallId: id,\n toolName: blockToolName(name),\n result: (result ?? null) as never,\n isError,\n providerExecuted: true,\n dynamic: true,\n } as LanguageModelV3StreamPart;\n}\n\n/** Content-item equivalents of the tool parts above, for `doGenerate`. */\nfunction toolCallContent(id: string, name: string, input: unknown): LanguageModelV3Content {\n return {\n type: \"tool-call\",\n toolCallId: id,\n toolName: blockToolName(name),\n input: safeJsonString(input),\n providerExecuted: true,\n dynamic: true,\n } as LanguageModelV3Content;\n}\nfunction toolResultContent(\n id: string,\n name: string,\n result: unknown,\n isError: boolean,\n): LanguageModelV3Content {\n return {\n type: \"tool-result\",\n toolCallId: id,\n toolName: blockToolName(name),\n result: (result ?? null) as never,\n isError,\n providerExecuted: true,\n dynamic: true,\n } as LanguageModelV3Content;\n}\n\nexport const EMPTY_USAGE: LanguageModelV3Usage = {\n inputTokens: { total: undefined, noCache: undefined, cacheRead: undefined, cacheWrite: undefined },\n outputTokens: { total: undefined, text: undefined, reasoning: undefined },\n};\n\nexport function mapUsage(usage: CursorUsage): LanguageModelV3Usage {\n return {\n inputTokens: {\n total: usage.inputTokens,\n noCache: undefined,\n cacheRead: usage.cacheReadTokens,\n cacheWrite: usage.cacheWriteTokens,\n },\n outputTokens: { total: usage.outputTokens, text: undefined, reasoning: undefined },\n };\n}\n\n/**\n * Render Cursor's internal tool activity as a short, human-readable line.\n *\n * Cursor runs its own agent loop and executes its own tools (shell/read/edit/\n * mcp/…). We surface that activity as reasoning text — NOT as AI-SDK\n * `tool-call`/`tool-result` parts. opencode (a V3-native host) only treats\n * registered tools as callable; a provider-executed call naming a tool it\n * doesn't know (e.g. `mcp`, `shell`) is rejected as an \"unavailable tool\".\n * Rendering as reasoning keeps the activity visible without crossing the\n * tool-execution boundary. Tool outputs can be huge (file contents, search\n * dumps), so only the call (name + short arg summary) and error status are\n * shown — never the raw result.\n */\nfunction formatToolCall(name: string, input: unknown): string {\n let arg = \"\";\n try {\n const s = typeof input === \"string\" ? input : JSON.stringify(input);\n if (s && s !== \"{}\" && s !== '\"\"') arg = ` ${s.length > 120 ? `${s.slice(0, 120)}…` : s}`;\n } catch {\n // Non-serializable input; show the name only.\n }\n return `[tool] ${name}${arg}`;\n}\n\n/**\n * Synthetic error payload for a tool call whose completion never arrived\n * (run errored/cancelled/wedged mid-tool). Mirrors Cursor's own\n * `{status:\"error\"}` result union so consumers see a consistent shape.\n * Without a matching result, opencode renders the part as\n * \"Tool execution aborted\" and the block dangles forever.\n */\nconst DANGLING_TOOL_RESULT = {\n status: \"error\",\n error: \"Cursor run ended before this tool call completed.\",\n};\n\n/**\n * Translate the normalized Cursor agent events into an AI-SDK V3 stream.\n *\n * Pure with respect to the event source, so it can be tested by feeding a\n * fixed event sequence (no live agent required). Reasoning blocks are closed\n * before text begins so reasoning/text parts nest cleanly. Tool activity is\n * rendered into the reasoning channel (see {@link formatToolCall}).\n */\nexport function cursorEventsToStream(\n events: AsyncIterable<CursorEvent>,\n toolDisplay: ToolDisplay = \"reasoning\",\n): ReadableStream<LanguageModelV3StreamPart> {\n return new ReadableStream<LanguageModelV3StreamPart>({\n async start(controller) {\n controller.enqueue({ type: \"stream-start\", warnings: [] });\n\n let textId: string | undefined;\n let reasoningId: string | undefined;\n let reasoningCount = 0;\n let usage: LanguageModelV3Usage | undefined;\n let streamedText = false;\n // Open (unanswered) tool calls in blocks mode: id -> original tool name.\n const openToolCalls = new Map<string, string>();\n const closeDanglingToolCalls = () => {\n for (const [id, name] of openToolCalls) {\n controller.enqueue(toolResultPart(id, name, DANGLING_TOOL_RESULT, true));\n }\n openToolCalls.clear();\n };\n\n const closeReasoning = () => {\n if (reasoningId) {\n controller.enqueue({ type: \"reasoning-end\", id: reasoningId });\n reasoningId = undefined;\n }\n };\n const ensureText = () => {\n closeReasoning();\n if (!textId) {\n textId = \"text-0\";\n controller.enqueue({ type: \"text-start\", id: textId });\n }\n return textId;\n };\n const ensureReasoning = () => {\n if (!reasoningId) {\n reasoningId = `reasoning-${reasoningCount++}`;\n controller.enqueue({ type: \"reasoning-start\", id: reasoningId });\n }\n return reasoningId;\n };\n const reasoningLine = (text: string) => {\n controller.enqueue({ type: \"reasoning-delta\", id: ensureReasoning(), delta: text });\n };\n\n try {\n for await (const event of events) {\n switch (event.type) {\n case \"text-delta\":\n streamedText = true;\n controller.enqueue({ type: \"text-delta\", id: ensureText(), delta: event.text });\n break;\n case \"reasoning-delta\":\n reasoningLine(event.text);\n break;\n case \"tool-call\":\n if (toolDisplay === \"blocks\") {\n openToolCalls.set(event.id, event.name);\n controller.enqueue(toolCallPart(event.id, event.name, event.input));\n } else {\n reasoningLine(`\\n${formatToolCall(event.name, event.input)}\\n`);\n }\n break;\n case \"tool-result\":\n if (toolDisplay === \"blocks\") {\n openToolCalls.delete(event.id);\n controller.enqueue(\n toolResultPart(event.id, event.name, event.result, event.isError),\n );\n } else if (event.isError) {\n reasoningLine(`[tool] ${event.name} failed\\n`);\n }\n break;\n case \"usage\":\n usage = mapUsage(event.usage);\n break;\n case \"finish\":\n if (!streamedText && event.text) {\n controller.enqueue({ type: \"text-delta\", id: ensureText(), delta: event.text });\n }\n break;\n }\n }\n\n closeDanglingToolCalls();\n closeReasoning();\n if (textId) controller.enqueue({ type: \"text-end\", id: textId });\n controller.enqueue({ type: \"finish\", usage: usage ?? EMPTY_USAGE, finishReason: FINISH_STOP });\n controller.close();\n } catch (err) {\n controller.enqueue({ type: \"error\", error: err });\n closeDanglingToolCalls();\n closeReasoning();\n if (textId) controller.enqueue({ type: \"text-end\", id: textId });\n controller.enqueue({ type: \"finish\", usage: usage ?? EMPTY_USAGE, finishReason: FINISH_ERROR });\n controller.close();\n }\n },\n });\n}\n\n/**\n * Aggregate the normalized Cursor agent events into a non-streaming result for\n * `doGenerate`. Same event source contract as {@link cursorEventsToStream}.\n * Tool activity is folded into the reasoning text (display only).\n */\nexport async function cursorEventsToContent(\n events: AsyncIterable<CursorEvent>,\n toolDisplay: ToolDisplay = \"reasoning\",\n): Promise<{\n content: Array<LanguageModelV3Content>;\n finishReason: LanguageModelV3FinishReason;\n usage: LanguageModelV3Usage;\n}> {\n const content: Array<LanguageModelV3Content> = [];\n const toolParts: Array<LanguageModelV3Content> = [];\n // Open (unanswered) tool calls in blocks mode: id -> original tool name.\n const openToolCalls = new Map<string, string>();\n let text = \"\";\n let reasoning = \"\";\n let usage: LanguageModelV3Usage = EMPTY_USAGE;\n let finishReason: LanguageModelV3FinishReason = FINISH_STOP;\n\n try {\n for await (const event of events) {\n switch (event.type) {\n case \"text-delta\":\n text += event.text;\n break;\n case \"reasoning-delta\":\n reasoning += event.text;\n break;\n case \"tool-call\":\n if (toolDisplay === \"blocks\") {\n openToolCalls.set(event.id, event.name);\n toolParts.push(toolCallContent(event.id, event.name, event.input));\n } else {\n reasoning += `\\n${formatToolCall(event.name, event.input)}\\n`;\n }\n break;\n case \"tool-result\":\n if (toolDisplay === \"blocks\") {\n openToolCalls.delete(event.id);\n toolParts.push(toolResultContent(event.id, event.name, event.result, event.isError));\n } else if (event.isError) {\n reasoning += `[tool] ${event.name} failed\\n`;\n }\n break;\n case \"usage\":\n usage = mapUsage(event.usage);\n break;\n case \"finish\":\n if (!text && event.text) text = event.text;\n break;\n }\n }\n } catch {\n finishReason = FINISH_ERROR;\n }\n\n // Close out any tool call whose completion never arrived (see DANGLING_TOOL_RESULT).\n for (const [id, name] of openToolCalls) {\n toolParts.push(toolResultContent(id, name, DANGLING_TOOL_RESULT, true));\n }\n openToolCalls.clear();\n\n if (reasoning) content.push({ type: \"reasoning\", text: reasoning });\n content.push(...toolParts);\n if (text) content.push({ type: \"text\", text });\n\n return { content, finishReason, usage };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/provider/index.ts","../../src/provider/language-model.ts","../../src/provider/message-map.ts","../../src/provider/stream-map.ts"],"sourcesContent":["import type {\n\tEmbeddingModelV3,\n\tImageModelV3,\n\tProviderV3,\n} from \"@ai-sdk/provider\";\nimport { NoSuchModelError } from \"@ai-sdk/provider\";\nimport type {\n\tAgentDefinition,\n\tAgentModeOption,\n\tMcpServerConfig,\n\tSettingSource,\n} from \"@cursor/sdk\";\nimport { resolveCursorApiKey } from \"../api-key.js\";\nimport {\n\tCursorLanguageModel,\n\ttype CursorModelConfig,\n} from \"./language-model.js\";\nimport type { ToolDisplay } from \"./stream-map.js\";\n\nexport interface CursorProviderOptions {\n\t/**\n\t * Cursor API key. opencode passes this from the provider's resolved auth /\n\t * options. When omitted, falls back to the CURSOR_API_KEY environment\n\t * variable at call time.\n\t */\n\tapiKey?: string;\n\t/** Provider id, supplied by opencode as `name`. Defaults to \"cursor\". */\n\tname?: string;\n\t/** Working directory for the local Cursor agent. Defaults to process.cwd(). */\n\tcwd?: string;\n\t/** Default conversation mode: \"agent\" (default) or \"plan\". Overridable per-request. */\n\tmode?: AgentModeOption;\n\t/** Default Cursor model params (id -> value), e.g. { thinking: \"high\" }. */\n\tparams?: Record<string, string>;\n\t/**\n\t * MCP servers to make available to the Cursor agent, keyed by name. The\n\t * plugin's `config` hook populates this by translating opencode's configured\n\t * `config.mcp` servers, so the agent can use the same MCP servers (e.g.\n\t * Serena) that opencode does.\n\t */\n\tmcpServers?: Record<string, McpServerConfig>;\n\t/**\n\t * Cursor settings layers to load from the local filesystem (\"project\",\n\t * \"user\", \"all\", ...). Enables the agent to pick up your Cursor skills,\n\t * rules, and `.cursor/mcp.json` servers.\n\t */\n\tsettingSources?: SettingSource[];\n\t/** Run the agent's tools inside Cursor's sandbox. */\n\tsandbox?: boolean;\n\t/** Cursor subagent definitions (`{ description, prompt, model?, mcpServers? }`). */\n\tagents?: Record<string, AgentDefinition>;\n\t/**\n\t * Reuse one Cursor agent per opencode session (resume across turns instead of\n\t * creating a fresh agent each turn). Off by default.\n\t */\n\tsession?: boolean;\n\t/**\n\t * How Cursor's internal tool activity (shell/read/edit/mcp/…) is surfaced:\n\t * - `\"blocks\"` (default): structured provider-executed `tool-call`/\n\t * `tool-result` parts so opencode renders proper tool blocks. Requires a\n\t * V3-native opencode host (1.16+).\n\t * - `\"reasoning\"`: compact reasoning lines; the fallback for older/non-V3\n\t * hosts (works everywhere).\n\t */\n\ttoolDisplay?: ToolDisplay;\n}\n\n/**\n * Cursor provider for the Vercel AI SDK (V3), backed by the official\n * `@cursor/sdk` local agent runtime.\n *\n * opencode loads this package by its `npm` provider config, finds the export\n * whose name starts with `create`, calls it with `{ name, apiKey, ...options }`,\n * and then calls `.languageModel(modelId)`.\n */\nexport function createCursor(options: CursorProviderOptions = {}): ProviderV3 {\n\tconst mcpServers =\n\t\toptions.mcpServers && Object.keys(options.mcpServers).length > 0\n\t\t\t? options.mcpServers\n\t\t\t: undefined;\n\tconst config: CursorModelConfig = {\n\t\tproviderName: options.name ?? \"cursor\",\n\t\tapiKey: resolveCursorApiKey(options.apiKey),\n\t\tcwd: options.cwd ?? process.cwd(),\n\t\tmode: options.mode ?? \"agent\",\n\t\t...(options.params ? { params: options.params } : {}),\n\t\t...(mcpServers ? { mcpServers } : {}),\n\t\t...(options.settingSources\n\t\t\t? { settingSources: options.settingSources }\n\t\t\t: {}),\n\t\t...(options.sandbox !== undefined ? { sandbox: options.sandbox } : {}),\n\t\t...(options.agents ? { agents: options.agents } : {}),\n\t\t...(options.session !== undefined ? { session: options.session } : {}),\n\t\ttoolDisplay: options.toolDisplay ?? \"blocks\",\n\t};\n\n\tconst notImplemented = (kind: string, modelId: string): never => {\n\t\tthrow new NoSuchModelError({\n\t\t\tmodelId,\n\t\t\tmodelType: kind as \"languageModel\",\n\t\t\tmessage: `The Cursor provider does not support ${kind} models.`,\n\t\t});\n\t};\n\n\treturn {\n\t\tspecificationVersion: \"v3\",\n\t\tlanguageModel: (modelId: string) =>\n\t\t\tnew CursorLanguageModel(modelId, config),\n\t\tembeddingModel: (modelId: string): EmbeddingModelV3 =>\n\t\t\tnotImplemented(\"embeddingModel\", modelId),\n\t\timageModel: (modelId: string): ImageModelV3 =>\n\t\t\tnotImplemented(\"imageModel\", modelId),\n\t};\n}\n","import type {\n\tLanguageModelV3,\n\tLanguageModelV3CallOptions,\n\tLanguageModelV3Content,\n\tLanguageModelV3FinishReason,\n\tLanguageModelV3StreamPart,\n\tLanguageModelV3Usage,\n} from \"@ai-sdk/provider\";\nimport { LoadAPIKeyError } from \"@ai-sdk/provider\";\nimport type {\n\tAgentDefinition,\n\tMcpServerConfig,\n\tSettingSource,\n\tAgentModeOption,\n} from \"@cursor/sdk\";\nimport { resolveCursorApiKey } from \"../api-key.js\";\nimport { latestUserMessage, promptToCursorMessage } from \"./message-map.js\";\nimport { streamAgentTurn, type CursorEvent } from \"./agent-events.js\";\nimport {\n\tcursorEventsToContent,\n\tcursorEventsToStream,\n\ttype ToolDisplay,\n} from \"./stream-map.js\";\nimport { resolveControls } from \"./controls.js\";\nimport { acquireAgent } from \"./session-pool.js\";\n\nexport interface CursorModelConfig {\n\t/** Provider id used for logging and the providerOptions key (e.g. \"cursor\"). */\n\tproviderName: string;\n\t/** Explicit API key; re-resolved against the env at call time when absent. */\n\tapiKey?: string;\n\t/** Working directory the local Cursor agent operates in. */\n\tcwd: string;\n\t/** Default conversation mode; overridable per-request via providerOptions. */\n\tmode: AgentModeOption;\n\t/** Default Cursor model params (id -> value); overridable per-request. */\n\tparams?: Record<string, string>;\n\t/** MCP servers forwarded to the Cursor agent (e.g. opencode's Serena). */\n\tmcpServers?: Record<string, McpServerConfig>;\n\t/** Cursor settings layers to load from disk (skills, rules, .cursor/mcp.json). */\n\tsettingSources?: SettingSource[];\n\t/** Run the agent's tools inside Cursor's sandbox. */\n\tsandbox?: boolean;\n\t/** Cursor subagent definitions made available to the agent. */\n\tagents?: Record<string, AgentDefinition>;\n\t/**\n\t * Reuse one Cursor agent per opencode session (resume across turns, sending\n\t * only the new message). Off by default; the default per-turn-fresh path\n\t * re-sends the full transcript and is robust to opencode's non-chat calls.\n\t */\n\tsession?: boolean;\n\t/**\n\t * How Cursor's internal tool activity is surfaced (see {@link ToolDisplay}).\n\t * Defaults to `\"blocks\"`.\n\t */\n\ttoolDisplay?: ToolDisplay;\n}\n\n/**\n * A Vercel AI SDK `LanguageModelV3` backed by a local Cursor agent. opencode\n * loads this via the provider factory and calls `doStream` / `doGenerate`.\n * The event→stream translation lives in stream-map.ts so it can be unit tested\n * without a live agent.\n */\nexport class CursorLanguageModel implements LanguageModelV3 {\n\treadonly specificationVersion = \"v3\" as const;\n\treadonly modelId: string;\n\treadonly provider: string;\n\t// Images are passed inline as base64 data, so no URLs are fetched natively.\n\treadonly supportedUrls: Record<string, RegExp[]> = {};\n\n\tconstructor(\n\t\tmodelId: string,\n\t\tprivate readonly config: CursorModelConfig,\n\t) {\n\t\tthis.modelId = modelId;\n\t\tthis.provider = config.providerName;\n\t}\n\n\tprivate requireApiKey(): string {\n\t\tconst apiKey = resolveCursorApiKey(this.config.apiKey);\n\t\tif (!apiKey) {\n\t\t\tthrow new LoadAPIKeyError({\n\t\t\t\tmessage:\n\t\t\t\t\t\"Cursor API key missing. Run `opencode auth login` and choose Cursor, or set CURSOR_API_KEY.\",\n\t\t\t});\n\t\t}\n\t\treturn apiKey;\n\t}\n\n\tprivate async *agentRun(\n\t\toptions: LanguageModelV3CallOptions,\n\t): AsyncGenerator<CursorEvent> {\n\t\t// opencode delivers per-request controls (merged model options + selected\n\t\t// variant) under providerOptions keyed by our provider id. The session id is\n\t\t// injected there by the plugin's chat.params hook.\n\t\tconst providerOptions = options.providerOptions?.[this.provider] as\n\t\t\t| Record<string, unknown>\n\t\t\t| undefined;\n\t\tconst { mode, modelSelection } = resolveControls(\n\t\t\tthis.modelId,\n\t\t\t{ mode: this.config.mode, params: this.config.params },\n\t\t\tproviderOptions,\n\t\t);\n\t\tconst sessionID =\n\t\t\ttypeof providerOptions?.[\"sessionID\"] === \"string\"\n\t\t\t\t? (providerOptions[\"sessionID\"] as string)\n\t\t\t\t: undefined;\n\t\tconst useSession = this.config.session === true && Boolean(sessionID);\n\t\t// Power users can resume a specific Cursor agent via\n\t\t// `providerOptions.cursor.agentId`; it takes precedence over session pooling.\n\t\tconst explicitAgentId =\n\t\t\ttypeof providerOptions?.[\"agentId\"] === \"string\"\n\t\t\t\t? (providerOptions[\"agentId\"] as string)\n\t\t\t\t: undefined;\n\n\t\tconst acquired = await acquireAgent({\n\t\t\tapiKey: this.requireApiKey(),\n\t\t\tmodelSelection,\n\t\t\tmode,\n\t\t\tcwd: this.config.cwd,\n\t\t\t...(this.config.settingSources\n\t\t\t\t? { settingSources: this.config.settingSources }\n\t\t\t\t: {}),\n\t\t\t...(this.config.sandbox !== undefined\n\t\t\t\t? { sandbox: this.config.sandbox }\n\t\t\t\t: {}),\n\t\t\t...(this.config.mcpServers ? { mcpServers: this.config.mcpServers } : {}),\n\t\t\t...(this.config.agents ? { agents: this.config.agents } : {}),\n\t\t\t...(useSession ? { name: `opencode/${sessionID!.slice(-8)}` } : {}),\n\t\t\t...(explicitAgentId ? { agentId: explicitAgentId } : {}),\n\t\t\tsessionID,\n\t\t\tsession: useSession,\n\t\t});\n\n\t\t// A resumed agent already remembers the prior conversation, so send only the\n\t\t// new turn; otherwise send the full transcript.\n\t\tconst message = acquired.resumed\n\t\t\t? (latestUserMessage(options.prompt) ??\n\t\t\t\tpromptToCursorMessage(options.prompt))\n\t\t\t: promptToCursorMessage(options.prompt);\n\n\t\ttry {\n\t\t\tyield* streamAgentTurn(acquired.agent, message, {\n\t\t\t\tmode,\n\t\t\t\tabortSignal: options.abortSignal,\n\t\t\t});\n\t\t} finally {\n\t\t\tacquired.release();\n\t\t}\n\t}\n\n\tasync doStream(options: LanguageModelV3CallOptions): Promise<{\n\t\tstream: ReadableStream<LanguageModelV3StreamPart>;\n\t}> {\n\t\treturn {\n\t\t\tstream: cursorEventsToStream(\n\t\t\t\tthis.agentRun(options),\n\t\t\t\tthis.config.toolDisplay,\n\t\t\t),\n\t\t};\n\t}\n\n\tasync doGenerate(options: LanguageModelV3CallOptions): Promise<{\n\t\tcontent: Array<LanguageModelV3Content>;\n\t\tfinishReason: LanguageModelV3FinishReason;\n\t\tusage: LanguageModelV3Usage;\n\t\twarnings: Array<never>;\n\t}> {\n\t\tconst result = await cursorEventsToContent(\n\t\t\tthis.agentRun(options),\n\t\t\tthis.config.toolDisplay,\n\t\t);\n\t\treturn { ...result, warnings: [] };\n\t}\n}\n","import type { LanguageModelV3Prompt } from \"@ai-sdk/provider\";\nimport type { SDKImage, SDKUserMessage } from \"@cursor/sdk\";\n\n/**\n * Convert an AI-SDK prompt (the full conversation opencode sends on every call)\n * into a single Cursor `SDKUserMessage`.\n *\n * The Cursor agent keeps its own per-agent conversation memory, but opencode\n * re-sends the whole history each turn. To stay correct without double-counting\n * context, we create a fresh agent per turn (see language-model.ts) and flatten\n * the entire prompt into one transcript message. Images from the final user\n * turn are attached natively so multimodal models can see them.\n */\nexport function promptToCursorMessage(prompt: LanguageModelV3Prompt): SDKUserMessage {\n const lines: string[] = [];\n const images: SDKImage[] = [];\n\n prompt.forEach((message, index) => {\n const isLast = index === prompt.length - 1;\n switch (message.role) {\n case \"system\":\n lines.push(`# System\\n${message.content}`);\n break;\n case \"user\": {\n const text: string[] = [];\n for (const part of message.content) {\n if (part.type === \"text\") text.push(part.text);\n else if (part.type === \"file\" && part.mediaType.startsWith(\"image/\")) {\n const image = fileToImage(part.data, part.mediaType);\n // Only attach images natively for the final user turn; earlier ones\n // are referenced by transcript order.\n if (isLast && image) images.push(image);\n text.push(\"[image attached]\");\n }\n }\n lines.push(`# User\\n${text.join(\"\\n\")}`);\n break;\n }\n case \"assistant\": {\n const text: string[] = [];\n for (const part of message.content) {\n if (part.type === \"text\") text.push(part.text);\n else if (part.type === \"reasoning\") text.push(`(thinking) ${part.text}`);\n else if (part.type === \"tool-call\") text.push(`[called ${part.toolName}(${part.input})]`);\n else if (part.type === \"tool-result\") text.push(`[result of ${part.toolName}]`);\n }\n lines.push(`# Assistant\\n${text.join(\"\\n\")}`);\n break;\n }\n case \"tool\": {\n for (const part of message.content) {\n if (part.type === \"tool-result\") {\n lines.push(`# Tool result (${part.toolName})\\n${JSON.stringify(part.output)}`);\n }\n }\n break;\n }\n }\n });\n\n const out: SDKUserMessage = { text: lines.join(\"\\n\\n\") };\n if (images.length > 0) out.images = images;\n return out;\n}\n\nfunction fileToImage(\n data: string | Uint8Array | URL,\n mediaType: string,\n): SDKImage | undefined {\n if (data instanceof URL) return { url: data.toString() };\n if (typeof data === \"string\") {\n // Either a URL or already-base64 encoded data.\n if (/^https?:\\/\\//i.test(data)) return { url: data };\n return { data, mimeType: mediaType };\n }\n if (data instanceof Uint8Array) {\n return { data: Buffer.from(data).toString(\"base64\"), mimeType: mediaType };\n }\n return undefined;\n}\n\n/**\n * Extract only the final user turn as a Cursor message. Used when resuming a\n * pooled agent that already remembers the prior conversation, so we send just\n * the new message instead of the whole transcript. Returns `undefined` if the\n * last message isn't a user turn (caller should fall back to the full transcript).\n */\nexport function latestUserMessage(prompt: LanguageModelV3Prompt): SDKUserMessage | undefined {\n const last = prompt[prompt.length - 1];\n if (!last || last.role !== \"user\") return undefined;\n\n const text: string[] = [];\n const images: SDKImage[] = [];\n for (const part of last.content) {\n if (part.type === \"text\") text.push(part.text);\n else if (part.type === \"file\" && part.mediaType.startsWith(\"image/\")) {\n const image = fileToImage(part.data, part.mediaType);\n if (image) images.push(image);\n text.push(\"[image attached]\");\n }\n }\n\n const out: SDKUserMessage = { text: text.join(\"\\n\") };\n if (images.length > 0) out.images = images;\n return out;\n}\n\n","import type {\n\tLanguageModelV3Content,\n\tLanguageModelV3FinishReason,\n\tLanguageModelV3StreamPart,\n\tLanguageModelV3Usage,\n} from \"@ai-sdk/provider\";\nimport type { CursorEvent, CursorUsage } from \"./agent-events.js\";\n\n/**\n * How Cursor's internal tool activity (shell/read/edit/mcp/…) is surfaced to\n * opencode:\n * - `\"blocks\"` (default): emitted as provider-executed AI-SDK\n * `tool-call`/`tool-result` parts so opencode renders structured tool\n * blocks. Requires a V3-native opencode host (1.16+). The parts must carry\n * BOTH `providerExecuted: true` AND `dynamic: true` — ai's `parseToolCall`\n * (v6, `doParseToolCall`) only exempts that combination from registered-tool\n * validation; without `dynamic` an unknown name raises `NoSuchToolError`,\n * which opencode's `experimental_repairToolCall` rewrites into its \"invalid\"\n * tool. Names are also prefixed (`cursor_…`) so they can never collide with\n * a tool opencode has registered (`read`, `grep`, `task`, …) — a colliding\n * name is validated against that tool's input schema instead of being\n * treated as dynamic.\n */\nexport type ToolDisplay = \"reasoning\" | \"blocks\";\n\nconst FINISH_STOP: LanguageModelV3FinishReason = {\n\tunified: \"stop\",\n\traw: undefined,\n};\nconst FINISH_ERROR: LanguageModelV3FinishReason = {\n\tunified: \"error\",\n\traw: undefined,\n};\n\nfunction safeJsonString(input: unknown): string {\n\ttry {\n\t\treturn typeof input === \"string\" ? input : JSON.stringify(input ?? {});\n\t} catch {\n\t\treturn \"{}\";\n\t}\n}\n\n/**\n * Tool name as it crosses into opencode in \"blocks\" mode. Prefixed so it can\n * never collide with a tool opencode has registered, and sanitized because MCP\n * names contain `/` (e.g. `serena/find_symbol` → `cursor_serena_find_symbol`).\n */\nfunction blockToolName(name: string): string {\n\treturn `cursor_${name.replace(/[^A-Za-z0-9_-]/g, \"_\")}`;\n}\n\n/**\n * A blocks-mode tool part. `tool-call` / `tool-result` are structurally\n * identical in `LanguageModelV3StreamPart` (streaming) and\n * `LanguageModelV3Content` (`doGenerate`), so the builders below produce one\n * shape that both consumers cast to their respective union.\n */\ntype BlockToolPart = LanguageModelV3StreamPart;\n\n/**\n * Build a provider-executed dynamic `tool-call`. The name is `cursor_`-prefixed\n * so it can't collide with a tool opencode has registered; `input` is a\n * stringified JSON object per the V3 spec.\n */\nfunction toolCallObj(id: string, name: string, input: unknown): BlockToolPart {\n\treturn {\n\t\ttype: \"tool-call\",\n\t\ttoolCallId: id,\n\t\ttoolName: blockToolName(name),\n\t\tinput: safeJsonString(input),\n\t\tproviderExecuted: true,\n\t\tdynamic: true,\n\t} as BlockToolPart;\n}\n\n/**\n * Build a provider-executed dynamic `tool-result`. Per the V3 spec (and ai v6's\n * `runToolsTransformation`, which reads `chunk.result` / `chunk.isError`) the\n * payload goes in `result`; `result` is typed `NonNullable<JSONValue>` so a\n * missing Cursor result is coalesced to `null` and cast.\n */\nfunction toolResultObj(\n\tid: string,\n\tname: string,\n\tresult: unknown,\n\tisError: boolean,\n): BlockToolPart {\n\treturn {\n\t\ttype: \"tool-result\",\n\t\ttoolCallId: id,\n\t\ttoolName: blockToolName(name),\n\t\tresult: (result ?? null) as never,\n\t\tisError,\n\t\tproviderExecuted: true,\n\t\tdynamic: true,\n\t} as BlockToolPart;\n}\n\n/** Cursor's file-edit tool surfaces with this name (its `toolCall.type`). */\nconst EDIT_TOOL_NAME = \"edit\";\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n\treturn typeof v === \"object\" && v !== null;\n}\n\n/** Extract the edit target path from Cursor's edit tool-call args (`{ path }`). */\nfunction editFilePath(input: unknown): string {\n\treturn isRecord(input) && typeof input[\"path\"] === \"string\"\n\t\t? input[\"path\"]\n\t\t: \"\";\n}\n\n/**\n * If `result` is a successful Cursor edit result carrying a unified diff, return\n * its `diffString`; otherwise null (caller falls back to a safe generic block).\n * Cursor shape: `{ status:\"success\", value:{ diffString?, linesAdded?, linesRemoved? } }`.\n */\nfunction editDiffString(result: unknown): string | null {\n\tif (!isRecord(result) || result[\"status\"] !== \"success\") return null;\n\tconst value = result[\"value\"];\n\tif (!isRecord(value)) return null;\n\tconst diff = value[\"diffString\"];\n\treturn typeof diff === \"string\" && diff.length > 0 ? diff : null;\n}\n\n/**\n * Reconstruct opencode `edit` `{oldString,newString}` from a unified diff:\n * removed (`-`) lines → oldString, added (`+`) lines → newString (file/hunk\n * headers skipped). Faithful for a single hunk; approximate (concatenated)\n * across multiple hunks. Used only to satisfy opencode's edit input schema — the\n * call is provider-executed, so these strings are never applied to disk; the\n * rendered diff comes from `metadata.diff`.\n */\nfunction reconstructEditStrings(diff: string): {\n\toldString: string;\n\tnewString: string;\n} {\n\tconst oldLines: string[] = [];\n\tconst newLines: string[] = [];\n\tfor (const line of diff.split(\"\\n\")) {\n\t\tif (\n\t\t\tline.startsWith(\"---\") ||\n\t\t\tline.startsWith(\"+++\") ||\n\t\t\tline.startsWith(\"@@\") ||\n\t\t\tline.startsWith(\"Index:\") ||\n\t\t\tline.startsWith(\"===\")\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (line.startsWith(\"-\")) oldLines.push(line.slice(1));\n\t\telse if (line.startsWith(\"+\")) newLines.push(line.slice(1));\n\t}\n\treturn { oldString: oldLines.join(\"\\n\"), newString: newLines.join(\"\\n\") };\n}\n\n/**\n * Build the opencode-native `edit` `tool-call` payload for a completed Cursor\n * edit. Emitted under the registered name `edit` (so opencode's diff viewer\n * renders) with a schema-valid `{filePath, oldString, newString}` input. Still\n * carries `providerExecuted` + `dynamic` so a host without a registered `edit`\n * tool degrades to a dynamic generic block instead of erroring.\n */\nfunction editCallFields(\n\tid: string,\n\tfilePath: string,\n\tdiff: string,\n): BlockToolPart {\n\tconst { oldString, newString } = reconstructEditStrings(diff);\n\treturn {\n\t\ttype: \"tool-call\",\n\t\ttoolCallId: id,\n\t\ttoolName: EDIT_TOOL_NAME,\n\t\tinput: safeJsonString({ filePath, oldString, newString }),\n\t\tproviderExecuted: true,\n\t\tdynamic: true,\n\t} as BlockToolPart;\n}\n\n/**\n * Build the opencode-native `edit` `tool-result` payload. opencode's processor\n * folds a tool-result's payload into `state.{title,metadata,output}`; the Edit\n * renderer's diff viewer keys on `metadata.diff`.\n */\nfunction editResultFields(\n\tid: string,\n\tfilePath: string,\n\tdiff: string,\n\tresult: unknown,\n): BlockToolPart {\n\tconst value = isRecord(result) ? result[\"value\"] : undefined;\n\tconst added =\n\t\tisRecord(value) && typeof value[\"linesAdded\"] === \"number\"\n\t\t\t? value[\"linesAdded\"]\n\t\t\t: undefined;\n\tconst removed =\n\t\tisRecord(value) && typeof value[\"linesRemoved\"] === \"number\"\n\t\t\t? value[\"linesRemoved\"]\n\t\t\t: undefined;\n\tconst counts =\n\t\tadded !== undefined || removed !== undefined\n\t\t\t? ` (+${added ?? 0}/-${removed ?? 0})`\n\t\t\t: \"\";\n\treturn {\n\t\ttype: \"tool-result\" as const,\n\t\ttoolCallId: id,\n\t\ttoolName: EDIT_TOOL_NAME,\n\t\tresult: {\n\t\t\ttitle: filePath,\n\t\t\tmetadata: { diff, diagnostics: {} },\n\t\t\toutput: `Edit applied${counts}.`,\n\t\t} as never,\n\t\tisError: false,\n\t\tproviderExecuted: true,\n\t\tdynamic: true,\n\t} as BlockToolPart;\n}\n\n/**\n * Per-turn blocks-mode tool bookkeeping, shared by the streaming and\n * `doGenerate` paths:\n * - `openToolCalls`: non-edit calls awaiting their result (id → original name).\n * - `pendingEdits`: edit calls held until their result, which carries the diff\n * needed to emit a schema-valid native `edit` call (id → filePath).\n */\ninterface BlockToolState {\n\topenToolCalls: Map<string, string>;\n\tpendingEdits: Map<string, string>;\n}\n\nfunction newBlockToolState(): BlockToolState {\n\treturn { openToolCalls: new Map(), pendingEdits: new Map() };\n}\n\n/** Parts to emit for a blocks-mode `tool-call` event (edits are buffered). */\nfunction blockToolCallParts(\n\tid: string,\n\tname: string,\n\tinput: unknown,\n\tstate: BlockToolState,\n): BlockToolPart[] {\n\tif (name === EDIT_TOOL_NAME) {\n\t\t// Hold the edit call until its result (which carries the diff).\n\t\tstate.pendingEdits.set(id, editFilePath(input));\n\t\treturn [];\n\t}\n\tstate.openToolCalls.set(id, name);\n\treturn [toolCallObj(id, name, input)];\n}\n\n/** Parts to emit for a blocks-mode `tool-result` event. */\nfunction blockToolResultParts(\n\tid: string,\n\tname: string,\n\tresult: unknown,\n\tisError: boolean,\n\tstate: BlockToolState,\n): BlockToolPart[] {\n\tif (state.pendingEdits.has(id)) {\n\t\tconst filePath = state.pendingEdits.get(id)!;\n\t\tstate.pendingEdits.delete(id);\n\t\tconst diff = isError ? null : editDiffString(result);\n\t\tif (diff && filePath) {\n\t\t\t// Native edit: opencode renders its built-in diff viewer.\n\t\t\treturn [\n\t\t\t\teditCallFields(id, filePath, diff),\n\t\t\t\teditResultFields(id, filePath, diff, result),\n\t\t\t];\n\t\t}\n\t\t// No usable diff (error / unexpected shape): safe generic fallback.\n\t\treturn [\n\t\t\ttoolCallObj(id, EDIT_TOOL_NAME, { path: filePath }),\n\t\t\ttoolResultObj(id, EDIT_TOOL_NAME, result, isError),\n\t\t];\n\t}\n\tstate.openToolCalls.delete(id);\n\treturn [toolResultObj(id, name, result, isError)];\n}\n\n/**\n * Parts that close out any tool call whose completion never arrived (run\n * errored/cancelled mid-tool) so blocks never dangle as \"Tool execution\n * aborted\". Clears the state.\n */\nfunction blockDanglingParts(state: BlockToolState): BlockToolPart[] {\n\tconst parts: BlockToolPart[] = [];\n\tfor (const [id, name] of state.openToolCalls) {\n\t\tparts.push(toolResultObj(id, name, DANGLING_TOOL_RESULT, true));\n\t}\n\tstate.openToolCalls.clear();\n\t// Edits whose result never arrived: safe generic block + synthetic error\n\t// (no diff available to build a native edit).\n\tfor (const [id, filePath] of state.pendingEdits) {\n\t\tparts.push(toolCallObj(id, EDIT_TOOL_NAME, { path: filePath }));\n\t\tparts.push(toolResultObj(id, EDIT_TOOL_NAME, DANGLING_TOOL_RESULT, true));\n\t}\n\tstate.pendingEdits.clear();\n\treturn parts;\n}\n\nexport const EMPTY_USAGE: LanguageModelV3Usage = {\n\tinputTokens: {\n\t\ttotal: undefined,\n\t\tnoCache: undefined,\n\t\tcacheRead: undefined,\n\t\tcacheWrite: undefined,\n\t},\n\toutputTokens: { total: undefined, text: undefined, reasoning: undefined },\n};\n\nexport function mapUsage(usage: CursorUsage): LanguageModelV3Usage {\n\treturn {\n\t\tinputTokens: {\n\t\t\ttotal: usage.inputTokens,\n\t\t\tnoCache: undefined,\n\t\t\tcacheRead: usage.cacheReadTokens,\n\t\t\tcacheWrite: usage.cacheWriteTokens,\n\t\t},\n\t\toutputTokens: {\n\t\t\ttotal: usage.outputTokens,\n\t\t\ttext: undefined,\n\t\t\treasoning: undefined,\n\t\t},\n\t};\n}\n\n/**\n * Render Cursor's internal tool activity as a short, human-readable line.\n *\n * Cursor runs its own agent loop and executes its own tools (shell/read/edit/\n * mcp/…). We surface that activity as reasoning text — NOT as AI-SDK\n * `tool-call`/`tool-result` parts. opencode (a V3-native host) only treats\n * registered tools as callable; a provider-executed call naming a tool it\n * doesn't know (e.g. `mcp`, `shell`) is rejected as an \"unavailable tool\".\n * Rendering as reasoning keeps the activity visible without crossing the\n * tool-execution boundary. Tool outputs can be huge (file contents, search\n * dumps), so only the call (name + short arg summary) and error status are\n * shown — never the raw result.\n */\nfunction formatToolCall(name: string, input: unknown): string {\n\tlet arg = \"\";\n\ttry {\n\t\tconst s = typeof input === \"string\" ? input : JSON.stringify(input);\n\t\tif (s && s !== \"{}\" && s !== '\"\"')\n\t\t\targ = ` ${s.length > 120 ? `${s.slice(0, 120)}…` : s}`;\n\t} catch {\n\t\t// Non-serializable input; show the name only.\n\t}\n\treturn `[tool] ${name}${arg}`;\n}\n\n/**\n * Synthetic error payload for a tool call whose completion never arrived\n * (run errored/cancelled/wedged mid-tool). Mirrors Cursor's own\n * `{status:\"error\"}` result union so consumers see a consistent shape.\n * Without a matching result, opencode renders the part as\n * \"Tool execution aborted\" and the block dangles forever.\n */\nconst DANGLING_TOOL_RESULT = {\n\tstatus: \"error\",\n\terror: \"Cursor run ended before this tool call completed.\",\n};\n\n/**\n * Translate the normalized Cursor agent events into an AI-SDK V3 stream.\n *\n * Pure with respect to the event source, so it can be tested by feeding a\n * fixed event sequence (no live agent required). Reasoning blocks are closed\n * before text begins so reasoning/text parts nest cleanly. Tool activity is\n * surfaced per {@link ToolDisplay} (default `\"blocks\"`): structured tool parts,\n * or reasoning lines when `\"reasoning\"` (see {@link formatToolCall}).\n */\nexport function cursorEventsToStream(\n\tevents: AsyncIterable<CursorEvent>,\n\ttoolDisplay: ToolDisplay = \"blocks\",\n): ReadableStream<LanguageModelV3StreamPart> {\n\treturn new ReadableStream<LanguageModelV3StreamPart>({\n\t\tasync start(controller) {\n\t\t\tcontroller.enqueue({ type: \"stream-start\", warnings: [] });\n\n\t\t\tlet textId: string | undefined;\n\t\t\tlet textCount = 0;\n\t\t\tlet reasoningId: string | undefined;\n\t\t\tlet reasoningCount = 0;\n\t\t\tlet usage: LanguageModelV3Usage | undefined;\n\t\t\tlet streamedText = false;\n\t\t\t// Blocks-mode tool bookkeeping (open non-edit calls + buffered edits).\n\t\t\tconst toolState = newBlockToolState();\n\t\t\tconst closeDanglingToolCalls = () => {\n\t\t\t\tfor (const part of blockDanglingParts(toolState)) {\n\t\t\t\t\tcontroller.enqueue(part);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst closeReasoning = () => {\n\t\t\t\tif (reasoningId) {\n\t\t\t\t\tcontroller.enqueue({ type: \"reasoning-end\", id: reasoningId });\n\t\t\t\t\treasoningId = undefined;\n\t\t\t\t}\n\t\t\t};\n\t\t\t// Close the open text part when reasoning resumes: hosts position a part\n\t\t\t// where it STARTED, so appending later text to an earlier part would\n\t\t\t// render the final answer above the reasoning that preceded it.\n\t\t\tconst closeText = () => {\n\t\t\t\tif (textId) {\n\t\t\t\t\tcontroller.enqueue({ type: \"text-end\", id: textId });\n\t\t\t\t\ttextId = undefined;\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst ensureText = () => {\n\t\t\t\tcloseReasoning();\n\t\t\t\tif (!textId) {\n\t\t\t\t\ttextId = `text-${textCount++}`;\n\t\t\t\t\tcontroller.enqueue({ type: \"text-start\", id: textId });\n\t\t\t\t}\n\t\t\t\treturn textId;\n\t\t\t};\n\t\t\tconst ensureReasoning = () => {\n\t\t\t\tcloseText();\n\t\t\t\tif (!reasoningId) {\n\t\t\t\t\treasoningId = `reasoning-${reasoningCount++}`;\n\t\t\t\t\tcontroller.enqueue({ type: \"reasoning-start\", id: reasoningId });\n\t\t\t\t}\n\t\t\t\treturn reasoningId;\n\t\t\t};\n\t\t\tconst reasoningLine = (text: string) => {\n\t\t\t\tcontroller.enqueue({\n\t\t\t\t\ttype: \"reasoning-delta\",\n\t\t\t\t\tid: ensureReasoning(),\n\t\t\t\t\tdelta: text,\n\t\t\t\t});\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\tfor await (const event of events) {\n\t\t\t\t\tswitch (event.type) {\n\t\t\t\t\t\tcase \"text-delta\":\n\t\t\t\t\t\t\tstreamedText = true;\n\t\t\t\t\t\t\tcontroller.enqueue({\n\t\t\t\t\t\t\t\ttype: \"text-delta\",\n\t\t\t\t\t\t\t\tid: ensureText(),\n\t\t\t\t\t\t\t\tdelta: event.text,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"reasoning-delta\":\n\t\t\t\t\t\t\treasoningLine(event.text);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"tool-call\":\n\t\t\t\t\t\t\tif (toolDisplay === \"blocks\") {\n\t\t\t\t\t\t\t\tfor (const part of blockToolCallParts(\n\t\t\t\t\t\t\t\t\tevent.id,\n\t\t\t\t\t\t\t\t\tevent.name,\n\t\t\t\t\t\t\t\t\tevent.input,\n\t\t\t\t\t\t\t\t\ttoolState,\n\t\t\t\t\t\t\t\t)) {\n\t\t\t\t\t\t\t\t\tcontroller.enqueue(part);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\treasoningLine(`\\n${formatToolCall(event.name, event.input)}\\n`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"tool-result\":\n\t\t\t\t\t\t\tif (toolDisplay === \"blocks\") {\n\t\t\t\t\t\t\t\tfor (const part of blockToolResultParts(\n\t\t\t\t\t\t\t\t\tevent.id,\n\t\t\t\t\t\t\t\t\tevent.name,\n\t\t\t\t\t\t\t\t\tevent.result,\n\t\t\t\t\t\t\t\t\tevent.isError,\n\t\t\t\t\t\t\t\t\ttoolState,\n\t\t\t\t\t\t\t\t)) {\n\t\t\t\t\t\t\t\t\tcontroller.enqueue(part);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if (event.isError) {\n\t\t\t\t\t\t\t\treasoningLine(`[tool] ${event.name} failed\\n`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"usage\":\n\t\t\t\t\t\t\tusage = mapUsage(event.usage);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"finish\":\n\t\t\t\t\t\t\tif (!streamedText && event.text) {\n\t\t\t\t\t\t\t\tcontroller.enqueue({\n\t\t\t\t\t\t\t\t\ttype: \"text-delta\",\n\t\t\t\t\t\t\t\t\tid: ensureText(),\n\t\t\t\t\t\t\t\t\tdelta: event.text,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcloseDanglingToolCalls();\n\t\t\t\tcloseReasoning();\n\t\t\t\tcloseText();\n\t\t\t\tcontroller.enqueue({\n\t\t\t\t\ttype: \"finish\",\n\t\t\t\t\tusage: usage ?? EMPTY_USAGE,\n\t\t\t\t\tfinishReason: FINISH_STOP,\n\t\t\t\t});\n\t\t\t\tcontroller.close();\n\t\t\t} catch (err) {\n\t\t\t\tcontroller.enqueue({ type: \"error\", error: err });\n\t\t\t\tcloseDanglingToolCalls();\n\t\t\t\tcloseReasoning();\n\t\t\t\tcloseText();\n\t\t\t\tcontroller.enqueue({\n\t\t\t\t\ttype: \"finish\",\n\t\t\t\t\tusage: usage ?? EMPTY_USAGE,\n\t\t\t\t\tfinishReason: FINISH_ERROR,\n\t\t\t\t});\n\t\t\t\tcontroller.close();\n\t\t\t}\n\t\t},\n\t});\n}\n\n/**\n * Aggregate the normalized Cursor agent events into a non-streaming result for\n * `doGenerate`. Same event source contract as {@link cursorEventsToStream}\n * (consumed via `for await`). Tool activity is surfaced per {@link ToolDisplay}\n * (default `\"blocks\"`): structured tool parts (see {@link blockToolCallParts} /\n * {@link blockToolResultParts}), or folded into the reasoning text when\n * `\"reasoning\"`.\n */\nexport async function cursorEventsToContent(\n\tevents: AsyncIterable<CursorEvent>,\n\ttoolDisplay: ToolDisplay = \"blocks\",\n): Promise<{\n\tcontent: Array<LanguageModelV3Content>;\n\tfinishReason: LanguageModelV3FinishReason;\n\tusage: LanguageModelV3Usage;\n}> {\n\tconst content: Array<LanguageModelV3Content> = [];\n\tconst toolParts: Array<LanguageModelV3Content> = [];\n\t// Blocks-mode tool bookkeeping (open non-edit calls + buffered edits).\n\tconst toolState = newBlockToolState();\n\tlet text = \"\";\n\tlet reasoning = \"\";\n\tlet usage: LanguageModelV3Usage = EMPTY_USAGE;\n\tlet finishReason: LanguageModelV3FinishReason = FINISH_STOP;\n\n\ttry {\n\t\tfor await (const event of events) {\n\t\t\tswitch (event.type) {\n\t\t\t\tcase \"text-delta\":\n\t\t\t\t\ttext += event.text;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"reasoning-delta\":\n\t\t\t\t\treasoning += event.text;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"tool-call\":\n\t\t\t\t\tif (toolDisplay === \"blocks\") {\n\t\t\t\t\t\tfor (const part of blockToolCallParts(\n\t\t\t\t\t\t\tevent.id,\n\t\t\t\t\t\t\tevent.name,\n\t\t\t\t\t\t\tevent.input,\n\t\t\t\t\t\t\ttoolState,\n\t\t\t\t\t\t)) {\n\t\t\t\t\t\t\ttoolParts.push(part as LanguageModelV3Content);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\treasoning += `\\n${formatToolCall(event.name, event.input)}\\n`;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"tool-result\":\n\t\t\t\t\tif (toolDisplay === \"blocks\") {\n\t\t\t\t\t\tfor (const part of blockToolResultParts(\n\t\t\t\t\t\t\tevent.id,\n\t\t\t\t\t\t\tevent.name,\n\t\t\t\t\t\t\tevent.result,\n\t\t\t\t\t\t\tevent.isError,\n\t\t\t\t\t\t\ttoolState,\n\t\t\t\t\t\t)) {\n\t\t\t\t\t\t\ttoolParts.push(part as LanguageModelV3Content);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (event.isError) {\n\t\t\t\t\t\treasoning += `[tool] ${event.name} failed\\n`;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"usage\":\n\t\t\t\t\tusage = mapUsage(event.usage);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"finish\":\n\t\t\t\t\tif (!text && event.text) text = event.text;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\tfinishReason = FINISH_ERROR;\n\t}\n\n\t// Close out any tool call whose completion never arrived (see DANGLING_TOOL_RESULT).\n\tfor (const part of blockDanglingParts(toolState)) {\n\t\ttoolParts.push(part as LanguageModelV3Content);\n\t}\n\n\tif (reasoning) content.push({ type: \"reasoning\", text: reasoning });\n\tcontent.push(...toolParts);\n\tif (text) content.push({ type: \"text\", text });\n\n\treturn { content, finishReason, usage };\n}\n"],"mappings":";;;;;;;;AAKA,SAAS,wBAAwB;;;ACGjC,SAAS,uBAAuB;;;ACKzB,SAAS,sBAAsB,QAA+C;AACnF,QAAM,QAAkB,CAAC;AACzB,QAAM,SAAqB,CAAC;AAE5B,SAAO,QAAQ,CAAC,SAAS,UAAU;AACjC,UAAM,SAAS,UAAU,OAAO,SAAS;AACzC,YAAQ,QAAQ,MAAM;AAAA,MACpB,KAAK;AACH,cAAM,KAAK;AAAA,EAAa,QAAQ,OAAO,EAAE;AACzC;AAAA,MACF,KAAK,QAAQ;AACX,cAAM,OAAiB,CAAC;AACxB,mBAAW,QAAQ,QAAQ,SAAS;AAClC,cAAI,KAAK,SAAS,OAAQ,MAAK,KAAK,KAAK,IAAI;AAAA,mBACpC,KAAK,SAAS,UAAU,KAAK,UAAU,WAAW,QAAQ,GAAG;AACpE,kBAAM,QAAQ,YAAY,KAAK,MAAM,KAAK,SAAS;AAGnD,gBAAI,UAAU,MAAO,QAAO,KAAK,KAAK;AACtC,iBAAK,KAAK,kBAAkB;AAAA,UAC9B;AAAA,QACF;AACA,cAAM,KAAK;AAAA,EAAW,KAAK,KAAK,IAAI,CAAC,EAAE;AACvC;AAAA,MACF;AAAA,MACA,KAAK,aAAa;AAChB,cAAM,OAAiB,CAAC;AACxB,mBAAW,QAAQ,QAAQ,SAAS;AAClC,cAAI,KAAK,SAAS,OAAQ,MAAK,KAAK,KAAK,IAAI;AAAA,mBACpC,KAAK,SAAS,YAAa,MAAK,KAAK,cAAc,KAAK,IAAI,EAAE;AAAA,mBAC9D,KAAK,SAAS,YAAa,MAAK,KAAK,WAAW,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;AAAA,mBAC/E,KAAK,SAAS,cAAe,MAAK,KAAK,cAAc,KAAK,QAAQ,GAAG;AAAA,QAChF;AACA,cAAM,KAAK;AAAA,EAAgB,KAAK,KAAK,IAAI,CAAC,EAAE;AAC5C;AAAA,MACF;AAAA,MACA,KAAK,QAAQ;AACX,mBAAW,QAAQ,QAAQ,SAAS;AAClC,cAAI,KAAK,SAAS,eAAe;AAC/B,kBAAM,KAAK,kBAAkB,KAAK,QAAQ;AAAA,EAAM,KAAK,UAAU,KAAK,MAAM,CAAC,EAAE;AAAA,UAC/E;AAAA,QACF;AACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AAED,QAAM,MAAsB,EAAE,MAAM,MAAM,KAAK,MAAM,EAAE;AACvD,MAAI,OAAO,SAAS,EAAG,KAAI,SAAS;AACpC,SAAO;AACT;AAEA,SAAS,YACP,MACA,WACsB;AACtB,MAAI,gBAAgB,IAAK,QAAO,EAAE,KAAK,KAAK,SAAS,EAAE;AACvD,MAAI,OAAO,SAAS,UAAU;AAE5B,QAAI,gBAAgB,KAAK,IAAI,EAAG,QAAO,EAAE,KAAK,KAAK;AACnD,WAAO,EAAE,MAAM,UAAU,UAAU;AAAA,EACrC;AACA,MAAI,gBAAgB,YAAY;AAC9B,WAAO,EAAE,MAAM,OAAO,KAAK,IAAI,EAAE,SAAS,QAAQ,GAAG,UAAU,UAAU;AAAA,EAC3E;AACA,SAAO;AACT;AAQO,SAAS,kBAAkB,QAA2D;AAC3F,QAAM,OAAO,OAAO,OAAO,SAAS,CAAC;AACrC,MAAI,CAAC,QAAQ,KAAK,SAAS,OAAQ,QAAO;AAE1C,QAAM,OAAiB,CAAC;AACxB,QAAM,SAAqB,CAAC;AAC5B,aAAW,QAAQ,KAAK,SAAS;AAC/B,QAAI,KAAK,SAAS,OAAQ,MAAK,KAAK,KAAK,IAAI;AAAA,aACpC,KAAK,SAAS,UAAU,KAAK,UAAU,WAAW,QAAQ,GAAG;AACpE,YAAM,QAAQ,YAAY,KAAK,MAAM,KAAK,SAAS;AACnD,UAAI,MAAO,QAAO,KAAK,KAAK;AAC5B,WAAK,KAAK,kBAAkB;AAAA,IAC9B;AAAA,EACF;AAEA,QAAM,MAAsB,EAAE,MAAM,KAAK,KAAK,IAAI,EAAE;AACpD,MAAI,OAAO,SAAS,EAAG,KAAI,SAAS;AACpC,SAAO;AACT;;;AChFA,IAAM,cAA2C;AAAA,EAChD,SAAS;AAAA,EACT,KAAK;AACN;AACA,IAAM,eAA4C;AAAA,EACjD,SAAS;AAAA,EACT,KAAK;AACN;AAEA,SAAS,eAAe,OAAwB;AAC/C,MAAI;AACH,WAAO,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,SAAS,CAAC,CAAC;AAAA,EACtE,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAOA,SAAS,cAAc,MAAsB;AAC5C,SAAO,UAAU,KAAK,QAAQ,mBAAmB,GAAG,CAAC;AACtD;AAeA,SAAS,YAAY,IAAY,MAAc,OAA+B;AAC7E,SAAO;AAAA,IACN,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU,cAAc,IAAI;AAAA,IAC5B,OAAO,eAAe,KAAK;AAAA,IAC3B,kBAAkB;AAAA,IAClB,SAAS;AAAA,EACV;AACD;AAQA,SAAS,cACR,IACA,MACA,QACA,SACgB;AAChB,SAAO;AAAA,IACN,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU,cAAc,IAAI;AAAA,IAC5B,QAAS,UAAU;AAAA,IACnB;AAAA,IACA,kBAAkB;AAAA,IAClB,SAAS;AAAA,EACV;AACD;AAGA,IAAM,iBAAiB;AAEvB,SAAS,SAAS,GAA0C;AAC3D,SAAO,OAAO,MAAM,YAAY,MAAM;AACvC;AAGA,SAAS,aAAa,OAAwB;AAC7C,SAAO,SAAS,KAAK,KAAK,OAAO,MAAM,MAAM,MAAM,WAChD,MAAM,MAAM,IACZ;AACJ;AAOA,SAAS,eAAe,QAAgC;AACvD,MAAI,CAAC,SAAS,MAAM,KAAK,OAAO,QAAQ,MAAM,UAAW,QAAO;AAChE,QAAM,QAAQ,OAAO,OAAO;AAC5B,MAAI,CAAC,SAAS,KAAK,EAAG,QAAO;AAC7B,QAAM,OAAO,MAAM,YAAY;AAC/B,SAAO,OAAO,SAAS,YAAY,KAAK,SAAS,IAAI,OAAO;AAC7D;AAUA,SAAS,uBAAuB,MAG9B;AACD,QAAM,WAAqB,CAAC;AAC5B,QAAM,WAAqB,CAAC;AAC5B,aAAW,QAAQ,KAAK,MAAM,IAAI,GAAG;AACpC,QACC,KAAK,WAAW,KAAK,KACrB,KAAK,WAAW,KAAK,KACrB,KAAK,WAAW,IAAI,KACpB,KAAK,WAAW,QAAQ,KACxB,KAAK,WAAW,KAAK,GACpB;AACD;AAAA,IACD;AACA,QAAI,KAAK,WAAW,GAAG,EAAG,UAAS,KAAK,KAAK,MAAM,CAAC,CAAC;AAAA,aAC5C,KAAK,WAAW,GAAG,EAAG,UAAS,KAAK,KAAK,MAAM,CAAC,CAAC;AAAA,EAC3D;AACA,SAAO,EAAE,WAAW,SAAS,KAAK,IAAI,GAAG,WAAW,SAAS,KAAK,IAAI,EAAE;AACzE;AASA,SAAS,eACR,IACA,UACA,MACgB;AAChB,QAAM,EAAE,WAAW,UAAU,IAAI,uBAAuB,IAAI;AAC5D,SAAO;AAAA,IACN,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,OAAO,eAAe,EAAE,UAAU,WAAW,UAAU,CAAC;AAAA,IACxD,kBAAkB;AAAA,IAClB,SAAS;AAAA,EACV;AACD;AAOA,SAAS,iBACR,IACA,UACA,MACA,QACgB;AAChB,QAAM,QAAQ,SAAS,MAAM,IAAI,OAAO,OAAO,IAAI;AACnD,QAAM,QACL,SAAS,KAAK,KAAK,OAAO,MAAM,YAAY,MAAM,WAC/C,MAAM,YAAY,IAClB;AACJ,QAAM,UACL,SAAS,KAAK,KAAK,OAAO,MAAM,cAAc,MAAM,WACjD,MAAM,cAAc,IACpB;AACJ,QAAM,SACL,UAAU,UAAa,YAAY,SAChC,MAAM,SAAS,CAAC,KAAK,WAAW,CAAC,MACjC;AACJ,SAAO;AAAA,IACN,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,QAAQ;AAAA,MACP,OAAO;AAAA,MACP,UAAU,EAAE,MAAM,aAAa,CAAC,EAAE;AAAA,MAClC,QAAQ,eAAe,MAAM;AAAA,IAC9B;AAAA,IACA,SAAS;AAAA,IACT,kBAAkB;AAAA,IAClB,SAAS;AAAA,EACV;AACD;AAcA,SAAS,oBAAoC;AAC5C,SAAO,EAAE,eAAe,oBAAI,IAAI,GAAG,cAAc,oBAAI,IAAI,EAAE;AAC5D;AAGA,SAAS,mBACR,IACA,MACA,OACA,OACkB;AAClB,MAAI,SAAS,gBAAgB;AAE5B,UAAM,aAAa,IAAI,IAAI,aAAa,KAAK,CAAC;AAC9C,WAAO,CAAC;AAAA,EACT;AACA,QAAM,cAAc,IAAI,IAAI,IAAI;AAChC,SAAO,CAAC,YAAY,IAAI,MAAM,KAAK,CAAC;AACrC;AAGA,SAAS,qBACR,IACA,MACA,QACA,SACA,OACkB;AAClB,MAAI,MAAM,aAAa,IAAI,EAAE,GAAG;AAC/B,UAAM,WAAW,MAAM,aAAa,IAAI,EAAE;AAC1C,UAAM,aAAa,OAAO,EAAE;AAC5B,UAAM,OAAO,UAAU,OAAO,eAAe,MAAM;AACnD,QAAI,QAAQ,UAAU;AAErB,aAAO;AAAA,QACN,eAAe,IAAI,UAAU,IAAI;AAAA,QACjC,iBAAiB,IAAI,UAAU,MAAM,MAAM;AAAA,MAC5C;AAAA,IACD;AAEA,WAAO;AAAA,MACN,YAAY,IAAI,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAAA,MAClD,cAAc,IAAI,gBAAgB,QAAQ,OAAO;AAAA,IAClD;AAAA,EACD;AACA,QAAM,cAAc,OAAO,EAAE;AAC7B,SAAO,CAAC,cAAc,IAAI,MAAM,QAAQ,OAAO,CAAC;AACjD;AAOA,SAAS,mBAAmB,OAAwC;AACnE,QAAM,QAAyB,CAAC;AAChC,aAAW,CAAC,IAAI,IAAI,KAAK,MAAM,eAAe;AAC7C,UAAM,KAAK,cAAc,IAAI,MAAM,sBAAsB,IAAI,CAAC;AAAA,EAC/D;AACA,QAAM,cAAc,MAAM;AAG1B,aAAW,CAAC,IAAI,QAAQ,KAAK,MAAM,cAAc;AAChD,UAAM,KAAK,YAAY,IAAI,gBAAgB,EAAE,MAAM,SAAS,CAAC,CAAC;AAC9D,UAAM,KAAK,cAAc,IAAI,gBAAgB,sBAAsB,IAAI,CAAC;AAAA,EACzE;AACA,QAAM,aAAa,MAAM;AACzB,SAAO;AACR;AAEO,IAAM,cAAoC;AAAA,EAChD,aAAa;AAAA,IACZ,OAAO;AAAA,IACP,SAAS;AAAA,IACT,WAAW;AAAA,IACX,YAAY;AAAA,EACb;AAAA,EACA,cAAc,EAAE,OAAO,QAAW,MAAM,QAAW,WAAW,OAAU;AACzE;AAEO,SAAS,SAAS,OAA0C;AAClE,SAAO;AAAA,IACN,aAAa;AAAA,MACZ,OAAO,MAAM;AAAA,MACb,SAAS;AAAA,MACT,WAAW,MAAM;AAAA,MACjB,YAAY,MAAM;AAAA,IACnB;AAAA,IACA,cAAc;AAAA,MACb,OAAO,MAAM;AAAA,MACb,MAAM;AAAA,MACN,WAAW;AAAA,IACZ;AAAA,EACD;AACD;AAeA,SAAS,eAAe,MAAc,OAAwB;AAC7D,MAAI,MAAM;AACV,MAAI;AACH,UAAM,IAAI,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,KAAK;AAClE,QAAI,KAAK,MAAM,QAAQ,MAAM;AAC5B,YAAM,IAAI,EAAE,SAAS,MAAM,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,WAAM,CAAC;AAAA,EACtD,QAAQ;AAAA,EAER;AACA,SAAO,UAAU,IAAI,GAAG,GAAG;AAC5B;AASA,IAAM,uBAAuB;AAAA,EAC5B,QAAQ;AAAA,EACR,OAAO;AACR;AAWO,SAAS,qBACf,QACA,cAA2B,UACiB;AAC5C,SAAO,IAAI,eAA0C;AAAA,IACpD,MAAM,MAAM,YAAY;AACvB,iBAAW,QAAQ,EAAE,MAAM,gBAAgB,UAAU,CAAC,EAAE,CAAC;AAEzD,UAAI;AACJ,UAAI,YAAY;AAChB,UAAI;AACJ,UAAI,iBAAiB;AACrB,UAAI;AACJ,UAAI,eAAe;AAEnB,YAAM,YAAY,kBAAkB;AACpC,YAAM,yBAAyB,MAAM;AACpC,mBAAW,QAAQ,mBAAmB,SAAS,GAAG;AACjD,qBAAW,QAAQ,IAAI;AAAA,QACxB;AAAA,MACD;AAEA,YAAM,iBAAiB,MAAM;AAC5B,YAAI,aAAa;AAChB,qBAAW,QAAQ,EAAE,MAAM,iBAAiB,IAAI,YAAY,CAAC;AAC7D,wBAAc;AAAA,QACf;AAAA,MACD;AAIA,YAAM,YAAY,MAAM;AACvB,YAAI,QAAQ;AACX,qBAAW,QAAQ,EAAE,MAAM,YAAY,IAAI,OAAO,CAAC;AACnD,mBAAS;AAAA,QACV;AAAA,MACD;AACA,YAAM,aAAa,MAAM;AACxB,uBAAe;AACf,YAAI,CAAC,QAAQ;AACZ,mBAAS,QAAQ,WAAW;AAC5B,qBAAW,QAAQ,EAAE,MAAM,cAAc,IAAI,OAAO,CAAC;AAAA,QACtD;AACA,eAAO;AAAA,MACR;AACA,YAAM,kBAAkB,MAAM;AAC7B,kBAAU;AACV,YAAI,CAAC,aAAa;AACjB,wBAAc,aAAa,gBAAgB;AAC3C,qBAAW,QAAQ,EAAE,MAAM,mBAAmB,IAAI,YAAY,CAAC;AAAA,QAChE;AACA,eAAO;AAAA,MACR;AACA,YAAM,gBAAgB,CAAC,SAAiB;AACvC,mBAAW,QAAQ;AAAA,UAClB,MAAM;AAAA,UACN,IAAI,gBAAgB;AAAA,UACpB,OAAO;AAAA,QACR,CAAC;AAAA,MACF;AAEA,UAAI;AACH,yBAAiB,SAAS,QAAQ;AACjC,kBAAQ,MAAM,MAAM;AAAA,YACnB,KAAK;AACJ,6BAAe;AACf,yBAAW,QAAQ;AAAA,gBAClB,MAAM;AAAA,gBACN,IAAI,WAAW;AAAA,gBACf,OAAO,MAAM;AAAA,cACd,CAAC;AACD;AAAA,YACD,KAAK;AACJ,4BAAc,MAAM,IAAI;AACxB;AAAA,YACD,KAAK;AACJ,kBAAI,gBAAgB,UAAU;AAC7B,2BAAW,QAAQ;AAAA,kBAClB,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN;AAAA,gBACD,GAAG;AACF,6BAAW,QAAQ,IAAI;AAAA,gBACxB;AAAA,cACD,OAAO;AACN,8BAAc;AAAA,EAAK,eAAe,MAAM,MAAM,MAAM,KAAK,CAAC;AAAA,CAAI;AAAA,cAC/D;AACA;AAAA,YACD,KAAK;AACJ,kBAAI,gBAAgB,UAAU;AAC7B,2BAAW,QAAQ;AAAA,kBAClB,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN,MAAM;AAAA,kBACN;AAAA,gBACD,GAAG;AACF,6BAAW,QAAQ,IAAI;AAAA,gBACxB;AAAA,cACD,WAAW,MAAM,SAAS;AACzB,8BAAc,UAAU,MAAM,IAAI;AAAA,CAAW;AAAA,cAC9C;AACA;AAAA,YACD,KAAK;AACJ,sBAAQ,SAAS,MAAM,KAAK;AAC5B;AAAA,YACD,KAAK;AACJ,kBAAI,CAAC,gBAAgB,MAAM,MAAM;AAChC,2BAAW,QAAQ;AAAA,kBAClB,MAAM;AAAA,kBACN,IAAI,WAAW;AAAA,kBACf,OAAO,MAAM;AAAA,gBACd,CAAC;AAAA,cACF;AACA;AAAA,UACF;AAAA,QACD;AAEA,+BAAuB;AACvB,uBAAe;AACf,kBAAU;AACV,mBAAW,QAAQ;AAAA,UAClB,MAAM;AAAA,UACN,OAAO,SAAS;AAAA,UAChB,cAAc;AAAA,QACf,CAAC;AACD,mBAAW,MAAM;AAAA,MAClB,SAAS,KAAK;AACb,mBAAW,QAAQ,EAAE,MAAM,SAAS,OAAO,IAAI,CAAC;AAChD,+BAAuB;AACvB,uBAAe;AACf,kBAAU;AACV,mBAAW,QAAQ;AAAA,UAClB,MAAM;AAAA,UACN,OAAO,SAAS;AAAA,UAChB,cAAc;AAAA,QACf,CAAC;AACD,mBAAW,MAAM;AAAA,MAClB;AAAA,IACD;AAAA,EACD,CAAC;AACF;AAUA,eAAsB,sBACrB,QACA,cAA2B,UAKzB;AACF,QAAM,UAAyC,CAAC;AAChD,QAAM,YAA2C,CAAC;AAElD,QAAM,YAAY,kBAAkB;AACpC,MAAI,OAAO;AACX,MAAI,YAAY;AAChB,MAAI,QAA8B;AAClC,MAAI,eAA4C;AAEhD,MAAI;AACH,qBAAiB,SAAS,QAAQ;AACjC,cAAQ,MAAM,MAAM;AAAA,QACnB,KAAK;AACJ,kBAAQ,MAAM;AACd;AAAA,QACD,KAAK;AACJ,uBAAa,MAAM;AACnB;AAAA,QACD,KAAK;AACJ,cAAI,gBAAgB,UAAU;AAC7B,uBAAW,QAAQ;AAAA,cAClB,MAAM;AAAA,cACN,MAAM;AAAA,cACN,MAAM;AAAA,cACN;AAAA,YACD,GAAG;AACF,wBAAU,KAAK,IAA8B;AAAA,YAC9C;AAAA,UACD,OAAO;AACN,yBAAa;AAAA,EAAK,eAAe,MAAM,MAAM,MAAM,KAAK,CAAC;AAAA;AAAA,UAC1D;AACA;AAAA,QACD,KAAK;AACJ,cAAI,gBAAgB,UAAU;AAC7B,uBAAW,QAAQ;AAAA,cAClB,MAAM;AAAA,cACN,MAAM;AAAA,cACN,MAAM;AAAA,cACN,MAAM;AAAA,cACN;AAAA,YACD,GAAG;AACF,wBAAU,KAAK,IAA8B;AAAA,YAC9C;AAAA,UACD,WAAW,MAAM,SAAS;AACzB,yBAAa,UAAU,MAAM,IAAI;AAAA;AAAA,UAClC;AACA;AAAA,QACD,KAAK;AACJ,kBAAQ,SAAS,MAAM,KAAK;AAC5B;AAAA,QACD,KAAK;AACJ,cAAI,CAAC,QAAQ,MAAM,KAAM,QAAO,MAAM;AACtC;AAAA,MACF;AAAA,IACD;AAAA,EACD,QAAQ;AACP,mBAAe;AAAA,EAChB;AAGA,aAAW,QAAQ,mBAAmB,SAAS,GAAG;AACjD,cAAU,KAAK,IAA8B;AAAA,EAC9C;AAEA,MAAI,UAAW,SAAQ,KAAK,EAAE,MAAM,aAAa,MAAM,UAAU,CAAC;AAClE,UAAQ,KAAK,GAAG,SAAS;AACzB,MAAI,KAAM,SAAQ,KAAK,EAAE,MAAM,QAAQ,KAAK,CAAC;AAE7C,SAAO,EAAE,SAAS,cAAc,MAAM;AACvC;;;AFxhBO,IAAM,sBAAN,MAAqD;AAAA,EAO3D,YACC,SACiB,QAChB;AADgB;AAEjB,SAAK,UAAU;AACf,SAAK,WAAW,OAAO;AAAA,EACxB;AAAA,EAJkB;AAAA,EART,uBAAuB;AAAA,EACvB;AAAA,EACA;AAAA;AAAA,EAEA,gBAA0C,CAAC;AAAA,EAU5C,gBAAwB;AAC/B,UAAM,SAAS,oBAAoB,KAAK,OAAO,MAAM;AACrD,QAAI,CAAC,QAAQ;AACZ,YAAM,IAAI,gBAAgB;AAAA,QACzB,SACC;AAAA,MACF,CAAC;AAAA,IACF;AACA,WAAO;AAAA,EACR;AAAA,EAEA,OAAe,SACd,SAC8B;AAI9B,UAAM,kBAAkB,QAAQ,kBAAkB,KAAK,QAAQ;AAG/D,UAAM,EAAE,MAAM,eAAe,IAAI;AAAA,MAChC,KAAK;AAAA,MACL,EAAE,MAAM,KAAK,OAAO,MAAM,QAAQ,KAAK,OAAO,OAAO;AAAA,MACrD;AAAA,IACD;AACA,UAAM,YACL,OAAO,kBAAkB,WAAW,MAAM,WACtC,gBAAgB,WAAW,IAC5B;AACJ,UAAM,aAAa,KAAK,OAAO,YAAY,QAAQ,QAAQ,SAAS;AAGpE,UAAM,kBACL,OAAO,kBAAkB,SAAS,MAAM,WACpC,gBAAgB,SAAS,IAC1B;AAEJ,UAAM,WAAW,MAAM,aAAa;AAAA,MACnC,QAAQ,KAAK,cAAc;AAAA,MAC3B;AAAA,MACA;AAAA,MACA,KAAK,KAAK,OAAO;AAAA,MACjB,GAAI,KAAK,OAAO,iBACb,EAAE,gBAAgB,KAAK,OAAO,eAAe,IAC7C,CAAC;AAAA,MACJ,GAAI,KAAK,OAAO,YAAY,SACzB,EAAE,SAAS,KAAK,OAAO,QAAQ,IAC/B,CAAC;AAAA,MACJ,GAAI,KAAK,OAAO,aAAa,EAAE,YAAY,KAAK,OAAO,WAAW,IAAI,CAAC;AAAA,MACvE,GAAI,KAAK,OAAO,SAAS,EAAE,QAAQ,KAAK,OAAO,OAAO,IAAI,CAAC;AAAA,MAC3D,GAAI,aAAa,EAAE,MAAM,YAAY,UAAW,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC;AAAA,MACjE,GAAI,kBAAkB,EAAE,SAAS,gBAAgB,IAAI,CAAC;AAAA,MACtD;AAAA,MACA,SAAS;AAAA,IACV,CAAC;AAID,UAAM,UAAU,SAAS,UACrB,kBAAkB,QAAQ,MAAM,KAClC,sBAAsB,QAAQ,MAAM,IACnC,sBAAsB,QAAQ,MAAM;AAEvC,QAAI;AACH,aAAO,gBAAgB,SAAS,OAAO,SAAS;AAAA,QAC/C;AAAA,QACA,aAAa,QAAQ;AAAA,MACtB,CAAC;AAAA,IACF,UAAE;AACD,eAAS,QAAQ;AAAA,IAClB;AAAA,EACD;AAAA,EAEA,MAAM,SAAS,SAEZ;AACF,WAAO;AAAA,MACN,QAAQ;AAAA,QACP,KAAK,SAAS,OAAO;AAAA,QACrB,KAAK,OAAO;AAAA,MACb;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM,WAAW,SAKd;AACF,UAAM,SAAS,MAAM;AAAA,MACpB,KAAK,SAAS,OAAO;AAAA,MACrB,KAAK,OAAO;AAAA,IACb;AACA,WAAO,EAAE,GAAG,QAAQ,UAAU,CAAC,EAAE;AAAA,EAClC;AACD;;;ADpGO,SAAS,aAAa,UAAiC,CAAC,GAAe;AAC7E,QAAM,aACL,QAAQ,cAAc,OAAO,KAAK,QAAQ,UAAU,EAAE,SAAS,IAC5D,QAAQ,aACR;AACJ,QAAM,SAA4B;AAAA,IACjC,cAAc,QAAQ,QAAQ;AAAA,IAC9B,QAAQ,oBAAoB,QAAQ,MAAM;AAAA,IAC1C,KAAK,QAAQ,OAAO,QAAQ,IAAI;AAAA,IAChC,MAAM,QAAQ,QAAQ;AAAA,IACtB,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,IACnD,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,IACnC,GAAI,QAAQ,iBACT,EAAE,gBAAgB,QAAQ,eAAe,IACzC,CAAC;AAAA,IACJ,GAAI,QAAQ,YAAY,SAAY,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;AAAA,IACpE,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,IACnD,GAAI,QAAQ,YAAY,SAAY,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;AAAA,IACpE,aAAa,QAAQ,eAAe;AAAA,EACrC;AAEA,QAAM,iBAAiB,CAAC,MAAc,YAA2B;AAChE,UAAM,IAAI,iBAAiB;AAAA,MAC1B;AAAA,MACA,WAAW;AAAA,MACX,SAAS,wCAAwC,IAAI;AAAA,IACtD,CAAC;AAAA,EACF;AAEA,SAAO;AAAA,IACN,sBAAsB;AAAA,IACtB,eAAe,CAAC,YACf,IAAI,oBAAoB,SAAS,MAAM;AAAA,IACxC,gBAAgB,CAAC,YAChB,eAAe,kBAAkB,OAAO;AAAA,IACzC,YAAY,CAAC,YACZ,eAAe,cAAc,OAAO;AAAA,EACtC;AACD;","names":[]}
|