@khalilgharbaoui/opencode-claude-code-plugin 0.63.3 → 0.64.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
@@ -18,8 +18,6 @@
18
18
  [![License](https://img.shields.io/github/license/khalilgharbaoui/opencode-claude-code-plugin?style=flat-square&label=license&labelColor=15181E&color=FFC46B)](./LICENSE)
19
19
  [![Buy me a coffee](https://img.shields.io/badge/support-buy%20me%20a%20coffee-FFC46B?style=flat-square&labelColor=15181E&logo=buymeacoffee&logoColor=FFC46B)](https://www.buymeacoffee.com/khalilgharbaoui)
20
20
 
21
- <a href="https://www.buymeacoffee.com/khalilgharbaoui"><img src="site/public/buy-me-a-coffee.png" alt="Buy me a coffee" width="214" height="60"></a>
22
-
23
21
  **Claude Code is the provider.** This opencode plugin runs Anthropic's Claude models through the official **Claude Code CLI** (`claude`) as a subprocess instead of calling the HTTP API. opencode inherits whatever that CLI is logged in as (a Claude subscription, an API key, Bedrock or Vertex), gets Claude's own tools, MCP servers and skills, and keeps running the tools that touch your machine itself, behind its own permission prompts. One package serves opencode 1.x and 2.x.
24
22
 
25
23
  - **Your CLI's login, untouched.** The plugin never reads, stores or replays a token. Lifting the OAuth session out of the official client is what proxy-style plugins do, and Anthropic disallowed that for third-party Claude use in February 2026. This plugin structurally cannot do it.
@@ -46,9 +44,13 @@
46
44
  }
47
45
  ```
48
46
 
49
- `~/.config/opencode/opencode.json` on opencode 1.x. opencode 2 reads the same key; its native spelling is `plugins`.
47
+ `~/.config/opencode/opencode.json`, on opencode 1.x and 2.x alike. opencode 2's native key is `plugins`, and `opencode plugin add @khalilgharbaoui/opencode-claude-code-plugin` writes that entry and installs the package for you.
48
+
49
+ 3. **Quit opencode fully and relaunch.** Plugins load once, at process start. The model picker now has a **Claude Code** provider (opencode 1.x labels it with its id, `claude-code`) with entries such as `Claude Sonnet 5.5 (2×)` and `Claude Opus 5 (5×)`; the suffix is each model's list price relative to Haiku. A model's full id is `claude-code/<model>`, so one line checks it from a terminal:
50
50
 
51
- 3. **Quit opencode fully and relaunch.** Plugins load once, at process start. The model picker now has a **Claude Code (Default)** provider with entries such as `Claude Sonnet 5.5 (2×)` and `Claude Opus 5 (5×)`; the suffix is each model's list price relative to Haiku.
51
+ ```bash
52
+ opencode run -m claude-code/claude-haiku-5-5 "reply with ok"
53
+ ```
52
54
 
53
55
  Nothing in the picker? [Troubleshooting](./docs/troubleshooting/symptoms.md) is keyed on the first thing you see. `/claude-code-doctor` in any session prints what the plugin thinks is happening, without calling a model.
54
56
 
@@ -70,12 +72,14 @@ Nothing in the picker? [Troubleshooting](./docs/troubleshooting/symptoms.md) is
70
72
  | | opencode's native `anthropic` provider | This plugin | Proxy and token-reuse plugins |
71
73
  |---|---|---|---|
72
74
  | **Authentication** | A Platform API key in opencode's auth store. | Whatever the official `claude` CLI holds. No token is read, stored or replayed. | The Claude OAuth session, used outside the official client. |
73
- | **Terms-of-service status** | The ordinary API route. | Sanctioned: the official client does the authenticating. | Disallowed. Anthropic disallowed reusing subscription authentication for third-party Claude use in February 2026, and each of those projects carries its own disclaimer. |
75
+ | **Terms-of-service status** | The ordinary API route. | Uses the official client: Claude Code does the authenticating, the same as running `claude -p` yourself. Anthropic's [legal page](https://code.claude.com/docs/en/legal-and-compliance) allows signing in to the unmodified binary; it has not approved or endorsed this plugin. | Disallowed. Anthropic disallowed reusing subscription authentication for third-party Claude use in February 2026, and each of those projects carries its own disclaimer. |
74
76
  | **Who runs Bash, Edit, Write** | opencode. | opencode, by default; `Read`, `Grep`, `Glob` run in Claude Code. | opencode. |
75
77
  | **What it costs you** | Baseline. | A `claude` child per conversation under a cap of 16; Claude Code may compact its own context behind opencode's back. | One more moving part, plus the account risk above. |
76
78
 
77
79
  The [full comparison](./docs/comparison.md) has nine rows, names the projects in the third column, and quotes their own READMEs.
78
80
 
81
+ On opencode 2.2.3 or later with one Claude login, also look at opencode's own **Claude Agent** provider: it drives your own `claude` too, runs every tool in opencode, and leaves your `~/.claude` setup out. The comparison has [a section on it](./docs/comparison.md#opencodes-built-in-claude-agent-provider), including what this plugin still adds (opencode 1.x, several accounts, your Claude Code setup, fast mode, `/btw`, the sidebar).
82
+
79
83
  ## Built from measurements
80
84
 
81
85
  A dozen test files drive a fake `claude` through real turns: the stream parser, the proxy broker, both watchdogs, abort, respawn, account failover and the model fallback chain are exercised end to end. Every rule in [`AGENTS.md`](./AGENTS.md) names the probe, the version and the number that produced it, and the evidence lives in [`docs/agents-history.md`](./docs/agents-history.md). Two runtime dependencies. The [site](https://opencode-claude-code-plugin.dev/) reports the live numbers: it rebuilds itself after every release, on every push that moves a figure, and every six hours.
package/dist/index.js CHANGED
@@ -3200,6 +3200,11 @@ var DISPATCH_COMBOS = [
3200
3200
  effort: "high",
3201
3201
  description: "Most capable. Design work, tricky debugging, wide blast radius."
3202
3202
  },
3203
+ {
3204
+ model: "claude-opus-5-5",
3205
+ effort: "xhigh",
3206
+ description: "Most capable, thinks longer. For hard problems where high falls short."
3207
+ },
3203
3208
  {
3204
3209
  model: "claude-opus-5-5",
3205
3210
  effort: "max",
@@ -4054,6 +4059,15 @@ function forkSiblingSignature(sessionKey2) {
4054
4059
  blanked[3] = "*";
4055
4060
  return blanked.join("::");
4056
4061
  }
4062
+ function withoutSpawnSettings(segment) {
4063
+ if (!segment.startsWith("context=")) return segment;
4064
+ try {
4065
+ const context = JSON.parse(segment.slice("context=".length));
4066
+ if (Array.isArray(context)) return `context=${JSON.stringify(context.slice(0, 2))}`;
4067
+ } catch {
4068
+ }
4069
+ return segment;
4070
+ }
4057
4071
  function modelSiblingSignature(sessionKey2, accountProviders) {
4058
4072
  const parts = sessionKey2.split("::");
4059
4073
  if (parts.length < 5) return null;
@@ -4062,6 +4076,7 @@ function modelSiblingSignature(sessionKey2, accountProviders) {
4062
4076
  if (withoutEffort.length < 5) return null;
4063
4077
  const blanked = [...withoutEffort];
4064
4078
  blanked[1] = "*";
4079
+ blanked[blanked.length - 1] = withoutSpawnSettings(blanked[blanked.length - 1]);
4065
4080
  const signature = blanked.join("::");
4066
4081
  return accountProviders && accountProviders.size > 0 ? blankAccountProvider(signature, accountProviders) : signature;
4067
4082
  }
@@ -8455,9 +8470,9 @@ async function releaseIdleForHandover(sessionID) {
8455
8470
  }
8456
8471
  return released;
8457
8472
  }
8458
- function transferClaudeSession(fromKey, toKey) {
8473
+ function transferClaudeSession(fromKey, toKey, recorded) {
8459
8474
  if (fromKey === toKey) return void 0;
8460
- const claudeSessionId = claudeSessions.get(fromKey);
8475
+ const claudeSessionId = claudeSessions.get(fromKey) ?? recorded;
8461
8476
  if (!claudeSessionId) return void 0;
8462
8477
  if (claudeSessions.has(toKey)) return void 0;
8463
8478
  claudeSessions.delete(fromKey);
@@ -8480,14 +8495,7 @@ function effortSessionKey(baseKey, effort) {
8480
8495
  function spawnIdentity(key) {
8481
8496
  const parts = key.split("::");
8482
8497
  if (parts.length > 1 && parts[parts.length - 1].startsWith("effort=")) parts.pop();
8483
- const last = parts.length - 1;
8484
- if (parts[last].startsWith("context=")) {
8485
- try {
8486
- const context = JSON.parse(parts[last].slice("context=".length));
8487
- if (Array.isArray(context)) parts[last] = `context=${JSON.stringify(context.slice(0, 2))}`;
8488
- } catch {
8489
- }
8490
- }
8498
+ parts[parts.length - 1] = withoutSpawnSettings(parts[parts.length - 1]);
8491
8499
  return parts.join("::");
8492
8500
  }
8493
8501
  function spawnHasPendingWork(key) {
@@ -8543,7 +8551,8 @@ function invalidateOtherSpawnVariants(currentKey, options = {}) {
8543
8551
  clearBackgroundTasks(key);
8544
8552
  continue;
8545
8553
  }
8546
- deleteClaudeSessionId(key);
8554
+ if (carry && !claudeSessions.has(key)) forgetClaudeSessionInMemory(key);
8555
+ else deleteClaudeSessionId(key);
8547
8556
  clearCompression(key);
8548
8557
  clearBackgroundTasks(key);
8549
8558
  }
@@ -19104,7 +19113,7 @@ var ClaudeCodeLanguageModel = class {
19104
19113
  });
19105
19114
  } else {
19106
19115
  deleteActiveProcess(sibling.siblingKey);
19107
- const carried = transferClaudeSession(sibling.siblingKey, sk);
19116
+ const carried = transferClaudeSession(sibling.siblingKey, sk, sibling.claudeSessionId);
19108
19117
  if (carried) {
19109
19118
  if (carriedSessionId && carriedSessionId !== carried) {
19110
19119
  setClaudeSessionId(sk, carriedSessionId);