@khalilgharbaoui/opencode-claude-code-plugin 0.12.0 → 0.13.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 +37 -2
- package/dist/index.d.ts +39 -2
- package/dist/index.js +445 -38
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -181,8 +181,9 @@ The account model IDs are internally suffixed, for example `claude-sonnet-4-6@wo
|
|
|
181
181
|
| `cwd` | string | `process.cwd()` | Working directory for the spawned CLI. Resolved **lazily per request**, so opencode's project switching works. |
|
|
182
182
|
| `skipPermissions` | boolean | `true` | Pass `--dangerously-skip-permissions` to `claude`. Ignored when `proxyTools` is set — the proxy handles permissions through opencode instead. |
|
|
183
183
|
| `permissionMode` | `acceptEdits` \| `auto` \| `bypassPermissions` \| `default` \| `dontAsk` \| `plan` | – | Forwarded to `claude --permission-mode`. |
|
|
184
|
-
| `proxyTools` | string[] | `["Bash", "Edit", "Write", "WebFetch", "Task"]` | Claude built-in tools to route through opencode's executor + permission UI. See [Selective tool proxy](#selective-tool-proxy). |
|
|
184
|
+
| `proxyTools` | string[] | `["Bash", "Edit", "Write", "WebFetch", "Task"]` | Claude built-in tools to route through opencode's executor + permission UI. Opt-in extras: `"Question"`, `"Compress"`. See [Selective tool proxy](#selective-tool-proxy). |
|
|
185
185
|
| `proxyToolTimeoutMs` | `Record<string, number>` | – | Per-tool proxy call deadline in ms, keyed by proxy tool name (`bash`, `task`, …). Defaults: 10 min flat, `task` → 60 min. For `bash`, the call's own `input.timeout` is honoured on top (`max(resolved, input.timeout)`). See [Selective tool proxy](#selective-tool-proxy). |
|
|
186
|
+
| `planModeQuestion` | boolean | `false` | Route `ExitPlanMode` approval through opencode's native `question` tool instead of a text "(yes/no)" prompt. Off because opencode's question form is currently broken upstream. See [Plan mode](#plan-mode). |
|
|
186
187
|
| `controlRequestBehavior` | `allow` \| `deny` | `allow` | Default response when `skipPermissions: false` and Claude sends a `can_use_tool` control request. |
|
|
187
188
|
| `controlRequestToolBehaviors` | `Record<string, "allow" \| "deny">` | – | Per-tool override for `can_use_tool`. Example: `{ "Bash": "deny", "Read": "allow" }`. |
|
|
188
189
|
| `controlRequestDenyMessage` | string | built-in message | Message returned to Claude on a deny. |
|
|
@@ -272,6 +273,7 @@ By default, the plugin proxies `Bash`, `Edit`, `Write`, `WebFetch`, and `Task`.
|
|
|
272
273
|
| `"WebFetch"` | `WebFetch` | `mcp__opencode_proxy__webfetch` |
|
|
273
274
|
| `"Task"` | `Agent` | `mcp__opencode_proxy__task` |
|
|
274
275
|
| `"Question"` | `AskUserQuestion` | `mcp__opencode_proxy__question` |
|
|
276
|
+
| `"Compress"` | none | `mcp__opencode_proxy__compress` |
|
|
275
277
|
|
|
276
278
|
### OpenCode-native subagents
|
|
277
279
|
|
|
@@ -296,7 +298,21 @@ recovery step for harnesses that defer MCP tool schemas. Both apply per Claude
|
|
|
296
298
|
process at spawn, and provider options are read once at opencode startup, so
|
|
297
299
|
`proxyTools` changes need a full opencode restart.
|
|
298
300
|
|
|
299
|
-
|
|
301
|
+
### Context compression
|
|
302
|
+
|
|
303
|
+
`"Compress"` is off by default. Add it when you run a harness that expects the model to manage its own context (opencode-dcp injects exactly those instructions), and the plugin exposes `mcp__opencode_proxy__compress`:
|
|
304
|
+
|
|
305
|
+
```json
|
|
306
|
+
"options": {
|
|
307
|
+
"proxyTools": ["Bash", "Edit", "Write", "WebFetch", "Task", "Compress"]
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
It is the one proxy tool opencode never sees. The call is answered inside the plugin: the model passes a `summary`, the plugin stores it, and the turn continues normally. At the start of the **next** turn the Claude Code session is discarded and a fresh `claude` starts with that summary prepended to its system prompt, and nothing else. The earlier conversation is not replayed, so a thin summary means real lost context. The reset waits if the incoming turn is carrying tool results for the running process.
|
|
312
|
+
|
|
313
|
+
Without it, the appended system prompt tells the model that `compress` is unavailable and to ignore instructions that ask for it, which is the right answer when nothing implements it.
|
|
314
|
+
|
|
315
|
+
Only those seven values are actually proxied; anything else you put in `proxyTools` is ignored. Proxying `Edit` also disables `MultiEdit` — opencode has no batched-edit equivalent, so Claude is forced to fan out into single `Edit` calls that each flow through the permission UI. The `"Question"` proxy is version-gated on opencode's built-in `question` tool: on builds that lack the registry entry the def is silently dropped (a forwarded call would otherwise render as `⚙ invalid`), so add it only on opencode versions that ship the `question` tool.
|
|
300
316
|
|
|
301
317
|
Without `"Task"` in `proxyTools`, Claude's built-in `Agent` tool stays enabled and Claude orchestrates subagents internally with no opencode child-session visibility. To opt out of all proxying, including Task, use an explicit empty list:
|
|
302
318
|
|
|
@@ -450,6 +466,25 @@ Each chat keeps a long-lived `claude` subprocess so the model retains its native
|
|
|
450
466
|
|
|
451
467
|
Set `permissionMode: "plan"` to forward `--permission-mode plan` to Claude. The plugin handles `ExitPlanMode` specially — instead of forwarding it as a tool call, it converts it to a confirmation prompt that flows through opencode normally.
|
|
452
468
|
|
|
469
|
+
By default that prompt is text: the plan is rendered as markdown, followed by `**Do you want to proceed with this plan?** (yes/no)`, and you answer in your next message.
|
|
470
|
+
|
|
471
|
+
### Approval as a real form (`planModeQuestion`, opt-in)
|
|
472
|
+
|
|
473
|
+
Set `planModeQuestion: true` to route the approval through opencode's native `question` tool instead:
|
|
474
|
+
|
|
475
|
+
```json
|
|
476
|
+
"options": {
|
|
477
|
+
"permissionMode": "plan",
|
|
478
|
+
"planModeQuestion": true
|
|
479
|
+
}
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
The plan is still rendered, but the turn then ends on `tool-calls` and opencode runs its own `question` tool, so approval is a form rather than prose. Your answer is fed back to the CLI as the `tool_result` for the original `ExitPlanMode` call, which is what actually unlocks plan mode on the Claude side. A "yes" typed as ordinary text never does that. Anything other than picking `yes` (including custom text) comes back as rejection feedback the model is told to act on.
|
|
483
|
+
|
|
484
|
+
> **Leave this off for now.** It depends on the same opencode `question` form that is [broken upstream](#with-question-in-proxytools-currently-blocked-upstream--leave-it-off): with it on, a plan approval hangs until you interrupt the turn. On opencode builds with no `question` registry entry at all the plugin silently keeps the text path (look for `plan-mode question gate` in the log). Re-test when [anomalyco/opencode#36603](https://github.com/anomalyco/opencode/pull/36603) merges.
|
|
485
|
+
|
|
486
|
+
Approval bridge contributed by [@CollieIsCute](https://github.com/CollieIsCute).
|
|
487
|
+
|
|
453
488
|
---
|
|
454
489
|
|
|
455
490
|
## AskUserQuestion
|
package/dist/index.d.ts
CHANGED
|
@@ -162,6 +162,14 @@ interface ClaudeCodeConfig {
|
|
|
162
162
|
controlRequestDenyMessage?: string;
|
|
163
163
|
proxyTools?: string[];
|
|
164
164
|
proxyToolTimeoutMs?: Record<string, number>;
|
|
165
|
+
/**
|
|
166
|
+
* Route `ExitPlanMode` through opencode's native `question` tool so plan
|
|
167
|
+
* approval is a real form instead of a "(yes/no)" line the operator has to
|
|
168
|
+
* answer in prose. Off by default: opencode's question form is currently
|
|
169
|
+
* broken upstream, so enabling this trades a working text prompt for a
|
|
170
|
+
* silent hang. See the plan-mode gotcha in AGENTS.md.
|
|
171
|
+
*/
|
|
172
|
+
planModeQuestion?: boolean;
|
|
165
173
|
webSearch?: WebSearchRouting;
|
|
166
174
|
hotReloadMcp?: boolean;
|
|
167
175
|
proxyOpencodeMcpTools?: boolean;
|
|
@@ -292,6 +300,23 @@ interface ClaudeCodeProviderSettings {
|
|
|
292
300
|
* long build the caller explicitly asked to run is never undercut.
|
|
293
301
|
*/
|
|
294
302
|
proxyToolTimeoutMs?: Record<string, number>;
|
|
303
|
+
/**
|
|
304
|
+
* Route Claude's `ExitPlanMode` through opencode's native `question` tool.
|
|
305
|
+
*
|
|
306
|
+
* Off (default): the plan is rendered as markdown followed by
|
|
307
|
+
* `**Do you want to proceed with this plan?** (yes/no)` and the operator
|
|
308
|
+
* answers in prose. On: the plan is rendered, the turn ends on
|
|
309
|
+
* `tool-calls`, and opencode runs its own `question` tool so approval is a
|
|
310
|
+
* real form; the answer is fed back to the CLI as the `tool_result` for
|
|
311
|
+
* the original `ExitPlanMode` call, which is what unlocks plan mode.
|
|
312
|
+
*
|
|
313
|
+
* Two reasons it is opt-in. opencode's `question` form does not currently
|
|
314
|
+
* render (upstream anomalyco/opencode#36604), so an enabled bridge hangs
|
|
315
|
+
* the turn until the operator interrupts; and older opencode builds have
|
|
316
|
+
* no `question` registry entry at all, in which case the plugin silently
|
|
317
|
+
* keeps the text path. See the plan-mode gotcha in AGENTS.md.
|
|
318
|
+
*/
|
|
319
|
+
planModeQuestion?: boolean;
|
|
295
320
|
/**
|
|
296
321
|
* Strip `ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN` from the environment of
|
|
297
322
|
* every spawned `claude` process. When an API key is present, Claude Code
|
|
@@ -525,9 +550,20 @@ declare class ClaudeCodeLanguageModel implements LanguageModelV3 {
|
|
|
525
550
|
* call resolves to `⚙ invalid`; the version gate drops the def.
|
|
526
551
|
*
|
|
527
552
|
* Returns undefined/false when the SDK client is unavailable (direct
|
|
528
|
-
* AI-SDK use, tests) so the static defs stand.
|
|
553
|
+
* AI-SDK use, tests) so the static defs stand. `resolved` distinguishes
|
|
554
|
+
* "the registry answered and has no `question` entry" from "nobody
|
|
555
|
+
* answered": only the former is a real version-gate signal.
|
|
529
556
|
*/
|
|
530
557
|
private fetchLiveToolInfo;
|
|
558
|
+
/** Share one lazy registry request within a turn without making it stale. */
|
|
559
|
+
private createLiveToolInfoLoader;
|
|
560
|
+
/**
|
|
561
|
+
* Whether the ExitPlanMode approval bridge is live for this turn: the
|
|
562
|
+
* operator opted in AND opencode's registry actually has the `question`
|
|
563
|
+
* tool. Without the registry entry the emitted tool-call would render as
|
|
564
|
+
* `⚙ invalid` and wedge the turn, so the plugin keeps the text path.
|
|
565
|
+
*/
|
|
566
|
+
private resolvePlanModeQuestion;
|
|
531
567
|
/**
|
|
532
568
|
* Create a proxy MCP server for a single active Claude process/session.
|
|
533
569
|
* The process lifecycle owns the server lifecycle via session-manager.
|
|
@@ -619,6 +655,7 @@ interface ClaudeCodeProvider {
|
|
|
619
655
|
(modelId: string): LanguageModelV3;
|
|
620
656
|
languageModel(modelId: string): LanguageModelV3;
|
|
621
657
|
}
|
|
658
|
+
declare const DEFAULT_PROXY_TOOL_NAMES: string[];
|
|
622
659
|
declare function createClaudeCode(settings?: ClaudeCodeProviderSettings): ClaudeCodeProvider;
|
|
623
660
|
/**
|
|
624
661
|
* Build models in OpenCode's config schema format (flat properties like
|
|
@@ -637,4 +674,4 @@ declare const _default: {
|
|
|
637
674
|
server: OpenCodePlugin;
|
|
638
675
|
};
|
|
639
676
|
|
|
640
|
-
export { type ClaudeCodeConfig, ClaudeCodeLanguageModel, type ClaudeCodeProvider, type ClaudeCodeProviderSettings, type ClaudeStreamMessage, type OpenCodeHooks, type OpenCodeModel, type OpenCodePlugin, bridgeOpencodeMcp, claudeCodeProviders, configModelsForProvider, createClaudeCode, _default as default, defaultModels };
|
|
677
|
+
export { type ClaudeCodeConfig, ClaudeCodeLanguageModel, type ClaudeCodeProvider, type ClaudeCodeProviderSettings, type ClaudeStreamMessage, DEFAULT_PROXY_TOOL_NAMES, type OpenCodeHooks, type OpenCodeModel, type OpenCodePlugin, bridgeOpencodeMcp, claudeCodeProviders, configModelsForProvider, createClaudeCode, _default as default, defaultModels };
|