@khalilgharbaoui/opencode-claude-code-plugin 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -311,7 +311,7 @@ Set `permissionMode: "plan"` to forward `--permission-mode plan` to Claude. The
311
311
 
312
312
  - **Empty text blocks are dropped.** Claude sometimes opens a `content_block_start` for text but never sends a delta. The plugin no longer emits the empty block (which was triggering Anthropic 400s like `cache_control cannot be set for empty text blocks`).
313
313
  - **`AskUserQuestion`** from the CLI is converted into plain text content rather than forwarded as a tool call.
314
- - **Result fallback timer.** If the CLI finishes a text block but never sends a `result` message, the stream closes gracefully after 5 seconds rather than hanging.
314
+ - **Wire-inactivity watchdog.** Once the CLI has produced any content, the stream closes gracefully if stdout goes silent for 60 seconds without a `result` message arriving. Resets on every line received, so long mid-turn pauses (Sonnet between text-end and the next tool_use, for example) are tolerated. On a user-initiated abort, the watchdog shortens to 5 seconds.
315
315
  - **Per-iteration usage.** When the CLI internally retries with tools, the plugin only counts the last iteration's usage so opencode's context accounting stays accurate.
316
316
  - **Lazy `cwd`.** The working directory is re-resolved at every request, so opencode's project-aware behavior works without restarting the plugin.
317
317
  - **Variants survive merge.** opencode recalculates variant lists after the plugin loads; the plugin re-injects defaults into runtime config so your variants don't disappear.
package/dist/index.d.ts CHANGED
@@ -114,6 +114,7 @@ interface ClaudeCodeConfig {
114
114
  proxyTools?: string[];
115
115
  webSearch?: WebSearchRouting;
116
116
  hotReloadMcp?: boolean;
117
+ proxyOpencodeMcpTools?: boolean;
117
118
  }
118
119
  type WebSearchRouting = "claude" | "disabled" | (string & {});
119
120
  interface ClaudeCodeProviderSettings {
@@ -191,6 +192,21 @@ interface ClaudeCodeProviderSettings {
191
192
  * survives MCP changes until the chat is reset).
192
193
  */
193
194
  hotReloadMcp?: boolean;
195
+ /**
196
+ * Route opencode MCP server tools through the in-process `opencode_proxy`
197
+ * MCP server instead of bridging them directly into Claude CLI's
198
+ * `--mcp-config`. With both layers configured for the same MCP server,
199
+ * direct bridging causes each tool invocation to execute twice — once by
200
+ * Claude CLI's own MCP child process and once by opencode. Routing through
201
+ * the proxy keeps a single execution site (opencode) while preserving the
202
+ * tool-call/result surface in opencode's UI and its permission prompts.
203
+ *
204
+ * Defaults to `true`. Set to `false` to restore the prior direct-bridge
205
+ * behavior (Claude CLI executes MCP tools itself; opencode also re-executes
206
+ * — accept the duplication if you need Claude to invoke the tool without
207
+ * an opencode round-trip).
208
+ */
209
+ proxyOpencodeMcpTools?: boolean;
194
210
  }
195
211
  type PermissionMode = "acceptEdits" | "auto" | "bypassPermissions" | "default" | "dontAsk" | "plan";
196
212
  type ControlRequestBehavior = "allow" | "deny";
@@ -305,6 +321,16 @@ declare class ClaudeCodeLanguageModel implements LanguageModelV3 {
305
321
  private effectiveMcpConfig;
306
322
  /** Resolve ProxyToolDef[] for the configured proxyTools names. */
307
323
  private resolvedProxyTools;
324
+ /**
325
+ * Resolve ProxyToolDef[] for opencode's MCP-bridged tools so they go
326
+ * through the in-process proxy instead of being bridged into Claude CLI's
327
+ * `--mcp-config`. Direct bridging causes double execution because both
328
+ * Claude CLI's own MCP child and opencode hold their own connection to
329
+ * the same server; routing through the proxy keeps a single execution
330
+ * site (opencode). Returns null when the feature is disabled, the SDK
331
+ * client is unavailable, or no MCP servers are configured.
332
+ */
333
+ private resolvedProxyMcpTools;
308
334
  /**
309
335
  * Create a proxy MCP server for a single active Claude process/session.
310
336
  * The process lifecycle owns the server lifecycle via session-manager.
@@ -339,6 +365,18 @@ interface BridgedMcp {
339
365
  path: string;
340
366
  /** Stable hash of the merged opencode mcp block (pre-translation). */
341
367
  hash: string;
368
+ /**
369
+ * Names of opencode MCP servers that were bridged into Claude CLI's
370
+ * `--mcp-config`. Excludes any servers passed in `excludeServers`.
371
+ */
372
+ serverNames: string[];
373
+ /**
374
+ * Names of every enabled opencode MCP server after merge + runtime
375
+ * overlay, regardless of whether they ended up bridged or excluded.
376
+ * Callers (e.g. the proxy-tool builder) use this to decide which
377
+ * `<server>_<tool>` IDs in opencode's tool catalog are MCP-origin.
378
+ */
379
+ allEnabledServerNames: string[];
342
380
  }
343
381
  /**
344
382
  * Per-server runtime status from opencode's `client.mcp.status()`. Used as
@@ -362,7 +400,7 @@ type RuntimeMcpStatus = Record<string, string>;
362
400
  * return its path + a stable hash. Returns null when no enabled MCP servers
363
401
  * remain after the merge + overlay.
364
402
  */
365
- declare function bridgeOpencodeMcp(cwd: string, runtimeStatus?: RuntimeMcpStatus): BridgedMcp | null;
403
+ declare function bridgeOpencodeMcp(cwd: string, runtimeStatus?: RuntimeMcpStatus, excludeServers?: ReadonlySet<string>): BridgedMcp | null;
366
404
 
367
405
  declare const defaultModels: Record<string, OpenCodeModel>;
368
406