@khalilgharbaoui/opencode-claude-code-plugin 0.33.1 → 0.34.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 +21 -3
- package/dist/index.d.ts +22 -0
- package/dist/index.js +2030 -1861
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/skills/claude-code-plugin/SKILL.md +143 -83
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ Three ways to reach Claude from opencode. They differ in who authenticates, who
|
|
|
21
21
|
| **Authentication** | An Anthropic Platform API key, held in opencode's own auth store. | Whatever the official `claude` CLI already holds: a subscription login, an API key, Bedrock, or Vertex. The plugin never reads, stores, or replays a token of its own, and there is no subscription token here to lift. | The Claude OAuth session, used outside the official client. Meridian runs a local proxy that maps Anthropic-style HTTP onto the Claude Agent SDK and your Claude session; `opencode-claude-auth` reads the OAuth tokens out of the macOS Keychain or `~/.claude/.credentials.json` and refreshes them against Anthropic's OAuth endpoint itself. |
|
|
22
22
|
| **What is billed, and to whom** | Pay as you go on the Platform account that owns the key. | Whatever the CLI's own authentication bills. Headless `--print` is the Agent SDK path; an API key found anywhere the CLI looks switches the same turn onto Console pay-as-you-go instead. `apiKeySource` on the CLI's `system` init event is the field that says which, and the plugin warns once per process when a key is in effect. On a subscription, headless and interactive turns both draw from the plan's ordinary usage limits. See [which login bills what](#which-login-bills-what). | The subscription the reused session belongs to. Meridian's own FAQ: "Usage limits follow your Max subscription, not Anthropic API billing tiers." |
|
|
23
23
|
| **Terms-of-service status** | The ordinary API route. Nothing unusual about it. | Sanctioned: the official client does the authenticating, and driving `claude` is what `claude` is for. | Disallowed. Anthropic disallowed reusing subscription authentication for third-party Claude use in February 2026, and each project says so in its own words: Meridian's wrapper "makes no claims regarding compliance with Anthropic's Terms of Service"; `opencode-claude-auth` calls itself "a community workaround" and notes that the terms say subscription tokens "should only be used with official Anthropic clients"; `opencode-claude-plan` quotes Consumer Terms 3.7 and asks you to accept that your account "could be suspended or terminated". |
|
|
24
|
-
| **Model list and fast mode** | Whatever opencode's own provider registers. |
|
|
24
|
+
| **Model list and fast mode** | Whatever opencode's own provider registers. | 18 ids auto-registered, Haiku 4.5 through Opus 5.5 plus Fable and Mythos, each carrying a `(N×)` list-price suffix, and any other id `claude --model` accepts passes straight through. Three `-fast` Opus ids are this plugin's own markers and opt a headless session into fast mode through `--settings` (CLI 2.1.220+). See [Models](#models). | `opencode-claude-auth`'s README lists 14 model ids. Meridian's lists none, because model metadata comes from opencode's own `anthropic` provider. Neither README mentions fast mode. |
|
|
25
25
|
| **Which tools run where, under whose permissions** | All of them are opencode's, behind opencode's permission prompts and audit log. | Your choice, per tool. `Bash`, `Edit`, `Write`, `WebFetch` and `Task` are proxied by default: Claude calls an in-process MCP tool and **opencode** executes it, under its own permissions and audit log. Anything neither proxied nor named in `extraDisallowedTools` runs inside Claude Code under `--dangerously-skip-permissions`. See [Selective tool proxy](#selective-tool-proxy) and [Read-only mode](#read-only-mode). | All of them are opencode's, because the model call is an ordinary provider call. This is the one row where the third column matches the native provider and this plugin has to work for the same result. |
|
|
26
26
|
| **Reasoning and effort** | opencode's own reasoning controls. | Five picker variants per model, `low` through `max`, handed to the CLI as `CLAUDE_CODE_EFFORT_LEVEL` at spawn. Effort is fixed for the life of a `claude` process, so it is part of the session key, and an agent's own `reasoningEffort` beats the effort a call arrived with. Thinking is Anthropic's summarized digest, not raw chain-of-thought. See [Extended thinking](#extended-thinking). | Meridian's SDK-features file exposes a `thinking` key. Neither README documents per-model effort variants. |
|
|
27
27
|
| **Context window** | Whatever the model exposes. | The registered limits: 200k context / 64k output on the 4.5 generation, 1M / 128k on 4.6 and later, all at standard pricing with no above-200K tier. Claude Code may also compact or clear its own context mid-conversation, which the plugin can announce but not prevent. | Not stated in either README. |
|
|
@@ -102,7 +102,7 @@ The same package runs on opencode 1.x and 2.x, and nothing changes for 1.x. The
|
|
|
102
102
|
}
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
Your existing `provider.claude-code.options` block keeps working, because opencode 2 still reads 1.x config files.
|
|
105
|
+
Your existing `provider.claude-code.options` block keeps working, because opencode 2 still reads 1.x config files. opencode 2's own spelling is `providers.claude-code.settings` (note the plural `providers`). All four places the plugin reads its settings from, lowest precedence first: `provider.claude-code.options`, `provider.claude-code.settings`, `providers.claude-code.settings`, and the plugin entry's own `options`, which wins over all of them. Plugin-level settings such as `accounts` usually go in that last one: `{"package": "@khalilgharbaoui/opencode-claude-code-plugin", "options": {"accounts": ["work"]}}`.
|
|
106
106
|
|
|
107
107
|
For a local checkout, point opencode 2 at the **`dist` directory**, not the repository root. It loads `<dir>/server` or `<dir>/index` from a directory and never reads `package.json#main`:
|
|
108
108
|
|
|
@@ -468,7 +468,8 @@ reaches the CLI, so there is nothing there to fall back from.
|
|
|
468
468
|
| `bridgeOpencodeMcp` | boolean | `true` | Auto-translate your opencode `mcp` block into Claude's `--mcp-config`. See [MCP bridge](#mcp-bridge). |
|
|
469
469
|
| `mcpConfig` | string \| string[] | – | Extra `--mcp-config` paths/JSON passed alongside the bridged config. |
|
|
470
470
|
| `strictMcpConfig` | boolean | `false` | Pass `--strict-mcp-config` so Claude loads **only** the configured servers and ignores `~/.claude/settings.json`. |
|
|
471
|
-
| `hotReloadMcp` | boolean | `true` | With MCP bridging on, compare the merged MCP config and runtime status at the start of each turn and respawn the `claude` process when they drifted, so a server you just enabled or
|
|
471
|
+
| `hotReloadMcp` | boolean | `true` | With MCP bridging on, compare the merged MCP config and runtime status at the start of each turn and respawn the `claude` process when they drifted, so a server you just enabled, disabled or finished connecting becomes visible without restarting opencode or opening a new chat. It only ever acts at a safe boundary: never during `/compact`, never on the interactive transport, never while a proxied call is still in the air, a turn is still running or a plan-mode approval is outstanding, and the Claude session id is preserved for `--resume` so the conversation continues. A log line at INFO names which servers joined and left. A server that flaps buys at most one respawn per minute per conversation (`CLAUDE_CODE_MCP_HOT_RELOAD_COOLDOWN_MS`). Set `false` to keep a cached subprocess until the chat is reset. It does not reload other provider options and does not watch the contents of files named in `mcpConfig`. |
|
|
472
|
+
| `mcpConnectWaitMs` | number | `3000` | How long the first turn of a conversation waits for MCP servers opencode reports as still connecting before planning the `claude` spawn without them. Only opencode 2 can report that state (`pending`); opencode 1's own status call blocks until every server has decided, so this budget is what makes the two majors behave alike. Set `0` to always plan with whatever the host says at that instant. A server slower than the budget is not lost either way: it is still bridged, and `hotReloadMcp` moves the conversation onto a process that has it on the next turn. |
|
|
472
473
|
| `proxyOpencodeMcpTools` | boolean | `false` | Route opencode's MCP-backed tools through the in-process `opencode_proxy` server instead of bridging them straight into Claude's `--mcp-config`, so each call executes once, inside opencode, with its permission prompt and its tool row. **The default changed from `true` to `false` in this release, and no behaviour changed with it:** at `true` it used to route nothing at all, because discovery read opencode's tool registry, which contains built-ins and plugin-declared tools and has never contained an MCP tool. Discovery now reads the model tool set opencode passes the provider, which is where MCP tools actually are, so the option works, and turning it on is the operator's decision rather than a silent migration of traffic that the direct bridge is handling today. Two caveats before enabling it: pair it with `strictMcpConfig: true`, because a server also registered in Claude Code's own config is reached directly and bypasses the proxy entirely; and a routed call runs in opencode with the calling agent's permissions, the same trade [`proxyOpencodeTools`](#options-reference) makes. Servers whose tools are not found stay on the direct bridge, and a warning says so, so do not treat this as an exactly-once guarantee for write-capable tools. |
|
|
473
474
|
| `proxyOpencodeTools` | string[] | `[]` | Forward explicitly named opencode tools through the proxy (for example, a plugin's `compress` or V2 Code Mode `execute`). V1 uses registry ids; V2 uses the current model tool snapshot, including its real JSON Schema and agent visibility, not the registry's empty schemas. A forwarded tool runs inside opencode with the calling agent's permissions. A name already held by a proxy def is dropped with a warning. The read-only preset refuses `execute`. See [Forwarding opencode's own tools](#forwarding-opencode-s-own-tools) and [V2 Code Mode](#v2-code-mode). |
|
|
474
475
|
| `stripContextReminders` | boolean | `false` | Remove opencode-dcp's `<dcp-system-reminder>` blocks from message text when no `compress` tool is proxied, so an order the model cannot follow stops being re-sent with every message that carries it. Inert as soon as `compress` is reachable. See [Trimming unsatisfiable context reminders](#trimming-unsatisfiable-context-reminders). |
|
|
@@ -507,6 +508,7 @@ Every variable the plugin itself reads, in one place. Config is read once at ope
|
|
|
507
508
|
| `OPENCODE_CLAUDE_CODE_PLUGIN_FORCE_CLEANUP` | startup cleanup | `1` runs that cleanup even when the marker at `$XDG_STATE_HOME/opencode-claude-code-plugin/cleanup-stale.json` (default `~/.local/state/...`) records that this plugin version already swept. Without it the cleanup walks opencode's plugin cache once per installed version rather than on every launch. |
|
|
508
509
|
| `OPENCODE_CLAUDE_CODE_NO_TMP_SWEEP` | scratch directory | `1` skips the sweep of `<tmpdir>/opencode-claude-code-<pid>` directories left behind by plugin processes that were killed. See [Scratch files on disk](#scratch-files-on-disk). |
|
|
509
510
|
| `OPENCODE_WORKTREE` | MCP bridge | Overrides worktree-root detection, which otherwise walks up from the working directory looking for a `.git` entry. |
|
|
511
|
+
| `CLAUDE_CODE_MCP_HOT_RELOAD_COOLDOWN_MS` | MCP bridge | Minimum gap between two `hotReloadMcp` respawns of one conversation, default `60000`. A server that flaps between connected and failed would otherwise cost a kill and a `--resume` spawn on every turn. `0` disables the guard; a real second change lands on the first turn after the gap. |
|
|
510
512
|
| `OPENCODE_CONFIG` / `OPENCODE_CONFIG_DIR` | config discovery | Where the plugin looks for your opencode config when bridging MCP and skills. See [Discovery order](#discovery-order-highest-to-lowest-priority). |
|
|
511
513
|
| `OPENCODE_VERSION` | startup diagnostics | Reported as the opencode version when set, sparing the plugin a `--version` spawn. Diagnostics only. |
|
|
512
514
|
| `ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN` | spawn environment | Not set by the plugin: these are yours, and Claude Code authenticates with them in preference to your subscription login when present. `ignoreAnthropicApiKey: true` strips them from the spawn. See [Billing](#billing). |
|
|
@@ -1071,6 +1073,22 @@ The disk bridge reads global config, then `OPENCODE_CONFIG`, then project direct
|
|
|
1071
1073
|
|
|
1072
1074
|
On V2, project discovery walks to the filesystem root (including ancestors above the repo). Direct files are applied parent-first, then `.opencode` files parent-first: the closest file wins within each group, and all `.opencode` files override direct files. Each higher-precedence server entry **replaces the entire server object**, so repeat its type, URL/command and other required fields in an override. Both `.json` and `.jsonc` are read, with `.jsonc` winning within a directory. Runtime toggles continue to participate in the hot-reload hash.
|
|
1073
1075
|
|
|
1076
|
+
### Servers that connect late
|
|
1077
|
+
|
|
1078
|
+
A server opencode has not finished connecting to when a turn is planned used to be dropped from that turn's `claude` spawn, and a reused process keeps the `--mcp-config` it was spawned with, so it stayed invisible for the rest of the conversation. Two things stop that now.
|
|
1079
|
+
|
|
1080
|
+
First, "still connecting" is no longer read as "not connected". opencode 2 reports such a server as `pending`, which is not a decision, so the bridge leaves its configured state alone instead of forcing it off, and the turn waits up to `mcpConnectWaitMs` (3 s by default, `0` to disable) for the host to decide. opencode 1 has no `pending` status: its own status call blocks until every server resolves, so nothing changes there and the wait costs one status call exactly as before.
|
|
1081
|
+
|
|
1082
|
+
Second, if the server joins later anyway, `hotReloadMcp` moves the conversation onto a `claude` process with the new config and `--resume`, at the start of a later turn. That only happens at a safe boundary: not during `/compact`, not on the interactive transport, and not while a proxied call is still in the air, a turn is still running or a plan-mode approval is outstanding. The log line names the servers:
|
|
1083
|
+
|
|
1084
|
+
```
|
|
1085
|
+
INFO: opencode MCP servers changed, respawning claude {"joined":["slowmcp"],"left":[],...}
|
|
1086
|
+
```
|
|
1087
|
+
|
|
1088
|
+
A server that flaps between connected and failed is capped at one respawn per minute per conversation; override with `CLAUDE_CODE_MCP_HOT_RELOAD_COOLDOWN_MS`.
|
|
1089
|
+
|
|
1090
|
+
This matters most where a turn can arrive before the host has started its servers: `opencode run`, scripted use and slow servers. The TUI normally connects everything before the first prompt.
|
|
1091
|
+
|
|
1074
1092
|
### V2 Code Mode
|
|
1075
1093
|
|
|
1076
1094
|
V2 normally exposes MCP tools through Code Mode's `execute` and its catalog, rather than as individual server-prefixed model tools. `proxyOpencodeMcpTools` matches individual tools only; on a Code Mode-only snapshot it warns and falls back to the direct Claude MCP bridge. This fallback does **not** execute tools under opencode's permission policy.
|
package/dist/index.d.ts
CHANGED
|
@@ -406,6 +406,7 @@ interface ClaudeCodeConfig {
|
|
|
406
406
|
planModeQuestion?: boolean;
|
|
407
407
|
webSearch?: WebSearchRouting;
|
|
408
408
|
hotReloadMcp?: boolean;
|
|
409
|
+
mcpConnectWaitMs?: number;
|
|
409
410
|
proxyOpencodeMcpTools?: boolean;
|
|
410
411
|
multiStepContinuation?: boolean;
|
|
411
412
|
autoContinueIncompleteTurns?: boolean | "smart";
|
|
@@ -784,6 +785,25 @@ interface ClaudeCodeProviderSettings {
|
|
|
784
785
|
* survives MCP changes until the chat is reset).
|
|
785
786
|
*/
|
|
786
787
|
hotReloadMcp?: boolean;
|
|
788
|
+
/**
|
|
789
|
+
* How long a turn waits for opencode MCP servers it reports as still
|
|
790
|
+
* connecting (`pending`) before planning the spawn without them, in
|
|
791
|
+
* milliseconds. Defaults to 3000; `0` disables the wait.
|
|
792
|
+
*
|
|
793
|
+
* This only ever engages on opencode 2, which answers its MCP status call
|
|
794
|
+
* immediately and reports a server it has not finished connecting to as
|
|
795
|
+
* `pending`. opencode 1 has no such status: its own status call blocks
|
|
796
|
+
* until every server has reached a decision, so this budget is what makes
|
|
797
|
+
* a 2.x host behave like a 1.x one. Without it, a conversation whose first
|
|
798
|
+
* turn arrives while opencode is still starting a server spawns `claude`
|
|
799
|
+
* without that server, and only the next turn's hot reload brings it in.
|
|
800
|
+
*
|
|
801
|
+
* Raise it for a slow server, or set `0` to always plan with whatever the
|
|
802
|
+
* host says at that instant. A server slower than the budget is not lost
|
|
803
|
+
* either way: `hotReloadMcp` moves the conversation onto a process that
|
|
804
|
+
* has it on the next fresh turn.
|
|
805
|
+
*/
|
|
806
|
+
mcpConnectWaitMs?: number;
|
|
787
807
|
/**
|
|
788
808
|
* Route opencode MCP server tools through the in-process `opencode_proxy`
|
|
789
809
|
* MCP server instead of bridging them directly into Claude CLI's
|
|
@@ -1257,6 +1277,8 @@ interface BridgedMcp {
|
|
|
1257
1277
|
*
|
|
1258
1278
|
* Treatment per server:
|
|
1259
1279
|
* - "connected" → force `enabled: true` (mirror opencode)
|
|
1280
|
+
* - "pending" → leave disk value (opencode 2 is still connecting;
|
|
1281
|
+
* see `MCP_PENDING_STATUS`)
|
|
1260
1282
|
* - any other status → force `enabled: false` (don't ship a server
|
|
1261
1283
|
* opencode can't run; user fixes it in opencode first)
|
|
1262
1284
|
* - missing entry → leave disk value
|