@stablekernel/opencode-cursor 0.1.0 → 0.2.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 +20 -0
- package/README.md +14 -0
- package/dist/provider/index.js +367 -12
- package/dist/provider/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.2.0] — 2026-06-11
|
|
8
|
+
|
|
9
|
+
- **More Cursor tools map onto opencode's native tool renderers (blocks mode).**
|
|
10
|
+
Following the `edit` → diff-viewer mapping, Cursor's `shell`, `read`, `write`,
|
|
11
|
+
`glob`, `grep`, `ls`, `updateTodos`, and `task` tool activity is now surfaced
|
|
12
|
+
under opencode's registered `bash`, `read`, `write`, `glob`, `grep`, `list`,
|
|
13
|
+
`todowrite`, and `task` tools, and Cursor's web search (which runs as an MCP
|
|
14
|
+
tool) maps onto opencode's `websearch` renderer — so opencode renders its
|
|
15
|
+
native UI (shell console, file viewer, todo checklist, subagent card, search
|
|
16
|
+
results, …) instead of generic `cursor_*` blocks. Cursor's arg shape is
|
|
17
|
+
translated to opencode's (e.g. `path` → `filePath`, `globPattern` → `pattern`,
|
|
18
|
+
`fileText` → `content`); calls stay provider-executed (display-only, never
|
|
19
|
+
re-run on disk).
|
|
20
|
+
- **Cleaner fallback blocks for tools without an opencode counterpart.**
|
|
21
|
+
`readLints` and `delete` now render as formatted `cursor_*` blocks (a
|
|
22
|
+
diagnostics list / a one-line confirmation) instead of raw JSON, and every MCP
|
|
23
|
+
tool's `content` array is flattened to readable text. Anything else — or a
|
|
24
|
+
result with an unexpected shape — still falls back to a safe `cursor_*` block
|
|
25
|
+
with the raw payload.
|
|
26
|
+
|
|
7
27
|
## [0.1.0] — 2026-06-10
|
|
8
28
|
|
|
9
29
|
> Pre-releases: `0.1.0-rc.1` and `0.1.0-rc.2` were published to the npm `next`
|
package/README.md
CHANGED
|
@@ -336,6 +336,20 @@ that activity appears in opencode:
|
|
|
336
336
|
and outputs. opencode skips execution for provider-executed calls (they're display-only), so
|
|
337
337
|
Cursor's tools (`shell`, `mcp`, …) don't trigger an "unavailable tool" error. Requires a
|
|
338
338
|
V3-native opencode host (1.16+).
|
|
339
|
+
|
|
340
|
+
Where a Cursor tool has a natural opencode counterpart, it's surfaced under opencode's
|
|
341
|
+
**registered** tool name so its native renderer is used instead of a generic block: `edit` →
|
|
342
|
+
opencode's diff viewer (via `metadata.diff`), `shell` → `bash` console, `task` → the subagent
|
|
343
|
+
card, web search (which Cursor runs as an MCP tool) → the `websearch` renderer, and
|
|
344
|
+
`read`/`write`/`glob`/`grep`/`ls`/`updateTodos` → opencode's
|
|
345
|
+
`read`/`write`/`glob`/`grep`/`list`/`todowrite` renderers. Cursor's arg shape is translated to
|
|
346
|
+
opencode's (e.g. `path` → `filePath`); the call stays provider-executed, so it's display-only and
|
|
347
|
+
never re-run on disk.
|
|
348
|
+
|
|
349
|
+
Tools with no opencode counterpart still get cleaned up: `readLints` and `delete` render as
|
|
350
|
+
formatted `cursor_*` blocks (a diagnostics list / a one-line confirmation) rather than raw JSON,
|
|
351
|
+
and any MCP tool's `content` is flattened to readable text. Anything else — or a result with an
|
|
352
|
+
unexpected shape — falls back to a prefixed `cursor_*` block with the raw payload.
|
|
339
353
|
- **`"reasoning"` (fallback)** — each tool call is shown as a compact reasoning line
|
|
340
354
|
(`[tool] write {"path":…}`; failures as `[tool] x failed`). Robust on every host: no tool-call
|
|
341
355
|
parts cross into opencode, so there's no dependency on how the host treats provider-executed
|
package/dist/provider/index.js
CHANGED
|
@@ -111,31 +111,366 @@ function safeJsonString(input) {
|
|
|
111
111
|
function blockToolName(name) {
|
|
112
112
|
return `cursor_${name.replace(/[^A-Za-z0-9_-]/g, "_")}`;
|
|
113
113
|
}
|
|
114
|
-
function
|
|
114
|
+
function nativeToolCall(id, toolName, input) {
|
|
115
115
|
return {
|
|
116
116
|
type: "tool-call",
|
|
117
117
|
toolCallId: id,
|
|
118
|
-
toolName
|
|
118
|
+
toolName,
|
|
119
119
|
input: safeJsonString(input),
|
|
120
120
|
providerExecuted: true,
|
|
121
121
|
dynamic: true
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
|
-
function
|
|
124
|
+
function nativeToolResult(id, toolName, result, isError) {
|
|
125
125
|
return {
|
|
126
126
|
type: "tool-result",
|
|
127
127
|
toolCallId: id,
|
|
128
|
-
toolName
|
|
128
|
+
toolName,
|
|
129
129
|
result: result ?? null,
|
|
130
130
|
isError,
|
|
131
131
|
providerExecuted: true,
|
|
132
132
|
dynamic: true
|
|
133
133
|
};
|
|
134
134
|
}
|
|
135
|
+
function toolCallObj(id, name, input) {
|
|
136
|
+
return nativeToolCall(id, blockToolName(name), input);
|
|
137
|
+
}
|
|
138
|
+
function toolResultObj(id, name, result, isError) {
|
|
139
|
+
return nativeToolResult(id, blockToolName(name), result, isError);
|
|
140
|
+
}
|
|
135
141
|
var EDIT_TOOL_NAME = "edit";
|
|
136
142
|
function isRecord(v) {
|
|
137
143
|
return typeof v === "object" && v !== null;
|
|
138
144
|
}
|
|
145
|
+
function strField(v, key) {
|
|
146
|
+
return isRecord(v) && typeof v[key] === "string" ? v[key] : void 0;
|
|
147
|
+
}
|
|
148
|
+
function numField(v, key) {
|
|
149
|
+
return isRecord(v) && typeof v[key] === "number" ? v[key] : void 0;
|
|
150
|
+
}
|
|
151
|
+
function successValue(result) {
|
|
152
|
+
return isRecord(result) && result["status"] === "success" ? result["value"] : void 0;
|
|
153
|
+
}
|
|
154
|
+
function flattenMcpContent(value) {
|
|
155
|
+
if (!isRecord(value) || !Array.isArray(value["content"])) return null;
|
|
156
|
+
const parts = value["content"].flatMap((item) => {
|
|
157
|
+
const text = isRecord(item) ? strField(item["text"], "text") : void 0;
|
|
158
|
+
if (text !== void 0) return [text];
|
|
159
|
+
if (isRecord(item) && isRecord(item["image"])) return ["[image]"];
|
|
160
|
+
return [];
|
|
161
|
+
});
|
|
162
|
+
return parts.join("\n");
|
|
163
|
+
}
|
|
164
|
+
function mcpFold(result) {
|
|
165
|
+
const text = flattenMcpContent(successValue(result));
|
|
166
|
+
if (text === null) return null;
|
|
167
|
+
return { title: "", metadata: {}, output: text };
|
|
168
|
+
}
|
|
169
|
+
function mcpInputArgs(args) {
|
|
170
|
+
return isRecord(args) ? args["args"] : void 0;
|
|
171
|
+
}
|
|
172
|
+
function webSearchProvider(args) {
|
|
173
|
+
const id = (strField(args, "providerIdentifier") ?? "").toLowerCase();
|
|
174
|
+
if (id.includes("exa")) return "exa";
|
|
175
|
+
if (id.includes("parallel")) return "parallel";
|
|
176
|
+
return void 0;
|
|
177
|
+
}
|
|
178
|
+
function isWebSearchName(name) {
|
|
179
|
+
return /web[_-]?search/i.test(name);
|
|
180
|
+
}
|
|
181
|
+
var WEBSEARCH_ADAPTER = {
|
|
182
|
+
tool: "websearch",
|
|
183
|
+
input: (args) => {
|
|
184
|
+
const query = strField(mcpInputArgs(args), "query");
|
|
185
|
+
return query !== void 0 ? { query } : {};
|
|
186
|
+
},
|
|
187
|
+
result: (value, args) => {
|
|
188
|
+
const provider = webSearchProvider(args);
|
|
189
|
+
return {
|
|
190
|
+
title: "",
|
|
191
|
+
metadata: provider ? { provider } : {},
|
|
192
|
+
output: flattenMcpContent(value) ?? ""
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
function resolveAdapter(name, _input) {
|
|
197
|
+
const exact = NATIVE_ADAPTERS[name];
|
|
198
|
+
if (exact) return exact;
|
|
199
|
+
if (isWebSearchName(name)) return WEBSEARCH_ADAPTER;
|
|
200
|
+
return void 0;
|
|
201
|
+
}
|
|
202
|
+
function mapTodoStatus(status) {
|
|
203
|
+
if (status === "inProgress") return "in_progress";
|
|
204
|
+
return typeof status === "string" ? status : "pending";
|
|
205
|
+
}
|
|
206
|
+
function mapTodos(args) {
|
|
207
|
+
const todos = isRecord(args) && Array.isArray(args["todos"]) ? args["todos"] : [];
|
|
208
|
+
return todos.flatMap(
|
|
209
|
+
(t) => isRecord(t) && typeof t["content"] === "string" ? [
|
|
210
|
+
{
|
|
211
|
+
content: t["content"],
|
|
212
|
+
status: mapTodoStatus(t["status"])
|
|
213
|
+
}
|
|
214
|
+
] : []
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
var NATIVE_ADAPTERS = {
|
|
218
|
+
// Cursor `shell` → opencode `bash` (console renderer).
|
|
219
|
+
shell: {
|
|
220
|
+
tool: "bash",
|
|
221
|
+
input: (args) => ({ command: strField(args, "command") ?? "" }),
|
|
222
|
+
result: (value, args) => {
|
|
223
|
+
if (!isRecord(value)) return null;
|
|
224
|
+
const command = strField(args, "command") ?? "";
|
|
225
|
+
const stdout = strField(value, "stdout") ?? "";
|
|
226
|
+
const stderr = strField(value, "stderr") ?? "";
|
|
227
|
+
const exit = numField(value, "exitCode");
|
|
228
|
+
const body = [stdout, stderr].filter((s) => s.length > 0).join("\n");
|
|
229
|
+
const output = exit !== void 0 && exit !== 0 ? `${body}${body ? "\n" : ""}(exit ${exit})` : body;
|
|
230
|
+
return {
|
|
231
|
+
title: command,
|
|
232
|
+
metadata: { command, output, exit: exit ?? 0 },
|
|
233
|
+
output
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
// Cursor `read` → opencode `read`.
|
|
238
|
+
read: {
|
|
239
|
+
tool: "read",
|
|
240
|
+
input: (args) => ({ filePath: strField(args, "path") ?? "" }),
|
|
241
|
+
result: (value, args) => {
|
|
242
|
+
const content = strField(value, "content");
|
|
243
|
+
if (content === void 0) return null;
|
|
244
|
+
const filePath = strField(args, "path") ?? "";
|
|
245
|
+
const totalLines = numField(value, "totalLines");
|
|
246
|
+
return {
|
|
247
|
+
title: filePath,
|
|
248
|
+
metadata: {
|
|
249
|
+
preview: content.split("\n").slice(0, 20).join("\n"),
|
|
250
|
+
loaded: [],
|
|
251
|
+
...totalLines !== void 0 ? { totalLines } : {}
|
|
252
|
+
},
|
|
253
|
+
output: content
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
// Cursor `write` → opencode `write` (renders input.content as the new file).
|
|
258
|
+
write: {
|
|
259
|
+
tool: "write",
|
|
260
|
+
input: (args) => ({
|
|
261
|
+
filePath: strField(args, "path") ?? "",
|
|
262
|
+
content: strField(args, "fileText") ?? ""
|
|
263
|
+
}),
|
|
264
|
+
result: (value, args) => {
|
|
265
|
+
const filePath = strField(args, "path") ?? "";
|
|
266
|
+
const lines = numField(value, "linesCreated");
|
|
267
|
+
const output = lines !== void 0 ? `Wrote ${lines} line${lines === 1 ? "" : "s"}.` : "Wrote file successfully.";
|
|
268
|
+
return {
|
|
269
|
+
title: filePath,
|
|
270
|
+
metadata: { diagnostics: {}, filepath: filePath, exists: false },
|
|
271
|
+
output
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
// Cursor `glob` → opencode `glob`.
|
|
276
|
+
glob: {
|
|
277
|
+
tool: "glob",
|
|
278
|
+
input: (args) => {
|
|
279
|
+
const pattern = strField(args, "globPattern") ?? "";
|
|
280
|
+
const dir = strField(args, "targetDirectory");
|
|
281
|
+
return dir ? { pattern, path: dir } : { pattern };
|
|
282
|
+
},
|
|
283
|
+
result: (value) => {
|
|
284
|
+
if (!isRecord(value) || !Array.isArray(value["files"])) return null;
|
|
285
|
+
const files = value["files"].filter(
|
|
286
|
+
(f) => typeof f === "string"
|
|
287
|
+
);
|
|
288
|
+
const truncated = value["clientTruncated"] === true || value["ripgrepTruncated"] === true;
|
|
289
|
+
return {
|
|
290
|
+
title: "",
|
|
291
|
+
metadata: { count: files.length, truncated },
|
|
292
|
+
output: files.length > 0 ? files.join("\n") : "No files found"
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
// Cursor `grep` → opencode `grep` (flatten matches into ripgrep-style text).
|
|
297
|
+
grep: {
|
|
298
|
+
tool: "grep",
|
|
299
|
+
input: (args) => {
|
|
300
|
+
const out = {
|
|
301
|
+
pattern: strField(args, "pattern") ?? ""
|
|
302
|
+
};
|
|
303
|
+
const p = strField(args, "path");
|
|
304
|
+
if (p) out["path"] = p;
|
|
305
|
+
const g = strField(args, "glob");
|
|
306
|
+
if (g) out["include"] = g;
|
|
307
|
+
return out;
|
|
308
|
+
},
|
|
309
|
+
result: (value) => {
|
|
310
|
+
if (!isRecord(value)) return null;
|
|
311
|
+
const unions = [];
|
|
312
|
+
const ws = value["workspaceResults"];
|
|
313
|
+
if (isRecord(ws)) unions.push(...Object.values(ws));
|
|
314
|
+
if (value["activeEditorResult"] !== void 0)
|
|
315
|
+
unions.push(value["activeEditorResult"]);
|
|
316
|
+
const lines = [];
|
|
317
|
+
let total = 0;
|
|
318
|
+
let current = "";
|
|
319
|
+
for (const u of unions) {
|
|
320
|
+
if (!isRecord(u)) continue;
|
|
321
|
+
const output = u["output"];
|
|
322
|
+
if (u["type"] === "content" && isRecord(output) && Array.isArray(output["matches"])) {
|
|
323
|
+
for (const m of output["matches"]) {
|
|
324
|
+
if (!isRecord(m)) continue;
|
|
325
|
+
const file = strField(m, "file") ?? "";
|
|
326
|
+
const line = numField(m, "lineNumber");
|
|
327
|
+
const text = strField(m, "line") ?? "";
|
|
328
|
+
if (current !== file) {
|
|
329
|
+
if (current) lines.push("");
|
|
330
|
+
current = file;
|
|
331
|
+
lines.push(`${file}:`);
|
|
332
|
+
}
|
|
333
|
+
lines.push(
|
|
334
|
+
line !== void 0 ? ` Line ${line}: ${text}` : ` ${text}`
|
|
335
|
+
);
|
|
336
|
+
total++;
|
|
337
|
+
}
|
|
338
|
+
} else if (u["type"] === "files" && isRecord(output) && Array.isArray(output["files"])) {
|
|
339
|
+
for (const f of output["files"]) {
|
|
340
|
+
if (typeof f === "string") {
|
|
341
|
+
lines.push(f);
|
|
342
|
+
total++;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return {
|
|
348
|
+
title: "",
|
|
349
|
+
metadata: { matches: total, truncated: false },
|
|
350
|
+
output: total > 0 ? [
|
|
351
|
+
`Found ${total} match${total === 1 ? "" : "es"}`,
|
|
352
|
+
"",
|
|
353
|
+
...lines
|
|
354
|
+
].join("\n") : "No matches found"
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
// Cursor `ls` → opencode `list` (flatten the directory tree into paths).
|
|
359
|
+
ls: {
|
|
360
|
+
tool: "list",
|
|
361
|
+
input: (args) => ({ path: strField(args, "path") ?? "" }),
|
|
362
|
+
result: (value) => {
|
|
363
|
+
if (!isRecord(value)) return null;
|
|
364
|
+
const root = value["directoryTreeRoot"];
|
|
365
|
+
if (!isRecord(root)) return null;
|
|
366
|
+
const out = [];
|
|
367
|
+
const walk = (node) => {
|
|
368
|
+
const base = strField(node, "absPath") ?? "";
|
|
369
|
+
const files = Array.isArray(node["childrenFiles"]) ? node["childrenFiles"] : [];
|
|
370
|
+
for (const f of files) {
|
|
371
|
+
const name = strField(f, "name");
|
|
372
|
+
if (name) out.push(`${base}/${name}`);
|
|
373
|
+
}
|
|
374
|
+
const dirs = Array.isArray(node["childrenDirs"]) ? node["childrenDirs"] : [];
|
|
375
|
+
for (const d of dirs) {
|
|
376
|
+
if (!isRecord(d)) continue;
|
|
377
|
+
out.push(`${strField(d, "absPath") ?? ""}/`);
|
|
378
|
+
walk(d);
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
walk(root);
|
|
382
|
+
return {
|
|
383
|
+
title: strField(root, "absPath") ?? "",
|
|
384
|
+
metadata: {},
|
|
385
|
+
output: out.length > 0 ? out.join("\n") : "(empty)"
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
|
+
// Cursor `updateTodos` → opencode `todowrite` (todo checklist renderer).
|
|
390
|
+
updateTodos: {
|
|
391
|
+
tool: "todowrite",
|
|
392
|
+
input: (args) => ({ todos: mapTodos(args) }),
|
|
393
|
+
result: (_value, args) => {
|
|
394
|
+
const todos = mapTodos(args);
|
|
395
|
+
const done = todos.filter((t) => t.status === "completed").length;
|
|
396
|
+
return {
|
|
397
|
+
title: `${done}/${todos.length}`,
|
|
398
|
+
metadata: { todos },
|
|
399
|
+
output: `Updated ${todos.length} todo${todos.length === 1 ? "" : "s"}.`
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
// Cursor `task` (subagent) → opencode `task` (agent card: name + description).
|
|
404
|
+
// Non-clickable here — the subagent ran inside Cursor, not as an opencode
|
|
405
|
+
// child session — but the native card reads far better than raw JSON.
|
|
406
|
+
task: {
|
|
407
|
+
tool: "task",
|
|
408
|
+
input: (args) => {
|
|
409
|
+
const description = strField(args, "description") ?? "";
|
|
410
|
+
const sub = isRecord(args) ? args["subagentType"] : void 0;
|
|
411
|
+
const subagent = strField(sub, "name") ?? strField(sub, "kind") ?? void 0;
|
|
412
|
+
return subagent ? { description, subagent_type: subagent } : { description };
|
|
413
|
+
},
|
|
414
|
+
result: (value, args) => {
|
|
415
|
+
const description = strField(args, "description") ?? "";
|
|
416
|
+
const suffix = strField(value, "resultSuffix");
|
|
417
|
+
const background = isRecord(value) && value["isBackground"] === true;
|
|
418
|
+
return {
|
|
419
|
+
title: description,
|
|
420
|
+
metadata: background ? { background: true } : {},
|
|
421
|
+
output: suffix ?? "Subagent task completed."
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
// Cursor `readLints` has no opencode counterpart — format-only: render the
|
|
426
|
+
// diagnostics as a readable list instead of dumping the nested JSON.
|
|
427
|
+
readLints: {
|
|
428
|
+
input: (args) => {
|
|
429
|
+
const paths = isRecord(args) && Array.isArray(args["paths"]) ? args["paths"] : [];
|
|
430
|
+
return { paths };
|
|
431
|
+
},
|
|
432
|
+
result: (value) => {
|
|
433
|
+
const files = isRecord(value) && Array.isArray(value["fileDiagnostics"]) ? value["fileDiagnostics"] : [];
|
|
434
|
+
const lines = [];
|
|
435
|
+
let total = 0;
|
|
436
|
+
for (const file of files) {
|
|
437
|
+
if (!isRecord(file)) continue;
|
|
438
|
+
const diags = Array.isArray(file["diagnostics"]) ? file["diagnostics"] : [];
|
|
439
|
+
if (diags.length === 0) continue;
|
|
440
|
+
lines.push(`${strField(file, "path") ?? ""}`);
|
|
441
|
+
for (const d of diags) {
|
|
442
|
+
if (!isRecord(d)) continue;
|
|
443
|
+
const severity = strField(d, "severity") ?? "info";
|
|
444
|
+
const start = isRecord(d["range"]) ? d["range"]["start"] : void 0;
|
|
445
|
+
const line = numField(start, "line");
|
|
446
|
+
const char = numField(start, "character");
|
|
447
|
+
const loc = line !== void 0 ? ` L${line + 1}${char !== void 0 ? `:${char + 1}` : ""}` : "";
|
|
448
|
+
lines.push(` ${severity}${loc}: ${strField(d, "message") ?? ""}`);
|
|
449
|
+
total++;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return {
|
|
453
|
+
title: total > 0 ? `${total} problem${total === 1 ? "" : "s"}` : "No problems",
|
|
454
|
+
metadata: { count: total },
|
|
455
|
+
output: total > 0 ? lines.join("\n") : "No problems found."
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
// Cursor `delete` has no opencode counterpart — format-only: a one-line
|
|
460
|
+
// confirmation instead of `{"fileSize":N}`.
|
|
461
|
+
delete: {
|
|
462
|
+
input: (args) => ({ path: strField(args, "path") ?? "" }),
|
|
463
|
+
result: (value, args) => {
|
|
464
|
+
const path = strField(args, "path") ?? "";
|
|
465
|
+
const size = numField(value, "fileSize");
|
|
466
|
+
return {
|
|
467
|
+
title: path,
|
|
468
|
+
metadata: {},
|
|
469
|
+
output: size !== void 0 ? `Deleted ${path} (${size} bytes).` : `Deleted ${path}.`
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
};
|
|
139
474
|
function editFilePath(input) {
|
|
140
475
|
return isRecord(input) && typeof input["path"] === "string" ? input["path"] : "";
|
|
141
476
|
}
|
|
@@ -189,15 +524,22 @@ function editResultFields(id, filePath, diff, result) {
|
|
|
189
524
|
};
|
|
190
525
|
}
|
|
191
526
|
function newBlockToolState() {
|
|
192
|
-
return {
|
|
527
|
+
return { open: /* @__PURE__ */ new Map(), pendingEdits: /* @__PURE__ */ new Map() };
|
|
193
528
|
}
|
|
194
529
|
function blockToolCallParts(id, name, input, state) {
|
|
195
530
|
if (name === EDIT_TOOL_NAME) {
|
|
196
531
|
state.pendingEdits.set(id, editFilePath(input));
|
|
197
532
|
return [];
|
|
198
533
|
}
|
|
199
|
-
|
|
200
|
-
|
|
534
|
+
const adapter = resolveAdapter(name, input);
|
|
535
|
+
if (adapter) {
|
|
536
|
+
const toolName2 = adapter.tool ?? blockToolName(name);
|
|
537
|
+
state.open.set(id, { toolName: toolName2, adapter, args: input });
|
|
538
|
+
return [nativeToolCall(id, toolName2, adapter.input(input))];
|
|
539
|
+
}
|
|
540
|
+
const toolName = blockToolName(name);
|
|
541
|
+
state.open.set(id, { toolName, args: input });
|
|
542
|
+
return [nativeToolCall(id, toolName, input)];
|
|
201
543
|
}
|
|
202
544
|
function blockToolResultParts(id, name, result, isError, state) {
|
|
203
545
|
if (state.pendingEdits.has(id)) {
|
|
@@ -215,15 +557,28 @@ function blockToolResultParts(id, name, result, isError, state) {
|
|
|
215
557
|
toolResultObj(id, EDIT_TOOL_NAME, result, isError)
|
|
216
558
|
];
|
|
217
559
|
}
|
|
218
|
-
state.
|
|
219
|
-
|
|
560
|
+
const open = state.open.get(id);
|
|
561
|
+
state.open.delete(id);
|
|
562
|
+
const toolName = open?.toolName ?? blockToolName(name);
|
|
563
|
+
if (open?.adapter && !isError) {
|
|
564
|
+
const value = successValue(result);
|
|
565
|
+
if (value !== void 0) {
|
|
566
|
+
const folded = open.adapter.result(value, open.args);
|
|
567
|
+
if (folded) return [nativeToolResult(id, toolName, folded, false)];
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
if (!isError) {
|
|
571
|
+
const folded = mcpFold(result);
|
|
572
|
+
if (folded) return [nativeToolResult(id, toolName, folded, false)];
|
|
573
|
+
}
|
|
574
|
+
return [nativeToolResult(id, toolName, result, isError)];
|
|
220
575
|
}
|
|
221
576
|
function blockDanglingParts(state) {
|
|
222
577
|
const parts = [];
|
|
223
|
-
for (const [id,
|
|
224
|
-
parts.push(
|
|
578
|
+
for (const [id, open] of state.open) {
|
|
579
|
+
parts.push(nativeToolResult(id, open.toolName, DANGLING_TOOL_RESULT, true));
|
|
225
580
|
}
|
|
226
|
-
state.
|
|
581
|
+
state.open.clear();
|
|
227
582
|
for (const [id, filePath] of state.pendingEdits) {
|
|
228
583
|
parts.push(toolCallObj(id, EDIT_TOOL_NAME, { path: filePath }));
|
|
229
584
|
parts.push(toolResultObj(id, EDIT_TOOL_NAME, DANGLING_TOOL_RESULT, true));
|
|
@@ -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 {\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":"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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` under an EXACT (already-final)\n * tool name. `input` is a stringified JSON object per the V3 spec. Both\n * `providerExecuted` and `dynamic` are set so ai's `parseToolCall` accepts the\n * part without registered-tool validation, and a host that hasn't registered\n * the named tool degrades to a generic dynamic block instead of erroring.\n */\nfunction nativeToolCall(\n\tid: string,\n\ttoolName: string,\n\tinput: unknown,\n): BlockToolPart {\n\treturn {\n\t\ttype: \"tool-call\",\n\t\ttoolCallId: id,\n\t\ttoolName,\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` under an EXACT tool name. Per\n * the V3 spec (and ai v6's `runToolsTransformation`, which reads\n * `chunk.result` / `chunk.isError`) the payload goes in `result`; `result` is\n * typed `NonNullable<JSONValue>` so a missing payload is coalesced to `null`.\n */\nfunction nativeToolResult(\n\tid: string,\n\ttoolName: string,\n\tresult: unknown,\n\tisError: boolean,\n): BlockToolPart {\n\treturn {\n\t\ttype: \"tool-result\",\n\t\ttoolCallId: id,\n\t\ttoolName,\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/**\n * Build a generic `tool-call` for a Cursor tool with no native opencode\n * counterpart. The name is `cursor_`-prefixed so it can't collide with a tool\n * opencode has registered.\n */\nfunction toolCallObj(id: string, name: string, input: unknown): BlockToolPart {\n\treturn nativeToolCall(id, blockToolName(name), input);\n}\n\n/** Build a generic (`cursor_`-prefixed) `tool-result`. */\nfunction toolResultObj(\n\tid: string,\n\tname: string,\n\tresult: unknown,\n\tisError: boolean,\n): BlockToolPart {\n\treturn nativeToolResult(id, blockToolName(name), result, isError);\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\nfunction strField(v: unknown, key: string): string | undefined {\n\treturn isRecord(v) && typeof v[key] === \"string\"\n\t\t? (v[key] as string)\n\t\t: undefined;\n}\n\nfunction numField(v: unknown, key: string): number | undefined {\n\treturn isRecord(v) && typeof v[key] === \"number\"\n\t\t? (v[key] as number)\n\t\t: undefined;\n}\n\n/** Unwrap a Cursor `{ status:\"success\", value }` result to its `value`. */\nfunction successValue(result: unknown): unknown {\n\treturn isRecord(result) && result[\"status\"] === \"success\"\n\t\t? result[\"value\"]\n\t\t: undefined;\n}\n\n/** The `{title, metadata, output}` shape opencode folds into a tool part's state. */\ninterface FoldedResult {\n\ttitle: string;\n\tmetadata: Record<string, unknown>;\n\toutput: string;\n}\n\n/**\n * Maps a Cursor tool's call/result onto an opencode tool so opencode renders\n * something nicer than a raw-JSON block. Mirrors the `edit` mapping: parts are\n * emitted `providerExecuted` + `dynamic`, so the call is never executed on disk\n * and a host that hasn't registered the tool degrades to a generic dynamic\n * block.\n *\n * - `tool` is opencode's REGISTERED tool name when there's a native renderer to\n * reuse (`bash`, `read`, `websearch`, …). Omit it for \"format-only\" adapters\n * (`readLints`, `delete`): the part stays a `cursor_*` block, but `result`\n * still folds the payload into a clean `output` string so opencode's generic\n * renderer shows formatted text instead of dumped JSON.\n * - `input` translates Cursor's arg keys to the names opencode's renderer reads\n * (e.g. Cursor `path` → opencode `filePath`).\n * - `result` folds a SUCCESSFUL Cursor result `value` into `{title, metadata,\n * output}`; returning `null` falls back to a generic block (unexpected shape).\n */\ninterface NativeToolAdapter {\n\ttool?: string;\n\tinput(args: unknown): Record<string, unknown>;\n\tresult(value: unknown, args: unknown): FoldedResult | null;\n}\n\n/**\n * Flatten a Cursor MCP result `value` (`{ content: [{ text: { text } }, …] }`)\n * into plain text. Returns `null` when `value` isn't MCP-shaped, so callers can\n * fall back to the raw payload. An MCP `content` array that holds no text\n * (e.g. only images) yields a `\"[image]\"`-style placeholder rather than `null`.\n */\nfunction flattenMcpContent(value: unknown): string | null {\n\tif (!isRecord(value) || !Array.isArray(value[\"content\"])) return null;\n\tconst parts = (value[\"content\"] as unknown[]).flatMap((item) => {\n\t\tconst text = isRecord(item) ? strField(item[\"text\"], \"text\") : undefined;\n\t\tif (text !== undefined) return [text];\n\t\tif (isRecord(item) && isRecord(item[\"image\"])) return [\"[image]\"];\n\t\treturn [];\n\t});\n\treturn parts.join(\"\\n\");\n}\n\n/**\n * Fold a generic (non-adapter) Cursor result into a clean `output` string IF\n * it's an MCP result; otherwise `null` so the raw payload is passed through.\n * This stops every MCP tool (web search, custom servers, …) from dumping the\n * nested `{content:[{text:{text}}]}` JSON into the block.\n */\nfunction mcpFold(result: unknown): FoldedResult | null {\n\tconst text = flattenMcpContent(successValue(result));\n\tif (text === null) return null;\n\treturn { title: \"\", metadata: {}, output: text };\n}\n\n/** Cursor MCP call args nest the real tool input under `args.args`. */\nfunction mcpInputArgs(args: unknown): unknown {\n\treturn isRecord(args) ? args[\"args\"] : undefined;\n}\n\n/** Map a Cursor MCP `providerIdentifier` to a websearch provider label key. */\nfunction webSearchProvider(args: unknown): string | undefined {\n\tconst id = (strField(args, \"providerIdentifier\") ?? \"\").toLowerCase();\n\tif (id.includes(\"exa\")) return \"exa\";\n\tif (id.includes(\"parallel\")) return \"parallel\";\n\treturn undefined;\n}\n\n/** A Cursor MCP tool whose name looks like a web search (`web_search`, …). */\nfunction isWebSearchName(name: string): boolean {\n\treturn /web[_-]?search/i.test(name);\n}\n\n/**\n * Cursor web search arrives as an MCP tool; map it onto opencode's native\n * `websearch` renderer (query subtitle + result body). The query lives in the\n * nested MCP input (`args.args.query`); the result is MCP `content`.\n */\nconst WEBSEARCH_ADAPTER: NativeToolAdapter = {\n\ttool: \"websearch\",\n\tinput: (args) => {\n\t\tconst query = strField(mcpInputArgs(args), \"query\");\n\t\treturn query !== undefined ? { query } : {};\n\t},\n\tresult: (value, args) => {\n\t\tconst provider = webSearchProvider(args);\n\t\treturn {\n\t\t\ttitle: \"\",\n\t\t\tmetadata: provider ? { provider } : {},\n\t\t\toutput: flattenMcpContent(value) ?? \"\",\n\t\t};\n\t},\n};\n\n/**\n * Resolve a Cursor tool name (+ call args) to an adapter, or `undefined` for a\n * plain `cursor_*` block. `edit` is handled separately (its native call input\n * depends on the diff in the result).\n */\nfunction resolveAdapter(\n\tname: string,\n\t_input: unknown,\n): NativeToolAdapter | undefined {\n\tconst exact = NATIVE_ADAPTERS[name];\n\tif (exact) return exact;\n\tif (isWebSearchName(name)) return WEBSEARCH_ADAPTER;\n\treturn undefined;\n}\n\n/** Cursor todo status (`inProgress`) → opencode todo status (`in_progress`). */\nfunction mapTodoStatus(status: unknown): string {\n\tif (status === \"inProgress\") return \"in_progress\";\n\treturn typeof status === \"string\" ? status : \"pending\";\n}\n\n/** Normalize Cursor `updateTodos` args into opencode `todowrite` todos. */\nfunction mapTodos(args: unknown): Array<{ content: string; status: string }> {\n\tconst todos =\n\t\tisRecord(args) && Array.isArray(args[\"todos\"]) ? args[\"todos\"] : [];\n\treturn (todos as unknown[]).flatMap((t) =>\n\t\tisRecord(t) && typeof t[\"content\"] === \"string\"\n\t\t\t? [\n\t\t\t\t\t{\n\t\t\t\t\t\tcontent: t[\"content\"] as string,\n\t\t\t\t\t\tstatus: mapTodoStatus(t[\"status\"]),\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t: [],\n\t);\n}\n\n/**\n * Cursor tool name → opencode native tool adapter. Cursor tools without a\n * natural opencode counterpart (`delete`, `mcp`, `semSearch`, `readLints`,\n * `generateImage`, `createPlan`, `recordScreen`, `task`) are intentionally\n * absent and fall through to generic `cursor_*` blocks. `edit` is handled\n * separately (its native call input depends on the diff in the result).\n */\nconst NATIVE_ADAPTERS: Record<string, NativeToolAdapter> = {\n\t// Cursor `shell` → opencode `bash` (console renderer).\n\tshell: {\n\t\ttool: \"bash\",\n\t\tinput: (args) => ({ command: strField(args, \"command\") ?? \"\" }),\n\t\tresult: (value, args) => {\n\t\t\tif (!isRecord(value)) return null;\n\t\t\tconst command = strField(args, \"command\") ?? \"\";\n\t\t\tconst stdout = strField(value, \"stdout\") ?? \"\";\n\t\t\tconst stderr = strField(value, \"stderr\") ?? \"\";\n\t\t\tconst exit = numField(value, \"exitCode\");\n\t\t\tconst body = [stdout, stderr].filter((s) => s.length > 0).join(\"\\n\");\n\t\t\tconst output =\n\t\t\t\texit !== undefined && exit !== 0\n\t\t\t\t\t? `${body}${body ? \"\\n\" : \"\"}(exit ${exit})`\n\t\t\t\t\t: body;\n\t\t\treturn {\n\t\t\t\ttitle: command,\n\t\t\t\tmetadata: { command, output, exit: exit ?? 0 },\n\t\t\t\toutput,\n\t\t\t};\n\t\t},\n\t},\n\t// Cursor `read` → opencode `read`.\n\tread: {\n\t\ttool: \"read\",\n\t\tinput: (args) => ({ filePath: strField(args, \"path\") ?? \"\" }),\n\t\tresult: (value, args) => {\n\t\t\tconst content = strField(value, \"content\");\n\t\t\tif (content === undefined) return null;\n\t\t\tconst filePath = strField(args, \"path\") ?? \"\";\n\t\t\tconst totalLines = numField(value, \"totalLines\");\n\t\t\treturn {\n\t\t\t\ttitle: filePath,\n\t\t\t\tmetadata: {\n\t\t\t\t\tpreview: content.split(\"\\n\").slice(0, 20).join(\"\\n\"),\n\t\t\t\t\tloaded: [] as string[],\n\t\t\t\t\t...(totalLines !== undefined ? { totalLines } : {}),\n\t\t\t\t},\n\t\t\t\toutput: content,\n\t\t\t};\n\t\t},\n\t},\n\t// Cursor `write` → opencode `write` (renders input.content as the new file).\n\twrite: {\n\t\ttool: \"write\",\n\t\tinput: (args) => ({\n\t\t\tfilePath: strField(args, \"path\") ?? \"\",\n\t\t\tcontent: strField(args, \"fileText\") ?? \"\",\n\t\t}),\n\t\tresult: (value, args) => {\n\t\t\tconst filePath = strField(args, \"path\") ?? \"\";\n\t\t\tconst lines = numField(value, \"linesCreated\");\n\t\t\tconst output =\n\t\t\t\tlines !== undefined\n\t\t\t\t\t? `Wrote ${lines} line${lines === 1 ? \"\" : \"s\"}.`\n\t\t\t\t\t: \"Wrote file successfully.\";\n\t\t\treturn {\n\t\t\t\ttitle: filePath,\n\t\t\t\tmetadata: { diagnostics: {}, filepath: filePath, exists: false },\n\t\t\t\toutput,\n\t\t\t};\n\t\t},\n\t},\n\t// Cursor `glob` → opencode `glob`.\n\tglob: {\n\t\ttool: \"glob\",\n\t\tinput: (args) => {\n\t\t\tconst pattern = strField(args, \"globPattern\") ?? \"\";\n\t\t\tconst dir = strField(args, \"targetDirectory\");\n\t\t\treturn dir ? { pattern, path: dir } : { pattern };\n\t\t},\n\t\tresult: (value) => {\n\t\t\tif (!isRecord(value) || !Array.isArray(value[\"files\"])) return null;\n\t\t\tconst files = (value[\"files\"] as unknown[]).filter(\n\t\t\t\t(f): f is string => typeof f === \"string\",\n\t\t\t);\n\t\t\tconst truncated =\n\t\t\t\tvalue[\"clientTruncated\"] === true || value[\"ripgrepTruncated\"] === true;\n\t\t\treturn {\n\t\t\t\ttitle: \"\",\n\t\t\t\tmetadata: { count: files.length, truncated },\n\t\t\t\toutput: files.length > 0 ? files.join(\"\\n\") : \"No files found\",\n\t\t\t};\n\t\t},\n\t},\n\t// Cursor `grep` → opencode `grep` (flatten matches into ripgrep-style text).\n\tgrep: {\n\t\ttool: \"grep\",\n\t\tinput: (args) => {\n\t\t\tconst out: Record<string, unknown> = {\n\t\t\t\tpattern: strField(args, \"pattern\") ?? \"\",\n\t\t\t};\n\t\t\tconst p = strField(args, \"path\");\n\t\t\tif (p) out[\"path\"] = p;\n\t\t\tconst g = strField(args, \"glob\");\n\t\t\tif (g) out[\"include\"] = g;\n\t\t\treturn out;\n\t\t},\n\t\tresult: (value) => {\n\t\t\tif (!isRecord(value)) return null;\n\t\t\tconst unions: unknown[] = [];\n\t\t\tconst ws = value[\"workspaceResults\"];\n\t\t\tif (isRecord(ws)) unions.push(...Object.values(ws));\n\t\t\tif (value[\"activeEditorResult\"] !== undefined)\n\t\t\t\tunions.push(value[\"activeEditorResult\"]);\n\t\t\tconst lines: string[] = [];\n\t\t\tlet total = 0;\n\t\t\tlet current = \"\";\n\t\t\tfor (const u of unions) {\n\t\t\t\tif (!isRecord(u)) continue;\n\t\t\t\tconst output = u[\"output\"];\n\t\t\t\tif (\n\t\t\t\t\tu[\"type\"] === \"content\" &&\n\t\t\t\t\tisRecord(output) &&\n\t\t\t\t\tArray.isArray(output[\"matches\"])\n\t\t\t\t) {\n\t\t\t\t\tfor (const m of output[\"matches\"] as unknown[]) {\n\t\t\t\t\t\tif (!isRecord(m)) continue;\n\t\t\t\t\t\tconst file = strField(m, \"file\") ?? \"\";\n\t\t\t\t\t\tconst line = numField(m, \"lineNumber\");\n\t\t\t\t\t\tconst text = strField(m, \"line\") ?? \"\";\n\t\t\t\t\t\tif (current !== file) {\n\t\t\t\t\t\t\tif (current) lines.push(\"\");\n\t\t\t\t\t\t\tcurrent = file;\n\t\t\t\t\t\t\tlines.push(`${file}:`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlines.push(\n\t\t\t\t\t\t\tline !== undefined ? ` Line ${line}: ${text}` : ` ${text}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\ttotal++;\n\t\t\t\t\t}\n\t\t\t\t} else if (\n\t\t\t\t\tu[\"type\"] === \"files\" &&\n\t\t\t\t\tisRecord(output) &&\n\t\t\t\t\tArray.isArray(output[\"files\"])\n\t\t\t\t) {\n\t\t\t\t\tfor (const f of output[\"files\"] as unknown[]) {\n\t\t\t\t\t\tif (typeof f === \"string\") {\n\t\t\t\t\t\t\tlines.push(f);\n\t\t\t\t\t\t\ttotal++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn {\n\t\t\t\ttitle: \"\",\n\t\t\t\tmetadata: { matches: total, truncated: false },\n\t\t\t\toutput:\n\t\t\t\t\ttotal > 0\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t`Found ${total} match${total === 1 ? \"\" : \"es\"}`,\n\t\t\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t\t\t...lines,\n\t\t\t\t\t\t\t].join(\"\\n\")\n\t\t\t\t\t\t: \"No matches found\",\n\t\t\t};\n\t\t},\n\t},\n\t// Cursor `ls` → opencode `list` (flatten the directory tree into paths).\n\tls: {\n\t\ttool: \"list\",\n\t\tinput: (args) => ({ path: strField(args, \"path\") ?? \"\" }),\n\t\tresult: (value) => {\n\t\t\tif (!isRecord(value)) return null;\n\t\t\tconst root = value[\"directoryTreeRoot\"];\n\t\t\tif (!isRecord(root)) return null;\n\t\t\tconst out: string[] = [];\n\t\t\tconst walk = (node: Record<string, unknown>) => {\n\t\t\t\tconst base = strField(node, \"absPath\") ?? \"\";\n\t\t\t\tconst files = Array.isArray(node[\"childrenFiles\"])\n\t\t\t\t\t? node[\"childrenFiles\"]\n\t\t\t\t\t: [];\n\t\t\t\tfor (const f of files) {\n\t\t\t\t\tconst name = strField(f, \"name\");\n\t\t\t\t\tif (name) out.push(`${base}/${name}`);\n\t\t\t\t}\n\t\t\t\tconst dirs = Array.isArray(node[\"childrenDirs\"])\n\t\t\t\t\t? node[\"childrenDirs\"]\n\t\t\t\t\t: [];\n\t\t\t\tfor (const d of dirs) {\n\t\t\t\t\tif (!isRecord(d)) continue;\n\t\t\t\t\tout.push(`${strField(d, \"absPath\") ?? \"\"}/`);\n\t\t\t\t\twalk(d);\n\t\t\t\t}\n\t\t\t};\n\t\t\twalk(root);\n\t\t\treturn {\n\t\t\t\ttitle: strField(root, \"absPath\") ?? \"\",\n\t\t\t\tmetadata: {},\n\t\t\t\toutput: out.length > 0 ? out.join(\"\\n\") : \"(empty)\",\n\t\t\t};\n\t\t},\n\t},\n\t// Cursor `updateTodos` → opencode `todowrite` (todo checklist renderer).\n\tupdateTodos: {\n\t\ttool: \"todowrite\",\n\t\tinput: (args) => ({ todos: mapTodos(args) }),\n\t\tresult: (_value, args) => {\n\t\t\tconst todos = mapTodos(args);\n\t\t\tconst done = todos.filter((t) => t.status === \"completed\").length;\n\t\t\treturn {\n\t\t\t\ttitle: `${done}/${todos.length}`,\n\t\t\t\tmetadata: { todos },\n\t\t\t\toutput: `Updated ${todos.length} todo${todos.length === 1 ? \"\" : \"s\"}.`,\n\t\t\t};\n\t\t},\n\t},\n\t// Cursor `task` (subagent) → opencode `task` (agent card: name + description).\n\t// Non-clickable here — the subagent ran inside Cursor, not as an opencode\n\t// child session — but the native card reads far better than raw JSON.\n\ttask: {\n\t\ttool: \"task\",\n\t\tinput: (args) => {\n\t\t\tconst description = strField(args, \"description\") ?? \"\";\n\t\t\tconst sub = isRecord(args) ? args[\"subagentType\"] : undefined;\n\t\t\tconst subagent =\n\t\t\t\tstrField(sub, \"name\") ?? strField(sub, \"kind\") ?? undefined;\n\t\t\treturn subagent\n\t\t\t\t? { description, subagent_type: subagent }\n\t\t\t\t: { description };\n\t\t},\n\t\tresult: (value, args) => {\n\t\t\tconst description = strField(args, \"description\") ?? \"\";\n\t\t\tconst suffix = strField(value, \"resultSuffix\");\n\t\t\tconst background = isRecord(value) && value[\"isBackground\"] === true;\n\t\t\treturn {\n\t\t\t\ttitle: description,\n\t\t\t\tmetadata: background ? { background: true } : {},\n\t\t\t\toutput: suffix ?? \"Subagent task completed.\",\n\t\t\t};\n\t\t},\n\t},\n\t// Cursor `readLints` has no opencode counterpart — format-only: render the\n\t// diagnostics as a readable list instead of dumping the nested JSON.\n\treadLints: {\n\t\tinput: (args) => {\n\t\t\tconst paths =\n\t\t\t\tisRecord(args) && Array.isArray(args[\"paths\"]) ? args[\"paths\"] : [];\n\t\t\treturn { paths };\n\t\t},\n\t\tresult: (value) => {\n\t\t\tconst files =\n\t\t\t\tisRecord(value) && Array.isArray(value[\"fileDiagnostics\"])\n\t\t\t\t\t? (value[\"fileDiagnostics\"] as unknown[])\n\t\t\t\t\t: [];\n\t\t\tconst lines: string[] = [];\n\t\t\tlet total = 0;\n\t\t\tfor (const file of files) {\n\t\t\t\tif (!isRecord(file)) continue;\n\t\t\t\tconst diags = Array.isArray(file[\"diagnostics\"])\n\t\t\t\t\t? (file[\"diagnostics\"] as unknown[])\n\t\t\t\t\t: [];\n\t\t\t\tif (diags.length === 0) continue;\n\t\t\t\tlines.push(`${strField(file, \"path\") ?? \"\"}`);\n\t\t\t\tfor (const d of diags) {\n\t\t\t\t\tif (!isRecord(d)) continue;\n\t\t\t\t\tconst severity = strField(d, \"severity\") ?? \"info\";\n\t\t\t\t\tconst start = isRecord(d[\"range\"]) ? d[\"range\"][\"start\"] : undefined;\n\t\t\t\t\tconst line = numField(start, \"line\");\n\t\t\t\t\tconst char = numField(start, \"character\");\n\t\t\t\t\tconst loc =\n\t\t\t\t\t\tline !== undefined\n\t\t\t\t\t\t\t? ` L${line + 1}${char !== undefined ? `:${char + 1}` : \"\"}`\n\t\t\t\t\t\t\t: \"\";\n\t\t\t\t\tlines.push(` ${severity}${loc}: ${strField(d, \"message\") ?? \"\"}`);\n\t\t\t\t\ttotal++;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn {\n\t\t\t\ttitle:\n\t\t\t\t\ttotal > 0\n\t\t\t\t\t\t? `${total} problem${total === 1 ? \"\" : \"s\"}`\n\t\t\t\t\t\t: \"No problems\",\n\t\t\t\tmetadata: { count: total },\n\t\t\t\toutput: total > 0 ? lines.join(\"\\n\") : \"No problems found.\",\n\t\t\t};\n\t\t},\n\t},\n\t// Cursor `delete` has no opencode counterpart — format-only: a one-line\n\t// confirmation instead of `{\"fileSize\":N}`.\n\tdelete: {\n\t\tinput: (args) => ({ path: strField(args, \"path\") ?? \"\" }),\n\t\tresult: (value, args) => {\n\t\t\tconst path = strField(args, \"path\") ?? \"\";\n\t\t\tconst size = numField(value, \"fileSize\");\n\t\t\treturn {\n\t\t\t\ttitle: path,\n\t\t\t\tmetadata: {},\n\t\t\t\toutput:\n\t\t\t\t\tsize !== undefined\n\t\t\t\t\t\t? `Deleted ${path} (${size} bytes).`\n\t\t\t\t\t\t: `Deleted ${path}.`,\n\t\t\t};\n\t\t},\n\t},\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 * - `open`: non-edit calls awaiting their result. Stores the FINAL emitted tool\n * name (native, e.g. `bash`, or generic `cursor_*`), the native adapter (if\n * any) used to fold the result, and the original Cursor args (some adapters\n * build their result from the call args, e.g. `write`/`updateTodos`).\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 OpenToolCall {\n\ttoolName: string;\n\tadapter?: NativeToolAdapter;\n\targs: unknown;\n}\n\ninterface BlockToolState {\n\topen: Map<string, OpenToolCall>;\n\tpendingEdits: Map<string, string>;\n}\n\nfunction newBlockToolState(): BlockToolState {\n\treturn { open: 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\tconst adapter = resolveAdapter(name, input);\n\tif (adapter) {\n\t\t// Adapter mapping: native registered tool (`adapter.tool`) when there's a\n\t\t// renderer to reuse, else a `cursor_*` block whose result is still folded\n\t\t// into clean output (format-only adapters).\n\t\tconst toolName = adapter.tool ?? blockToolName(name);\n\t\tstate.open.set(id, { toolName, adapter, args: input });\n\t\treturn [nativeToolCall(id, toolName, adapter.input(input))];\n\t}\n\t// No adapter: generic prefixed block.\n\tconst toolName = blockToolName(name);\n\tstate.open.set(id, { toolName, args: input });\n\treturn [nativeToolCall(id, toolName, 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\tconst open = state.open.get(id);\n\tstate.open.delete(id);\n\tconst toolName = open?.toolName ?? blockToolName(name);\n\tif (open?.adapter && !isError) {\n\t\tconst value = successValue(result);\n\t\tif (value !== undefined) {\n\t\t\tconst folded = open.adapter.result(value, open.args);\n\t\t\tif (folded) return [nativeToolResult(id, toolName, folded, false)];\n\t\t}\n\t}\n\tif (!isError) {\n\t\t// No adapter (or it declined): if this is an MCP result, fold its `content`\n\t\t// into readable text so the block isn't a raw JSON dump.\n\t\tconst folded = mcpFold(result);\n\t\tif (folded) return [nativeToolResult(id, toolName, folded, false)];\n\t}\n\t// Generic block / error / unexpected shape: emit the raw Cursor result under\n\t// the (already-resolved) tool name.\n\treturn [nativeToolResult(id, toolName, 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, open] of state.open) {\n\t\tparts.push(nativeToolResult(id, open.toolName, DANGLING_TOOL_RESULT, true));\n\t}\n\tstate.open.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":"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","names":["toolName"]}
|
package/package.json
CHANGED