@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 +9 -5
- package/dist/index.js +21 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/claude-code-plugin/SKILL.md +28 -11
package/README.md
CHANGED
|
@@ -18,8 +18,6 @@
|
|
|
18
18
|
[](./LICENSE)
|
|
19
19
|
[](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
|
|
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
|
-
|
|
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. |
|
|
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
|
-
|
|
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
|
-
|
|
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);
|