@stablekernel/opencode-cursor 0.4.0 → 0.4.1-next.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/README.md CHANGED
@@ -267,10 +267,6 @@ Override with `OPENCODE_CURSOR_SIDECAR=1` (always sidecar) or `OPENCODE_CURSOR_S
267
267
  on your `PATH`. Install Node.js 22+, or force the sidecar with `OPENCODE_CURSOR_SIDECAR=1`.
268
268
  - **"Running under Bun without a usable Node sidecar" warning.** Install Node.js 22+, or set
269
269
  `OPENCODE_CURSOR_SIDECAR=0` to accept in-process behavior and silence the warning.
270
- - **"Could not locate the bindings file" / `node_sqlite3.node` not found.** The `@cursor/sdk`
271
- native sqlite3 addon was skipped during Bun install. The plugin self-heals on first load (needs
272
- Node on `PATH`). If that fails, `cd` into the printed sqlite3 directory and run
273
- `npx prebuild-install -r napi`.
274
270
  - **Plugin enabled but no `cursor` provider/models appear.** Stale opencode plugin cache. Pin an
275
271
  exact version (`@stablekernel/opencode-cursor@<version>`) or delete
276
272
  `~/.cache/opencode/packages/` and restart.
@@ -157,139 +157,28 @@ function resolveControls(modelId, staticControls, providerOptions) {
157
157
  return { mode, modelSelection: buildModelSelection(modelId, params) };
158
158
  }
159
159
 
160
- // src/native-binding.ts
161
- import { execSync, spawn } from "child_process";
162
- import { existsSync, readdirSync, statSync } from "fs";
163
- import { createRequire } from "module";
164
- import { dirname, join } from "path";
165
- var BINDING_ROOTS = ["build", "lib/binding", "compiled"];
166
- function hasNodeFile(dir, depth) {
167
- if (depth < 0) return false;
168
- let entries;
169
- try {
170
- entries = readdirSync(dir);
171
- } catch {
172
- return false;
173
- }
174
- for (const entry of entries) {
175
- const path = join(dir, entry);
176
- if (entry.endsWith(".node")) {
177
- try {
178
- if (statSync(path).isFile()) return true;
179
- } catch {
180
- }
181
- continue;
182
- }
183
- try {
184
- if (statSync(path).isDirectory() && hasNodeFile(path, depth - 1)) return true;
185
- } catch {
186
- }
187
- }
188
- return false;
189
- }
190
- function hasSqliteBinding(sqliteDir) {
191
- return BINDING_ROOTS.some((root) => hasNodeFile(join(sqliteDir, root), 3));
192
- }
193
- function resolveSqliteDir() {
194
- const req = createRequire(import.meta.url);
195
- try {
196
- const sdkPkg = req.resolve("@cursor/sdk/package.json");
197
- return dirname(createRequire(sdkPkg).resolve("sqlite3/package.json"));
198
- } catch {
199
- }
200
- try {
201
- return dirname(req.resolve("sqlite3/package.json"));
202
- } catch {
203
- return void 0;
204
- }
205
- }
206
- function detectNodeExecutable() {
207
- const isBun = typeof globalThis.Bun !== "undefined";
208
- if (!isBun) return process.execPath;
209
- try {
210
- const out = execSync(process.platform === "win32" ? "where node" : "command -v node", {
211
- encoding: "utf8",
212
- stdio: ["ignore", "pipe", "ignore"]
213
- }).trim();
214
- return out.split("\n")[0] || process.execPath;
215
- } catch {
216
- return process.execPath;
217
- }
218
- }
219
- async function runPrebuildInstall(sqliteDir) {
220
- let bin;
221
- try {
222
- const req = createRequire(join(sqliteDir, "package.json"));
223
- const pkgPath = req.resolve("prebuild-install/package.json");
224
- const pkg = await import(pkgPath, { with: { type: "json" } });
225
- const binField = pkg.default.bin;
226
- const rel = typeof binField === "string" ? binField : binField?.["prebuild-install"];
227
- if (!rel) return false;
228
- bin = join(dirname(pkgPath), rel);
229
- } catch {
230
- return false;
231
- }
232
- if (!existsSync(bin)) return false;
233
- return new Promise((resolve) => {
234
- const child = spawn(detectNodeExecutable(), [bin, "-r", "napi"], {
235
- cwd: sqliteDir,
236
- stdio: ["ignore", "ignore", "pipe"]
237
- });
238
- let stderr = "";
239
- child.stderr?.on("data", (chunk) => {
240
- stderr += chunk.toString();
241
- });
242
- child.on("error", () => resolve(false));
243
- child.on("exit", (code) => {
244
- if (code !== 0 && stderr && process.env["OPENCODE_CURSOR_DEBUG"]) {
245
- console.error(`[opencode-cursor] prebuild-install stderr: ${stderr.trim()}`);
246
- }
247
- resolve(code === 0);
248
- });
249
- });
250
- }
251
- var cached;
252
- function ensureSqliteBinding(options = {}) {
253
- cached ??= (async () => {
254
- const log = options.log ?? ((message) => console.error(message));
255
- const sqliteDir = options.sqliteDir ?? resolveSqliteDir();
256
- if (!sqliteDir || !existsSync(join(sqliteDir, "package.json"))) {
257
- return "not-found";
258
- }
259
- if (hasSqliteBinding(sqliteDir)) return "present";
260
- const run = options.run ?? runPrebuildInstall;
261
- const ok = await run(sqliteDir).catch(() => false);
262
- if (ok && hasSqliteBinding(sqliteDir)) return "repaired";
263
- log(
264
- `[opencode-cursor] sqlite3 native binding is missing in ${sqliteDir} and automatic repair failed. @cursor/sdk will not load. Fix manually with: cd ${sqliteDir} && npx prebuild-install -r napi (or: npm rebuild sqlite3)`
265
- );
266
- return "failed";
267
- })();
268
- return cached;
269
- }
270
-
271
160
  // src/cursor-runtime.ts
272
- var cached2;
161
+ var cached;
273
162
  async function loadCursorSdk() {
274
- if (!cached2) {
275
- cached2 = ensureSqliteBinding().then(() => import("@cursor/sdk")).catch((err) => {
276
- cached2 = void 0;
163
+ if (!cached) {
164
+ cached = import("@cursor/sdk").catch((err) => {
165
+ cached = void 0;
277
166
  const detail = err instanceof Error ? err.message : String(err);
278
167
  throw new Error(
279
168
  `[opencode-cursor] Failed to load "@cursor/sdk". Make sure it is installed (\`npm install @cursor/sdk\`). Original error: ${detail}`
280
169
  );
281
170
  });
282
171
  }
283
- return cached2;
172
+ return cached;
284
173
  }
285
174
 
286
175
  // src/provider/agent-backend.ts
287
- import { execSync as execSync2 } from "child_process";
288
- import { existsSync as existsSync2 } from "fs";
176
+ import { execSync } from "child_process";
177
+ import { existsSync } from "fs";
289
178
  import { fileURLToPath } from "url";
290
179
 
291
180
  // src/provider/sidecar-client.ts
292
- import { spawn as spawn2 } from "child_process";
181
+ import { spawn } from "child_process";
293
182
  import { createInterface } from "readline";
