@khalilgharbaoui/opencode-claude-code-plugin 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,278 @@
1
+ # @khalilgharbaoui/opencode-claude-code-plugin
2
+
3
+ A standalone [opencode](https://github.com/opencodeco/opencode) provider plugin that uses [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) as a backend. It spawns `claude` as a subprocess with `--output-format stream-json --input-format stream-json`, implements the AI SDK `LanguageModelV2` interface, and streams responses back to opencode.
4
+
5
+ > Maintained fork of [`unixfox/opencode-claude-code-plugin`](https://github.com/unixfox/opencode-claude-code-plugin), published as `@khalilgharbaoui/opencode-claude-code-plugin` on npm.
6
+
7
+ This is a **standalone npm package** that opencode loads dynamically via its external provider system -- no modifications to opencode's source code required.
8
+
9
+ ## Prerequisites
10
+
11
+ - [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) installed and authenticated (`claude` available in your PATH)
12
+ - [opencode](https://github.com/opencodeco/opencode) installed
13
+
14
+ ## Installation
15
+
16
+ ### From npm
17
+
18
+ ```bash
19
+ npm install @khalilgharbaoui/opencode-claude-code-plugin
20
+ ```
21
+
22
+ ### Local development
23
+
24
+ ```bash
25
+ git clone https://github.com/khalilgharbaoui/opencode-claude-code-plugin
26
+ cd opencode-claude-code-plugin
27
+ bun install
28
+ bun run build
29
+ ```
30
+
31
+ Then reference it via `file://` in your `opencode.json`.
32
+
33
+ ## Configuration
34
+
35
+ Add this to your project's `opencode.json`:
36
+
37
+ ```json
38
+ {
39
+ "provider": {
40
+ "claude-code": {
41
+ "npm": "@khalilgharbaoui/opencode-claude-code-plugin",
42
+ "models": {
43
+ "haiku": {
44
+ "name": "Claude Code Haiku",
45
+ "attachment": false,
46
+ "limit": { "context": 200000, "output": 8192 },
47
+ "capabilities": { "reasoning": false, "toolcall": true }
48
+ },
49
+ "sonnet": {
50
+ "name": "Claude Code Sonnet",
51
+ "attachment": false,
52
+ "limit": { "context": 1000000, "output": 16384 },
53
+ "capabilities": { "reasoning": true, "toolcall": true }
54
+ },
55
+ "opus": {
56
+ "name": "Claude Code Opus",
57
+ "attachment": false,
58
+ "limit": { "context": 1000000, "output": 16384 },
59
+ "capabilities": { "reasoning": true, "toolcall": true }
60
+ }
61
+ },
62
+ "options": {
63
+ "cliPath": "claude",
64
+ "proxyTools": ["Bash", "Edit", "Write", "WebFetch"]
65
+ }
66
+ }
67
+ }
68
+ }
69
+ ```
70
+
71
+ Replace `"@khalilgharbaoui/opencode-claude-code-plugin"` with a `file://` path if you're using a local build.
72
+
73
+ The model IDs (`haiku`, `sonnet`, `opus`) are passed directly to `claude --model`, which accepts these aliases natively.
74
+
75
+ ### Options
76
+
77
+ - `cliPath` (string, default `"claude"`): path to the Claude Code CLI binary.
78
+ - `cwd` (string, default `process.cwd()`): working directory for the spawned CLI.
79
+ - `skipPermissions` (boolean, default `true`): pass `--dangerously-skip-permissions` to the CLI. Ignored when `proxyTools` is set (the proxy handles permissions instead).
80
+ - `permissionMode` (string, optional): pass Claude CLI `--permission-mode` (`acceptEdits`, `auto`, `bypassPermissions`, `default`, `dontAsk`, `plan`).
81
+ - `proxyTools` (string[], optional): list of Claude built-in tools to route through opencode instead of letting the CLI execute them directly. See [Selective Tool Proxy](#selective-tool-proxy) below.
82
+ - `controlRequestBehavior` (`allow` | `deny`, default `allow`): default behavior for Claude stream-json `control_request` messages with subtype `can_use_tool` when `skipPermissions` is `false`.
83
+ - `controlRequestToolBehaviors` (`Record<string, "allow" | "deny">`, optional): per-tool overrides for `can_use_tool` requests (eg. `{ "Bash": "deny", "Read": "allow" }`).
84
+ - `controlRequestDenyMessage` (string, optional): custom deny message returned to Claude for denied `can_use_tool` requests.
85
+ - `bridgeOpencodeMcp` (boolean, default `true`): auto-translate the `mcp` block from your opencode config (`opencode.jsonc` / `opencode.json`, discovered via `cwd`, `OPENCODE_CONFIG`, `OPENCODE_CONFIG_DIR`, and `$XDG_CONFIG_HOME/opencode`) into Claude CLI's `--mcp-config` format. Set to `false` to disable the bridge and manage MCP servers only via `~/.claude/settings.json`.
86
+ - `mcpConfig` (string | string[]): extra `--mcp-config` file path(s) or JSON string(s) passed through alongside the bridged config.
87
+ - `strictMcpConfig` (boolean, default `false`): pass `--strict-mcp-config` so the CLI loads **only** the servers from `--mcp-config` and ignores `~/.claude/settings.json` / user MCP registrations.
88
+
89
+ ## How it works
90
+
91
+ ### Architecture
92
+
93
+ ```
94
+ opencode --> streamText() --> ClaudeCodeLanguageModel.doStream()
95
+ |
96
+ v
97
+ claude CLI subprocess
98
+ (stream-json mode)
99
+ |
100
+ +-------------+-------------+
101
+ | |
102
+ native tools proxy MCP server
103
+ (Read, Glob, Grep, (127.0.0.1:random)
104
+ TodoWrite, etc.) |
105
+ | v
106
+ executed by CLI opencode tool executor
107
+ (bash, edit, write)
108
+ |
109
+ v
110
+ opencode permission UI
111
+ ```
112
+
113
+ ### Session management
114
+
115
+ Sessions are keyed by `(cwd, model, opencode-session-id)`. One active Claude CLI process is kept alive per key and reused across conversation turns within that chat. The opencode session ID comes from the `x-session-affinity` header opencode sets on LLM calls to third-party providers (see `packages/opencode/src/session/llm.ts`), so two chats opened simultaneously in the same project against the same model get separate CLI processes instead of racing on one.
116
+
117
+ - **Same chat, multiple turns**: the CLI process stays alive between messages. Claude retains full native context.
118
+ - **New chat**: a first message with no prior history spawns a fresh process under the new session key.
119
+ - **Resumed chat after restart**: in-memory session state is lost; a new CLI process is spawned and the conversation history is summarized and prepended as context.
120
+ - **Abort (Ctrl+C)**: the stream closes but the CLI process stays alive for the next message in that chat.
121
+ - **Eviction**: live CLI processes are capped at 16 with LRU eviction to avoid accumulating one subprocess per chat indefinitely.
122
+
123
+ ### Selective Tool Proxy
124
+
125
+ The key feature of this plugin is the ability to selectively route Claude's built-in tools through opencode's own tool execution and permission system.
126
+
127
+ **Why this exists**: Claude CLI normally executes tools (Bash, Edit, Write, etc.) internally, bypassing opencode's permission UI entirely. By proxying selected tools, you get opencode's native permission prompts, audit trail, and policy rules for dangerous operations while keeping Claude CLI for authentication and model access.
128
+
129
+ **How it works**:
130
+
131
+ 1. The plugin starts an in-process HTTP MCP server on `127.0.0.1` (random port).
132
+ 2. For each tool listed in `proxyTools`, the plugin:
133
+ - Passes `--disallowedTools <ToolName>` to the CLI, disabling Claude's built-in version.
134
+ - Exposes an equivalent tool via the MCP server (e.g. `mcp__opencode_proxy__bash`).
135
+ 3. When Claude decides to use a proxied tool, the MCP call blocks.
136
+ 4. The plugin emits a client-executed `tool-call` to opencode.
137
+ 5. Opencode runs the tool through its own executor (with permission checks, UI prompts, etc.).
138
+ 6. The tool result flows back into the blocked MCP call, and Claude continues.
139
+
140
+ **Supported proxy tools**:
141
+
142
+ | `proxyTools` value | Claude built-in disabled | Proxy MCP tool exposed |
143
+ |---|---|---|
144
+ | `"Bash"` | `Bash` | `mcp__opencode_proxy__bash` |
145
+ | `"Edit"` | `Edit` | `mcp__opencode_proxy__edit` |
146
+ | `"Write"` | `Write` | `mcp__opencode_proxy__write` |
147
+ | `"WebFetch"` | `WebFetch` | `mcp__opencode_proxy__webfetch` |
148
+
149
+ Tools not listed in `proxyTools` remain fully native to Claude CLI (fast, no permission overhead).
150
+
151
+ **Example configuration**:
152
+
153
+ ```json
154
+ {
155
+ "provider": {
156
+ "claude-code": {
157
+ "npm": "@khalilgharbaoui/opencode-claude-code-plugin",
158
+ "options": {
159
+ "cliPath": "claude",
160
+ "proxyTools": ["Bash", "Edit", "Write", "WebFetch"]
161
+ }
162
+ }
163
+ }
164
+ }
165
+ ```
166
+
167
+ **What Claude keeps doing**:
168
+ - All LLM reasoning, planning, and tool selection
169
+ - System prompts, conversation state, multi-turn continuation
170
+ - Native execution of non-proxied tools (Read, Glob, Grep, TodoWrite, etc.)
171
+ - Authentication via your Claude CLI subscription
172
+
173
+ **What opencode now handles**:
174
+ - Executing the proxied tools (bash commands, file writes, file edits)
175
+ - Permission prompts for those tools through opencode's native UI
176
+ - Policy enforcement via opencode's permission rules
177
+
178
+ ### Tool handling
179
+
180
+ Claude CLI executes non-proxied tools internally (Read, Glob, Grep, etc.). Tool calls and results are streamed to opencode for UI display with `providerExecuted: true`.
181
+
182
+ Proxied tools follow a different path: Claude calls the MCP proxy, the plugin pauses the stream, opencode executes the tool, and the result is fed back to Claude on the next turn.
183
+
184
+ Tool name mapping:
185
+ - **Built-in tools**: `Edit` -> `edit`, `Write` -> `write`, `Bash` -> `bash`, etc. (lowercased)
186
+ - **MCP tools**: `mcp__server__tool` -> `server_tool` (Claude CLI format to opencode format)
187
+ - **Proxy tools**: `mcp__opencode_proxy__bash` -> `bash` (proxy prefix stripped)
188
+ - **Claude CLI internal tools**: `ToolSearch`, `Agent`, `AskFollowupQuestion` are silently skipped
189
+ - **Questions**: `AskUserQuestion` is rendered as text in the stream
190
+
191
+ ### Permissions
192
+
193
+ When `proxyTools` is configured (recommended), permission handling is straightforward: proxied tools go through opencode's native permission system, and non-proxied tools are handled by Claude CLI directly.
194
+
195
+ When `proxyTools` is not set and `skipPermissions` is `false`, the plugin handles Claude stream-json control requests (`type: control_request`, `subtype: can_use_tool`) with auto allow/deny based on config. This prevents stream deadlocks but does not open opencode's permission UI.
196
+
197
+ Control request behavior is configurable with:
198
+
199
+ - `controlRequestBehavior` - global default allow/deny
200
+ - `controlRequestToolBehaviors` - per-tool allow/deny overrides
201
+ - `controlRequestDenyMessage` - message returned on denied requests
202
+
203
+ ### Stream sequencing
204
+
205
+ The plugin ensures proper event ordering for opencode's processor:
206
+ - `text-start` -> `text-delta`* -> `text-end`
207
+ - `reasoning-start` -> `reasoning-delta`* -> `reasoning-end`
208
+ - `tool-input-start` -> `tool-input-delta`* -> `tool-call` -> `tool-result`
209
+
210
+ ## Package structure
211
+
212
+ ```
213
+ src/
214
+ index.ts # Factory: createClaudeCode()
215
+ claude-code-language-model.ts # LanguageModelV2 impl (doGenerate + doStream)
216
+ types.ts # Type definitions
217
+ tool-mapping.ts # Tool name/input conversion
218
+ message-builder.ts # AI SDK prompt -> Claude CLI JSON messages
219
+ session-manager.ts # CLI process lifecycle (spawn, reuse, cleanup)
220
+ proxy-mcp.ts # In-process HTTP MCP server for tool proxying
221
+ proxy-broker.ts # Pause/resume broker for proxied tool calls
222
+ mcp-bridge.ts # Opencode MCP config -> Claude CLI translation
223
+ logger.ts # Debug logging
224
+ ```
225
+
226
+ ## Development
227
+
228
+ ```bash
229
+ bun install
230
+ bun run build # Build with tsup
231
+ bun run dev # Build in watch mode
232
+ bun run typecheck # Type check without emitting
233
+ ```
234
+
235
+ ### Debug logging
236
+
237
+ Set `DEBUG=opencode-claude-code` to enable verbose logging to stderr:
238
+
239
+ ```bash
240
+ DEBUG=opencode-claude-code opencode
241
+ ```
242
+
243
+ ### Running tests
244
+
245
+ ```bash
246
+ bun run test.ts
247
+ ```
248
+
249
+ Requires the `claude` CLI to be installed and authenticated.
250
+
251
+ ## Plan mode
252
+
253
+ When Claude finishes planning, the plugin does **not** automatically exit plan mode (since a plugin cannot switch opencode's mode). Instead, the plan is displayed as text with a confirmation prompt.
254
+
255
+ To proceed after reviewing the plan:
256
+ 1. Switch to **build mode** using `Tab`
257
+ 2. Enter `yes` (or `no` to reject) into the prompt
258
+
259
+ ## Known limitations
260
+
261
+ - **Proxy tool set is currently limited**: only `Bash`, `Edit`, `Write`, and `WebFetch` are supported as proxy targets. More tools can be added when opencode gains matching built-in executors (e.g. `NotebookEdit`).
262
+ - **Non-proxied tools bypass opencode permissions**: tools that remain native to Claude CLI (Read, Glob, Grep, etc.) are executed by the CLI directly without opencode permission checks. This is by design for performance, but means those tools are not subject to opencode's permission rules.
263
+ - **Claude upstream bug [#34046](https://github.com/anthropics/claude-code/issues/34046)**: Claude CLI does not reliably emit `can_use_tool` control requests for built-in tools even when `--permission-prompt-tool` is set. The selective proxy approach works around this entirely by disabling the built-in tools and replacing them with MCP equivalents.
264
+
265
+ ## Publishing
266
+
267
+ To publish a new version to npm, bump the version in `package.json` and push a tag:
268
+
269
+ ```bash
270
+ git tag v0.1.1
271
+ git push origin v0.1.1
272
+ ```
273
+
274
+ The GitHub Actions workflow will automatically build and publish to npm on any `v*` tag.
275
+
276
+ ## License
277
+
278
+ MIT
@@ -0,0 +1,303 @@
1
+ import { LanguageModelV3, LanguageModelV3CallOptions } from '@ai-sdk/provider';
2
+
3
+ type ModelID = string;
4
+ type ProviderID = string;
5
+ type OpenCodeModel = {
6
+ id: ModelID;
7
+ providerID: ProviderID;
8
+ api: {
9
+ id: string;
10
+ url: string;
11
+ npm: string;
12
+ };
13
+ name: string;
14
+ family?: string;
15
+ capabilities: {
16
+ temperature: boolean;
17
+ reasoning: boolean;
18
+ attachment: boolean;
19
+ toolcall: boolean;
20
+ input: {
21
+ text: boolean;
22
+ audio: boolean;
23
+ image: boolean;
24
+ video: boolean;
25
+ pdf: boolean;
26
+ };
27
+ output: {
28
+ text: boolean;
29
+ audio: boolean;
30
+ image: boolean;
31
+ video: boolean;
32
+ pdf: boolean;
33
+ };
34
+ interleaved: boolean | {
35
+ field: "reasoning_content" | "reasoning_details";
36
+ };
37
+ };
38
+ cost: {
39
+ input: number;
40
+ output: number;
41
+ cache: {
42
+ read: number;
43
+ write: number;
44
+ };
45
+ };
46
+ limit: {
47
+ context: number;
48
+ input?: number;
49
+ output: number;
50
+ };
51
+ status: "alpha" | "beta" | "deprecated" | "active";
52
+ options: Record<string, unknown>;
53
+ headers: Record<string, string>;
54
+ release_date: string;
55
+ variants?: Record<string, Record<string, unknown>>;
56
+ };
57
+ type OpenCodeProvider = {
58
+ id: ProviderID;
59
+ name?: string;
60
+ source?: string;
61
+ options?: Record<string, unknown>;
62
+ models: Record<string, OpenCodeModel>;
63
+ };
64
+ type OpenCodeConfig = {
65
+ provider?: Record<string, {
66
+ name?: string;
67
+ npm?: string;
68
+ env?: string[];
69
+ options?: Record<string, unknown>;
70
+ models?: Record<string, unknown>;
71
+ }>;
72
+ };
73
+ type OpenCodeHooks = {
74
+ config?: (input: OpenCodeConfig) => Promise<void>;
75
+ provider?: {
76
+ id: string;
77
+ models?: (provider: OpenCodeProvider) => Promise<Record<string, OpenCodeModel>>;
78
+ };
79
+ };
80
+ type OpenCodePlugin = (input: unknown, options?: Record<string, unknown>) => Promise<OpenCodeHooks>;
81
+
82
+ interface ClaudeCodeConfig {
83
+ provider: string;
84
+ cliPath: string;
85
+ cwd?: string;
86
+ skipPermissions?: boolean;
87
+ permissionMode?: PermissionMode;
88
+ mcpConfig?: string | string[];
89
+ strictMcpConfig?: boolean;
90
+ bridgeOpencodeMcp?: boolean;
91
+ controlRequestBehavior?: ControlRequestBehavior;
92
+ controlRequestToolBehaviors?: Record<string, ControlRequestBehavior>;
93
+ controlRequestDenyMessage?: string;
94
+ proxyTools?: string[];
95
+ }
96
+ interface ClaudeCodeProviderSettings {
97
+ cliPath?: string;
98
+ cwd?: string;
99
+ name?: string;
100
+ skipPermissions?: boolean;
101
+ permissionMode?: PermissionMode;
102
+ mcpConfig?: string | string[];
103
+ strictMcpConfig?: boolean;
104
+ /**
105
+ * Auto-translate opencode's `mcp` config block (from opencode.json/jsonc
106
+ * discovered via cwd/OPENCODE_CONFIG/XDG) into a Claude CLI `--mcp-config`
107
+ * file and pass it through on spawn. Defaults to `true` so the CLI sees
108
+ * the same MCP servers opencode is configured with.
109
+ */
110
+ bridgeOpencodeMcp?: boolean;
111
+ /**
112
+ * Behavior for Claude CLI `control_request` permission checks
113
+ * (`subtype: can_use_tool`) when `skipPermissions` is false.
114
+ *
115
+ * - allow: approve tool use requests automatically.
116
+ * - deny: reject tool use requests automatically.
117
+ *
118
+ * Defaults to `allow`.
119
+ */
120
+ controlRequestBehavior?: ControlRequestBehavior;
121
+ /**
122
+ * Optional per-tool overrides for control-request behavior.
123
+ * Keys are Claude tool names (eg. `Bash`, `Read`, `mcp__github__list_prs`) and
124
+ * values are `allow` or `deny`.
125
+ */
126
+ controlRequestToolBehaviors?: Record<string, ControlRequestBehavior>;
127
+ /**
128
+ * Custom deny message sent back to Claude CLI when behavior resolves to deny.
129
+ */
130
+ controlRequestDenyMessage?: string;
131
+ /**
132
+ * Proxy these Claude built-in tools through opencode instead of letting the
133
+ * CLI execute them directly. When a tool is listed here, the plugin:
134
+ * - passes `--disallowedTools <ClaudeName>` to the CLI, and
135
+ * - exposes an equivalent tool via an in-process HTTP MCP server named
136
+ * `opencode_proxy`. Claude calls the MCP tool, which blocks on
137
+ * opencode's tool executor (with its native permission UI) and returns
138
+ * the result.
139
+ *
140
+ * Supported: `bash`, `write`, `edit`, `webfetch`. Leave empty or unset to disable proxying.
141
+ */
142
+ proxyTools?: string[];
143
+ }
144
+ type PermissionMode = "acceptEdits" | "auto" | "bypassPermissions" | "default" | "dontAsk" | "plan";
145
+ type ControlRequestBehavior = "allow" | "deny";
146
+ /**
147
+ * Claude CLI stream-json message types.
148
+ */
149
+ interface ClaudeStreamMessage {
150
+ type: string;
151
+ subtype?: string;
152
+ request_id?: string;
153
+ request?: {
154
+ subtype?: string;
155
+ tool_name?: string;
156
+ input?: Record<string, unknown>;
157
+ tool_use_id?: string;
158
+ permission_suggestions?: unknown[];
159
+ blocked_path?: string;
160
+ decision_reason?: string;
161
+ title?: string;
162
+ display_name?: string;
163
+ agent_id?: string;
164
+ description?: string;
165
+ };
166
+ message?: {
167
+ role?: string;
168
+ model?: string;
169
+ content?: Array<{
170
+ type: string;
171
+ text?: string;
172
+ name?: string;
173
+ input?: unknown;
174
+ id?: string;
175
+ tool_use_id?: string;
176
+ content?: string | Array<{
177
+ type: string;
178
+ text?: string;
179
+ }>;
180
+ thinking?: string;
181
+ }>;
182
+ };
183
+ tool?: {
184
+ name?: string;
185
+ id?: string;
186
+ input?: unknown;
187
+ };
188
+ tool_result?: {
189
+ tool_use_id?: string;
190
+ content?: string | Array<{
191
+ type: string;
192
+ text?: string;
193
+ }>;
194
+ is_error?: boolean;
195
+ };
196
+ session_id?: string;
197
+ total_cost_usd?: number;
198
+ duration_ms?: number;
199
+ duration_api_ms?: number;
200
+ id?: string;
201
+ result?: string;
202
+ is_error?: boolean;
203
+ num_turns?: number;
204
+ usage?: {
205
+ input_tokens?: number;
206
+ output_tokens?: number;
207
+ cache_read_input_tokens?: number;
208
+ cache_creation_input_tokens?: number;
209
+ iterations?: Array<{
210
+ input_tokens?: number;
211
+ output_tokens?: number;
212
+ cache_read_input_tokens?: number;
213
+ cache_creation_input_tokens?: number;
214
+ }>;
215
+ };
216
+ content_block?: {
217
+ type: string;
218
+ text?: string;
219
+ id?: string;
220
+ name?: string;
221
+ input?: string;
222
+ thinking?: string;
223
+ };
224
+ delta?: {
225
+ type: string;
226
+ text?: string;
227
+ partial_json?: string;
228
+ thinking?: string;
229
+ };
230
+ index?: number;
231
+ }
232
+
233
+ declare class ClaudeCodeLanguageModel implements LanguageModelV3 {
234
+ readonly specificationVersion = "v3";
235
+ readonly modelId: string;
236
+ private readonly config;
237
+ constructor(modelId: string, config: ClaudeCodeConfig);
238
+ readonly supportedUrls: Record<string, RegExp[]>;
239
+ get provider(): string;
240
+ private toUsage;
241
+ private toFinishReason;
242
+ private requestScope;
243
+ /**
244
+ * Build the combined `--mcp-config` list: user-configured paths plus the
245
+ * auto-bridged opencode MCP config (when enabled and present) and the
246
+ * proxy MCP scratch file (when proxyTools are enabled).
247
+ */
248
+ private effectiveMcpConfig;
249
+ /** Resolve ProxyToolDef[] for the configured proxyTools names. */
250
+ private resolvedProxyTools;
251
+ /**
252
+ * Create a proxy MCP server for a single active Claude process/session.
253
+ * The process lifecycle owns the server lifecycle via session-manager.
254
+ */
255
+ private ensureProxyServer;
256
+ private extractPendingProxyResult;
257
+ /**
258
+ * Opencode sets `x-session-affinity: <sessionID>` on LLM calls for
259
+ * third-party providers (packages/opencode/src/session/llm.ts). Use it so
260
+ * two chats in the same cwd+model get separate CLI processes instead of
261
+ * stomping on each other. Falls back to "default" when absent (older
262
+ * opencode, direct AI-SDK use, title synthesis paths, etc).
263
+ */
264
+ private sessionAffinity;
265
+ private controlRequestBehaviorForTool;
266
+ private writeControlResponse;
267
+ /**
268
+ * Handle Claude stream-json control requests (`can_use_tool`, etc.) and
269
+ * respond via stdin with a matching `control_response`.
270
+ */
271
+ private handleControlRequest;
272
+ private getReasoningEffort;
273
+ private latestUserText;
274
+ private synthesizeTitle;
275
+ private doGenerateViaStream;
276
+ doGenerate(options: LanguageModelV3CallOptions): Promise<Awaited<ReturnType<LanguageModelV3["doGenerate"]>>>;
277
+ doStream(options: LanguageModelV3CallOptions): Promise<Awaited<ReturnType<LanguageModelV3["doStream"]>>>;
278
+ }
279
+
280
+ /**
281
+ * Read opencode config file(s), translate their `mcp` block to Claude CLI
282
+ * format, write a scratch file, and return its path. Later files override
283
+ * earlier files per server-name (matching opencode's own merge semantics).
284
+ *
285
+ * Returns null when no opencode config with MCP servers is found — callers
286
+ * should treat that as "nothing to bridge" and carry on.
287
+ */
288
+ declare function bridgeOpencodeMcp(cwd: string): string | null;
289
+
290
+ declare const defaultModels: Record<string, OpenCodeModel>;
291
+
292
+ interface ClaudeCodeProvider {
293
+ specificationVersion: "v3";
294
+ (modelId: string): LanguageModelV3;
295
+ languageModel(modelId: string): LanguageModelV3;
296
+ }
297
+ declare function createClaudeCode(settings?: ClaudeCodeProviderSettings): ClaudeCodeProvider;
298
+ declare const _default: {
299
+ id: string;
300
+ server: OpenCodePlugin;
301
+ };
302
+
303
+ export { type ClaudeCodeConfig, ClaudeCodeLanguageModel, type ClaudeCodeProvider, type ClaudeCodeProviderSettings, type ClaudeStreamMessage, type OpenCodeHooks, type OpenCodeModel, type OpenCodePlugin, bridgeOpencodeMcp, createClaudeCode, _default as default, defaultModels };