@stablekernel/opencode-cursor 0.4.7-next.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/README.md +55 -16
- package/dist/{chunk-SVIXYMHP.js → chunk-LAOFD3JB.js} +487 -292
- package/dist/chunk-LAOFD3JB.js.map +1 -0
- package/dist/plugin/index.js +28 -4
- package/dist/plugin/index.js.map +1 -1
- package/dist/provider/index.d.ts +12 -0
- package/dist/provider/index.js +205 -23
- package/dist/provider/index.js.map +1 -1
- package/dist/sidecar/agent-host.d.ts +9 -2
- package/dist/sidecar/agent-host.js +7 -1
- package/dist/sidecar/agent-host.js.map +1 -1
- package/package.json +6 -5
- package/dist/chunk-SVIXYMHP.js.map +0 -1
|
@@ -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\";\nimport type { SystemPromptMode } from \"./message-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 * Per-model floor params keyed by model id, e.g. `{ \"composer-2.5\": { fast:\n\t * \"false\" } }`. Seeded by the plugin's `config` hook; applied under `params`\n\t * and per-request options.\n\t */\n\tmodelParamDefaults?: Record<string, 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\t/**\n\t * How opencode's system prompt reaches the Cursor agent:\n\t * - \"rules\" (default): written to `<cwd>/.cursor/rules/opencode.mdc`\n\t * (git-ignored, alwaysApply) and loaded via the `project` settings layer —\n\t * Cursor's authoritative channel, so it is not rejected as prompt injection.\n\t * Note: a project rule also applies to your own Cursor IDE in this repo, and\n\t * enabling the project layer also loads other `.cursor/` config.\n\t * - \"message\": legacy inline `# System` block (may be flagged as injection).\n\t * - \"omit\": not forwarded at all.\n\t */\n\tsystemPrompt?: SystemPromptMode;\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...(options.modelParamDefaults\n\t\t\t? { modelParamDefaults: options.modelParamDefaults }\n\t\t\t: {}),\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\tsystemPrompt: options.systemPrompt ?? \"rules\",\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\tSDKUserMessage,\n} from \"@cursor/sdk\";\nimport { resolveCursorApiKey } from \"../api-key.js\";\nimport {\n\tlatestUserMessage,\n\tpromptToCursorMessage,\n\ttrailingUserMessages,\n\ttype SystemPromptMode,\n} from \"./message-map.js\";\nimport { extractSystemText, resolveSystemDelivery } from \"./system-rule.js\";\nimport {\n\tsendAgentTurnSilently,\n\tstreamAgentTurn,\n\ttype CursorEvent,\n} from \"./agent-events.js\";\nimport {\n\tcursorEventsToContent,\n\tcursorEventsToStream,\n\ttype ToolDisplay,\n} from \"./stream-map.js\";\nimport { resolveControls } from \"./controls.js\";\nimport {\n\tacquireAgent,\n\tdropSessionRecord,\n\tgetSessionRecord,\n} 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/**\n\t * Per-model floor params keyed by model id, seeded by the plugin's `config`\n\t * hook. Passed as {@link resolveControls}'s `defaults` for the active model.\n\t */\n\tmodelParamDefaults?: Record<string, 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\t/**\n\t * How opencode's system prompt reaches the Cursor agent (see\n\t * {@link SystemPromptMode}). Defaults to \"rules\".\n\t */\n\tsystemPrompt?: SystemPromptMode;\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// The local Cursor agent has no attachment channel, so file parts (images,\n\t// directories, other media) are noted as text in message-map rather than\n\t// fetched or attached; no URLs are resolved 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\t/** Messages already emitted, so degradation warnings fire once, not per turn. */\n\tprivate readonly warned = new Set<string>();\n\n\tprivate warnOnce(message: string): void {\n\t\tif (this.warned.has(message)) return;\n\t\tthis.warned.add(message);\n\t\tconsole.warn(`[${this.provider}] ${message}`);\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{\n\t\t\t\tmode: this.config.mode,\n\t\t\t\tparams: this.config.params,\n\t\t\t\tdefaults: this.config.modelParamDefaults?.[this.modelId],\n\t\t\t},\n\t\t\tproviderOptions,\n\t\t);\n\t\tif (process.env[\"OPENCODE_CURSOR_DEBUG\"] === \"1\") {\n\t\t\tconsole.error(\n\t\t\t\t`[cursor:debug] model=${this.modelId} selection=${JSON.stringify(modelSelection)}`,\n\t\t\t);\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\t// Number of new trailing user messages for a multi-message interjection\n\t\t// (>= 2). Stays 0 for every other turn kind. When set, and the agent is\n\t\t// resumed, we replay just those new messages as sequential turns instead\n\t\t// of a cold full-transcript replay.\n\t\tlet multiNewUserCount = 0;\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\tcase \"continuation-multi\": {\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\tif (classification.kind === \"continuation-multi\") {\n\t\t\t\t\t\tmultiNewUserCount = classification.newUserCount ?? 0;\n\t\t\t\t\t}\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: classification.kind === \"continuation-multi\"\n\t\t\t\t\t\t\t? `resume-multi:${multiNewUserCount}`\n\t\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\t// A multi-message interjection: two-or-more user messages were queued while\n\t\t// the agent was busy, forming a contiguous user-turn tail (the classifier\n\t\t// guarantees this shape for \"continuation-multi\"). On a resumed agent we\n\t\t// replay just those new messages as sequential turns.\n\t\t//\n\t\t// Defensive invariant check: if the recovered tail doesn't match the\n\t\t// classifier's count (unreachable today, but one classifier refactor away\n\t\t// from real), we must NOT degrade to sending only the latest message —\n\t\t// the session record keeps the full N-message fingerprint, so messages\n\t\t// 1..N-1 would be silently lost. Instead force the cold path: clear the\n\t\t// resume id so a FRESH agent gets the FULL transcript, which matches the\n\t\t// record being written and loses nothing.\n\t\t//\n\t\t// Computed before acquireAgent so a mismatched tail can clear\n\t\t// resumeAgentId in time to affect which agent we acquire.\n\t\tlet multiTurns: SDKUserMessage[] | undefined;\n\t\tif (multiNewUserCount >= 2) {\n\t\t\tconst turns = trailingUserMessages(options.prompt, multiNewUserCount);\n\t\t\tif (turns.length === multiNewUserCount) {\n\t\t\t\tmultiTurns = turns;\n\t\t\t} else {\n\t\t\t\tresumeAgentId = undefined;\n\t\t\t}\n\t\t}\n\n\t\t// In \"rules\" mode (default), deliver opencode's system prompt through\n\t\t// Cursor's authoritative rules channel instead of the user transcript.\n\t\t// Degrades to inline \"message\" delivery when the user explicitly opted\n\t\t// out of the \"project\" settings layer, when the rule file is user-owned,\n\t\t// or when the write fails (read-only checkout etc.).\n\t\tconst delivery = resolveSystemDelivery({\n\t\t\tmode: this.config.systemPrompt ?? \"rules\",\n\t\t\tsettingSources: this.config.settingSources,\n\t\t\tcwd: this.config.cwd,\n\t\t\tsystemText: extractSystemText(options.prompt),\n\t\t\twarn: (message) => this.warnOnce(message),\n\t\t});\n\t\tconst systemMode: SystemPromptMode = delivery.mode;\n\t\tconst settingSources = delivery.settingSources;\n\n\t\t// Shared acquire params. The retry path reuses this verbatim (minus\n\t\t// resumeAgentId) so a fresh agent can never drift from the first attempt's\n\t\t// config (sandbox, settingSources, MCP, etc.).\n\t\tconst baseAcquire = {\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...(settingSources ? { settingSources } : {}),\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...(poolKey ? { poolKey } : {}),\n\t\t\t...(record ? { record } : {}),\n\t\t};\n\n\t\tconst acquired = await acquireAgent({\n\t\t\t...baseAcquire,\n\t\t\t...(resumeAgentId ? { resumeAgentId } : {}),\n\t\t});\n\n\t\tlet yielded = false;\n\t\tlet releasedOriginal = false;\n\t\ttry {\n\t\t\t// Replay the queued messages as sequential turns: leading ones silent,\n\t\t\t// only the final one streamed. Note silent turns are FULL agent runs —\n\t\t\t// tools may execute with nothing surfaced until the last turn streams,\n\t\t\t// and each run is awaited serially (see sendAgentTurnSilently for the\n\t\t\t// trade-offs and why concatenation was rejected).\n\t\t\t//\n\t\t\t// Guard on acquired.resumed: multiTurns is computed before acquire (so a\n\t\t\t// mismatched tail can clear resumeAgentId), but the silent-replay path\n\t\t\t// only makes sense against a resumed agent. A fresh agent falls through\n\t\t\t// to the full-transcript replay below.\n\t\t\tif (acquired.resumed && multiTurns) {\n\t\t\t\t// The pool record was written optimistically with the FULL new\n\t\t\t\t// fingerprint before any send. If delivery stops partway (error or\n\t\t\t\t// abort), drop the record so the next turn classifies fresh instead\n\t\t\t\t// of resuming on top of messages the agent never received.\n\t\t\t\tlet delivered = false;\n\t\t\t\ttry {\n\t\t\t\t\tlet aborted = false;\n\t\t\t\t\tfor (let i = 0; i < multiTurns.length - 1; i++) {\n\t\t\t\t\t\tif (options.abortSignal?.aborted) {\n\t\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tawait sendAgentTurnSilently(acquired.agent, multiTurns[i]!, {\n\t\t\t\t\t\t\tmode,\n\t\t\t\t\t\t\tabortSignal: options.abortSignal,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tif (!aborted && !options.abortSignal?.aborted) {\n\t\t\t\t\t\tfor await (const event of streamAgentTurn(\n\t\t\t\t\t\t\tacquired.agent,\n\t\t\t\t\t\t\tmultiTurns[multiTurns.length - 1]!,\n\t\t\t\t\t\t\t{ mode, abortSignal: options.abortSignal },\n\t\t\t\t\t\t)) {\n\t\t\t\t\t\t\tyielded = true;\n\t\t\t\t\t\t\tyield event;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdelivered = true;\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\tif (!delivered && sessionID) dropSessionRecord(sessionID);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// A resumed agent already remembers the prior conversation, so send\n\t\t\t\t// only the new turn; otherwise send the full transcript.\n\t\t\t\tconst message = acquired.resumed\n\t\t\t\t\t? (latestUserMessage(options.prompt) ??\n\t\t\t\t\t\tpromptToCursorMessage(options.prompt, systemMode))\n\t\t\t\t\t: promptToCursorMessage(options.prompt, systemMode);\n\t\t\t\ttry {\n\t\t\t\t\tfor await (const event of streamAgentTurn(acquired.agent, message, {\n\t\t\t\t\t\tmode,\n\t\t\t\t\t\tabortSignal: options.abortSignal,\n\t\t\t\t\t})) {\n\t\t\t\t\t\tyielded = true;\n\t\t\t\t\t\tyield event;\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\t// Resume-aware retry: a resumed agent can pass resume() yet fail the\n\t\t\t\t\t// actual send when Cursor's server has already expired the agent (its\n\t\t\t\t\t// server-side retention is shorter than our local 7-day reuse window,\n\t\t\t\t\t// and not documented). If nothing has been emitted downstream yet and\n\t\t\t\t\t// the user hasn't aborted, transparently re-create a fresh agent and\n\t\t\t\t\t// replay the full transcript — self-healing, no context loss. The\n\t\t\t\t\t// fresh agent re-pools under the same session (overwriting the dead\n\t\t\t\t\t// agentId) via acquireAgent's existing pooling path.\n\t\t\t\t\t//\n\t\t\t\t\t// Deliberate tradeoff: the retry fires on ANY error class (including\n\t\t\t\t\t// rate-limit or network failures) because Cursor's status:\"error\"\n\t\t\t\t\t// carries no machine-readable class to discriminate on. Bounded to a\n\t\t\t\t\t// single attempt, so the worst case is one extra create.\n\t\t\t\t\tif (acquired.resumed && !yielded && !options.abortSignal?.aborted) {\n\t\t\t\t\t\tif (process.env[\"OPENCODE_CURSOR_DEBUG\"] === \"1\") {\n\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t\"[cursor:debug] resumed turn failed before emitting; retrying with a fresh agent\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tacquired.release();\n\t\t\t\t\t\treleasedOriginal = true;\n\t\t\t\t\t\t// A fresh create (no resumeAgentId) re-pools under the same\n\t\t\t\t\t\t// session, overwriting the dead agentId. If re-acquiring itself\n\t\t\t\t\t\t// fails (e.g. transient create error), surface that but keep the\n\t\t\t\t\t\t// original resume failure as the cause for diagnosability.\n\t\t\t\t\t\tlet retry: Awaited<ReturnType<typeof acquireAgent>>;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tretry = await acquireAgent({ ...baseAcquire });\n\t\t\t\t\t\t} catch (retryErr) {\n\t\t\t\t\t\t\tif (retryErr instanceof Error && retryErr.cause === undefined) {\n\t\t\t\t\t\t\t\tretryErr.cause = err;\n\t\t\t\t\t\t\t} else if (process.env[\"OPENCODE_CURSOR_DEBUG\"] === \"1\") {\n\t\t\t\t\t\t\t\t// Non-Error throw or pre-existing cause: the original resume\n\t\t\t\t\t\t\t\t// failure can't ride along as `cause`, so log it instead of\n\t\t\t\t\t\t\t\t// dropping it silently.\n\t\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t\t\"[cursor:debug] original resume failure (not attachable as cause):\",\n\t\t\t\t\t\t\t\t\terr,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow retryErr;\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst replay = promptToCursorMessage(options.prompt, systemMode);\n\t\t\t\t\t\t\tyield* streamAgentTurn(retry.agent, replay, {\n\t\t\t\t\t\t\t\tmode,\n\t\t\t\t\t\t\t\tabortSignal: options.abortSignal,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\tretry.release();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow err;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tif (!releasedOriginal) acquired.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 { fileURLToPath } from \"node:url\";\nimport type {\n\tLanguageModelV3FilePart,\n\tLanguageModelV3Prompt,\n} from \"@ai-sdk/provider\";\nimport type { SDKUserMessage } from \"@cursor/sdk\";\n\n/**\n * How opencode's system prompt reaches the Cursor agent.\n * - \"rules\" (default): delivered out-of-band as a Cursor project rule\n * (see system-rule.ts) and therefore omitted from this flattened transcript.\n * - \"message\": legacy — inlined as a `# System` block in the transcript.\n * Injection-hardened Cursor models may reject this; kept for back-compat.\n * - \"omit\": dropped entirely (no rule, no inline).\n */\nexport type SystemPromptMode = \"rules\" | \"message\" | \"omit\";\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. File attachments (images and\n * other files alike) are noted as text rather than attached natively: the\n * Cursor LOCAL SDK agent — the only backend this chat path uses — cannot accept\n * images in any form (URL images throw \"URL images are only supported for cloud\n * SDK agents\"; inline base64 images fail the run with an empty `status:\"error\"`,\n * surfacing as \"Cursor run ended with status error\" on an `@image` mention).\n */\nexport function promptToCursorMessage(\n\tprompt: LanguageModelV3Prompt,\n\tsystemPrompt: SystemPromptMode = \"rules\",\n): SDKUserMessage {\n\tconst lines: string[] = [];\n\n\tprompt.forEach((message) => {\n\t\tswitch (message.role) {\n\t\t\tcase \"system\":\n\t\t\t\t// Only inline in legacy \"message\" mode. In \"rules\" mode the system\n\t\t\t\t// prompt is delivered via .cursor/rules (authoritative, not flagged);\n\t\t\t\t// in \"omit\" mode it is dropped.\n\t\t\t\tif (systemPrompt === \"message\") {\n\t\t\t\t\tlines.push(`# System\\n${message.content}`);\n\t\t\t\t}\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\t// File parts (images and other files) can't be forwarded to the\n\t\t\t\t\t// local Cursor agent, so note them as text instead of dropping\n\t\t\t\t\t// them — the agent still learns a file was referenced.\n\t\t\t\t\telse if (part.type === \"file\") text.push(fileNote(part));\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\treturn { text: lines.join(\"\\n\\n\") };\n}\n\n/**\n * A short text note standing in for a file attachment that can't be forwarded\n * to the local Cursor agent.\n *\n * opencode hands `@`-mentions to the provider as file parts; `text/plain` and\n * directory mentions are already inlined as text upstream, so what reaches the\n * provider here is images and other media/binaries. The Cursor LOCAL SDK agent\n * (the only backend this chat path uses) cannot accept any of them:\n * - `{ url }` images throw `ConfigurationError: URL images are only supported\n * for cloud SDK agents`,\n * - `{ data, mimeType }` inline-base64 images fail the run with an empty\n * `status:\"error\"` (the \"Cursor run ended with status error\" a user hits on\n * an `@image` mention — regardless of model).\n * So rather than attaching — and failing the whole turn — we note the file as\n * text. The run completes and the agent still learns a file was referenced.\n */\nfunction fileNote(part: LanguageModelV3FilePart): string {\n\tconst name = part.filename ?? describeSource(part.data) ?? \"file\";\n\treturn `[attached file: ${name} (${part.mediaType}) — not forwarded to Cursor]`;\n}\n\n/** Matches strings with a URL scheme followed by `://` (http, https, file, …). */\nconst URL_SCHEME = /^[a-z][a-z0-9+.-]*:\\/\\//i;\n\nfunction describeSource(data: string | Uint8Array | URL): string | undefined {\n\t// file:// sources become filesystem paths: the agent runs locally with\n\t// workspace tools that operate on paths, so a path is actionable where a\n\t// file:// href is not.\n\tif (data instanceof URL)\n\t\treturn data.protocol === \"file:\" ? fileUrlToPath(data) : data.href;\n\t// Only accept strings that look like a URL. AI-SDK file parts may carry\n\t// raw base64 in `data` (no `data:` prefix); returning that verbatim would\n\t// inline the entire blob into the note text.\n\tif (typeof data === \"string\" && URL_SCHEME.test(data))\n\t\treturn data.startsWith(\"file://\") ? fileUrlToPath(data) : data;\n\treturn undefined;\n}\n\n/** Convert a file:// URL to a filesystem path, falling back to the href when invalid. */\nfunction fileUrlToPath(url: string | URL): string {\n\ttry {\n\t\treturn fileURLToPath(url);\n\t} catch {\n\t\treturn typeof url === \"string\" ? url : url.href;\n\t}\n}\n\n/**\n * Map one AI-SDK user turn into a Cursor `SDKUserMessage`. File parts (images\n * and other files) can't be forwarded to the local Cursor agent, so they're\n * noted as text via {@link fileNote} instead of attached natively.\n */\nfunction userTurnToCursorMessage(\n\tmessage: Extract<LanguageModelV3Prompt[number], { role: \"user\" }>,\n): SDKUserMessage {\n\tconst text: string[] = [];\n\tfor (const part of message.content) {\n\t\tif (part.type === \"text\") text.push(part.text);\n\t\telse if (part.type === \"file\") text.push(fileNote(part));\n\t}\n\n\treturn { text: text.join(\"\\n\") };\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\treturn userTurnToCursorMessage(last);\n}\n\n/**\n * Extract the last `count` CONTIGUOUS trailing user turns as Cursor messages,\n * in conversation order (oldest of the tail first, newest last). Used when\n * resuming a pooled agent after two-or-more user messages were queued while it\n * was busy: we replay just those new messages as sequential turns.\n *\n * Only the contiguous trailing run of user turns is considered; if the final\n * message isn't a user turn the result is empty. Returns fewer than `count`\n * entries when the trailing run is shorter (caller should fall back to a full\n * transcript replay when the array is empty or shorter than expected).\n */\nexport function trailingUserMessages(\n\tprompt: LanguageModelV3Prompt,\n\tcount: number,\n): SDKUserMessage[] {\n\tif (count <= 0) return [];\n\tconst collected: SDKUserMessage[] = [];\n\tfor (let i = prompt.length - 1; i >= 0 && collected.length < count; i--) {\n\t\tconst message = prompt[i];\n\t\tif (!message || message.role !== \"user\") break;\n\t\tcollected.push(userTurnToCursorMessage(message));\n\t}\n\treturn collected.reverse();\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\n/** Cursor plan-mode tool; markdown lives in call args, result is empty. */\nconst CREATE_PLAN_TOOL_NAME = \"createPlan\";\n\nfunction isCreatePlanTool(name: string): boolean {\n\treturn name === CREATE_PLAN_TOOL_NAME;\n}\n\nfunction createPlanContent(input: unknown): string | undefined {\n\treturn strField(input, \"plan\");\n}\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`, `recordScreen`) are intentionally absent and fall through\n * to generic `cursor_*` blocks. `edit` and `createPlan` are handled separately\n * (edit: native call input depends on the diff in the result; createPlan:\n * emitted as assistant markdown text so opencode renders it like a normal plan).\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\tdropped: Set<string>;\n}\n\nfunction newBlockToolState(): BlockToolState {\n\treturn { open: new Map(), pendingEdits: new Map(), dropped: new Set() };\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 (isCreatePlanTool(event.name)) {\n\t\t\t\t\t\t\t\tconst plan = createPlanContent(event.input);\n\t\t\t\t\t\t\t\tif (plan) {\n\t\t\t\t\t\t\t\t\tcloseReasoning();\n\t\t\t\t\t\t\t\t\tstreamedText = true;\n\t\t\t\t\t\t\t\t\tcontroller.enqueue({\n\t\t\t\t\t\t\t\t\t\ttype: \"text-delta\",\n\t\t\t\t\t\t\t\t\t\tid: ensureText(),\n\t\t\t\t\t\t\t\t\t\tdelta: plan,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\ttoolState.dropped.add(event.id);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\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 (toolState.dropped.delete(event.id)) break;\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 (isCreatePlanTool(event.name)) {\n\t\t\t\t\t\tconst plan = createPlanContent(event.input);\n\t\t\t\t\t\tif (plan) text += plan;\n\t\t\t\t\t\ttoolState.dropped.add(event.id);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\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 (toolState.dropped.delete(event.id)) break;\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/** Prior user sequence is a strict prefix + two-or-more new trailing user messages. */\n\t| \"continuation-multi\"\n\t/** Edit / revert / compaction — 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\t/**\n\t * Number of new trailing user messages relative to the prior record. Set on\n\t * `continuation` (always 1) and `continuation-multi` (>= 2); undefined for\n\t * other kinds. Lets the caller know how many tail messages to send on resume.\n\t */\n\tnewUserCount?: number;\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. prior user hashes are a strict prefix AND two-or-more new user messages\n * forming a CONTIGUOUS user-turn tail of the prompt -> \"continuation-multi\"\n * (interleaved assistant turns — e.g. an aborted reply between queued\n * messages — disqualify, because a resumed replay of only the contiguous\n * tail would silently drop the earlier queued message)\n * 5. otherwise -> \"divergence\" (edit/revert/compaction)\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 newUserCount = fp.userHashes.length - prev.userHashes.length;\n\tconst isPrefix = isStrictPrefix(prev.userHashes, fp.userHashes);\n\tif (lastIsUser && isPrefix && newUserCount === 1) {\n\t\treturn { kind: \"continuation\", fingerprint: fp, newUserCount: 1 };\n\t}\n\t// The N new messages must be the prompt's contiguous trailing user turns.\n\t// When an assistant turn sits between them (aborted reply between queued\n\t// interjections), a resumed tail-only replay would drop the earlier queued\n\t// message — so that shape must take the divergence full-replay path.\n\tconst tailContiguous =\n\t\tnewUserCount >= 2 &&\n\t\tprompt.length >= newUserCount &&\n\t\tprompt\n\t\t\t.slice(prompt.length - newUserCount)\n\t\t\t.every((m) => m.role === \"user\");\n\tif (lastIsUser && isPrefix && tailContiguous) {\n\t\treturn { kind: \"continuation-multi\", fingerprint: fp, newUserCount };\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 { setPreferredTransport } from \"./agent-backend.js\";\nimport {\n\tCursorLanguageModel,\n\ttype CursorModelConfig,\n} from \"./language-model.js\";\nimport type { ToolDisplay } from \"./stream-map.js\";\nimport type { SystemPromptMode } from \"./message-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 * Per-model floor params keyed by model id, e.g. `{ \"composer-2.5\": { fast:\n\t * \"false\" } }`. Seeded by the plugin's `config` hook; applied under `params`\n\t * and per-request options.\n\t */\n\tmodelParamDefaults?: Record<string, 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/**\n\t * Cursor's classifier-backed Auto review mode: gates tool calls through a\n\t * classifier instead of running them unconditionally. Defaults to `false`.\n\t * Best-effort tool-call gating, not a security boundary.\n\t */\n\tautoReview?: 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\t/**\n\t * How opencode's system prompt reaches the Cursor agent:\n\t * - \"rules\" (default): written to `<cwd>/.cursor/rules/opencode.mdc`\n\t * (git-ignored, alwaysApply) and loaded via the `project` settings layer —\n\t * Cursor's authoritative channel, so it is not rejected as prompt injection.\n\t * Note: a project rule also applies to your own Cursor IDE in this repo, and\n\t * enabling the project layer also loads other `.cursor/` config.\n\t * - \"message\": legacy inline `# System` block (may be flagged as injection).\n\t * - \"omit\": not forwarded at all.\n\t */\n\tsystemPrompt?: SystemPromptMode;\n\t/**\n\t * Transport for Cursor agent traffic: \"http1\" (in-process, Bun-safe),\n\t * \"http2-direct\" (in-process, Node only), \"sidecar\" (Node child, rollback).\n\t * Beats OPENCODE_CURSOR_TRANSPORT. Process-global: last provider to set it wins.\n\t */\n\ttransport?: \"http1\" | \"http2-direct\" | \"sidecar\";\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\tif (options.transport) setPreferredTransport(options.transport);\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...(options.modelParamDefaults\n\t\t\t? { modelParamDefaults: options.modelParamDefaults }\n\t\t\t: {}),\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.autoReview !== undefined\n\t\t\t? { autoReview: options.autoReview }\n\t\t\t: {}),\n\t\t...(options.agents ? { agents: options.agents } : {}),\n\t\tsession: options.session ?? \"auto\",\n\t\ttoolDisplay: options.toolDisplay ?? \"blocks\",\n\t\tsystemPrompt: options.systemPrompt ?? \"rules\",\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\tSDKUserMessage,\n} from \"@cursor/sdk\";\nimport { resolveCursorApiKey } from \"../api-key.js\";\nimport {\n\tlatestUserMessage,\n\tpromptToCursorMessage,\n\ttrailingUserMessages,\n\ttype SystemPromptMode,\n} from \"./message-map.js\";\nimport { extractSystemText, resolveSystemDelivery } from \"./system-rule.js\";\nimport { classifyError } from \"./error-classify.js\";\nimport {\n\taddUsage,\n\tsendAgentTurnSilently,\n\tstreamAgentTurn,\n\ttype CursorEvent,\n\ttype CursorUsage,\n} from \"./agent-events.js\";\nimport {\n\tcursorEventsToContent,\n\tcursorEventsToStream,\n\ttype ToolDisplay,\n} from \"./stream-map.js\";\nimport { resolveControls } from \"./controls.js\";\nimport {\n\tacquireAgent,\n\tdropSessionRecord,\n\tgetSessionRecord,\n} from \"./session-pool.js\";\nimport {\n\tclassifyTurn,\n\tfingerprint,\n\tmcpServersFingerprint,\n\tsendIdempotencyKey,\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/**\n\t * Per-model floor params keyed by model id, seeded by the plugin's `config`\n\t * hook. Passed as {@link resolveControls}'s `defaults` for the active model.\n\t */\n\tmodelParamDefaults?: Record<string, 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's classifier-backed Auto review mode (tool-call gating). */\n\tautoReview?: 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\t/**\n\t * How opencode's system prompt reaches the Cursor agent (see\n\t * {@link SystemPromptMode}). Defaults to \"rules\".\n\t */\n\tsystemPrompt?: SystemPromptMode;\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// The local Cursor agent has no attachment channel, so file parts (images,\n\t// directories, other media) are noted as text in message-map rather than\n\t// fetched or attached; no URLs are resolved 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\t/** Messages already emitted, so degradation warnings fire once, not per turn. */\n\tprivate readonly warned = new Set<string>();\n\n\tprivate warnOnce(message: string): void {\n\t\tif (this.warned.has(message)) return;\n\t\tthis.warned.add(message);\n\t\tconsole.warn(`[${this.provider}] ${message}`);\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{\n\t\t\t\tmode: this.config.mode,\n\t\t\t\tparams: this.config.params,\n\t\t\t\tdefaults: this.config.modelParamDefaults?.[this.modelId],\n\t\t\t},\n\t\t\tproviderOptions,\n\t\t);\n\t\tif (process.env[\"OPENCODE_CURSOR_DEBUG\"] === \"1\") {\n\t\t\tconsole.error(\n\t\t\t\t`[cursor:debug] model=${this.modelId} selection=${JSON.stringify(modelSelection)}`,\n\t\t\t);\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\t// Number of new trailing user messages for a multi-message interjection\n\t\t// (>= 2). Stays 0 for every other turn kind. When set, and the agent is\n\t\t// resumed, we replay just those new messages as sequential turns instead\n\t\t// of a cold full-transcript replay.\n\t\tlet multiNewUserCount = 0;\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\tcase \"continuation-multi\": {\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\tif (classification.kind === \"continuation-multi\") {\n\t\t\t\t\t\tmultiNewUserCount = classification.newUserCount ?? 0;\n\t\t\t\t\t}\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: classification.kind === \"continuation-multi\"\n\t\t\t\t\t\t\t? `resume-multi:${multiNewUserCount}`\n\t\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\t// A multi-message interjection: two-or-more user messages were queued while\n\t\t// the agent was busy, forming a contiguous user-turn tail (the classifier\n\t\t// guarantees this shape for \"continuation-multi\"). On a resumed agent we\n\t\t// replay just those new messages as sequential turns.\n\t\t//\n\t\t// Defensive invariant check: if the recovered tail doesn't match the\n\t\t// classifier's count (unreachable today, but one classifier refactor away\n\t\t// from real), we must NOT degrade to sending only the latest message —\n\t\t// the session record keeps the full N-message fingerprint, so messages\n\t\t// 1..N-1 would be silently lost. Instead force the cold path: clear the\n\t\t// resume id so a FRESH agent gets the FULL transcript, which matches the\n\t\t// record being written and loses nothing.\n\t\t//\n\t\t// Computed before acquireAgent so a mismatched tail can clear\n\t\t// resumeAgentId in time to affect which agent we acquire.\n\t\tlet multiTurns: SDKUserMessage[] | undefined;\n\t\tif (multiNewUserCount >= 2) {\n\t\t\tconst turns = trailingUserMessages(options.prompt, multiNewUserCount);\n\t\t\tif (turns.length === multiNewUserCount) {\n\t\t\t\tmultiTurns = turns;\n\t\t\t} else {\n\t\t\t\tresumeAgentId = undefined;\n\t\t\t}\n\t\t}\n\n\t\tconst latestUser = latestUserMessage(options.prompt);\n\t\tconst idempotencyKey = sendIdempotencyKey(\n\t\t\tsessionID,\n\t\t\trecord,\n\t\t\tlatestUser?.text ?? JSON.stringify(options.prompt),\n\t\t);\n\n\t\t// In \"rules\" mode (default), deliver opencode's system prompt through\n\t\t// Cursor's authoritative rules channel instead of the user transcript.\n\t\t// Degrades to inline \"message\" delivery when the user explicitly opted\n\t\t// out of the \"project\" settings layer, when the rule file is user-owned,\n\t\t// or when the write fails (read-only checkout etc.).\n\t\tconst delivery = resolveSystemDelivery({\n\t\t\tmode: this.config.systemPrompt ?? \"rules\",\n\t\t\tsettingSources: this.config.settingSources,\n\t\t\tcwd: this.config.cwd,\n\t\t\tsystemText: extractSystemText(options.prompt),\n\t\t\twarn: (message) => this.warnOnce(message),\n\t\t});\n\t\tconst systemMode: SystemPromptMode = delivery.mode;\n\t\tconst settingSources = delivery.settingSources;\n\n\t\t// Shared acquire params. The retry path reuses this verbatim (minus\n\t\t// resumeAgentId) so a fresh agent can never drift from the first attempt's\n\t\t// config (sandbox, settingSources, MCP, etc.).\n\t\tconst baseAcquire = {\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...(settingSources ? { settingSources } : {}),\n\t\t\t...(this.config.sandbox !== undefined\n\t\t\t\t? { sandbox: this.config.sandbox }\n\t\t\t\t: {}),\n\t\t\t...(this.config.autoReview !== undefined\n\t\t\t\t? { autoReview: this.config.autoReview }\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...(poolKey ? { poolKey } : {}),\n\t\t\t...(record ? { record } : {}),\n\t\t};\n\n\t\tconst acquired = await acquireAgent({\n\t\t\t...baseAcquire,\n\t\t\t...(resumeAgentId ? { resumeAgentId } : {}),\n\t\t});\n\n\t\tlet yielded = false;\n\t\tlet releasedOriginal = false;\n\t\ttry {\n\t\t\t// Replay the queued messages as sequential turns: leading ones silent,\n\t\t\t// only the final one streamed. Note silent turns are FULL agent runs —\n\t\t\t// tools may execute with nothing surfaced until the last turn streams,\n\t\t\t// and each run is awaited serially (see sendAgentTurnSilently for the\n\t\t\t// trade-offs and why concatenation was rejected).\n\t\t\t//\n\t\t\t// Guard on acquired.resumed: multiTurns is computed before acquire (so a\n\t\t\t// mismatched tail can clear resumeAgentId), but the silent-replay path\n\t\t\t// only makes sense against a resumed agent. A fresh agent falls through\n\t\t\t// to the full-transcript replay below.\n\t\t\tif (acquired.resumed && multiTurns) {\n\t\t\t\t// The pool record was written optimistically with the FULL new\n\t\t\t\t// fingerprint before any send. If delivery stops partway (error or\n\t\t\t\t// abort), drop the record so the next turn classifies fresh instead\n\t\t\t\t// of resuming on top of messages the agent never received.\n\t\t\t\tlet delivered = false;\n\t\t\t\ttry {\n\t\t\t\t\tlet aborted = false;\n\t\t\t\t\t// Accumulate usage across silent replay turns so the final\n\t\t\t\t\t// streamed turn's reported usage includes the replay cost.\n\t\t\t\t\tlet replayUsage: CursorUsage | undefined;\n\t\t\t\t\tfor (let i = 0; i < multiTurns.length - 1; i++) {\n\t\t\t\t\t\tif (options.abortSignal?.aborted) {\n\t\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treplayUsage = addUsage(\n\t\t\t\t\t\t\treplayUsage,\n\t\t\t\t\t\t\tawait sendAgentTurnSilently(acquired.agent, multiTurns[i]!, {\n\t\t\t\t\t\t\t\tmode,\n\t\t\t\t\t\t\t\tabortSignal: options.abortSignal,\n\t\t\t\t\t\t\t\tidempotencyKey: sendIdempotencyKey(\n\t\t\t\t\t\t\t\t\tsessionID,\n\t\t\t\t\t\t\t\t\t{ userHashes: [...(record?.userHashes ?? []), String(i)] },\n\t\t\t\t\t\t\t\t\tmultiTurns[i]!.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);\n\t\t\t\t\t}\n\t\t\t\t\tif (!aborted && !options.abortSignal?.aborted) {\n\t\t\t\t\t\tfor await (const event of streamAgentTurn(\n\t\t\t\t\t\t\tacquired.agent,\n\t\t\t\t\t\t\tmultiTurns[multiTurns.length - 1]!,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tmode,\n\t\t\t\t\t\t\t\tabortSignal: options.abortSignal,\n\t\t\t\t\t\t\t\t// Key intentionally diverges from the single-turn key: the multi-replay and single-turn branches are mutually exclusive.\n\t\t\t\t\t\t\t\tidempotencyKey: sendIdempotencyKey(\n\t\t\t\t\t\t\t\t\tsessionID,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tuserHashes: [\n\t\t\t\t\t\t\t\t\t\t\t...(record?.userHashes ?? []),\n\t\t\t\t\t\t\t\t\t\t\tString(multiTurns.length - 1),\n\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tmultiTurns[multiTurns.length - 1]!.text,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t...(replayUsage ? { usageBase: replayUsage } : {}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t)) {\n\t\t\t\t\t\t\tyielded = true;\n\t\t\t\t\t\t\tyield event;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdelivered = true;\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\tif (!delivered && sessionID) dropSessionRecord(sessionID);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// A resumed agent already remembers the prior conversation, so send\n\t\t\t\t// only the new turn; otherwise send the full transcript.\n\t\t\t\tconst message = acquired.resumed\n\t\t\t\t\t? (latestUserMessage(options.prompt) ??\n\t\t\t\t\t\tpromptToCursorMessage(options.prompt, systemMode))\n\t\t\t\t\t: promptToCursorMessage(options.prompt, systemMode);\n\t\t\t\ttry {\n\t\t\t\t\tfor await (const event of streamAgentTurn(acquired.agent, message, {\n\t\t\t\t\t\tmode,\n\t\t\t\t\t\tabortSignal: options.abortSignal,\n\t\t\t\t\t\tidempotencyKey,\n\t\t\t\t\t})) {\n\t\t\t\t\t\tyielded = true;\n\t\t\t\t\t\tyield event;\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst classified = classifyError(err);\n\t\t\t\t\t// Auth/config: never a blind retry — replaying the transcript can't\n\t\t\t\t\t// fix a bad key or misconfiguration. Fail fast with actionable\n\t\t\t\t\t// guidance instead of burning a fresh create on a doomed resend.\n\t\t\t\t\tif (classified.kind === \"auth\" || classified.kind === \"config\") {\n\t\t\t\t\t\tthrow classified.helpUrl\n\t\t\t\t\t\t\t? new Error(\n\t\t\t\t\t\t\t\t\t`${classified.message} (see ${classified.helpUrl})`,\n\t\t\t\t\t\t\t\t\t{ cause: err },\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: err;\n\t\t\t\t\t}\n\t\t\t\t\t// Resume-aware replay: a resumed agent can pass resume() yet fail the\n\t\t\t\t\t// actual send when Cursor's server has already expired the agent (its\n\t\t\t\t\t// server-side retention is shorter than our local 7-day reuse window,\n\t\t\t\t\t// and not documented), or the send can die retryably before anything\n\t\t\t\t\t// emitted. If nothing has been emitted downstream yet and the user\n\t\t\t\t\t// hasn't aborted, transparently re-create a fresh agent and replay the\n\t\t\t\t\t// full transcript — self-healing, no context loss. The fresh agent\n\t\t\t\t\t// re-pools under the same session (overwriting the dead agentId) via\n\t\t\t\t\t// acquireAgent's existing pooling path.\n\t\t\t\t\t//\n\t\t\t\t\t// Gated on a classified, replayable set — agent-not-found (expired\n\t\t\t\t\t// resume), rate-limit, network, and unknown. auth/config fail fast\n\t\t\t\t\t// above; agent-busy is recovered at the send layer (sendWithRecovery),\n\t\t\t\t\t// so it never reaches here as a replay trigger. Bounded to a single\n\t\t\t\t\t// attempt, and the turn's idempotencyKey makes resends server-side\n\t\t\t\t\t// dedupes, so the worst case is one extra create.\n\t\t\t\t\tconst replayable =\n\t\t\t\t\t\tclassified.kind === \"agent-not-found\" ||\n\t\t\t\t\t\tclassified.kind === \"rate-limit\" ||\n\t\t\t\t\t\tclassified.kind === \"network\" ||\n\t\t\t\t\t\tclassified.kind === \"unknown\";\n\t\t\t\t\tif (\n\t\t\t\t\t\treplayable &&\n\t\t\t\t\t\tacquired.resumed &&\n\t\t\t\t\t\t!yielded &&\n\t\t\t\t\t\t!options.abortSignal?.aborted\n\t\t\t\t\t) {\n\t\t\t\t\t\tif (process.env[\"OPENCODE_CURSOR_DEBUG\"] === \"1\") {\n\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t\"[cursor:debug] resumed turn failed before emitting; retrying with a fresh agent\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tacquired.release();\n\t\t\t\t\t\treleasedOriginal = true;\n\t\t\t\t\t\t// A fresh create (no resumeAgentId) re-pools under the same\n\t\t\t\t\t\t// session, overwriting the dead agentId. If re-acquiring itself\n\t\t\t\t\t\t// fails (e.g. transient create error), surface that but keep the\n\t\t\t\t\t\t// original resume failure as the cause for diagnosability.\n\t\t\t\t\t\tlet retry: Awaited<ReturnType<typeof acquireAgent>>;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tretry = await acquireAgent({ ...baseAcquire });\n\t\t\t\t\t\t} catch (retryErr) {\n\t\t\t\t\t\t\tif (retryErr instanceof Error && retryErr.cause === undefined) {\n\t\t\t\t\t\t\t\tretryErr.cause = err;\n\t\t\t\t\t\t\t} else if (process.env[\"OPENCODE_CURSOR_DEBUG\"] === \"1\") {\n\t\t\t\t\t\t\t\t// Non-Error throw or pre-existing cause: the original resume\n\t\t\t\t\t\t\t\t// failure can't ride along as `cause`, so log it instead of\n\t\t\t\t\t\t\t\t// dropping it silently.\n\t\t\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\t\t\"[cursor:debug] original resume failure (not attachable as cause):\",\n\t\t\t\t\t\t\t\t\terr,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow retryErr;\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst replay = promptToCursorMessage(options.prompt, systemMode);\n\t\t\t\t\t\t\tyield* streamAgentTurn(retry.agent, replay, {\n\t\t\t\t\t\t\t\tmode,\n\t\t\t\t\t\t\t\tabortSignal: options.abortSignal,\n\t\t\t\t\t\t\t\tidempotencyKey,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\tretry.release();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow err;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tif (!releasedOriginal) acquired.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 { fileURLToPath } from \"node:url\";\nimport type {\n\tLanguageModelV3FilePart,\n\tLanguageModelV3Prompt,\n} from \"@ai-sdk/provider\";\nimport type { SDKUserMessage } from \"@cursor/sdk\";\n\n/**\n * How opencode's system prompt reaches the Cursor agent.\n * - \"rules\" (default): delivered out-of-band as a Cursor project rule\n * (see system-rule.ts) and therefore omitted from this flattened transcript.\n * - \"message\": legacy — inlined as a `# System` block in the transcript.\n * Injection-hardened Cursor models may reject this; kept for back-compat.\n * - \"omit\": dropped entirely (no rule, no inline).\n */\nexport type SystemPromptMode = \"rules\" | \"message\" | \"omit\";\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. File attachments (images and\n * other files alike) are noted as text rather than attached natively: the\n * Cursor LOCAL SDK agent — the only backend this chat path uses — cannot accept\n * images in any form (URL images throw \"URL images are only supported for cloud\n * SDK agents\"; inline base64 images fail the run with an empty `status:\"error\"`,\n * surfacing as \"Cursor run ended with status error\" on an `@image` mention).\n */\nexport function promptToCursorMessage(\n\tprompt: LanguageModelV3Prompt,\n\tsystemPrompt: SystemPromptMode = \"rules\",\n): SDKUserMessage {\n\tconst lines: string[] = [];\n\n\tprompt.forEach((message) => {\n\t\tswitch (message.role) {\n\t\t\tcase \"system\":\n\t\t\t\t// Only inline in legacy \"message\" mode. In \"rules\" mode the system\n\t\t\t\t// prompt is delivered via .cursor/rules (authoritative, not flagged);\n\t\t\t\t// in \"omit\" mode it is dropped.\n\t\t\t\tif (systemPrompt === \"message\") {\n\t\t\t\t\tlines.push(`# System\\n${message.content}`);\n\t\t\t\t}\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\t// File parts (images and other files) can't be forwarded to the\n\t\t\t\t\t// local Cursor agent, so note them as text instead of dropping\n\t\t\t\t\t// them — the agent still learns a file was referenced.\n\t\t\t\t\telse if (part.type === \"file\") text.push(fileNote(part));\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\treturn { text: lines.join(\"\\n\\n\") };\n}\n\n/**\n * A short text note standing in for a file attachment that can't be forwarded\n * to the local Cursor agent.\n *\n * opencode hands `@`-mentions to the provider as file parts; `text/plain` and\n * directory mentions are already inlined as text upstream, so what reaches the\n * provider here is images and other media/binaries. The Cursor LOCAL SDK agent\n * (the only backend this chat path uses) cannot accept any of them:\n * - `{ url }` images throw `ConfigurationError: URL images are only supported\n * for cloud SDK agents`,\n * - `{ data, mimeType }` inline-base64 images fail the run with an empty\n * `status:\"error\"` (the \"Cursor run ended with status error\" a user hits on\n * an `@image` mention — regardless of model).\n * So rather than attaching — and failing the whole turn — we note the file as\n * text. The run completes and the agent still learns a file was referenced.\n */\nfunction fileNote(part: LanguageModelV3FilePart): string {\n\tconst name = part.filename ?? describeSource(part.data) ?? \"file\";\n\treturn `[attached file: ${name} (${part.mediaType}) — not forwarded to Cursor]`;\n}\n\n/** Matches strings with a URL scheme followed by `://` (http, https, file, …). */\nconst URL_SCHEME = /^[a-z][a-z0-9+.-]*:\\/\\//i;\n\nfunction describeSource(data: string | Uint8Array | URL): string | undefined {\n\t// file:// sources become filesystem paths: the agent runs locally with\n\t// workspace tools that operate on paths, so a path is actionable where a\n\t// file:// href is not.\n\tif (data instanceof URL)\n\t\treturn data.protocol === \"file:\" ? fileUrlToPath(data) : data.href;\n\t// Only accept strings that look like a URL. AI-SDK file parts may carry\n\t// raw base64 in `data` (no `data:` prefix); returning that verbatim would\n\t// inline the entire blob into the note text.\n\tif (typeof data === \"string\" && URL_SCHEME.test(data))\n\t\treturn data.startsWith(\"file://\") ? fileUrlToPath(data) : data;\n\treturn undefined;\n}\n\n/** Convert a file:// URL to a filesystem path, falling back to the href when invalid. */\nfunction fileUrlToPath(url: string | URL): string {\n\ttry {\n\t\treturn fileURLToPath(url);\n\t} catch {\n\t\treturn typeof url === \"string\" ? url : url.href;\n\t}\n}\n\n/**\n * Map one AI-SDK user turn into a Cursor `SDKUserMessage`. File parts (images\n * and other files) can't be forwarded to the local Cursor agent, so they're\n * noted as text via {@link fileNote} instead of attached natively.\n */\nfunction userTurnToCursorMessage(\n\tmessage: Extract<LanguageModelV3Prompt[number], { role: \"user\" }>,\n): SDKUserMessage {\n\tconst text: string[] = [];\n\tfor (const part of message.content) {\n\t\tif (part.type === \"text\") text.push(part.text);\n\t\telse if (part.type === \"file\") text.push(fileNote(part));\n\t}\n\n\treturn { text: text.join(\"\\n\") };\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\treturn userTurnToCursorMessage(last);\n}\n\n/**\n * Extract the last `count` CONTIGUOUS trailing user turns as Cursor messages,\n * in conversation order (oldest of the tail first, newest last). Used when\n * resuming a pooled agent after two-or-more user messages were queued while it\n * was busy: we replay just those new messages as sequential turns.\n *\n * Only the contiguous trailing run of user turns is considered; if the final\n * message isn't a user turn the result is empty. Returns fewer than `count`\n * entries when the trailing run is shorter (caller should fall back to a full\n * transcript replay when the array is empty or shorter than expected).\n */\nexport function trailingUserMessages(\n\tprompt: LanguageModelV3Prompt,\n\tcount: number,\n): SDKUserMessage[] {\n\tif (count <= 0) return [];\n\tconst collected: SDKUserMessage[] = [];\n\tfor (let i = prompt.length - 1; i >= 0 && collected.length < count; i--) {\n\t\tconst message = prompt[i];\n\t\tif (!message || message.role !== \"user\") break;\n\t\tcollected.push(userTurnToCursorMessage(message));\n\t}\n\treturn collected.reverse();\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\n/** Cursor plan-mode tool; markdown lives in call args, result is empty. */\nconst CREATE_PLAN_TOOL_NAME = \"createPlan\";\n\nfunction isCreatePlanTool(name: string): boolean {\n\treturn name === CREATE_PLAN_TOOL_NAME;\n}\n\nfunction createPlanContent(input: unknown): string | undefined {\n\treturn strField(input, \"plan\");\n}\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`, `recordScreen`) keep their generic `cursor_*` block (no\n * native `tool` remap) but may still supply a `result` formatter to fold their\n * raw JSON into readable output. `edit` and `createPlan` are handled separately\n * (edit: native call input depends on the diff in the result; createPlan:\n * emitted as assistant markdown text so opencode renders it like a normal plan).\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 `semSearch` has no opencode counterpart — format-only: query title\n\t// + results body instead of the raw `{results}` JSON.\n\tsemSearch: {\n\t\tinput: (args) => {\n\t\t\tconst out: Record<string, unknown> = { query: strField(args, \"query\") ?? \"\" };\n\t\t\tconst dirs = isRecord(args) && Array.isArray(args[\"targetDirectories\"]) ? args[\"targetDirectories\"] : undefined;\n\t\t\tif (dirs && dirs.length > 0) out[\"targetDirectories\"] = dirs;\n\t\t\treturn out;\n\t\t},\n\t\tresult: (value, args) => {\n\t\t\tconst query = strField(args, \"query\") ?? \"\";\n\t\t\tconst results = strField(value, \"results\") ?? \"\";\n\t\t\tconst count = results ? results.split(\"\\n\").filter((l) => l.trim().length > 0).length : 0;\n\t\t\treturn {\n\t\t\t\ttitle: query,\n\t\t\t\tmetadata: { matches: count, truncated: false },\n\t\t\t\toutput: results || \"No results\",\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\tdropped: Set<string>;\n\tpartials: Map<string, { toolName: string; serialized: string }>;\n\tplanText: Map<string, string>;\n}\n\nfunction newBlockToolState(): BlockToolState {\n\treturn {\n\t\topen: new Map(),\n\t\tpendingEdits: new Map(),\n\t\tdropped: new Set(),\n\t\tpartials: new Map(),\n\t\tplanText: new Map(),\n\t};\n}\n\n/**\n * Resolve a Cursor tool name (+ call args) to the FINAL emitted tool name\n * (native registered tool via adapter, or `cursor_*` generic) plus the adapter\n * used. Factored out of {@link blockToolCallParts} so the live-input streaming\n * path can start a `tool-input-start` under the same name the eventual\n * `tool-call` will use.\n */\nfunction resolveToolName(\n\tname: string,\n\tinput: unknown,\n): { toolName: string; adapter?: NativeToolAdapter } {\n\tconst adapter = resolveAdapter(name, input);\n\treturn {\n\t\ttoolName: adapter?.tool ?? blockToolName(name),\n\t\t...(adapter ? { adapter } : {}),\n\t};\n}\n\n/**\n * Parts to emit for a blocks-mode `tool-input-partial` event: a\n * `tool-input-start` on the first partial for an id, then a `tool-input-delta`\n * carrying the JSON-suffix beyond what was already streamed. Kill-switch:\n * `OPENCODE_CURSOR_TOOL_INPUT_STREAM=0` disables live input streaming entirely.\n */\nfunction blockToolInputPartialParts(\n\tid: string,\n\tname: string,\n\tinput: unknown,\n\tstate: BlockToolState,\n): BlockToolPart[] {\n\tif (process.env[\"OPENCODE_CURSOR_TOOL_INPUT_STREAM\"] === \"0\") return [];\n\tconst serialized = safeJsonString(input);\n\tconst prev = state.partials.get(id);\n\tconst toolName = prev?.toolName ?? resolveToolName(name, input).toolName;\n\tstate.partials.set(id, { toolName, serialized });\n\tconst parts: BlockToolPart[] = [];\n\tif (!prev)\n\t\tparts.push({\n\t\t\ttype: \"tool-input-start\",\n\t\t\tid,\n\t\t\ttoolName,\n\t\t\tproviderExecuted: true,\n\t\t\tdynamic: true,\n\t\t} as BlockToolPart);\n\tconst delta =\n\t\tprev && serialized.startsWith(prev.serialized)\n\t\t\t? serialized.slice(prev.serialized.length)\n\t\t\t: serialized;\n\tif (delta) parts.push({ type: \"tool-input-delta\", id, delta } as BlockToolPart);\n\treturn parts;\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\t// Partial input streams whose tool-call never arrived (run died mid-stream):\n\t// close the started input, then emit a valid call+result pair so the block\n\t// isn't left dangling (invariant: exactly one terminal per started call).\n\tfor (const [id, partial] of state.partials) {\n\t\tparts.push({ type: \"tool-input-end\", id } as BlockToolPart);\n\t\tlet args: unknown = {};\n\t\ttry {\n\t\t\targs = JSON.parse(partial.serialized);\n\t\t} catch {\n\t\t\targs = {};\n\t\t}\n\t\tparts.push(nativeToolCall(id, partial.toolName, args));\n\t\tparts.push(\n\t\t\tnativeToolResult(id, partial.toolName, DANGLING_TOOL_RESULT, true),\n\t\t);\n\t}\n\tstate.partials.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\tlet thinkingMs = 0;\n\t\t\tlet compactions = 0;\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-input-partial\":\n\t\t\t\t\t\t\tif (isCreatePlanTool(event.name)) {\n\t\t\t\t\t\t\t\tconst plan = createPlanContent(event.input) ?? \"\";\n\t\t\t\t\t\t\t\tconst prevPlan = toolState.planText.get(event.id) ?? \"\";\n\t\t\t\t\t\t\t\tif (plan.length > prevPlan.length) {\n\t\t\t\t\t\t\t\t\tcloseReasoning();\n\t\t\t\t\t\t\t\t\tstreamedText = true;\n\t\t\t\t\t\t\t\t\tcontroller.enqueue({\n\t\t\t\t\t\t\t\t\t\ttype: \"text-delta\",\n\t\t\t\t\t\t\t\t\t\tid: ensureText(),\n\t\t\t\t\t\t\t\t\t\tdelta: plan.slice(prevPlan.length),\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\ttoolState.planText.set(event.id, plan);\n\t\t\t\t\t\t\t\ttoolState.dropped.add(event.id);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (toolDisplay === \"blocks\" && event.name !== EDIT_TOOL_NAME) {\n\t\t\t\t\t\t\t\tconst parts = blockToolInputPartialParts(\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\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) controller.enqueue(part);\n\t\t\t\t\t\t\t}\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 (isCreatePlanTool(event.name)) {\n\t\t\t\t\t\t\t\tconst plan = createPlanContent(event.input) ?? \"\";\n\t\t\t\t\t\t\t\tconst prevPlan = toolState.planText.get(event.id) ?? \"\";\n\t\t\t\t\t\t\t\tif (plan.length > prevPlan.length) {\n\t\t\t\t\t\t\t\t\tcloseReasoning();\n\t\t\t\t\t\t\t\t\tstreamedText = true;\n\t\t\t\t\t\t\t\t\tcontroller.enqueue({\n\t\t\t\t\t\t\t\t\t\ttype: \"text-delta\",\n\t\t\t\t\t\t\t\t\t\tid: ensureText(),\n\t\t\t\t\t\t\t\t\t\tdelta: plan.slice(prevPlan.length),\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\ttoolState.planText.set(event.id, plan);\n\t\t\t\t\t\t\t\ttoolState.dropped.add(event.id);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (toolDisplay === \"blocks\") {\n\t\t\t\t\t\t\t\tif (toolState.partials.delete(event.id)) {\n\t\t\t\t\t\t\t\t\tcontroller.enqueue({\n\t\t\t\t\t\t\t\t\t\ttype: \"tool-input-end\",\n\t\t\t\t\t\t\t\t\t\tid: event.id,\n\t\t\t\t\t\t\t\t\t} as LanguageModelV3StreamPart);\n\t\t\t\t\t\t\t\t}\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 (toolState.dropped.delete(event.id)) break;\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 \"reasoning-complete\":\n\t\t\t\t\t\t\tcloseReasoning();\n\t\t\t\t\t\t\tif (typeof event.durationMs === \"number\")\n\t\t\t\t\t\t\t\tthinkingMs += event.durationMs;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"compaction\":\n\t\t\t\t\t\t\tcompactions++;\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\t{\n\t\t\t\t\tconst cursorMeta: Record<string, number> = {};\n\t\t\t\t\tif (thinkingMs > 0) cursorMeta[\"thinkingDurationMs\"] = thinkingMs;\n\t\t\t\t\tif (compactions > 0) cursorMeta[\"compactions\"] = compactions;\n\t\t\t\t\tcontroller.enqueue({\n\t\t\t\t\t\ttype: \"finish\",\n\t\t\t\t\t\tusage: usage ?? EMPTY_USAGE,\n\t\t\t\t\t\tfinishReason: FINISH_STOP,\n\t\t\t\t\t\t...(Object.keys(cursorMeta).length > 0\n\t\t\t\t\t\t\t? { providerMetadata: { cursor: cursorMeta } }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t});\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\t{\n\t\t\t\t\tconst cursorMeta: Record<string, number> = {};\n\t\t\t\t\tif (thinkingMs > 0) cursorMeta[\"thinkingDurationMs\"] = thinkingMs;\n\t\t\t\t\tif (compactions > 0) cursorMeta[\"compactions\"] = compactions;\n\t\t\t\t\tcontroller.enqueue({\n\t\t\t\t\t\ttype: \"finish\",\n\t\t\t\t\t\tusage: usage ?? EMPTY_USAGE,\n\t\t\t\t\t\tfinishReason: FINISH_ERROR,\n\t\t\t\t\t\t...(Object.keys(cursorMeta).length > 0\n\t\t\t\t\t\t\t? { providerMetadata: { cursor: cursorMeta } }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t});\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-input-partial\":\n\t\t\t\t\t// Non-streaming path ignores partials; the final tool-call carries\n\t\t\t\t\t// the full args.\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"tool-call\":\n\t\t\t\t\tif (isCreatePlanTool(event.name)) {\n\t\t\t\t\t\tconst plan = createPlanContent(event.input);\n\t\t\t\t\t\tif (plan) text += plan;\n\t\t\t\t\t\ttoolState.dropped.add(event.id);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\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 (toolState.dropped.delete(event.id)) break;\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 \"reasoning-complete\":\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"compaction\":\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/** Prior user sequence is a strict prefix + two-or-more new trailing user messages. */\n\t| \"continuation-multi\"\n\t/** Edit / revert / compaction — 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\t/**\n\t * Number of new trailing user messages relative to the prior record. Set on\n\t * `continuation` (always 1) and `continuation-multi` (>= 2); undefined for\n\t * other kinds. Lets the caller know how many tail messages to send on resume.\n\t */\n\tnewUserCount?: number;\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. prior user hashes are a strict prefix AND two-or-more new user messages\n * forming a CONTIGUOUS user-turn tail of the prompt -> \"continuation-multi\"\n * (interleaved assistant turns — e.g. an aborted reply between queued\n * messages — disqualify, because a resumed replay of only the contiguous\n * tail would silently drop the earlier queued message)\n * 5. otherwise -> \"divergence\" (edit/revert/compaction)\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 newUserCount = fp.userHashes.length - prev.userHashes.length;\n\tconst isPrefix = isStrictPrefix(prev.userHashes, fp.userHashes);\n\tif (lastIsUser && isPrefix && newUserCount === 1) {\n\t\treturn { kind: \"continuation\", fingerprint: fp, newUserCount: 1 };\n\t}\n\t// The N new messages must be the prompt's contiguous trailing user turns.\n\t// When an assistant turn sits between them (aborted reply between queued\n\t// interjections), a resumed tail-only replay would drop the earlier queued\n\t// message — so that shape must take the divergence full-replay path.\n\tconst tailContiguous =\n\t\tnewUserCount >= 2 &&\n\t\tprompt.length >= newUserCount &&\n\t\tprompt\n\t\t\t.slice(prompt.length - newUserCount)\n\t\t\t.every((m) => m.role === \"user\");\n\tif (lastIsUser && isPrefix && tailContiguous) {\n\t\treturn { kind: \"continuation-multi\", fingerprint: fp, newUserCount };\n\t}\n\treturn { kind: \"divergence\", fingerprint: fp };\n}\n\n/**\n * Stable idempotency key for one turn's send: identical for retries of the\n * SAME logical turn (same session, same transcript prefix, same message), so\n * Cursor's server dedupes resends; distinct as soon as the transcript grows,\n * so a later identical user message is never swallowed.\n */\nexport function sendIdempotencyKey(\n\tsessionID: string | undefined,\n\trecord: { userHashes: string[] } | undefined,\n\tmessageText: string,\n): string {\n\treturn createHash(\"sha256\")\n\t\t.update(`${sessionID ?? \"ephemeral\"}|${record?.userHashes.join(\",\") ?? \"\"}|${messageText}`)\n\t\t.digest(\"hex\")\n\t\t.slice(0, 32);\n}\n"],"mappings":"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","names":["toolName"]}
|