294
183
  function reviveError(error) {
295
184
  const e = error ?? {};
@@ -311,7 +200,7 @@ var SidecarClient = class {
311
200
  ensureChild() {
312
201
  if (this.disposed) throw new Error("cursor sidecar client disposed");
313
202
  if (this.child) return this.child;
314
- const child = spawn2(this.options.nodePath ?? "node", [this.options.scriptPath], {
203
+ const child = spawn(this.options.nodePath ?? "node", [this.options.scriptPath], {
315
204
  stdio: ["pipe", "pipe", "pipe"],
316
205
  env: { ...process.env, ...this.options.env }
317
206
  });
@@ -488,7 +377,7 @@ function resolveBackendKind(env) {
488
377
  }
489
378
  function detectNode() {
490
379
  try {
491
- const out = execSync2(process.platform === "win32" ? "where node" : "command -v node", {
380
+ const out = execSync(process.platform === "win32" ? "where node" : "command -v node", {
492
381
  encoding: "utf8",
493
382
  stdio: ["ignore", "pipe", "ignore"]
494
383
  }).trim();
@@ -526,7 +415,7 @@ function resolveSidecarScript() {
526
415
  ];
527
416
  for (const candidate of candidates) {
528
417
  const path = fileURLToPath(new URL(candidate, import.meta.url));
529
- if (existsSync2(path)) return path;
418
+ if (existsSync(path)) return path;
530
419
  }
531
420
  return void 0;
532
421
  }
@@ -534,19 +423,13 @@ function sidecarBackend(nodePath, scriptPath) {
534
423
  const client = new SidecarClient({ scriptPath, nodePath });
535
424
  return {
536
425
  kind: "sidecar",
537
- createAgent: async (options) => {
538
- await ensureSqliteBinding();
539
- return client.createAgent(options);
540
- },
541
- resumeAgent: async (agentId, options) => {
542
- await ensureSqliteBinding();
543
- return client.resumeAgent(agentId, options);
544
- }
426
+ createAgent: (options) => client.createAgent(options),
427
+ resumeAgent: (agentId, options) => client.resumeAgent(agentId, options)
545
428
  };
546
429
  }
547
- var cached3;
430
+ var cached2;
548
431
  function loadAgentBackend() {
549
- if (!cached3) {
432
+ if (!cached2) {
550
433
  const env = detectEnvironment();
551
434
  const kind = resolveBackendKind(env);
552
435
  const scriptPath = kind === "sidecar" ? resolveSidecarScript() : void 0;
@@ -557,23 +440,23 @@ function loadAgentBackend() {
557
440
  `[opencode-cursor] Running under Bun without a usable Node sidecar (node: ${env.nodePath ?? "not found"}, script: ${scriptPath ?? "not found"}): Cursor native tool calls may fail (Bun node:http2 incompatibility). Install Node.js to enable the sidecar, or set OPENCODE_CURSOR_SIDECAR=0 to silence this warning.`
558
441
  );
559
442
  }
560
- cached3 = kind === "sidecar" && env.nodePath && scriptPath ? sidecarBackend(env.nodePath, scriptPath) : inProcessBackend();
443
+ cached2 = kind === "sidecar" && env.nodePath && scriptPath ? sidecarBackend(env.nodePath, scriptPath) : inProcessBackend();
561
444
  }
562
- return cached3;
445
+ return cached2;
563
446
  }
564
447
 
565
448
  // src/provider/session-store.ts
566
449
  import { mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
567
450
  import { homedir, tmpdir } from "os";
568
- import { join as join2 } from "path";
451
+ import { join } from "path";
569
452
  var ENTRY_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
570
453
  var MAX_ENTRIES = 200;
571
454
  function storeDir() {
572
- const base = process.env.XDG_CACHE_HOME?.trim() || (homedir() ? join2(homedir(), ".cache") : tmpdir());
573
- return join2(base, "opencode-cursor");
455
+ const base = process.env.XDG_CACHE_HOME?.trim() || (homedir() ? join(homedir(), ".cache") : tmpdir());
456
+ return join(base, "opencode-cursor");
574
457
  }
575
458
  function storeFile() {
576
- return join2(storeDir(), "session-pool.json");
459
+ return join(storeDir(), "session-pool.json");
577
460
  }
578
461
  function isStoredRecord(value) {
579
462
  if (typeof value !== "object" || value === null) return false;
@@ -681,4 +564,4 @@ export {
681
564
  getSessionRecord,
682
565
  acquireAgent
683
566
  };
684
- //# sourceMappingURL=chunk-BTI2NHEE.js.map
567
+ //# sourceMappingURL=chunk-KGDYXGZL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api-key.ts","../src/provider/agent-events.ts","../src/provider/controls.ts","../src/cursor-runtime.ts","../src/provider/agent-backend.ts","../src/provider/sidecar-client.ts","../src/provider/session-store.ts","../src/provider/session-pool.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\n\n/** Environment variable the Cursor SDK itself reads as a fallback. */\nexport const CURSOR_API_KEY_ENV_VAR = \"CURSOR_API_KEY\";\n\n/**\n * Values that are *not* real keys but rather instructions to read the key from\n * the environment. opencode config commonly stores literal `{env:...}` style\n * placeholders, and users sometimes paste the variable name itself.\n */\nconst PLACEHOLDERS = new Set<string>([\n CURSOR_API_KEY_ENV_VAR,\n `$${CURSOR_API_KEY_ENV_VAR}`,\n `\\${${CURSOR_API_KEY_ENV_VAR}}`,\n]);\n\n/**\n * Resolve a usable Cursor API key.\n *\n * Resolution order: an explicit, non-placeholder candidate (e.g. from opencode\n * auth storage or provider options) wins; otherwise fall back to the\n * `CURSOR_API_KEY` environment variable. Returns `undefined` when no key is\n * available so callers can present a clear \"needs auth\" path.\n *\n * The key is never logged or persisted by this module.\n */\nexport function resolveCursorApiKey(candidate?: string | null): string | undefined {\n const trimmed = candidate?.trim();\n if (trimmed && !PLACEHOLDERS.has(trimmed)) return trimmed;\n const fromEnv = process.env[CURSOR_API_KEY_ENV_VAR]?.trim();\n return fromEnv ? fromEnv : undefined;\n}\n\n/**\n * Produce a short, non-reversible fingerprint of an API key. Used purely to key\n * the on-disk model cache so the cache invalidates when the key changes. The\n * raw key is never written to disk.\n */\nexport function fingerprintApiKey(apiKey: string): string {\n return createHash(\"sha256\").update(apiKey).digest(\"hex\").slice(0, 16);\n}\n","import type { AgentModeOption, SDKUserMessage } from \"@cursor/sdk\";\nimport type { AgentLike, AgentRunLike } from \"./agent-backend.js\";\n\n/** Token usage as reported by Cursor's `turn-ended` update. */\nexport interface CursorUsage {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n}\n\n/** Normalized events bridged from the Cursor SDK's push callbacks. */\nexport type CursorEvent =\n | { type: \"text-delta\"; text: string }\n | { type: \"reasoning-delta\"; text: string }\n | { type: \"tool-call\"; id: string; name: string; input: unknown }\n | { type: \"tool-result\"; id: string; name: string; result: unknown; isError: boolean }\n | { type: \"usage\"; usage: CursorUsage }\n | { type: \"finish\"; text?: string };\n\nexport interface StreamAgentTurnOptions {\n mode: AgentModeOption;\n abortSignal?: AbortSignal;\n}\n\n/**\n * Human-readable name for a Cursor tool call. Most Cursor tools carry their\n * name in `toolCall.type` (shell/read/edit/…), but an MCP tool call has\n * `type: \"mcp\"` with the real tool in `args.toolName` (and server in\n * `args.providerIdentifier`) — surface that instead of the literal \"mcp\".\n */\nfunction toolDisplayName(toolCall: ({ type?: string } & Record<string, any>) | undefined): string {\n if (!toolCall) return \"tool\";\n if (toolCall.type === \"mcp\") {\n const name = toolCall.args?.toolName;\n const server = toolCall.args?.providerIdentifier;\n if (name) return server ? `${server}/${name}` : String(name);\n return \"mcp\";\n }\n return toolCall.type ?? \"tool\";\n}\n\n/**\n * Stream a single turn on an already-acquired Cursor agent and yield normalized\n * events. The agent's lifecycle (create/resume/close) is owned by the caller\n * (see session-pool.ts) so it can be reused across turns. The SDK streams via\n * `onDelta` callbacks; we bridge those into a pull-based async generator so both\n * `doStream` and `doGenerate` can consume them.\n */\nexport async function* streamAgentTurn(\n agent: AgentLike,\n message: SDKUserMessage,\n options: StreamAgentTurnOptions,\n): AsyncGenerator<CursorEvent> {\n const queue: CursorEvent[] = [];\n let wake: (() => void) | undefined;\n let finished = false;\n let failure: unknown;\n\n // Opt-in stderr tracing of what the live agent emits (set OPENCODE_CURSOR_DEBUG=1).\n const debug = process.env.OPENCODE_CURSOR_DEBUG === \"1\";\n const counts: Record<string, number> = {};\n\n const push = (event: CursorEvent) => {\n queue.push(event);\n wake?.();\n wake = undefined;\n };\n\n const onDelta = ({ update }: { update: { type: string } & Record<string, any> }) => {\n if (debug) counts[update.type] = (counts[update.type] ?? 0) + 1;\n switch (update.type) {\n case \"text-delta\":\n push({ type: \"text-delta\", text: update.text });\n break;\n case \"thinking-delta\":\n push({ type: \"reasoning-delta\", text: update.text });\n break;\n case \"tool-call-started\":\n push({\n type: \"tool-call\",\n id: String(update.callId),\n name: toolDisplayName(update.toolCall),\n input: update.toolCall?.args ?? {},\n });\n break;\n case \"tool-call-completed\": {\n const tool = update.toolCall ?? {};\n const result = tool.result;\n // MCP failures often arrive as {status:\"success\", value:{isError:true}}\n // (the MCP-protocol error flag), not as a top-level status error.\n const mcpError = tool.type === \"mcp\" && result?.value?.isError === true;\n push({\n type: \"tool-result\",\n id: String(update.callId),\n name: toolDisplayName(tool),\n result: result ?? null,\n isError: result?.status === \"error\" || mcpError,\n });\n break;\n }\n case \"turn-ended\":\n if (update.usage) push({ type: \"usage\", usage: update.usage as CursorUsage });\n break;\n }\n };\n\n const runHolder: { run?: AgentRunLike } = {};\n const onAbort = () => {\n void Promise.resolve(runHolder.run?.cancel()).catch(() => {});\n };\n options.abortSignal?.addEventListener(\"abort\", onAbort);\n\n // A previous opencode/CLI crash (or a second instance racing on the same\n // agent store) can leave a persisted run wedged; the SDK then rejects new\n // sends with AgentBusyError. Retry once with the SDK's documented recovery\n // path (local.force expires the wedged run) instead of failing the turn.\n const sendTurn = async (): Promise<AgentRunLike> => {\n try {\n return await agent.send(message, { mode: options.mode, onDelta });\n } catch (err) {\n if (err instanceof Error && err.name === \"AgentBusyError\") {\n if (debug) console.error(\"[cursor:debug] agent busy; retrying send with local.force\");\n return agent.send(message, { mode: options.mode, onDelta, local: { force: true } });\n }\n throw err;\n }\n };\n\n // Kick off the turn. Resolve text from run.wait() for models that don't emit\n // incremental text deltas.\n void sendTurn()\n .then(async (run) => {\n runHolder.run = run;\n const result = await run.wait();\n if (debug) {\n console.error(\n `[cursor:debug] updates=${JSON.stringify(counts)} status=${result.status} resultLen=${(result.result ?? \"\").length}`,\n );\n }\n if (result.status === \"error\") {\n // Surface the failure instead of finishing silently — a silent stop\n // leaves opencode showing dangling tool calls with no explanation.\n throw new Error(\n `Cursor run ended with status \"error\"${result.result ? `: ${result.result}` : \"\"}`,\n );\n }\n // A cancelled run finishes without fabricating final text.\n push({ type: \"finish\", ...(result.status === \"cancelled\" ? {} : { text: result.result }) });\n })\n .catch((err) => {\n failure = err;\n if (debug) console.error(`[cursor:debug] send failed: ${err instanceof Error ? err.message : String(err)}`);\n })\n .finally(() => {\n finished = true;\n wake?.();\n wake = undefined;\n });\n\n try {\n while (true) {\n if (queue.length > 0) {\n yield queue.shift()!;\n continue;\n }\n if (finished) break;\n await new Promise<void>((resolve) => {\n wake = resolve;\n });\n }\n // Drain anything queued right before completion.\n while (queue.length > 0) yield queue.shift()!;\n if (failure) throw failure;\n } finally {\n options.abortSignal?.removeEventListener(\"abort\", onAbort);\n }\n}\n","import type { AgentModeOption, ModelSelection } from \"@cursor/sdk\";\n\n/** Per-model static control defaults (from provider/model config options). */\nexport interface StaticControls {\n mode: AgentModeOption;\n /** Default Cursor model params (id -> value), e.g. { thinking: \"high\" }. */\n params?: Record<string, string>;\n}\n\nexport interface ResolvedControls {\n mode: AgentModeOption;\n modelSelection: ModelSelection;\n}\n\n/**\n * Build a Cursor `ModelSelection` from a model id and an optional map of model\n * params (e.g. `{ thinking: \"high\" }`). Shared by the provider control\n * resolution and the cloud/delegate tools so param handling stays consistent.\n */\nexport function buildModelSelection(\n modelId: string,\n params?: Record<string, string>,\n): ModelSelection {\n const paramList = Object.entries(params ?? {}).map(([id, value]) => ({ id, value }));\n return paramList.length > 0 ? { id: modelId, params: paramList } : { id: modelId };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isMode(value: unknown): value is AgentModeOption {\n return value === \"agent\" || value === \"plan\";\n}\n\n/**\n * Resolve the per-turn Cursor controls from static config plus opencode's\n * per-request `providerOptions.cursor` (which carries merged model `options` and\n * the selected model `variant`). Per-request values win over static defaults.\n *\n * Recognized keys in `providerOptions.cursor`:\n * - `mode`: \"agent\" | \"plan\"\n * - `params`: Record<string,string> of Cursor model params (e.g. { thinking: \"high\" })\n * - `thinking`: string convenience, mapped to the `thinking` param if not already set\n */\nexport function resolveControls(\n modelId: string,\n staticControls: StaticControls,\n providerOptions: Record<string, unknown> | undefined,\n): ResolvedControls {\n const po = providerOptions ?? {};\n\n const mode: AgentModeOption = isMode(po[\"mode\"]) ? po[\"mode\"] : staticControls.mode;\n\n const params: Record<string, string> = { ...(staticControls.params ?? {}) };\n if (isRecord(po[\"params\"])) {\n for (const [key, value] of Object.entries(po[\"params\"])) {\n if (value != null) params[key] = String(value);\n }\n }\n if (typeof po[\"thinking\"] === \"string\" && params[\"thinking\"] === undefined) {\n params[\"thinking\"] = po[\"thinking\"];\n }\n\n return { mode, modelSelection: buildModelSelection(modelId, params) };\n}\n","/**\n * Lazy loader for the official Cursor SDK (`@cursor/sdk`).\n *\n * The SDK is heavy and only needed once a Cursor model is actually used or\n * models are discovered, so it is imported on demand. A failed import (e.g. the\n * dependency is missing) degrades gracefully into a clear error instead of\n * crashing opencode at startup.\n */\nexport type CursorSdkModule = typeof import(\"@cursor/sdk\");\n\nlet cached: Promise<CursorSdkModule> | undefined;\n\nexport async function loadCursorSdk(): Promise<CursorSdkModule> {\n if (!cached) {\n cached = import(\"@cursor/sdk\").catch((err: unknown) => {\n // Allow a later retry if the failure was transient.\n cached = undefined;\n const detail = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[opencode-cursor] Failed to load \"@cursor/sdk\". Make sure it is installed ` +\n `(\\`npm install @cursor/sdk\\`). Original error: ${detail}`,\n );\n });\n }\n return cached;\n}\n","/**\n * Selects where Cursor agents run:\n *\n * - \"in-process\": straight through `@cursor/sdk` in this process (Node — the\n * normal path for tests, scripts, and any non-Bun host).\n * - \"sidecar\": a spawned Node child hosting the SDK (Bun — opencode's runtime —\n * has a `node:http2` bug that kills Cursor's streaming RPC with\n * NGHTTP2_FRAME_SIZE_ERROR, losing tool-completion updates; see\n * src/sidecar/agent-host.mjs).\n *\n * Override with OPENCODE_CURSOR_SIDECAR=1/0 (force on/off).\n */\nimport { execSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { loadCursorSdk } from \"../cursor-runtime.js\";\nimport { SidecarClient, type AgentLike } from \"./sidecar-client.js\";\n\nexport type { AgentLike, AgentRunLike, AgentSendOptions } from \"./sidecar-client.js\";\n\nexport type BackendKind = \"in-process\" | \"sidecar\";\n\nexport interface AgentBackend {\n kind: BackendKind;\n createAgent(options: unknown): Promise<AgentLike>;\n resumeAgent(agentId: string, options: unknown): Promise<AgentLike>;\n}\n\nexport interface BackendEnvironment {\n isBun: boolean;\n /** Resolved node executable, or undefined when not on PATH. */\n nodePath: string | undefined;\n}\n\n/** Pure selection logic (unit-testable without spawning anything). */\nexport function resolveBackendKind(env: BackendEnvironment): BackendKind {\n const override = process.env[\"OPENCODE_CURSOR_SIDECAR\"];\n if (override === \"0\" || override === \"false\") return \"in-process\";\n if (override === \"1\" || override === \"true\") return env.nodePath ? \"sidecar\" : \"in-process\";\n return env.isBun && env.nodePath ? \"sidecar\" : \"in-process\";\n}\n\nfunction detectNode(): string | undefined {\n try {\n const out = execSync(process.platform === \"win32\" ? \"where node\" : \"command -v node\", {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n return out.split(\"\\n\")[0] || undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction detectEnvironment(): BackendEnvironment {\n const isBun = typeof (globalThis as { Bun?: unknown }).Bun !== \"undefined\";\n // Only pay the PATH lookup when the answer can matter.\n const needsNode = isBun || process.env[\"OPENCODE_CURSOR_SIDECAR\"] === \"1\";\n return { isBun, nodePath: needsNode ? detectNode() : process.execPath };\n}\n\nfunction inProcessBackend(): AgentBackend {\n return {\n kind: \"in-process\",\n createAgent: async (options) => {\n const { Agent } = await loadCursorSdk();\n return (await Agent.create(options as never)) as unknown as AgentLike;\n },\n resumeAgent: async (agentId, options) => {\n const { Agent } = await loadCursorSdk();\n return (await Agent.resume(agentId, options as never)) as unknown as AgentLike;\n },\n };\n}\n\n/**\n * Locate the sidecar script across layouts: tsup may place this module in\n * dist/provider/index.js or hoist it into a root-level dist/chunk-*.js, and in\n * dev/tests it runs straight from src/. Try each known relative position.\n */\nexport function resolveSidecarScript(): string | undefined {\n const candidates = [\n \"./sidecar/agent-host.js\", // importer is a chunk at dist root\n \"../sidecar/agent-host.js\", // importer is dist/provider/index.js\n \"../sidecar/agent-host.mjs\", // importer is src/provider/*.ts (dev/tests)\n ];\n for (const candidate of candidates) {\n const path = fileURLToPath(new URL(candidate, import.meta.url));\n if (existsSync(path)) return path;\n }\n return undefined;\n}\n\nfunction sidecarBackend(nodePath: string, scriptPath: string): AgentBackend {\n const client = new SidecarClient({ scriptPath, nodePath });\n return {\n kind: \"sidecar\",\n createAgent: (options) => client.createAgent(options),\n resumeAgent: (agentId, options) => client.resumeAgent(agentId, options),\n };\n}\n\nlet cached: AgentBackend | undefined;\n\n/** Resolve (and cache) the agent backend for this process. */\nexport function loadAgentBackend(): AgentBackend {\n if (!cached) {\n const env = detectEnvironment();\n const kind = resolveBackendKind(env);\n const scriptPath = kind === \"sidecar\" ? resolveSidecarScript() : undefined;\n // A user who explicitly opted out (OPENCODE_CURSOR_SIDECAR=0/false) has\n // accepted the in-process behavior and should not be warned.\n const override = process.env[\"OPENCODE_CURSOR_SIDECAR\"];\n const optedOut = override === \"0\" || override === \"false\";\n if (env.isBun && !optedOut && (kind === \"in-process\" || !scriptPath)) {\n console.error(\n \"[opencode-cursor] Running under Bun without a usable Node sidecar \" +\n `(node: ${env.nodePath ?? \"not found\"}, script: ${scriptPath ?? \"not found\"}): ` +\n \"Cursor native tool calls may fail (Bun node:http2 incompatibility). \" +\n \"Install Node.js to enable the sidecar, or set OPENCODE_CURSOR_SIDECAR=0 \" +\n \"to silence this warning.\",\n );\n }\n cached =\n kind === \"sidecar\" && env.nodePath && scriptPath\n ? sidecarBackend(env.nodePath, scriptPath)\n : inProcessBackend();\n }\n return cached;\n}\n\n/** Test hook. */\nexport function resetAgentBackend(): void {\n cached = undefined;\n}\n","/**\n * Client half of the Node sidecar (see src/sidecar/agent-host.mjs for the\n * protocol and the why). Spawns one Node child per client and multiplexes\n * agent create/resume/send/cancel/close requests over JSON-lines stdio,\n * exposing agents through the same minimal surface the provider already\n * consumes ({@link AgentLike}), so session-pool/agent-events need no\n * sidecar-specific logic.\n */\nimport { spawn, type ChildProcessByStdio } from \"node:child_process\";\nimport { createInterface, type Interface } from \"node:readline\";\nimport type { Readable, Writable } from \"node:stream\";\n\n/** Minimal run surface the provider consumes (subset of the SDK's Run). */\nexport interface AgentRunLike {\n wait(): Promise<{ status: string; result?: string }>;\n cancel(): void | Promise<void>;\n}\n\nexport interface AgentSendOptions {\n mode?: string;\n onDelta?: (input: { update: Record<string, unknown> & { type: string } }) => void;\n local?: { force?: boolean };\n}\n\n/** Minimal agent surface the provider consumes (subset of the SDK's SDKAgent). */\nexport interface AgentLike {\n agentId: string;\n send(message: unknown, options?: AgentSendOptions): Promise<AgentRunLike>;\n close(): void;\n}\n\nexport interface SidecarClientOptions {\n /** Path to the agent-host script. */\n scriptPath: string;\n /** Node executable; default \"node\" from PATH. */\n nodePath?: string;\n /** Extra environment for the child (merged over process.env). */\n env?: Record<string, string>;\n /** Mirror child stderr to this process (debug aid). */\n debug?: boolean;\n}\n\ninterface Pending {\n resolve: (msg: Record<string, unknown>) => void;\n reject: (err: Error) => void;\n /** Streaming hooks for \"send\" requests. */\n onUpdate?: (update: Record<string, unknown> & { type: string }) => void;\n onResult?: (result: { status: string; result?: string }) => void;\n onStreamError?: (err: Error) => void;\n}\n\nfunction reviveError(error: unknown): Error {\n const e = (error ?? {}) as { name?: string; message?: string };\n const err = new Error(e.message ?? \"sidecar error\");\n if (e.name) err.name = e.name;\n return err;\n}\n\nexport class SidecarClient {\n private readonly options: SidecarClientOptions;\n private child: ChildProcessByStdio<Writable, Readable, Readable> | undefined;\n private reader: Interface | undefined;\n private readonly pending = new Map<number, Pending>();\n private nextId = 1;\n private disposed = false;\n\n constructor(options: SidecarClientOptions) {\n this.options = options;\n }\n\n /** Spawn (or reuse) the child process. */\n private ensureChild(): ChildProcessByStdio<Writable, Readable, Readable> {\n if (this.disposed) throw new Error(\"cursor sidecar client disposed\");\n if (this.child) return this.child;\n\n const child = spawn(this.options.nodePath ?? \"node\", [this.options.scriptPath], {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env: { ...process.env, ...this.options.env },\n });\n this.child = child;\n\n this.reader = createInterface({ input: child.stdout });\n this.reader.on(\"line\", (line) => this.handleLine(line));\n child.stderr.on(\"data\", (chunk: Buffer) => {\n if (this.options.debug || process.env[\"OPENCODE_CURSOR_DEBUG\"]) {\n process.stderr.write(`[cursor:sidecar] ${chunk}`);\n }\n });\n child.on(\"exit\", (code) => {\n this.failAll(new Error(`cursor sidecar exited (code ${code ?? \"unknown\"})`));\n this.child = undefined;\n this.reader?.close();\n this.reader = undefined;\n });\n child.on(\"error\", (err) => {\n this.failAll(new Error(`cursor sidecar failed to start: ${err.message}`));\n this.child = undefined;\n });\n this.updateRefs();\n return child;\n }\n\n /**\n * Keep the child (and its pipes) from holding the parent's event loop open\n * while idle, but ref it whenever a reply is outstanding so the loop can't\n * exit mid-request. Without this, any process that uses the provider and\n * never dispose()s — scripts, tests, opencode itself on shutdown — hangs.\n */\n private updateRefs(): void {\n const child = this.child;\n if (!child) return;\n const refable = [child, child.stdin, child.stdout, child.stderr] as Array<{\n ref?: () => void;\n unref?: () => void;\n }>;\n if (this.pending.size > 0) {\n for (const target of refable) target.ref?.();\n } else {\n for (const target of refable) target.unref?.();\n }\n }\n\n private failAll(err: Error): void {\n for (const pending of this.pending.values()) {\n pending.onStreamError?.(err);\n pending.reject(err);\n }\n this.pending.clear();\n this.updateRefs();\n }\n\n private handleLine(line: string): void {\n if (!line.trim()) return;\n let msg: Record<string, unknown>;\n try {\n msg = JSON.parse(line) as Record<string, unknown>;\n } catch {\n return; // ignore non-protocol noise on stdout\n }\n const id = msg[\"id\"];\n if (typeof id !== \"number\") return;\n const pending = this.pending.get(id);\n if (!pending) return;\n\n const ev = msg[\"ev\"];\n if (ev === \"update\") {\n pending.onUpdate?.(msg[\"update\"] as Record<string, unknown> & { type: string });\n return;\n }\n if (ev === \"result\") {\n this.pending.delete(id);\n this.updateRefs();\n pending.onResult?.(msg[\"result\"] as { status: string; result?: string });\n return;\n }\n if (ev === \"error\") {\n this.pending.delete(id);\n this.updateRefs();\n pending.onStreamError?.(reviveError(msg[\"error\"]));\n return;\n }\n\n if (msg[\"ok\"] === true) {\n // \"send\" acks stay pending for their streaming terminal event.\n if (!pending.onResult) {\n this.pending.delete(id);\n this.updateRefs();\n }\n pending.resolve(msg);\n } else {\n this.pending.delete(id);\n this.updateRefs();\n pending.reject(reviveError(msg[\"error\"]));\n }\n }\n\n private request(\n payload: Record<string, unknown>,\n hooks?: Pick<Pending, \"onUpdate\" | \"onResult\" | \"onStreamError\">,\n ): Promise<Record<string, unknown>> {\n const child = this.ensureChild();\n const id = this.nextId++;\n return new Promise<Record<string, unknown>>((resolve, reject) => {\n this.pending.set(id, { resolve, reject, ...hooks });\n this.updateRefs();\n child.stdin.write(`${JSON.stringify({ id, ...payload })}\\n`, (err) => {\n if (err) {\n this.pending.delete(id);\n this.updateRefs();\n reject(err);\n }\n });\n });\n }\n\n async createAgent(options: unknown): Promise<AgentLike> {\n const res = await this.request({ op: \"create\", options });\n return this.wrapAgent(String(res[\"agentId\"]));\n }\n\n async resumeAgent(agentId: string, options: unknown): Promise<AgentLike> {\n const res = await this.request({ op: \"resume\", agentId, options });\n return this.wrapAgent(String(res[\"agentId\"]));\n }\n\n private wrapAgent(agentId: string): AgentLike {\n return {\n agentId,\n send: (message, options) => this.sendTurn(agentId, message, options),\n close: () => {\n void this.request({ op: \"close\", agentId }).catch(() => {\n // best effort, mirrors SDKAgent.close()\n });\n },\n };\n }\n\n private async sendTurn(\n agentId: string,\n message: unknown,\n options?: AgentSendOptions,\n ): Promise<AgentRunLike> {\n let settle!: {\n resolve: (r: { status: string; result?: string }) => void;\n reject: (e: Error) => void;\n };\n const waited = new Promise<{ status: string; result?: string }>((resolve, reject) => {\n settle = { resolve, reject };\n });\n // Avoid unhandled-rejection noise when the consumer never calls wait().\n waited.catch(() => {});\n\n let sendId: number | undefined;\n const ack = this.request(\n {\n op: \"send\",\n agentId,\n message,\n ...(options?.mode ? { mode: options.mode } : {}),\n ...(options?.local?.force ? { force: true } : {}),\n },\n {\n onUpdate: (update) => options?.onDelta?.({ update }),\n onResult: (result) => settle.resolve(result),\n onStreamError: (err) => settle.reject(err),\n },\n );\n // The request id is allocated synchronously inside request(); capture it\n // for cancel by reading the id we just used.\n sendId = this.nextId - 1;\n\n await ack;\n return {\n wait: () => waited,\n cancel: async () => {\n if (sendId === undefined) return;\n await this.request({ op: \"cancel\", sendId }).catch(() => {});\n },\n };\n }\n\n /** Kill the child and reject anything in flight. */\n dispose(): void {\n this.disposed = true;\n this.failAll(new Error(\"cursor sidecar client disposed\"));\n this.reader?.close();\n this.reader = undefined;\n this.child?.kill();\n this.child = undefined;\n }\n}\n","import { mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir, tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { TranscriptRecord } from \"./transcript-fingerprint.js\";\n\n/**\n * Best-effort disk persistence for the session pool's fingerprint records, so\n * `session: \"auto\"` survives opencode restarts: the pool can re-resume a\n * session's Cursor agent (whose conversation lives in Cursor's own checkpoint\n * store) instead of paying a cache-cold full-transcript replay.\n *\n * Follows the model-cache pattern: JSON under `~/.cache/opencode-cursor/`,\n * never throws, treats the file as an optimization only. Multiple opencode\n * processes write last-wins on the whole file — a lost record costs exactly\n * one self-healing full replay, which is the same as not having the store.\n */\n\n/** A record persists this long after its last turn before being pruned. */\nconst ENTRY_TTL_MS = 7 * 24 * 60 * 60 * 1000;\n/** Cap stored sessions (most recently used win) to bound file growth. */\nconst MAX_ENTRIES = 200;\n\nexport interface StoredSessionRecord extends TranscriptRecord {\n\tupdatedAt: number;\n}\n\ninterface StoreEnvelope {\n\tsessions: Record<string, StoredSessionRecord>;\n}\n\nfunction storeDir(): string {\n\tconst base =\n\t\tprocess.env.XDG_CACHE_HOME?.trim() ||\n\t\t(homedir() ? join(homedir(), \".cache\") : tmpdir());\n\treturn join(base, \"opencode-cursor\");\n}\n\nfunction storeFile(): string {\n\treturn join(storeDir(), \"session-pool.json\");\n}\n\nfunction isStoredRecord(value: unknown): value is StoredSessionRecord {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst v = value as Record<string, unknown>;\n\treturn (\n\t\ttypeof v[\"agentId\"] === \"string\" &&\n\t\ttypeof v[\"systemHash\"] === \"string\" &&\n\t\tArray.isArray(v[\"userHashes\"]) &&\n\t\t(v[\"userHashes\"] as unknown[]).every((h) => typeof h === \"string\") &&\n\t\ttypeof v[\"updatedAt\"] === \"number\"\n\t);\n}\n\n/** Load persisted records, dropping expired/corrupt entries. Never throws. */\nexport function loadSessionRecords(\n\tnow = Date.now(),\n): Map<string, StoredSessionRecord> {\n\tconst out = new Map<string, StoredSessionRecord>();\n\ttry {\n\t\tconst parsed = JSON.parse(\n\t\t\treadFileSync(storeFile(), \"utf8\"),\n\t\t) as StoreEnvelope;\n\t\tif (typeof parsed?.sessions !== \"object\" || parsed.sessions === null)\n\t\t\treturn out;\n\t\tfor (const [key, value] of Object.entries(parsed.sessions)) {\n\t\t\tif (!isStoredRecord(value)) continue;\n\t\t\tif (now - value.updatedAt > ENTRY_TTL_MS) continue;\n\t\t\tout.set(key, value);\n\t\t}\n\t} catch {\n\t\t// Missing/corrupt store: start empty.\n\t}\n\treturn out;\n}\n\n/** Persist records (pruned to TTL + entry cap). Best-effort; never throws. */\nexport function saveSessionRecords(\n\trecords: ReadonlyMap<string, StoredSessionRecord>,\n\tnow = Date.now(),\n): void {\n\ttry {\n\t\tconst live = [...records.entries()]\n\t\t\t.filter(([, r]) => now - r.updatedAt <= ENTRY_TTL_MS)\n\t\t\t.sort(([, a], [, b]) => b.updatedAt - a.updatedAt)\n\t\t\t.slice(0, MAX_ENTRIES);\n\t\tmkdirSync(storeDir(), { recursive: true });\n\t\tconst envelope: StoreEnvelope = { sessions: Object.fromEntries(live) };\n\t\twriteFileSync(storeFile(), JSON.stringify(envelope), \"utf8\");\n\t} catch {\n\t\t// Persistence is an optimization; ignore write failures.\n\t}\n}\n\n/** Delete the store file (test/diagnostic helper). Never throws. */\nexport function deleteSessionStore(): void {\n\ttry {\n\t\trmSync(storeFile(), { force: true });\n\t} catch {\n\t\t// best effort\n\t}\n}\n","import type {\n\tAgentDefinition,\n\tAgentModeOption,\n\tMcpServerConfig,\n\tModelSelection,\n\tSettingSource,\n} from \"@cursor/sdk\";\nimport { loadAgentBackend, type AgentLike } from \"./agent-backend.js\";\nimport {\n\tdeleteSessionStore,\n\tloadSessionRecords,\n\tsaveSessionRecords,\n\ttype StoredSessionRecord,\n} from \"./session-store.js\";\nimport type { TranscriptRecord } from \"./transcript-fingerprint.js\";\n\n/** sessionID -> fingerprint record, so a session reuses one Cursor agent across turns. */\nconst pool = new Map<string, StoredSessionRecord>();\n\n/**\n * Lazily merge disk-persisted records into the in-memory pool (memory wins),\n * so `session: \"auto\"` resumes a session's Cursor agent even after an opencode\n * restart. The agent's conversation itself lives in Cursor's checkpoint store;\n * this only restores our agentId + fingerprint bookkeeping.\n */\nlet hydrated = false;\nfunction hydrate(): void {\n\tif (hydrated) return;\n\thydrated = true;\n\tfor (const [key, record] of loadSessionRecords()) {\n\t\tif (!pool.has(key)) pool.set(key, record);\n\t}\n}\n\n/** Read the fingerprint record pooled for a session (undefined if none). */\nexport function getSessionRecord(\n\tsessionID: string,\n): TranscriptRecord | undefined {\n\thydrate();\n\treturn pool.get(sessionID);\n}\n\n/** Test/diagnostic helpers. */\nexport function getPooledAgentId(sessionID: string): string | undefined {\n\thydrate();\n\treturn pool.get(sessionID)?.agentId;\n}\nexport function clearAgentPool(): void {\n\tpool.clear();\n\thydrated = true; // don't re-hydrate stale disk state into a cleared pool\n\tdeleteSessionStore();\n}\n/** Test hook: drop in-memory state only, as if the process restarted. */\nexport function resetSessionPoolMemory(): void {\n\tpool.clear();\n\thydrated = false;\n}\n\nexport interface AcquireAgentParams {\n\tapiKey: string;\n\tmodelSelection: ModelSelection;\n\tmode: AgentModeOption;\n\tcwd: string;\n\tsettingSources?: SettingSource[];\n\tsandbox?: boolean;\n\tmcpServers?: Record<string, McpServerConfig>;\n\tagents?: Record<string, AgentDefinition>;\n\tname?: string;\n\t/**\n\t * Resume this Cursor agent before falling back to a fresh create. Set for a\n\t * fingerprinted \"continuation\" (the pooled agentId) or an explicit\n\t * `providerOptions.cursor.agentId`. A failed resume degrades to create.\n\t */\n\tresumeAgentId?: string;\n\t/**\n\t * Pool the resulting agent under this opencode session id. When set, the\n\t * agent persists across turns (release() does not close it) and `record` is\n\t * stored for the next turn's classification. When undefined, no pooling and\n\t * the agent is closed on release.\n\t */\n\tpoolKey?: string;\n\t/** Fingerprint of the current prompt, stored when `poolKey` is set. */\n\trecord?: { systemHash: string; userHashes: string[]; mcpHash?: string };\n}\n\nexport interface AcquiredAgent {\n\tagent: AgentLike;\n\t/** True when an existing agent was resumed (send only the new turn). */\n\tresumed: boolean;\n\t/** Close the agent unless it's pooled (pooled agents persist for the next turn). */\n\trelease: () => void;\n}\n\n/**\n * Get an agent to run a turn. Attempts a resume of `resumeAgentId` when given,\n * otherwise creates a fresh agent; a failed resume degrades to a fresh create\n * (so a stale/expired pool entry becomes a correct full-transcript turn rather\n * than an error). When `poolKey` is set, the resulting agent + `record` are\n * pooled for the session and survive `release()`.\n */\nexport async function acquireAgent(\n\tparams: AcquireAgentParams,\n): Promise<AcquiredAgent> {\n\tconst backend = loadAgentBackend();\n\n\tconst createOptions = {\n\t\tapiKey: params.apiKey,\n\t\tmodel: params.modelSelection,\n\t\tmode: params.mode,\n\t\tlocal: {\n\t\t\tcwd: params.cwd,\n\t\t\t...(params.settingSources\n\t\t\t\t? { settingSources: params.settingSources }\n\t\t\t\t: {}),\n\t\t\t...(params.sandbox !== undefined\n\t\t\t\t? { sandboxOptions: { enabled: params.sandbox } }\n\t\t\t\t: {}),\n\t\t},\n\t\t...(params.mcpServers ? { mcpServers: params.mcpServers } : {}),\n\t\t...(params.agents ? { agents: params.agents } : {}),\n\t\t...(params.name ? { name: params.name } : {}),\n\t};\n\n\tlet agent: AgentLike | undefined;\n\tlet resumed = false;\n\tif (params.resumeAgentId) {\n\t\ttry {\n\t\t\tagent = await backend.resumeAgent(params.resumeAgentId, createOptions);\n\t\t\tresumed = true;\n\t\t} catch {\n\t\t\t// Stale/expired id: fall through to a fresh create (full replay).\n\t\t}\n\t}\n\tif (!agent) {\n\t\tagent = await backend.createAgent(createOptions);\n\t}\n\n\tconst pooling = params.poolKey !== undefined;\n\tif (pooling && params.record) {\n\t\thydrate();\n\t\tpool.set(params.poolKey!, {\n\t\t\tagentId: agent.agentId,\n\t\t\tsystemHash: params.record.systemHash,\n\t\t\tuserHashes: params.record.userHashes,\n\t\t\t...(params.record.mcpHash !== undefined\n\t\t\t\t? { mcpHash: params.record.mcpHash }\n\t\t\t\t: {}),\n\t\t\tupdatedAt: Date.now(),\n\t\t});\n\t\t// Persist so session reuse survives opencode restarts (best-effort).\n\t\tsaveSessionRecords(pool);\n\t}\n\n\tconst release = () => {\n\t\tif (!pooling) {\n\t\t\ttry {\n\t\t\t\tagent!.close();\n\t\t\t} catch {\n\t\t\t\t// best effort\n\t\t\t}\n\t\t}\n\t};\n\n\treturn { agent, resumed, release };\n}\n"],"mappings":"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","names":["cached"]}
@@ -6,7 +6,7 @@ import {
6
6
  resolveControls,
7
7
  resolveCursorApiKey,
8
8
  streamAgentTurn
9
- } from "../chunk-BTI2NHEE.js";
9
+ } from "../chunk-KGDYXGZL.js";
10
10
 
11
11
  // src/model-cache.ts
12
12
  import { mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -4,7 +4,7 @@ import {
4
4
  resolveControls,
5
5
  resolveCursorApiKey,
6
6
  streamAgentTurn
7
- } from "../chunk-BTI2NHEE.js";
7
+ } from "../chunk-KGDYXGZL.js";
8
8
 
9
9
  // src/provider/index.ts
10
10
  import { NoSuchModelError } from "@ai-sdk/provider";
@@ -258,6 +258,15 @@ var NATIVE_ADAPTERS = {
258
258
  }
259
259
  },
260
260
  // Cursor `read` → opencode `read`.
261
+ //
262
+ // Cursor's read tool takes ONLY `{ path }` — there is no `offset`/`limit`/
263
+ // line-range arg (see `@cursor/sdk` `ReadArgsSchema`, a `{ path: string }`
264
+ // "strip" object). The model therefore cannot request a sub-range, so two
265
+ // same-path reads in a transcript are RE-READS of the same content, never
266
+ // "different sections". The only per-call detail available is in the result
267
+ // `value` (`content`, `totalLines`, `fileSize`); we derive the lines-read
268
+ // count from `content` and surface `linesReturned/totalLines` in the title
269
+ // so a reader can see how much was read and spot redundant re-reads.
261
270
  read: {
262
271
  tool: "read",
263
272
  input: (args) => ({ filePath: strField(args, "path") ?? "" }),
@@ -266,12 +275,17 @@ var NATIVE_ADAPTERS = {
266
275
  if (content === void 0) return null;
267
276
  const filePath = strField(args, "path") ?? "";
268
277
  const totalLines = numField(value, "totalLines");
278
+ const fileSize = numField(value, "fileSize");
279
+ const linesReturned = content.split("\n").length;
280
+ const lineLabel = totalLines !== void 0 ? `${linesReturned}/${totalLines} lines` : `${linesReturned} lines`;
269
281
  return {
270
- title: filePath,
282
+ title: `${filePath} (${lineLabel})`,
271
283
  metadata: {
272
284
  preview: content.split("\n").slice(0, 20).join("\n"),
273
285
  loaded: [],
274
- ...totalLines !== void 0 ? { totalLines } : {}
286
+ linesReturned,
287
+ ...totalLines !== void 0 ? { totalLines } : {},
288
+ ...fileSize !== void 0 ? { fileSize } : {}
275
289
  },
276
290
  output: content
277
291
  };
@@ -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","../../src/provider/transcript-fingerprint.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 that\n\t * 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 * Session reuse strategy: `\"auto\"` (default) resumes the pooled Cursor agent\n\t * and sends only the new message on a clean continuation, falling back to a\n\t * fresh agent + full transcript on edits/reverts/compaction/side calls; `true`\n\t * is an alias for `\"auto\"`; `false` always creates a fresh agent per turn.\n\t */\n\tsession?: boolean | \"auto\";\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\tsession: options.session ?? \"auto\",\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, getSessionRecord } from \"./session-pool.js\";\nimport {\n\tclassifyTurn,\n\tfingerprint,\n\tmcpServersFingerprint,\n} from \"./transcript-fingerprint.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 from opencode's config. */\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 * Session reuse strategy:\n\t * - `\"auto\"` (default): fingerprint-guarded reuse — resume the pooled Cursor\n\t * agent and send only the new message on a clean continuation, otherwise\n\t * fall back to a fresh agent + full transcript. Robust to opencode's\n\t * non-chat side calls, message edits, reverts, and compaction.\n\t * - `true`: alias for `\"auto\"`.\n\t * - `false`: always create a fresh agent per turn and re-send the full\n\t * transcript (the original behavior; the escape hatch).\n\t */\n\tsession?: boolean | \"auto\";\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\t// MCP servers may be re-forwarded per turn by the plugin's chat.params hook\n\t\t// (reflecting live opencode enable/disable). When present, the dynamic set\n\t\t// wins over the static startup snapshot baked into config.mcpServers.\n\t\tconst dynamicMcp = providerOptions?.[\"mcpServers\"] as\n\t\t\t| Record<string, McpServerConfig>\n\t\t\t| undefined;\n\t\tconst mcpServers = dynamicMcp ?? this.config.mcpServers;\n\t\tconst mcpHash = mcpServersFingerprint(mcpServers);\n\t\t// `session` defaults to \"auto\" (fingerprint-guarded reuse); `true` is an\n\t\t// alias for \"auto\"; `false` keeps the per-turn-fresh full-transcript path.\n\t\tconst sessionEnabled = (this.config.session ?? \"auto\") !== false;\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\t\t// The plugin may mark opencode's non-chat side calls (e.g. title\n\t\t// generation) so they never resume or disturb the pooled agent.\n\t\tconst ephemeral = providerOptions?.[\"ephemeral\"] === true;\n\n\t\t// Decide create-vs-resume and whether to pool, from the turn classification.\n\t\tconst usePool = sessionEnabled && Boolean(sessionID) && !explicitAgentId;\n\t\tlet resumeAgentId: string | undefined = explicitAgentId;\n\t\tlet poolKey: string | undefined;\n\t\tlet record:\n\t\t\t| { systemHash: string; userHashes: string[]; mcpHash?: string }\n\t\t\t| undefined;\n\t\tif (usePool) {\n\t\t\tconst classification = ephemeral\n\t\t\t\t? {\n\t\t\t\t\t\tkind: \"side-call\" as const,\n\t\t\t\t\t\tfingerprint: fingerprint(options.prompt),\n\t\t\t\t\t}\n\t\t\t\t: classifyTurn(getSessionRecord(sessionID!), options.prompt);\n\t\t\tswitch (classification.kind) {\n\t\t\t\tcase \"continuation\": {\n\t\t\t\t\tconst prev = getSessionRecord(sessionID!);\n\t\t\t\t\t// A resumed agent keeps its original MCP servers, so only resume\n\t\t\t\t\t// when the live MCP set is unchanged; otherwise create fresh so the\n\t\t\t\t\t// new server set takes effect (re-pooled under the same session).\n\t\t\t\t\tif (prev?.mcpHash === mcpHash) {\n\t\t\t\t\t\tresumeAgentId = prev?.agentId;\n\t\t\t\t\t}\n\t\t\t\t\tpoolKey = sessionID;\n\t\t\t\t\trecord = { ...classification.fingerprint, mcpHash };\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"new\":\n\t\t\t\tcase \"divergence\":\n\t\t\t\t\tpoolKey = sessionID;\n\t\t\t\t\trecord = { ...classification.fingerprint, mcpHash };\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"side-call\":\n\t\t\t\t\t// fresh ephemeral agent; pool left untouched.\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (process.env[\"OPENCODE_CURSOR_DEBUG\"] === \"1\") {\n\t\t\t\tconst label =\n\t\t\t\t\tclassification.kind === \"continuation\"\n\t\t\t\t\t\t? \"resume\"\n\t\t\t\t\t\t: `fresh:${classification.kind}`;\n\t\t\t\tconsole.error(\n\t\t\t\t\t`[cursor:debug] turn classification=${label} session=${sessionID}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\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...(mcpServers ? { mcpServers } : {}),\n\t\t\t...(this.config.agents ? { agents: this.config.agents } : {}),\n\t\t\t...(poolKey ? { name: `opencode/${sessionID!.slice(-8)}` } : {}),\n\t\t\t...(resumeAgentId ? { resumeAgentId } : {}),\n\t\t\t...(poolKey ? { poolKey } : {}),\n\t\t\t...(record ? { record } : {}),\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 * Caps on inlined tool payloads in the flattened transcript. Tool outputs are\n * INCLUDED (truncated) rather than dropped so a fresh/diverged agent still sees\n * what prior tools produced, while a huge file read or search dump can't bloat\n * the replayed message unbounded.\n */\nconst TOOL_RESULT_CAP = 2000;\nconst TOOL_ARGS_CAP = 500;\n\nfunction stringify(value: unknown): string {\n\tif (typeof value === \"string\") return value;\n\ttry {\n\t\treturn JSON.stringify(value ?? null);\n\t} catch {\n\t\treturn String(value);\n\t}\n}\n\nfunction truncate(text: string, cap: number): string {\n\treturn text.length > cap\n\t\t? `${text.slice(0, cap)}…[+${text.length - cap} chars]`\n\t\t: text;\n}\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(\n\tprompt: LanguageModelV3Prompt,\n): SDKUserMessage {\n\tconst lines: string[] = [];\n\tconst images: SDKImage[] = [];\n\n\tprompt.forEach((message, index) => {\n\t\tconst isLast = index === prompt.length - 1;\n\t\tswitch (message.role) {\n\t\t\tcase \"system\":\n\t\t\t\tlines.push(`# System\\n${message.content}`);\n\t\t\t\tbreak;\n\t\t\tcase \"user\": {\n\t\t\t\tconst text: string[] = [];\n\t\t\t\tfor (const part of message.content) {\n\t\t\t\t\tif (part.type === \"text\") text.push(part.text);\n\t\t\t\t\telse if (\n\t\t\t\t\t\tpart.type === \"file\" &&\n\t\t\t\t\t\tpart.mediaType.startsWith(\"image/\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst image = fileToImage(part.data, part.mediaType);\n\t\t\t\t\t\t// Only attach images natively for the final user turn; earlier ones\n\t\t\t\t\t\t// are referenced by transcript order.\n\t\t\t\t\t\tif (isLast && image) images.push(image);\n\t\t\t\t\t\ttext.push(\"[image attached]\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlines.push(`# User\\n${text.join(\"\\n\")}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"assistant\": {\n\t\t\t\tconst text: string[] = [];\n\t\t\t\tfor (const part of message.content) {\n\t\t\t\t\tif (part.type === \"text\") text.push(part.text);\n\t\t\t\t\telse if (part.type === \"reasoning\")\n\t\t\t\t\t\ttext.push(`(thinking) ${part.text}`);\n\t\t\t\t\telse if (part.type === \"tool-call\")\n\t\t\t\t\t\ttext.push(\n\t\t\t\t\t\t\t`[called ${part.toolName}(${truncate(stringify(part.input), TOOL_ARGS_CAP)})]`,\n\t\t\t\t\t\t);\n\t\t\t\t\telse if (part.type === \"tool-result\")\n\t\t\t\t\t\ttext.push(\n\t\t\t\t\t\t\t`[result of ${part.toolName}: ${truncate(stringify(part.output), TOOL_RESULT_CAP)}]`,\n\t\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tlines.push(`# Assistant\\n${text.join(\"\\n\")}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"tool\": {\n\t\t\t\tfor (const part of message.content) {\n\t\t\t\t\tif (part.type === \"tool-result\") {\n\t\t\t\t\t\tlines.push(\n\t\t\t\t\t\t\t`# Tool result (${part.toolName})\\n${truncate(stringify(part.output), TOOL_RESULT_CAP)}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\n\tconst out: SDKUserMessage = { text: lines.join(\"\\n\\n\") };\n\tif (images.length > 0) out.images = images;\n\treturn out;\n}\n\nfunction fileToImage(\n\tdata: string | Uint8Array | URL,\n\tmediaType: string,\n): SDKImage | undefined {\n\tif (data instanceof URL) return { url: data.toString() };\n\tif (typeof data === \"string\") {\n\t\t// Either a URL or already-base64 encoded data.\n\t\tif (/^https?:\\/\\//i.test(data)) return { url: data };\n\t\treturn { data, mimeType: mediaType };\n\t}\n\tif (data instanceof Uint8Array) {\n\t\treturn { data: Buffer.from(data).toString(\"base64\"), mimeType: mediaType };\n\t}\n\treturn 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(\n\tprompt: LanguageModelV3Prompt,\n): SDKUserMessage | undefined {\n\tconst last = prompt[prompt.length - 1];\n\tif (!last || last.role !== \"user\") return undefined;\n\n\tconst text: string[] = [];\n\tconst images: SDKImage[] = [];\n\tfor (const part of last.content) {\n\t\tif (part.type === \"text\") text.push(part.text);\n\t\telse if (part.type === \"file\" && part.mediaType.startsWith(\"image/\")) {\n\t\t\tconst image = fileToImage(part.data, part.mediaType);\n\t\t\tif (image) images.push(image);\n\t\t\ttext.push(\"[image attached]\");\n\t\t}\n\t}\n\n\tconst out: SDKUserMessage = { text: text.join(\"\\n\") };\n\tif (images.length > 0) out.images = images;\n\treturn out;\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. `myserver/find_symbol` → `cursor_myserver_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, args) => {\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\tconst pattern = strField(args, \"globPattern\") ?? \"\";\n\t\t\tconst dir = strField(args, \"targetDirectory\");\n\t\t\treturn {\n\t\t\t\ttitle: dir ? `${pattern} in ${dir}` : pattern,\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, args) => {\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\tconst pattern = strField(args, \"pattern\") ?? \"\";\n\t\t\tconst glob = strField(args, \"glob\");\n\t\t\tconst path = strField(args, \"path\");\n\t\t\tlet title = pattern;\n\t\t\tif (glob) title += ` (${glob})`;\n\t\t\tif (path) title += ` in ${path}`;\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\tconst parts = 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// Edit calls buffer until their result (no parts yet) — keep\n\t\t\t\t\t\t\t\t// the open narration part alive across the gap. Every other\n\t\t\t\t\t\t\t\t// tool emits immediately, so close open text/reasoning first\n\t\t\t\t\t\t\t\t// so post-tool narration lands in a later part (hosts position\n\t\t\t\t\t\t\t\t// parts where they START).\n\t\t\t\t\t\t\t\tif (parts.length > 0) {\n\t\t\t\t\t\t\t\t\tcloseText();\n\t\t\t\t\t\t\t\t\tcloseReasoning();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfor (const part of parts) {\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\tconst parts = 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\tif (parts.length > 0) {\n\t\t\t\t\t\t\t\t\tcloseText();\n\t\t\t\t\t\t\t\t\tcloseReasoning();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfor (const part of parts) {\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","import { createHash } from \"node:crypto\";\nimport type { LanguageModelV3Prompt } from \"@ai-sdk/provider\";\nimport type { McpServerConfig } from \"@cursor/sdk\";\n\n/**\n * Per-session bookkeeping that lets the provider decide, on each turn, whether\n * it can safely resume the pooled Cursor agent (and send only the new message)\n * or must start fresh and re-send the whole transcript.\n *\n * We hash ONLY the parts opencode replays verbatim — the system prompt and the\n * user messages. We deliberately do NOT hash assistant output: opencode\n * re-serializes our streamed reply (reasoning, tool blocks) back into the next\n * prompt in a shape we can't predict byte-for-byte, so hashing it would\n * spuriously mismatch every turn and silently collapse to always-full-replay.\n * The system prompt + user-message sequence is the stable identity of a\n * conversation.\n */\nexport interface TranscriptRecord {\n\t/** Cursor agentId currently pooled for the session. */\n\tagentId: string;\n\t/** Hash of the concatenated system message content. */\n\tsystemHash: string;\n\t/** Ordered hash per user message (text + a stable image token). */\n\tuserHashes: string[];\n\t/**\n\t * Hash of the MCP server set the pooled agent was created with. A resumed\n\t * Cursor agent keeps its original MCP servers, so when this changes between\n\t * turns the pool must create a fresh agent rather than resume.\n\t */\n\tmcpHash?: string;\n}\n\n/** What kind of turn this is relative to the session's last recorded state. */\nexport type TurnKind =\n\t/** No prior record: first turn of the session. */\n\t| \"new\"\n\t/** System prompt differs (opencode's non-chat side call, e.g. title gen). */\n\t| \"side-call\"\n\t/** Prior user sequence is a strict prefix + exactly one new trailing user msg. */\n\t| \"continuation\"\n\t/** Edit / revert / compaction / multiple queued msgs — prior prefix no longer holds. */\n\t| \"divergence\";\n\nexport interface TurnClassification {\n\tkind: TurnKind;\n\t/** Fingerprint of the CURRENT prompt, to store when (re)pooling. */\n\tfingerprint: { systemHash: string; userHashes: string[] };\n}\n\nfunction sha(input: string): string {\n\treturn createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\n/**\n * Stable hash of the MCP server set handed to `Agent.create`. Keys are sorted\n * so map ordering never changes the result; empty/undefined sets hash to \"\".\n */\nexport function mcpServersFingerprint(\n\tservers: Record<string, McpServerConfig> | undefined,\n): string {\n\tif (!servers) return \"\";\n\tconst keys = Object.keys(servers).sort();\n\tif (keys.length === 0) return \"\";\n\treturn sha(JSON.stringify(keys.map((k) => [k, servers[k]])));\n}\n\n/** Stable key for one user message: its text plus a token per attached image. */\nfunction userMessageKey(\n\tmessage: Extract<LanguageModelV3Prompt[number], { role: \"user\" }>,\n): string {\n\tconst parts: string[] = [];\n\tfor (const part of message.content) {\n\t\tif (part.type === \"text\") parts.push(`t:${part.text}`);\n\t\telse if (part.type === \"file\") parts.push(`f:${part.mediaType}`);\n\t}\n\treturn parts.join(\"\\n\");\n}\n\n/** Compute the system + user-message fingerprint of a prompt. */\nexport function fingerprint(prompt: LanguageModelV3Prompt): {\n\tsystemHash: string;\n\tuserHashes: string[];\n} {\n\tconst systemParts: string[] = [];\n\tconst userHashes: string[] = [];\n\tfor (const message of prompt) {\n\t\tif (message.role === \"system\") systemParts.push(message.content);\n\t\telse if (message.role === \"user\")\n\t\t\tuserHashes.push(sha(userMessageKey(message)));\n\t}\n\treturn { systemHash: sha(systemParts.join(\"\\n\")), userHashes };\n}\n\n/** True when `prefix` is a strict element-wise prefix of `full`. */\nfunction isStrictPrefix(prefix: string[], full: string[]): boolean {\n\tif (prefix.length >= full.length) return false;\n\tfor (let i = 0; i < prefix.length; i++) {\n\t\tif (prefix[i] !== full[i]) return false;\n\t}\n\treturn true;\n}\n\n/**\n * Classify the current turn against the session's last recorded fingerprint.\n *\n * Order matters:\n * 1. no record -> \"new\"\n * 2. system prompt changed -> \"side-call\" (don't touch the pool)\n * 3. prior user hashes are a strict prefix AND exactly one new trailing user\n * message AND the last prompt message is a user turn -> \"continuation\"\n * 4. otherwise -> \"divergence\" (edit/revert/compaction/queued)\n *\n * Worst case on any misclassification is a single wasted full replay that\n * self-heals on the next turn — never worse than the `session: false` default.\n */\nexport function classifyTurn(\n\tprev: TranscriptRecord | undefined,\n\tprompt: LanguageModelV3Prompt,\n): TurnClassification {\n\tconst fp = fingerprint(prompt);\n\tif (!prev) return { kind: \"new\", fingerprint: fp };\n\tif (prev.systemHash !== fp.systemHash)\n\t\treturn { kind: \"side-call\", fingerprint: fp };\n\n\tconst lastIsUser = prompt[prompt.length - 1]?.role === \"user\";\n\tconst exactlyOneNew = fp.userHashes.length === prev.userHashes.length + 1;\n\tif (\n\t\tlastIsUser &&\n\t\texactlyOneNew &&\n\t\tisStrictPrefix(prev.userHashes, fp.userHashes)\n\t) {\n\t\treturn { kind: \"continuation\", fingerprint: fp };\n\t}\n\treturn { kind: \"divergence\", fingerprint: fp };\n}\n"],"mappings":"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","names":["toolName"]}
1
+ {"version":3,"sources":["../../src/provider/index.ts","../../src/provider/language-model.ts","../../src/provider/message-map.ts","../../src/provider/stream-map.ts","../../src/provider/transcript-fingerprint.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 that\n\t * 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 * Session reuse strategy: `\"auto\"` (default) resumes the pooled Cursor agent\n\t * and sends only the new message on a clean continuation, falling back to a\n\t * fresh agent + full transcript on edits/reverts/compaction/side calls; `true`\n\t * is an alias for `\"auto\"`; `false` always creates a fresh agent per turn.\n\t */\n\tsession?: boolean | \"auto\";\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\tsession: options.session ?? \"auto\",\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, getSessionRecord } from \"./session-pool.js\";\nimport {\n\tclassifyTurn,\n\tfingerprint,\n\tmcpServersFingerprint,\n} from \"./transcript-fingerprint.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 from opencode's config. */\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 * Session reuse strategy:\n\t * - `\"auto\"` (default): fingerprint-guarded reuse — resume the pooled Cursor\n\t * agent and send only the new message on a clean continuation, otherwise\n\t * fall back to a fresh agent + full transcript. Robust to opencode's\n\t * non-chat side calls, message edits, reverts, and compaction.\n\t * - `true`: alias for `\"auto\"`.\n\t * - `false`: always create a fresh agent per turn and re-send the full\n\t * transcript (the original behavior; the escape hatch).\n\t */\n\tsession?: boolean | \"auto\";\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\t// MCP servers may be re-forwarded per turn by the plugin's chat.params hook\n\t\t// (reflecting live opencode enable/disable). When present, the dynamic set\n\t\t// wins over the static startup snapshot baked into config.mcpServers.\n\t\tconst dynamicMcp = providerOptions?.[\"mcpServers\"] as\n\t\t\t| Record<string, McpServerConfig>\n\t\t\t| undefined;\n\t\tconst mcpServers = dynamicMcp ?? this.config.mcpServers;\n\t\tconst mcpHash = mcpServersFingerprint(mcpServers);\n\t\t// `session` defaults to \"auto\" (fingerprint-guarded reuse); `true` is an\n\t\t// alias for \"auto\"; `false` keeps the per-turn-fresh full-transcript path.\n\t\tconst sessionEnabled = (this.config.session ?? \"auto\") !== false;\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\t\t// The plugin may mark opencode's non-chat side calls (e.g. title\n\t\t// generation) so they never resume or disturb the pooled agent.\n\t\tconst ephemeral = providerOptions?.[\"ephemeral\"] === true;\n\n\t\t// Decide create-vs-resume and whether to pool, from the turn classification.\n\t\tconst usePool = sessionEnabled && Boolean(sessionID) && !explicitAgentId;\n\t\tlet resumeAgentId: string | undefined = explicitAgentId;\n\t\tlet poolKey: string | undefined;\n\t\tlet record:\n\t\t\t| { systemHash: string; userHashes: string[]; mcpHash?: string }\n\t\t\t| undefined;\n\t\tif (usePool) {\n\t\t\tconst classification = ephemeral\n\t\t\t\t? {\n\t\t\t\t\t\tkind: \"side-call\" as const,\n\t\t\t\t\t\tfingerprint: fingerprint(options.prompt),\n\t\t\t\t\t}\n\t\t\t\t: classifyTurn(getSessionRecord(sessionID!), options.prompt);\n\t\t\tswitch (classification.kind) {\n\t\t\t\tcase \"continuation\": {\n\t\t\t\t\tconst prev = getSessionRecord(sessionID!);\n\t\t\t\t\t// A resumed agent keeps its original MCP servers, so only resume\n\t\t\t\t\t// when the live MCP set is unchanged; otherwise create fresh so the\n\t\t\t\t\t// new server set takes effect (re-pooled under the same session).\n\t\t\t\t\tif (prev?.mcpHash === mcpHash) {\n\t\t\t\t\t\tresumeAgentId = prev?.agentId;\n\t\t\t\t\t}\n\t\t\t\t\tpoolKey = sessionID;\n\t\t\t\t\trecord = { ...classification.fingerprint, mcpHash };\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"new\":\n\t\t\t\tcase \"divergence\":\n\t\t\t\t\tpoolKey = sessionID;\n\t\t\t\t\trecord = { ...classification.fingerprint, mcpHash };\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"side-call\":\n\t\t\t\t\t// fresh ephemeral agent; pool left untouched.\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (process.env[\"OPENCODE_CURSOR_DEBUG\"] === \"1\") {\n\t\t\t\tconst label =\n\t\t\t\t\tclassification.kind === \"continuation\"\n\t\t\t\t\t\t? \"resume\"\n\t\t\t\t\t\t: `fresh:${classification.kind}`;\n\t\t\t\tconsole.error(\n\t\t\t\t\t`[cursor:debug] turn classification=${label} session=${sessionID}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\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...(mcpServers ? { mcpServers } : {}),\n\t\t\t...(this.config.agents ? { agents: this.config.agents } : {}),\n\t\t\t...(poolKey ? { name: `opencode/${sessionID!.slice(-8)}` } : {}),\n\t\t\t...(resumeAgentId ? { resumeAgentId } : {}),\n\t\t\t...(poolKey ? { poolKey } : {}),\n\t\t\t...(record ? { record } : {}),\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 * Caps on inlined tool payloads in the flattened transcript. Tool outputs are\n * INCLUDED (truncated) rather than dropped so a fresh/diverged agent still sees\n * what prior tools produced, while a huge file read or search dump can't bloat\n * the replayed message unbounded.\n */\nconst TOOL_RESULT_CAP = 2000;\nconst TOOL_ARGS_CAP = 500;\n\nfunction stringify(value: unknown): string {\n\tif (typeof value === \"string\") return value;\n\ttry {\n\t\treturn JSON.stringify(value ?? null);\n\t} catch {\n\t\treturn String(value);\n\t}\n}\n\nfunction truncate(text: string, cap: number): string {\n\treturn text.length > cap\n\t\t? `${text.slice(0, cap)}…[+${text.length - cap} chars]`\n\t\t: text;\n}\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(\n\tprompt: LanguageModelV3Prompt,\n): SDKUserMessage {\n\tconst lines: string[] = [];\n\tconst images: SDKImage[] = [];\n\n\tprompt.forEach((message, index) => {\n\t\tconst isLast = index === prompt.length - 1;\n\t\tswitch (message.role) {\n\t\t\tcase \"system\":\n\t\t\t\tlines.push(`# System\\n${message.content}`);\n\t\t\t\tbreak;\n\t\t\tcase \"user\": {\n\t\t\t\tconst text: string[] = [];\n\t\t\t\tfor (const part of message.content) {\n\t\t\t\t\tif (part.type === \"text\") text.push(part.text);\n\t\t\t\t\telse if (\n\t\t\t\t\t\tpart.type === \"file\" &&\n\t\t\t\t\t\tpart.mediaType.startsWith(\"image/\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst image = fileToImage(part.data, part.mediaType);\n\t\t\t\t\t\t// Only attach images natively for the final user turn; earlier ones\n\t\t\t\t\t\t// are referenced by transcript order.\n\t\t\t\t\t\tif (isLast && image) images.push(image);\n\t\t\t\t\t\ttext.push(\"[image attached]\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlines.push(`# User\\n${text.join(\"\\n\")}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"assistant\": {\n\t\t\t\tconst text: string[] = [];\n\t\t\t\tfor (const part of message.content) {\n\t\t\t\t\tif (part.type === \"text\") text.push(part.text);\n\t\t\t\t\telse if (part.type === \"reasoning\")\n\t\t\t\t\t\ttext.push(`(thinking) ${part.text}`);\n\t\t\t\t\telse if (part.type === \"tool-call\")\n\t\t\t\t\t\ttext.push(\n\t\t\t\t\t\t\t`[called ${part.toolName}(${truncate(stringify(part.input), TOOL_ARGS_CAP)})]`,\n\t\t\t\t\t\t);\n\t\t\t\t\telse if (part.type === \"tool-result\")\n\t\t\t\t\t\ttext.push(\n\t\t\t\t\t\t\t`[result of ${part.toolName}: ${truncate(stringify(part.output), TOOL_RESULT_CAP)}]`,\n\t\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tlines.push(`# Assistant\\n${text.join(\"\\n\")}`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"tool\": {\n\t\t\t\tfor (const part of message.content) {\n\t\t\t\t\tif (part.type === \"tool-result\") {\n\t\t\t\t\t\tlines.push(\n\t\t\t\t\t\t\t`# Tool result (${part.toolName})\\n${truncate(stringify(part.output), TOOL_RESULT_CAP)}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\n\tconst out: SDKUserMessage = { text: lines.join(\"\\n\\n\") };\n\tif (images.length > 0) out.images = images;\n\treturn out;\n}\n\nfunction fileToImage(\n\tdata: string | Uint8Array | URL,\n\tmediaType: string,\n): SDKImage | undefined {\n\tif (data instanceof URL) return { url: data.toString() };\n\tif (typeof data === \"string\") {\n\t\t// Either a URL or already-base64 encoded data.\n\t\tif (/^https?:\\/\\//i.test(data)) return { url: data };\n\t\treturn { data, mimeType: mediaType };\n\t}\n\tif (data instanceof Uint8Array) {\n\t\treturn { data: Buffer.from(data).toString(\"base64\"), mimeType: mediaType };\n\t}\n\treturn 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(\n\tprompt: LanguageModelV3Prompt,\n): SDKUserMessage | undefined {\n\tconst last = prompt[prompt.length - 1];\n\tif (!last || last.role !== \"user\") return undefined;\n\n\tconst text: string[] = [];\n\tconst images: SDKImage[] = [];\n\tfor (const part of last.content) {\n\t\tif (part.type === \"text\") text.push(part.text);\n\t\telse if (part.type === \"file\" && part.mediaType.startsWith(\"image/\")) {\n\t\t\tconst image = fileToImage(part.data, part.mediaType);\n\t\t\tif (image) images.push(image);\n\t\t\ttext.push(\"[image attached]\");\n\t\t}\n\t}\n\n\tconst out: SDKUserMessage = { text: text.join(\"\\n\") };\n\tif (images.length > 0) out.images = images;\n\treturn out;\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. `myserver/find_symbol` → `cursor_myserver_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\t//\n\t// Cursor's read tool takes ONLY `{ path }` — there is no `offset`/`limit`/\n\t// line-range arg (see `@cursor/sdk` `ReadArgsSchema`, a `{ path: string }`\n\t// \"strip\" object). The model therefore cannot request a sub-range, so two\n\t// same-path reads in a transcript are RE-READS of the same content, never\n\t// \"different sections\". The only per-call detail available is in the result\n\t// `value` (`content`, `totalLines`, `fileSize`); we derive the lines-read\n\t// count from `content` and surface `linesReturned/totalLines` in the title\n\t// so a reader can see how much was read and spot redundant re-reads.\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\tconst fileSize = numField(value, \"fileSize\");\n\t\t\tconst linesReturned = content.split(\"\\n\").length;\n\t\t\tconst lineLabel =\n\t\t\t\ttotalLines !== undefined\n\t\t\t\t\t? `${linesReturned}/${totalLines} lines`\n\t\t\t\t\t: `${linesReturned} lines`;\n\t\t\treturn {\n\t\t\t\ttitle: `${filePath} (${lineLabel})`,\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\tlinesReturned,\n\t\t\t\t\t...(totalLines !== undefined ? { totalLines } : {}),\n\t\t\t\t\t...(fileSize !== undefined ? { fileSize } : {}),\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, args) => {\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\tconst pattern = strField(args, \"globPattern\") ?? \"\";\n\t\t\tconst dir = strField(args, \"targetDirectory\");\n\t\t\treturn {\n\t\t\t\ttitle: dir ? `${pattern} in ${dir}` : pattern,\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, args) => {\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\tconst pattern = strField(args, \"pattern\") ?? \"\";\n\t\t\tconst glob = strField(args, \"glob\");\n\t\t\tconst path = strField(args, \"path\");\n\t\t\tlet title = pattern;\n\t\t\tif (glob) title += ` (${glob})`;\n\t\t\tif (path) title += ` in ${path}`;\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\tconst parts = 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// Edit calls buffer until their result (no parts yet) — keep\n\t\t\t\t\t\t\t\t// the open narration part alive across the gap. Every other\n\t\t\t\t\t\t\t\t// tool emits immediately, so close open text/reasoning first\n\t\t\t\t\t\t\t\t// so post-tool narration lands in a later part (hosts position\n\t\t\t\t\t\t\t\t// parts where they START).\n\t\t\t\t\t\t\t\tif (parts.length > 0) {\n\t\t\t\t\t\t\t\t\tcloseText();\n\t\t\t\t\t\t\t\t\tcloseReasoning();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfor (const part of parts) {\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\tconst parts = 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\tif (parts.length > 0) {\n\t\t\t\t\t\t\t\t\tcloseText();\n\t\t\t\t\t\t\t\t\tcloseReasoning();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfor (const part of parts) {\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","import { createHash } from \"node:crypto\";\nimport type { LanguageModelV3Prompt } from \"@ai-sdk/provider\";\nimport type { McpServerConfig } from \"@cursor/sdk\";\n\n/**\n * Per-session bookkeeping that lets the provider decide, on each turn, whether\n * it can safely resume the pooled Cursor agent (and send only the new message)\n * or must start fresh and re-send the whole transcript.\n *\n * We hash ONLY the parts opencode replays verbatim — the system prompt and the\n * user messages. We deliberately do NOT hash assistant output: opencode\n * re-serializes our streamed reply (reasoning, tool blocks) back into the next\n * prompt in a shape we can't predict byte-for-byte, so hashing it would\n * spuriously mismatch every turn and silently collapse to always-full-replay.\n * The system prompt + user-message sequence is the stable identity of a\n * conversation.\n */\nexport interface TranscriptRecord {\n\t/** Cursor agentId currently pooled for the session. */\n\tagentId: string;\n\t/** Hash of the concatenated system message content. */\n\tsystemHash: string;\n\t/** Ordered hash per user message (text + a stable image token). */\n\tuserHashes: string[];\n\t/**\n\t * Hash of the MCP server set the pooled agent was created with. A resumed\n\t * Cursor agent keeps its original MCP servers, so when this changes between\n\t * turns the pool must create a fresh agent rather than resume.\n\t */\n\tmcpHash?: string;\n}\n\n/** What kind of turn this is relative to the session's last recorded state. */\nexport type TurnKind =\n\t/** No prior record: first turn of the session. */\n\t| \"new\"\n\t/** System prompt differs (opencode's non-chat side call, e.g. title gen). */\n\t| \"side-call\"\n\t/** Prior user sequence is a strict prefix + exactly one new trailing user msg. */\n\t| \"continuation\"\n\t/** Edit / revert / compaction / multiple queued msgs — prior prefix no longer holds. */\n\t| \"divergence\";\n\nexport interface TurnClassification {\n\tkind: TurnKind;\n\t/** Fingerprint of the CURRENT prompt, to store when (re)pooling. */\n\tfingerprint: { systemHash: string; userHashes: string[] };\n}\n\nfunction sha(input: string): string {\n\treturn createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\n/**\n * Stable hash of the MCP server set handed to `Agent.create`. Keys are sorted\n * so map ordering never changes the result; empty/undefined sets hash to \"\".\n */\nexport function mcpServersFingerprint(\n\tservers: Record<string, McpServerConfig> | undefined,\n): string {\n\tif (!servers) return \"\";\n\tconst keys = Object.keys(servers).sort();\n\tif (keys.length === 0) return \"\";\n\treturn sha(JSON.stringify(keys.map((k) => [k, servers[k]])));\n}\n\n/** Stable key for one user message: its text plus a token per attached image. */\nfunction userMessageKey(\n\tmessage: Extract<LanguageModelV3Prompt[number], { role: \"user\" }>,\n): string {\n\tconst parts: string[] = [];\n\tfor (const part of message.content) {\n\t\tif (part.type === \"text\") parts.push(`t:${part.text}`);\n\t\telse if (part.type === \"file\") parts.push(`f:${part.mediaType}`);\n\t}\n\treturn parts.join(\"\\n\");\n}\n\n/** Compute the system + user-message fingerprint of a prompt. */\nexport function fingerprint(prompt: LanguageModelV3Prompt): {\n\tsystemHash: string;\n\tuserHashes: string[];\n} {\n\tconst systemParts: string[] = [];\n\tconst userHashes: string[] = [];\n\tfor (const message of prompt) {\n\t\tif (message.role === \"system\") systemParts.push(message.content);\n\t\telse if (message.role === \"user\")\n\t\t\tuserHashes.push(sha(userMessageKey(message)));\n\t}\n\treturn { systemHash: sha(systemParts.join(\"\\n\")), userHashes };\n}\n\n/** True when `prefix` is a strict element-wise prefix of `full`. */\nfunction isStrictPrefix(prefix: string[], full: string[]): boolean {\n\tif (prefix.length >= full.length) return false;\n\tfor (let i = 0; i < prefix.length; i++) {\n\t\tif (prefix[i] !== full[i]) return false;\n\t}\n\treturn true;\n}\n\n/**\n * Classify the current turn against the session's last recorded fingerprint.\n *\n * Order matters:\n * 1. no record -> \"new\"\n * 2. system prompt changed -> \"side-call\" (don't touch the pool)\n * 3. prior user hashes are a strict prefix AND exactly one new trailing user\n * message AND the last prompt message is a user turn -> \"continuation\"\n * 4. otherwise -> \"divergence\" (edit/revert/compaction/queued)\n *\n * Worst case on any misclassification is a single wasted full replay that\n * self-heals on the next turn — never worse than the `session: false` default.\n */\nexport function classifyTurn(\n\tprev: TranscriptRecord | undefined,\n\tprompt: LanguageModelV3Prompt,\n): TurnClassification {\n\tconst fp = fingerprint(prompt);\n\tif (!prev) return { kind: \"new\", fingerprint: fp };\n\tif (prev.systemHash !== fp.systemHash)\n\t\treturn { kind: \"side-call\", fingerprint: fp };\n\n\tconst lastIsUser = prompt[prompt.length - 1]?.role === \"user\";\n\tconst exactlyOneNew = fp.userHashes.length === prev.userHashes.length + 1;\n\tif (\n\t\tlastIsUser &&\n\t\texactlyOneNew &&\n\t\tisStrictPrefix(prev.userHashes, fp.userHashes)\n\t) {\n\t\treturn { kind: \"continuation\", fingerprint: fp };\n\t}\n\treturn { kind: \"divergence\", fingerprint: fp };\n}\n"],"mappings":"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","names":["toolName"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stablekernel/opencode-cursor",
3
- "version": "0.4.0",
3
+ "version": "0.4.1-next.0",
4
4
  "description": "opencode provider plugin backed by the official Cursor SDK (@cursor/sdk) — adds a Cursor provider and lists its models",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -56,7 +56,7 @@
56
56
  },
57
57
  "dependencies": {
58
58
  "@cursor/sdk": "^1.0.18",
59
- "@opencode-ai/plugin": "^1.17.1"
59
+ "@opencode-ai/plugin": "^1.17.7"
60
60
  },
61
61
  "overrides": {
62
62
  "undici": "^6.24.0",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api-key.ts","../src/provider/agent-events.ts","../src/provider/controls.ts","../src/native-binding.ts","../src/cursor-runtime.ts","../src/provider/agent-backend.ts","../src/provider/sidecar-client.ts","../src/provider/session-store.ts","../src/provider/session-pool.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\n\n/** Environment variable the Cursor SDK itself reads as a fallback. */\nexport const CURSOR_API_KEY_ENV_VAR = \"CURSOR_API_KEY\";\n\n/**\n * Values that are *not* real keys but rather instructions to read the key from\n * the environment. opencode config commonly stores literal `{env:...}` style\n * placeholders, and users sometimes paste the variable name itself.\n */\nconst PLACEHOLDERS = new Set<string>([\n CURSOR_API_KEY_ENV_VAR,\n `$${CURSOR_API_KEY_ENV_VAR}`,\n `\\${${CURSOR_API_KEY_ENV_VAR}}`,\n]);\n\n/**\n * Resolve a usable Cursor API key.\n *\n * Resolution order: an explicit, non-placeholder candidate (e.g. from opencode\n * auth storage or provider options) wins; otherwise fall back to the\n * `CURSOR_API_KEY` environment variable. Returns `undefined` when no key is\n * available so callers can present a clear \"needs auth\" path.\n *\n * The key is never logged or persisted by this module.\n */\nexport function resolveCursorApiKey(candidate?: string | null): string | undefined {\n const trimmed = candidate?.trim();\n if (trimmed && !PLACEHOLDERS.has(trimmed)) return trimmed;\n const fromEnv = process.env[CURSOR_API_KEY_ENV_VAR]?.trim();\n return fromEnv ? fromEnv : undefined;\n}\n\n/**\n * Produce a short, non-reversible fingerprint of an API key. Used purely to key\n * the on-disk model cache so the cache invalidates when the key changes. The\n * raw key is never written to disk.\n */\nexport function fingerprintApiKey(apiKey: string): string {\n return createHash(\"sha256\").update(apiKey).digest(\"hex\").slice(0, 16);\n}\n","import type { AgentModeOption, SDKUserMessage } from \"@cursor/sdk\";\nimport type { AgentLike, AgentRunLike } from \"./agent-backend.js\";\n\n/** Token usage as reported by Cursor's `turn-ended` update. */\nexport interface CursorUsage {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n}\n\n/** Normalized events bridged from the Cursor SDK's push callbacks. */\nexport type CursorEvent =\n | { type: \"text-delta\"; text: string }\n | { type: \"reasoning-delta\"; text: string }\n | { type: \"tool-call\"; id: string; name: string; input: unknown }\n | { type: \"tool-result\"; id: string; name: string; result: unknown; isError: boolean }\n | { type: \"usage\"; usage: CursorUsage }\n | { type: \"finish\"; text?: string };\n\nexport interface StreamAgentTurnOptions {\n mode: AgentModeOption;\n abortSignal?: AbortSignal;\n}\n\n/**\n * Human-readable name for a Cursor tool call. Most Cursor tools carry their\n * name in `toolCall.type` (shell/read/edit/…), but an MCP tool call has\n * `type: \"mcp\"` with the real tool in `args.toolName` (and server in\n * `args.providerIdentifier`) — surface that instead of the literal \"mcp\".\n */\nfunction toolDisplayName(toolCall: ({ type?: string } & Record<string, any>) | undefined): string {\n if (!toolCall) return \"tool\";\n if (toolCall.type === \"mcp\") {\n const name = toolCall.args?.toolName;\n const server = toolCall.args?.providerIdentifier;\n if (name) return server ? `${server}/${name}` : String(name);\n return \"mcp\";\n }\n return toolCall.type ?? \"tool\";\n}\n\n/**\n * Stream a single turn on an already-acquired Cursor agent and yield normalized\n * events. The agent's lifecycle (create/resume/close) is owned by the caller\n * (see session-pool.ts) so it can be reused across turns. The SDK streams via\n * `onDelta` callbacks; we bridge those into a pull-based async generator so both\n * `doStream` and `doGenerate` can consume them.\n */\nexport async function* streamAgentTurn(\n agent: AgentLike,\n message: SDKUserMessage,\n options: StreamAgentTurnOptions,\n): AsyncGenerator<CursorEvent> {\n const queue: CursorEvent[] = [];\n let wake: (() => void) | undefined;\n let finished = false;\n let failure: unknown;\n\n // Opt-in stderr tracing of what the live agent emits (set OPENCODE_CURSOR_DEBUG=1).\n const debug = process.env.OPENCODE_CURSOR_DEBUG === \"1\";\n const counts: Record<string, number> = {};\n\n const push = (event: CursorEvent) => {\n queue.push(event);\n wake?.();\n wake = undefined;\n };\n\n const onDelta = ({ update }: { update: { type: string } & Record<string, any> }) => {\n if (debug) counts[update.type] = (counts[update.type] ?? 0) + 1;\n switch (update.type) {\n case \"text-delta\":\n push({ type: \"text-delta\", text: update.text });\n break;\n case \"thinking-delta\":\n push({ type: \"reasoning-delta\", text: update.text });\n break;\n case \"tool-call-started\":\n push({\n type: \"tool-call\",\n id: String(update.callId),\n name: toolDisplayName(update.toolCall),\n input: update.toolCall?.args ?? {},\n });\n break;\n case \"tool-call-completed\": {\n const tool = update.toolCall ?? {};\n const result = tool.result;\n // MCP failures often arrive as {status:\"success\", value:{isError:true}}\n // (the MCP-protocol error flag), not as a top-level status error.\n const mcpError = tool.type === \"mcp\" && result?.value?.isError === true;\n push({\n type: \"tool-result\",\n id: String(update.callId),\n name: toolDisplayName(tool),\n result: result ?? null,\n isError: result?.status === \"error\" || mcpError,\n });\n break;\n }\n case \"turn-ended\":\n if (update.usage) push({ type: \"usage\", usage: update.usage as CursorUsage });\n break;\n }\n };\n\n const runHolder: { run?: AgentRunLike } = {};\n const onAbort = () => {\n void Promise.resolve(runHolder.run?.cancel()).catch(() => {});\n };\n options.abortSignal?.addEventListener(\"abort\", onAbort);\n\n // A previous opencode/CLI crash (or a second instance racing on the same\n // agent store) can leave a persisted run wedged; the SDK then rejects new\n // sends with AgentBusyError. Retry once with the SDK's documented recovery\n // path (local.force expires the wedged run) instead of failing the turn.\n const sendTurn = async (): Promise<AgentRunLike> => {\n try {\n return await agent.send(message, { mode: options.mode, onDelta });\n } catch (err) {\n if (err instanceof Error && err.name === \"AgentBusyError\") {\n if (debug) console.error(\"[cursor:debug] agent busy; retrying send with local.force\");\n return agent.send(message, { mode: options.mode, onDelta, local: { force: true } });\n }\n throw err;\n }\n };\n\n // Kick off the turn. Resolve text from run.wait() for models that don't emit\n // incremental text deltas.\n void sendTurn()\n .then(async (run) => {\n runHolder.run = run;\n const result = await run.wait();\n if (debug) {\n console.error(\n `[cursor:debug] updates=${JSON.stringify(counts)} status=${result.status} resultLen=${(result.result ?? \"\").length}`,\n );\n }\n if (result.status === \"error\") {\n // Surface the failure instead of finishing silently — a silent stop\n // leaves opencode showing dangling tool calls with no explanation.\n throw new Error(\n `Cursor run ended with status \"error\"${result.result ? `: ${result.result}` : \"\"}`,\n );\n }\n // A cancelled run finishes without fabricating final text.\n push({ type: \"finish\", ...(result.status === \"cancelled\" ? {} : { text: result.result }) });\n })\n .catch((err) => {\n failure = err;\n if (debug) console.error(`[cursor:debug] send failed: ${err instanceof Error ? err.message : String(err)}`);\n })\n .finally(() => {\n finished = true;\n wake?.();\n wake = undefined;\n });\n\n try {\n while (true) {\n if (queue.length > 0) {\n yield queue.shift()!;\n continue;\n }\n if (finished) break;\n await new Promise<void>((resolve) => {\n wake = resolve;\n });\n }\n // Drain anything queued right before completion.\n while (queue.length > 0) yield queue.shift()!;\n if (failure) throw failure;\n } finally {\n options.abortSignal?.removeEventListener(\"abort\", onAbort);\n }\n}\n","import type { AgentModeOption, ModelSelection } from \"@cursor/sdk\";\n\n/** Per-model static control defaults (from provider/model config options). */\nexport interface StaticControls {\n mode: AgentModeOption;\n /** Default Cursor model params (id -> value), e.g. { thinking: \"high\" }. */\n params?: Record<string, string>;\n}\n\nexport interface ResolvedControls {\n mode: AgentModeOption;\n modelSelection: ModelSelection;\n}\n\n/**\n * Build a Cursor `ModelSelection` from a model id and an optional map of model\n * params (e.g. `{ thinking: \"high\" }`). Shared by the provider control\n * resolution and the cloud/delegate tools so param handling stays consistent.\n */\nexport function buildModelSelection(\n modelId: string,\n params?: Record<string, string>,\n): ModelSelection {\n const paramList = Object.entries(params ?? {}).map(([id, value]) => ({ id, value }));\n return paramList.length > 0 ? { id: modelId, params: paramList } : { id: modelId };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isMode(value: unknown): value is AgentModeOption {\n return value === \"agent\" || value === \"plan\";\n}\n\n/**\n * Resolve the per-turn Cursor controls from static config plus opencode's\n * per-request `providerOptions.cursor` (which carries merged model `options` and\n * the selected model `variant`). Per-request values win over static defaults.\n *\n * Recognized keys in `providerOptions.cursor`:\n * - `mode`: \"agent\" | \"plan\"\n * - `params`: Record<string,string> of Cursor model params (e.g. { thinking: \"high\" })\n * - `thinking`: string convenience, mapped to the `thinking` param if not already set\n */\nexport function resolveControls(\n modelId: string,\n staticControls: StaticControls,\n providerOptions: Record<string, unknown> | undefined,\n): ResolvedControls {\n const po = providerOptions ?? {};\n\n const mode: AgentModeOption = isMode(po[\"mode\"]) ? po[\"mode\"] : staticControls.mode;\n\n const params: Record<string, string> = { ...(staticControls.params ?? {}) };\n if (isRecord(po[\"params\"])) {\n for (const [key, value] of Object.entries(po[\"params\"])) {\n if (value != null) params[key] = String(value);\n }\n }\n if (typeof po[\"thinking\"] === \"string\" && params[\"thinking\"] === undefined) {\n params[\"thinking\"] = po[\"thinking\"];\n }\n\n return { mode, modelSelection: buildModelSelection(modelId, params) };\n}\n","/**\n * Self-heal for sqlite3's native binding.\n *\n * `@cursor/sdk` depends on `sqlite3` (a native addon). opencode installs\n * plugin packages with Bun, which does not run sqlite3's `install` lifecycle\n * script (`prebuild-install -r napi || node-gyp rebuild`), so the installed\n * tree has **no** `node_sqlite3.node` binary and the SDK crashes at import\n * with \"Could not locate the bindings file\".\n *\n * Before loading the SDK (in-process or via the Node sidecar) we check for a\n * binding and, when it is missing, run sqlite3's own `prebuild-install -r napi`\n * to fetch the prebuilt NAPI binary (ABI-portable across Node versions, also\n * loadable by Bun). Failures degrade to a clear warning; the SDK import then\n * surfaces its own error.\n */\nimport { execSync, spawn } from \"node:child_process\";\nimport { existsSync, readdirSync, statSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join } from \"node:path\";\n\nexport type EnsureResult = \"present\" | \"repaired\" | \"failed\" | \"not-found\";\n\nexport interface EnsureOptions {\n /** Override the sqlite3 package directory (tests). */\n sqliteDir?: string;\n /** Override the repair runner (tests). Returns true when the command succeeded. */\n run?: (sqliteDir: string) => Promise<boolean>;\n /** Override the warning sink (tests). */\n log?: (message: string) => void;\n}\n\n/** Directories (relative to the sqlite3 package root) that may hold the binding. */\nconst BINDING_ROOTS = [\"build\", \"lib/binding\", \"compiled\"];\n\nfunction hasNodeFile(dir: string, depth: number): boolean {\n if (depth < 0) return false;\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return false;\n }\n for (const entry of entries) {\n const path = join(dir, entry);\n if (entry.endsWith(\".node\")) {\n try {\n if (statSync(path).isFile()) return true;\n } catch {\n // ignore unreadable entries\n }\n continue;\n }\n try {\n if (statSync(path).isDirectory() && hasNodeFile(path, depth - 1)) return true;\n } catch {\n // ignore unreadable entries\n }\n }\n return false;\n}\n\n/** True when the sqlite3 package dir contains a compiled `.node` binding. */\nexport function hasSqliteBinding(sqliteDir: string): boolean {\n return BINDING_ROOTS.some((root) => hasNodeFile(join(sqliteDir, root), 3));\n}\n\n/**\n * Locate the sqlite3 package directory that `@cursor/sdk` will load, walking\n * the same resolution chain (our module -> @cursor/sdk -> sqlite3).\n */\nexport function resolveSqliteDir(): string | undefined {\n const req = createRequire(import.meta.url);\n try {\n const sdkPkg = req.resolve(\"@cursor/sdk/package.json\");\n return dirname(createRequire(sdkPkg).resolve(\"sqlite3/package.json\"));\n } catch {\n // fall through: try resolving sqlite3 directly (hoisted installs)\n }\n try {\n return dirname(req.resolve(\"sqlite3/package.json\"));\n } catch {\n return undefined;\n }\n}\n\nfunction detectNodeExecutable(): string {\n const isBun = typeof (globalThis as { Bun?: unknown }).Bun !== \"undefined\";\n if (!isBun) return process.execPath;\n // Under Bun prefer a real Node (matches the sidecar runtime); prebuild-install\n // itself is plain JS, so Bun works as a last resort.\n try {\n const out = execSync(process.platform === \"win32\" ? \"where node\" : \"command -v node\", {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n return out.split(\"\\n\")[0] || process.execPath;\n } catch {\n return process.execPath;\n }\n}\n\n/** Default repair: run sqlite3's own `prebuild-install -r napi` in its package dir. */\nasync function runPrebuildInstall(sqliteDir: string): Promise<boolean> {\n let bin: string;\n try {\n const req = createRequire(join(sqliteDir, \"package.json\"));\n const pkgPath = req.resolve(\"prebuild-install/package.json\");\n const pkg = (await import(pkgPath, { with: { type: \"json\" } })) as {\n default: { bin?: string | Record<string, string> };\n };\n const binField = pkg.default.bin;\n const rel = typeof binField === \"string\" ? binField : binField?.[\"prebuild-install\"];\n if (!rel) return false;\n bin = join(dirname(pkgPath), rel);\n } catch {\n return false;\n }\n if (!existsSync(bin)) return false;\n\n return new Promise<boolean>((resolve) => {\n const child = spawn(detectNodeExecutable(), [bin, \"-r\", \"napi\"], {\n cwd: sqliteDir,\n stdio: [\"ignore\", \"ignore\", \"pipe\"],\n });\n let stderr = \"\";\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString();\n });\n child.on(\"error\", () => resolve(false));\n child.on(\"exit\", (code) => {\n if (code !== 0 && stderr && process.env[\"OPENCODE_CURSOR_DEBUG\"]) {\n console.error(`[opencode-cursor] prebuild-install stderr: ${stderr.trim()}`);\n }\n resolve(code === 0);\n });\n });\n}\n\nlet cached: Promise<EnsureResult> | undefined;\n\n/**\n * Ensure the sqlite3 native binding exists, repairing it once per process if\n * needed. Never throws; \"failed\"/\"not-found\" outcomes warn and let the SDK\n * import surface its own error.\n */\nexport function ensureSqliteBinding(options: EnsureOptions = {}): Promise<EnsureResult> {\n cached ??= (async () => {\n const log = options.log ?? ((message: string) => console.error(message));\n const sqliteDir = options.sqliteDir ?? resolveSqliteDir();\n if (!sqliteDir || !existsSync(join(sqliteDir, \"package.json\"))) {\n return \"not-found\";\n }\n if (hasSqliteBinding(sqliteDir)) return \"present\";\n\n const run = options.run ?? runPrebuildInstall;\n const ok = await run(sqliteDir).catch(() => false);\n if (ok && hasSqliteBinding(sqliteDir)) return \"repaired\";\n\n log(\n `[opencode-cursor] sqlite3 native binding is missing in ${sqliteDir} and automatic ` +\n `repair failed. @cursor/sdk will not load. Fix manually with: ` +\n `cd ${sqliteDir} && npx prebuild-install -r napi (or: npm rebuild sqlite3)`,\n );\n return \"failed\";\n })();\n return cached;\n}\n\n/** Test hook. */\nexport function resetNativeBinding(): void {\n cached = undefined;\n}\n","/**\n * Lazy loader for the official Cursor SDK (`@cursor/sdk`).\n *\n * The SDK is heavy and only needed once a Cursor model is actually used or\n * models are discovered, so it is imported on demand. A failed import (e.g. the\n * dependency is missing) degrades gracefully into a clear error instead of\n * crashing opencode at startup.\n */\nimport { ensureSqliteBinding } from \"./native-binding.js\";\n\nexport type CursorSdkModule = typeof import(\"@cursor/sdk\");\n\nlet cached: Promise<CursorSdkModule> | undefined;\n\nexport async function loadCursorSdk(): Promise<CursorSdkModule> {\n if (!cached) {\n // @cursor/sdk eagerly requires sqlite3 (native addon); opencode's Bun\n // install skips its build script, so repair the binding first if missing.\n cached = ensureSqliteBinding()\n .then(() => import(\"@cursor/sdk\"))\n .catch((err: unknown) => {\n // Allow a later retry if the failure was transient.\n cached = undefined;\n const detail = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[opencode-cursor] Failed to load \"@cursor/sdk\". Make sure it is installed ` +\n `(\\`npm install @cursor/sdk\\`). Original error: ${detail}`,\n );\n });\n }\n return cached;\n}\n","/**\n * Selects where Cursor agents run:\n *\n * - \"in-process\": straight through `@cursor/sdk` in this process (Node — the\n * normal path for tests, scripts, and any non-Bun host).\n * - \"sidecar\": a spawned Node child hosting the SDK (Bun — opencode's runtime —\n * has a `node:http2` bug that kills Cursor's streaming RPC with\n * NGHTTP2_FRAME_SIZE_ERROR, losing tool-completion updates; see\n * src/sidecar/agent-host.mjs).\n *\n * Override with OPENCODE_CURSOR_SIDECAR=1/0 (force on/off).\n */\nimport { execSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { loadCursorSdk } from \"../cursor-runtime.js\";\nimport { ensureSqliteBinding } from \"../native-binding.js\";\nimport { SidecarClient, type AgentLike } from \"./sidecar-client.js\";\n\nexport type { AgentLike, AgentRunLike, AgentSendOptions } from \"./sidecar-client.js\";\n\nexport type BackendKind = \"in-process\" | \"sidecar\";\n\nexport interface AgentBackend {\n kind: BackendKind;\n createAgent(options: unknown): Promise<AgentLike>;\n resumeAgent(agentId: string, options: unknown): Promise<AgentLike>;\n}\n\nexport interface BackendEnvironment {\n isBun: boolean;\n /** Resolved node executable, or undefined when not on PATH. */\n nodePath: string | undefined;\n}\n\n/** Pure selection logic (unit-testable without spawning anything). */\nexport function resolveBackendKind(env: BackendEnvironment): BackendKind {\n const override = process.env[\"OPENCODE_CURSOR_SIDECAR\"];\n if (override === \"0\" || override === \"false\") return \"in-process\";\n if (override === \"1\" || override === \"true\") return env.nodePath ? \"sidecar\" : \"in-process\";\n return env.isBun && env.nodePath ? \"sidecar\" : \"in-process\";\n}\n\nfunction detectNode(): string | undefined {\n try {\n const out = execSync(process.platform === \"win32\" ? \"where node\" : \"command -v node\", {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n return out.split(\"\\n\")[0] || undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction detectEnvironment(): BackendEnvironment {\n const isBun = typeof (globalThis as { Bun?: unknown }).Bun !== \"undefined\";\n // Only pay the PATH lookup when the answer can matter.\n const needsNode = isBun || process.env[\"OPENCODE_CURSOR_SIDECAR\"] === \"1\";\n return { isBun, nodePath: needsNode ? detectNode() : process.execPath };\n}\n\nfunction inProcessBackend(): AgentBackend {\n return {\n kind: \"in-process\",\n createAgent: async (options) => {\n const { Agent } = await loadCursorSdk();\n return (await Agent.create(options as never)) as unknown as AgentLike;\n },\n resumeAgent: async (agentId, options) => {\n const { Agent } = await loadCursorSdk();\n return (await Agent.resume(agentId, options as never)) as unknown as AgentLike;\n },\n };\n}\n\n/**\n * Locate the sidecar script across layouts: tsup may place this module in\n * dist/provider/index.js or hoist it into a root-level dist/chunk-*.js, and in\n * dev/tests it runs straight from src/. Try each known relative position.\n */\nexport function resolveSidecarScript(): string | undefined {\n const candidates = [\n \"./sidecar/agent-host.js\", // importer is a chunk at dist root\n \"../sidecar/agent-host.js\", // importer is dist/provider/index.js\n \"../sidecar/agent-host.mjs\", // importer is src/provider/*.ts (dev/tests)\n ];\n for (const candidate of candidates) {\n const path = fileURLToPath(new URL(candidate, import.meta.url));\n if (existsSync(path)) return path;\n }\n return undefined;\n}\n\nfunction sidecarBackend(nodePath: string, scriptPath: string): AgentBackend {\n const client = new SidecarClient({ scriptPath, nodePath });\n // The sidecar imports @cursor/sdk (which eagerly requires sqlite3's native\n // binding) in the child process; repair the binding before first use.\n return {\n kind: \"sidecar\",\n createAgent: async (options) => {\n await ensureSqliteBinding();\n return client.createAgent(options);\n },\n resumeAgent: async (agentId, options) => {\n await ensureSqliteBinding();\n return client.resumeAgent(agentId, options);\n },\n };\n}\n\nlet cached: AgentBackend | undefined;\n\n/** Resolve (and cache) the agent backend for this process. */\nexport function loadAgentBackend(): AgentBackend {\n if (!cached) {\n const env = detectEnvironment();\n const kind = resolveBackendKind(env);\n const scriptPath = kind === \"sidecar\" ? resolveSidecarScript() : undefined;\n // A user who explicitly opted out (OPENCODE_CURSOR_SIDECAR=0/false) has\n // accepted the in-process behavior and should not be warned.\n const override = process.env[\"OPENCODE_CURSOR_SIDECAR\"];\n const optedOut = override === \"0\" || override === \"false\";\n if (env.isBun && !optedOut && (kind === \"in-process\" || !scriptPath)) {\n console.error(\n \"[opencode-cursor] Running under Bun without a usable Node sidecar \" +\n `(node: ${env.nodePath ?? \"not found\"}, script: ${scriptPath ?? \"not found\"}): ` +\n \"Cursor native tool calls may fail (Bun node:http2 incompatibility). \" +\n \"Install Node.js to enable the sidecar, or set OPENCODE_CURSOR_SIDECAR=0 \" +\n \"to silence this warning.\",\n );\n }\n cached =\n kind === \"sidecar\" && env.nodePath && scriptPath\n ? sidecarBackend(env.nodePath, scriptPath)\n : inProcessBackend();\n }\n return cached;\n}\n\n/** Test hook. */\nexport function resetAgentBackend(): void {\n cached = undefined;\n}\n","/**\n * Client half of the Node sidecar (see src/sidecar/agent-host.mjs for the\n * protocol and the why). Spawns one Node child per client and multiplexes\n * agent create/resume/send/cancel/close requests over JSON-lines stdio,\n * exposing agents through the same minimal surface the provider already\n * consumes ({@link AgentLike}), so session-pool/agent-events need no\n * sidecar-specific logic.\n */\nimport { spawn, type ChildProcessByStdio } from \"node:child_process\";\nimport { createInterface, type Interface } from \"node:readline\";\nimport type { Readable, Writable } from \"node:stream\";\n\n/** Minimal run surface the provider consumes (subset of the SDK's Run). */\nexport interface AgentRunLike {\n wait(): Promise<{ status: string; result?: string }>;\n cancel(): void | Promise<void>;\n}\n\nexport interface AgentSendOptions {\n mode?: string;\n onDelta?: (input: { update: Record<string, unknown> & { type: string } }) => void;\n local?: { force?: boolean };\n}\n\n/** Minimal agent surface the provider consumes (subset of the SDK's SDKAgent). */\nexport interface AgentLike {\n agentId: string;\n send(message: unknown, options?: AgentSendOptions): Promise<AgentRunLike>;\n close(): void;\n}\n\nexport interface SidecarClientOptions {\n /** Path to the agent-host script. */\n scriptPath: string;\n /** Node executable; default \"node\" from PATH. */\n nodePath?: string;\n /** Extra environment for the child (merged over process.env). */\n env?: Record<string, string>;\n /** Mirror child stderr to this process (debug aid). */\n debug?: boolean;\n}\n\ninterface Pending {\n resolve: (msg: Record<string, unknown>) => void;\n reject: (err: Error) => void;\n /** Streaming hooks for \"send\" requests. */\n onUpdate?: (update: Record<string, unknown> & { type: string }) => void;\n onResult?: (result: { status: string; result?: string }) => void;\n onStreamError?: (err: Error) => void;\n}\n\nfunction reviveError(error: unknown): Error {\n const e = (error ?? {}) as { name?: string; message?: string };\n const err = new Error(e.message ?? \"sidecar error\");\n if (e.name) err.name = e.name;\n return err;\n}\n\nexport class SidecarClient {\n private readonly options: SidecarClientOptions;\n private child: ChildProcessByStdio<Writable, Readable, Readable> | undefined;\n private reader: Interface | undefined;\n private readonly pending = new Map<number, Pending>();\n private nextId = 1;\n private disposed = false;\n\n constructor(options: SidecarClientOptions) {\n this.options = options;\n }\n\n /** Spawn (or reuse) the child process. */\n private ensureChild(): ChildProcessByStdio<Writable, Readable, Readable> {\n if (this.disposed) throw new Error(\"cursor sidecar client disposed\");\n if (this.child) return this.child;\n\n const child = spawn(this.options.nodePath ?? \"node\", [this.options.scriptPath], {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env: { ...process.env, ...this.options.env },\n });\n this.child = child;\n\n this.reader = createInterface({ input: child.stdout });\n this.reader.on(\"line\", (line) => this.handleLine(line));\n child.stderr.on(\"data\", (chunk: Buffer) => {\n if (this.options.debug || process.env[\"OPENCODE_CURSOR_DEBUG\"]) {\n process.stderr.write(`[cursor:sidecar] ${chunk}`);\n }\n });\n child.on(\"exit\", (code) => {\n this.failAll(new Error(`cursor sidecar exited (code ${code ?? \"unknown\"})`));\n this.child = undefined;\n this.reader?.close();\n this.reader = undefined;\n });\n child.on(\"error\", (err) => {\n this.failAll(new Error(`cursor sidecar failed to start: ${err.message}`));\n this.child = undefined;\n });\n this.updateRefs();\n return child;\n }\n\n /**\n * Keep the child (and its pipes) from holding the parent's event loop open\n * while idle, but ref it whenever a reply is outstanding so the loop can't\n * exit mid-request. Without this, any process that uses the provider and\n * never dispose()s — scripts, tests, opencode itself on shutdown — hangs.\n */\n private updateRefs(): void {\n const child = this.child;\n if (!child) return;\n const refable = [child, child.stdin, child.stdout, child.stderr] as Array<{\n ref?: () => void;\n unref?: () => void;\n }>;\n if (this.pending.size > 0) {\n for (const target of refable) target.ref?.();\n } else {\n for (const target of refable) target.unref?.();\n }\n }\n\n private failAll(err: Error): void {\n for (const pending of this.pending.values()) {\n pending.onStreamError?.(err);\n pending.reject(err);\n }\n this.pending.clear();\n this.updateRefs();\n }\n\n private handleLine(line: string): void {\n if (!line.trim()) return;\n let msg: Record<string, unknown>;\n try {\n msg = JSON.parse(line) as Record<string, unknown>;\n } catch {\n return; // ignore non-protocol noise on stdout\n }\n const id = msg[\"id\"];\n if (typeof id !== \"number\") return;\n const pending = this.pending.get(id);\n if (!pending) return;\n\n const ev = msg[\"ev\"];\n if (ev === \"update\") {\n pending.onUpdate?.(msg[\"update\"] as Record<string, unknown> & { type: string });\n return;\n }\n if (ev === \"result\") {\n this.pending.delete(id);\n this.updateRefs();\n pending.onResult?.(msg[\"result\"] as { status: string; result?: string });\n return;\n }\n if (ev === \"error\") {\n this.pending.delete(id);\n this.updateRefs();\n pending.onStreamError?.(reviveError(msg[\"error\"]));\n return;\n }\n\n if (msg[\"ok\"] === true) {\n // \"send\" acks stay pending for their streaming terminal event.\n if (!pending.onResult) {\n this.pending.delete(id);\n this.updateRefs();\n }\n pending.resolve(msg);\n } else {\n this.pending.delete(id);\n this.updateRefs();\n pending.reject(reviveError(msg[\"error\"]));\n }\n }\n\n private request(\n payload: Record<string, unknown>,\n hooks?: Pick<Pending, \"onUpdate\" | \"onResult\" | \"onStreamError\">,\n ): Promise<Record<string, unknown>> {\n const child = this.ensureChild();\n const id = this.nextId++;\n return new Promise<Record<string, unknown>>((resolve, reject) => {\n this.pending.set(id, { resolve, reject, ...hooks });\n this.updateRefs();\n child.stdin.write(`${JSON.stringify({ id, ...payload })}\\n`, (err) => {\n if (err) {\n this.pending.delete(id);\n this.updateRefs();\n reject(err);\n }\n });\n });\n }\n\n async createAgent(options: unknown): Promise<AgentLike> {\n const res = await this.request({ op: \"create\", options });\n return this.wrapAgent(String(res[\"agentId\"]));\n }\n\n async resumeAgent(agentId: string, options: unknown): Promise<AgentLike> {\n const res = await this.request({ op: \"resume\", agentId, options });\n return this.wrapAgent(String(res[\"agentId\"]));\n }\n\n private wrapAgent(agentId: string): AgentLike {\n return {\n agentId,\n send: (message, options) => this.sendTurn(agentId, message, options),\n close: () => {\n void this.request({ op: \"close\", agentId }).catch(() => {\n // best effort, mirrors SDKAgent.close()\n });\n },\n };\n }\n\n private async sendTurn(\n agentId: string,\n message: unknown,\n options?: AgentSendOptions,\n ): Promise<AgentRunLike> {\n let settle!: {\n resolve: (r: { status: string; result?: string }) => void;\n reject: (e: Error) => void;\n };\n const waited = new Promise<{ status: string; result?: string }>((resolve, reject) => {\n settle = { resolve, reject };\n });\n // Avoid unhandled-rejection noise when the consumer never calls wait().\n waited.catch(() => {});\n\n let sendId: number | undefined;\n const ack = this.request(\n {\n op: \"send\",\n agentId,\n message,\n ...(options?.mode ? { mode: options.mode } : {}),\n ...(options?.local?.force ? { force: true } : {}),\n },\n {\n onUpdate: (update) => options?.onDelta?.({ update }),\n onResult: (result) => settle.resolve(result),\n onStreamError: (err) => settle.reject(err),\n },\n );\n // The request id is allocated synchronously inside request(); capture it\n // for cancel by reading the id we just used.\n sendId = this.nextId - 1;\n\n await ack;\n return {\n wait: () => waited,\n cancel: async () => {\n if (sendId === undefined) return;\n await this.request({ op: \"cancel\", sendId }).catch(() => {});\n },\n };\n }\n\n /** Kill the child and reject anything in flight. */\n dispose(): void {\n this.disposed = true;\n this.failAll(new Error(\"cursor sidecar client disposed\"));\n this.reader?.close();\n this.reader = undefined;\n this.child?.kill();\n this.child = undefined;\n }\n}\n","import { mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir, tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { TranscriptRecord } from \"./transcript-fingerprint.js\";\n\n/**\n * Best-effort disk persistence for the session pool's fingerprint records, so\n * `session: \"auto\"` survives opencode restarts: the pool can re-resume a\n * session's Cursor agent (whose conversation lives in Cursor's own checkpoint\n * store) instead of paying a cache-cold full-transcript replay.\n *\n * Follows the model-cache pattern: JSON under `~/.cache/opencode-cursor/`,\n * never throws, treats the file as an optimization only. Multiple opencode\n * processes write last-wins on the whole file — a lost record costs exactly\n * one self-healing full replay, which is the same as not having the store.\n */\n\n/** A record persists this long after its last turn before being pruned. */\nconst ENTRY_TTL_MS = 7 * 24 * 60 * 60 * 1000;\n/** Cap stored sessions (most recently used win) to bound file growth. */\nconst MAX_ENTRIES = 200;\n\nexport interface StoredSessionRecord extends TranscriptRecord {\n\tupdatedAt: number;\n}\n\ninterface StoreEnvelope {\n\tsessions: Record<string, StoredSessionRecord>;\n}\n\nfunction storeDir(): string {\n\tconst base =\n\t\tprocess.env.XDG_CACHE_HOME?.trim() ||\n\t\t(homedir() ? join(homedir(), \".cache\") : tmpdir());\n\treturn join(base, \"opencode-cursor\");\n}\n\nfunction storeFile(): string {\n\treturn join(storeDir(), \"session-pool.json\");\n}\n\nfunction isStoredRecord(value: unknown): value is StoredSessionRecord {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst v = value as Record<string, unknown>;\n\treturn (\n\t\ttypeof v[\"agentId\"] === \"string\" &&\n\t\ttypeof v[\"systemHash\"] === \"string\" &&\n\t\tArray.isArray(v[\"userHashes\"]) &&\n\t\t(v[\"userHashes\"] as unknown[]).every((h) => typeof h === \"string\") &&\n\t\ttypeof v[\"updatedAt\"] === \"number\"\n\t);\n}\n\n/** Load persisted records, dropping expired/corrupt entries. Never throws. */\nexport function loadSessionRecords(\n\tnow = Date.now(),\n): Map<string, StoredSessionRecord> {\n\tconst out = new Map<string, StoredSessionRecord>();\n\ttry {\n\t\tconst parsed = JSON.parse(\n\t\t\treadFileSync(storeFile(), \"utf8\"),\n\t\t) as StoreEnvelope;\n\t\tif (typeof parsed?.sessions !== \"object\" || parsed.sessions === null)\n\t\t\treturn out;\n\t\tfor (const [key, value] of Object.entries(parsed.sessions)) {\n\t\t\tif (!isStoredRecord(value)) continue;\n\t\t\tif (now - value.updatedAt > ENTRY_TTL_MS) continue;\n\t\t\tout.set(key, value);\n\t\t}\n\t} catch {\n\t\t// Missing/corrupt store: start empty.\n\t}\n\treturn out;\n}\n\n/** Persist records (pruned to TTL + entry cap). Best-effort; never throws. */\nexport function saveSessionRecords(\n\trecords: ReadonlyMap<string, StoredSessionRecord>,\n\tnow = Date.now(),\n): void {\n\ttry {\n\t\tconst live = [...records.entries()]\n\t\t\t.filter(([, r]) => now - r.updatedAt <= ENTRY_TTL_MS)\n\t\t\t.sort(([, a], [, b]) => b.updatedAt - a.updatedAt)\n\t\t\t.slice(0, MAX_ENTRIES);\n\t\tmkdirSync(storeDir(), { recursive: true });\n\t\tconst envelope: StoreEnvelope = { sessions: Object.fromEntries(live) };\n\t\twriteFileSync(storeFile(), JSON.stringify(envelope), \"utf8\");\n\t} catch {\n\t\t// Persistence is an optimization; ignore write failures.\n\t}\n}\n\n/** Delete the store file (test/diagnostic helper). Never throws. */\nexport function deleteSessionStore(): void {\n\ttry {\n\t\trmSync(storeFile(), { force: true });\n\t} catch {\n\t\t// best effort\n\t}\n}\n","import type {\n\tAgentDefinition,\n\tAgentModeOption,\n\tMcpServerConfig,\n\tModelSelection,\n\tSettingSource,\n} from \"@cursor/sdk\";\nimport { loadAgentBackend, type AgentLike } from \"./agent-backend.js\";\nimport {\n\tdeleteSessionStore,\n\tloadSessionRecords,\n\tsaveSessionRecords,\n\ttype StoredSessionRecord,\n} from \"./session-store.js\";\nimport type { TranscriptRecord } from \"./transcript-fingerprint.js\";\n\n/** sessionID -> fingerprint record, so a session reuses one Cursor agent across turns. */\nconst pool = new Map<string, StoredSessionRecord>();\n\n/**\n * Lazily merge disk-persisted records into the in-memory pool (memory wins),\n * so `session: \"auto\"` resumes a session's Cursor agent even after an opencode\n * restart. The agent's conversation itself lives in Cursor's checkpoint store;\n * this only restores our agentId + fingerprint bookkeeping.\n */\nlet hydrated = false;\nfunction hydrate(): void {\n\tif (hydrated) return;\n\thydrated = true;\n\tfor (const [key, record] of loadSessionRecords()) {\n\t\tif (!pool.has(key)) pool.set(key, record);\n\t}\n}\n\n/** Read the fingerprint record pooled for a session (undefined if none). */\nexport function getSessionRecord(\n\tsessionID: string,\n): TranscriptRecord | undefined {\n\thydrate();\n\treturn pool.get(sessionID);\n}\n\n/** Test/diagnostic helpers. */\nexport function getPooledAgentId(sessionID: string): string | undefined {\n\thydrate();\n\treturn pool.get(sessionID)?.agentId;\n}\nexport function clearAgentPool(): void {\n\tpool.clear();\n\thydrated = true; // don't re-hydrate stale disk state into a cleared pool\n\tdeleteSessionStore();\n}\n/** Test hook: drop in-memory state only, as if the process restarted. */\nexport function resetSessionPoolMemory(): void {\n\tpool.clear();\n\thydrated = false;\n}\n\nexport interface AcquireAgentParams {\n\tapiKey: string;\n\tmodelSelection: ModelSelection;\n\tmode: AgentModeOption;\n\tcwd: string;\n\tsettingSources?: SettingSource[];\n\tsandbox?: boolean;\n\tmcpServers?: Record<string, McpServerConfig>;\n\tagents?: Record<string, AgentDefinition>;\n\tname?: string;\n\t/**\n\t * Resume this Cursor agent before falling back to a fresh create. Set for a\n\t * fingerprinted \"continuation\" (the pooled agentId) or an explicit\n\t * `providerOptions.cursor.agentId`. A failed resume degrades to create.\n\t */\n\tresumeAgentId?: string;\n\t/**\n\t * Pool the resulting agent under this opencode session id. When set, the\n\t * agent persists across turns (release() does not close it) and `record` is\n\t * stored for the next turn's classification. When undefined, no pooling and\n\t * the agent is closed on release.\n\t */\n\tpoolKey?: string;\n\t/** Fingerprint of the current prompt, stored when `poolKey` is set. */\n\trecord?: { systemHash: string; userHashes: string[]; mcpHash?: string };\n}\n\nexport interface AcquiredAgent {\n\tagent: AgentLike;\n\t/** True when an existing agent was resumed (send only the new turn). */\n\tresumed: boolean;\n\t/** Close the agent unless it's pooled (pooled agents persist for the next turn). */\n\trelease: () => void;\n}\n\n/**\n * Get an agent to run a turn. Attempts a resume of `resumeAgentId` when given,\n * otherwise creates a fresh agent; a failed resume degrades to a fresh create\n * (so a stale/expired pool entry becomes a correct full-transcript turn rather\n * than an error). When `poolKey` is set, the resulting agent + `record` are\n * pooled for the session and survive `release()`.\n */\nexport async function acquireAgent(\n\tparams: AcquireAgentParams,\n): Promise<AcquiredAgent> {\n\tconst backend = loadAgentBackend();\n\n\tconst createOptions = {\n\t\tapiKey: params.apiKey,\n\t\tmodel: params.modelSelection,\n\t\tmode: params.mode,\n\t\tlocal: {\n\t\t\tcwd: params.cwd,\n\t\t\t...(params.settingSources\n\t\t\t\t? { settingSources: params.settingSources }\n\t\t\t\t: {}),\n\t\t\t...(params.sandbox !== undefined\n\t\t\t\t? { sandboxOptions: { enabled: params.sandbox } }\n\t\t\t\t: {}),\n\t\t},\n\t\t...(params.mcpServers ? { mcpServers: params.mcpServers } : {}),\n\t\t...(params.agents ? { agents: params.agents } : {}),\n\t\t...(params.name ? { name: params.name } : {}),\n\t};\n\n\tlet agent: AgentLike | undefined;\n\tlet resumed = false;\n\tif (params.resumeAgentId) {\n\t\ttry {\n\t\t\tagent = await backend.resumeAgent(params.resumeAgentId, createOptions);\n\t\t\tresumed = true;\n\t\t} catch {\n\t\t\t// Stale/expired id: fall through to a fresh create (full replay).\n\t\t}\n\t}\n\tif (!agent) {\n\t\tagent = await backend.createAgent(createOptions);\n\t}\n\n\tconst pooling = params.poolKey !== undefined;\n\tif (pooling && params.record) {\n\t\thydrate();\n\t\tpool.set(params.poolKey!, {\n\t\t\tagentId: agent.agentId,\n\t\t\tsystemHash: params.record.systemHash,\n\t\t\tuserHashes: params.record.userHashes,\n\t\t\t...(params.record.mcpHash !== undefined\n\t\t\t\t? { mcpHash: params.record.mcpHash }\n\t\t\t\t: {}),\n\t\t\tupdatedAt: Date.now(),\n\t\t});\n\t\t// Persist so session reuse survives opencode restarts (best-effort).\n\t\tsaveSessionRecords(pool);\n\t}\n\n\tconst release = () => {\n\t\tif (!pooling) {\n\t\t\ttry {\n\t\t\t\tagent!.close();\n\t\t\t} catch {\n\t\t\t\t// best effort\n\t\t\t}\n\t\t}\n\t};\n\n\treturn { agent, resumed, release };\n}\n"],"mappings":"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","names":["cached","execSync","existsSync","spawn","execSync","existsSync","cached","join"]}