@khalilgharbaoui/opencode-claude-code-plugin 0.6.3 → 0.8.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 +17 -11
- package/dist/index.js +45 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ claude --version
|
|
|
23
23
|
|
|
24
24
|
That's it. Restart opencode, pick a `claude-code` model, done.
|
|
25
25
|
|
|
26
|
-
The plugin self-registers the `claude-code` provider, all current Claude Code models (Haiku 4.5, Sonnet 4.5/4.6, Opus 4.5/4.6/4.7/4.8) with reasoning variants (`low` / `medium` / `high` / `xhigh` / `max`), and sensible defaults for tool proxying. You don't need to write a `provider` block at all unless you want to override something.
|
|
26
|
+
The plugin self-registers the `claude-code` provider, all current Claude Code models (Haiku 4.5, Sonnet 4.5/4.6, Opus 4.5/4.6/4.7/4.8, Fable 5, Mythos 5) with reasoning variants (`low` / `medium` / `high` / `xhigh` / `max`), and sensible defaults for tool proxying. You don't need to write a `provider` block at all unless you want to override something.
|
|
27
27
|
|
|
28
28
|
---
|
|
29
29
|
|
|
@@ -66,18 +66,24 @@ In your `opencode.json`, point at the local build with a `file://` URL:
|
|
|
66
66
|
|
|
67
67
|
The plugin auto-registers the following. They appear in the model picker without any extra config.
|
|
68
68
|
|
|
69
|
-
| ID | Display name | Context | Output | Reasoning variants |
|
|
70
|
-
|
|
71
|
-
| `claude-haiku-4-5` | Claude
|
|
72
|
-
| `claude-sonnet-4-5` | Claude
|
|
73
|
-
| `claude-sonnet-4-6` | Claude
|
|
74
|
-
| `claude-opus-4-5` | Claude
|
|
75
|
-
| `claude-opus-4-6` | Claude
|
|
76
|
-
| `claude-opus-4-7` | Claude
|
|
77
|
-
| `claude-opus-4-8` | Claude
|
|
69
|
+
| ID | Display name | Context | Output | Reasoning variants | Price × |
|
|
70
|
+
|---|---|---|---|---|---|
|
|
71
|
+
| `claude-haiku-4-5` | Claude Haiku 4.5 | 200k | 8,192 | – | 1× |
|
|
72
|
+
| `claude-sonnet-4-5` | Claude Sonnet 4.5 | 1M | 16,384 | low/medium/high/xhigh/max | 3× |
|
|
73
|
+
| `claude-sonnet-4-6` | Claude Sonnet 4.6 | 1M | 16,384 | low/medium/high/xhigh/max | 3× |
|
|
74
|
+
| `claude-opus-4-5` | Claude Opus 4.5 | 1M | 16,384 | low/medium/high/xhigh/max | 5× |
|
|
75
|
+
| `claude-opus-4-6` | Claude Opus 4.6 | 1M | 16,384 | low/medium/high/xhigh/max | 5× |
|
|
76
|
+
| `claude-opus-4-7` | Claude Opus 4.7 | 1M | 16,384 | low/medium/high/xhigh/max | 5× |
|
|
77
|
+
| `claude-opus-4-8` | Claude Opus 4.8 | 1M | 16,384 | low/medium/high/xhigh/max | 5× |
|
|
78
|
+
| `claude-fable-5` | Claude Fable 5 | 1M | 16,384 | low/medium/high/xhigh/max | 10× |
|
|
79
|
+
| `claude-mythos-5` | Claude Mythos 5 | 1M | 16,384 | low/medium/high/xhigh/max | 10× |
|
|
80
|
+
|
|
81
|
+
`claude-mythos-5` is Mythos-class like Fable 5 but without safety classifiers, and is **limited availability via [Project Glasswing](https://anthropic.com/glasswing)**. It's registered unconditionally; if your Claude account lacks access, `claude --model claude-mythos-5` just errors. Use `claude-fable-5` (generally available) otherwise.
|
|
78
82
|
|
|
79
83
|
Capabilities for every model: text + image input, text output, tool use, attachments. No temperature control, no PDF/audio/video, no interleaved streaming.
|
|
80
84
|
|
|
85
|
+
**Price ×** is each model's per-token list price relative to Haiku, the cheapest model. It's derived exactly from Anthropic's published pricing — input and output ratios both come out the same (Haiku $1/$5 = 1×, Sonnet $3/$15 = 3×, Opus 4.8 $5/$25 = 5×, Fable 5 / Mythos 5 $10/$50 = 10×), so **Fable 5 and Mythos 5 cost 2× Opus 4.8**. The same multiplier is shown as a `(N×)` suffix on the display name in opencode's model picker, since opencode has no dedicated multiplier field. On a flat Max/Pro subscription it doubles as a rough guide to how fast each model drains your usage limit.
|
|
86
|
+
|
|
81
87
|
The model ID is passed straight through to `claude --model`, so anything Claude Code accepts works.
|
|
82
88
|
|
|
83
89
|
### Picking a variant
|
|
@@ -319,7 +325,7 @@ Set `permissionMode: "plan"` to forward `--permission-mode plan` to Claude. The
|
|
|
319
325
|
opencode has no native structured ask-question executor to proxy through (unlike `Bash`/`Task`), so the plugin handles `AskUserQuestion` specially:
|
|
320
326
|
|
|
321
327
|
1. **It renders the full question.** The tool's payload — every question, header, option label, and option description — is emitted as readable markdown into the assistant stream so the user actually sees the choices (same approach as `ExitPlanMode`).
|
|
322
|
-
2. **It is never auto-allowed at the CLI gate.** Allowing it would let the headless Claude CLI resolve its own question (no TTY → fabricated/empty answer) and proceed on a guess. `controlRequestBehaviorForTool` hard-denies `AskUserQuestion` and returns a message telling the model to wait for the operator's answer —
|
|
328
|
+
2. **It is never auto-allowed at the CLI gate.** Allowing it would let the headless Claude CLI resolve its own question (no TTY → fabricated/empty answer) and proceed on a guess. `controlRequestBehaviorForTool` hard-denies `AskUserQuestion` and returns a message telling the model to **stop and wait for the operator's answer** — end the turn, call no further tools, and never self-answer. (Before v0.7.0 this message also offered an "if the run is non-interactive, proceed with a reasonable guess" fallback. The model could not reliably tell interactive opencode from a headless run and routinely took it, so questions appeared to be skipped — [issue #8](https://github.com/khalilgharbaoui/opencode-claude-code-plugin/issues/8). For genuinely unattended runs, use the `controlRequestToolBehaviors` override below instead.)
|
|
323
329
|
|
|
324
330
|
This hard-deny sits **below** `controlRequestToolBehaviors` in precedence but **above** the global `controlRequestBehavior`. So:
|
|
325
331
|
|
package/dist/index.js
CHANGED
|
@@ -2018,6 +2018,11 @@ function isAskUserQuestionTool(name) {
|
|
|
2018
2018
|
const n = name.toLowerCase();
|
|
2019
2019
|
return n === "askuserquestion" || n === "ask_user_question";
|
|
2020
2020
|
}
|
|
2021
|
+
var ASK_USER_QUESTION_DENY_MESSAGE = "Your question and its options have already been presented to the operator verbatim. Stop now: end your turn without calling any more tools and without answering the question yourself. Wait for the operator's reply, which arrives as the next user message. Do not guess, assume, or proceed on their behalf.";
|
|
2022
|
+
function denyMessageForTool(toolName, configuredDenyMessage) {
|
|
2023
|
+
if (isAskUserQuestionTool(toolName)) return ASK_USER_QUESTION_DENY_MESSAGE;
|
|
2024
|
+
return configuredDenyMessage ?? `Denied by opencode-claude-code policy for tool ${toolName}`;
|
|
2025
|
+
}
|
|
2021
2026
|
function formatAskUserQuestion(input) {
|
|
2022
2027
|
const anyInput = input;
|
|
2023
2028
|
const questions = Array.isArray(anyInput?.questions) ? anyInput.questions : [];
|
|
@@ -2460,7 +2465,10 @@ var ClaudeCodeLanguageModel = class {
|
|
|
2460
2465
|
toolName
|
|
2461
2466
|
});
|
|
2462
2467
|
} else {
|
|
2463
|
-
const denyMessage =
|
|
2468
|
+
const denyMessage = denyMessageForTool(
|
|
2469
|
+
toolName,
|
|
2470
|
+
this.config.controlRequestDenyMessage
|
|
2471
|
+
);
|
|
2464
2472
|
this.writeControlResponse(proc, requestId, {
|
|
2465
2473
|
behavior: "deny",
|
|
2466
2474
|
message: denyMessage,
|
|
@@ -4120,7 +4128,7 @@ function defineModel(opts) {
|
|
|
4120
4128
|
id: opts.id,
|
|
4121
4129
|
providerID: PROVIDER_ID,
|
|
4122
4130
|
api: { id: opts.id, url: "", npm: NPM },
|
|
4123
|
-
name: opts.name
|
|
4131
|
+
name: `${opts.name} (${opts.multiplier}\xD7)`,
|
|
4124
4132
|
family: opts.family,
|
|
4125
4133
|
capabilities: { ...baseCapabilities, reasoning: opts.reasoning },
|
|
4126
4134
|
cost: {
|
|
@@ -4138,7 +4146,8 @@ function defineModel(opts) {
|
|
|
4138
4146
|
}
|
|
4139
4147
|
var haikuCost = { input: 1e-6, output: 5e-6, cacheRead: 1e-7, cacheWrite: 125e-8 };
|
|
4140
4148
|
var sonnetCost = { input: 3e-6, output: 15e-6, cacheRead: 3e-7, cacheWrite: 375e-8 };
|
|
4141
|
-
var opusCost = { input:
|
|
4149
|
+
var opusCost = { input: 5e-6, output: 25e-6, cacheRead: 5e-7, cacheWrite: 625e-8 };
|
|
4150
|
+
var fableCost = { input: 1e-5, output: 5e-5, cacheRead: 1e-6, cacheWrite: 125e-7 };
|
|
4142
4151
|
function toConfigModel(model) {
|
|
4143
4152
|
const inputMods = [];
|
|
4144
4153
|
const outputMods = [];
|
|
@@ -4180,6 +4189,7 @@ var defaultModels = {
|
|
|
4180
4189
|
context: 2e5,
|
|
4181
4190
|
output: 8192,
|
|
4182
4191
|
cost: haikuCost,
|
|
4192
|
+
multiplier: 1,
|
|
4183
4193
|
releaseDate: "2024-10-22"
|
|
4184
4194
|
}),
|
|
4185
4195
|
"claude-sonnet-4-5": defineModel({
|
|
@@ -4190,6 +4200,7 @@ var defaultModels = {
|
|
|
4190
4200
|
context: 1e6,
|
|
4191
4201
|
output: 16384,
|
|
4192
4202
|
cost: sonnetCost,
|
|
4203
|
+
multiplier: 3,
|
|
4193
4204
|
releaseDate: "2025-04-14"
|
|
4194
4205
|
}),
|
|
4195
4206
|
"claude-sonnet-4-6": defineModel({
|
|
@@ -4200,6 +4211,7 @@ var defaultModels = {
|
|
|
4200
4211
|
context: 1e6,
|
|
4201
4212
|
output: 16384,
|
|
4202
4213
|
cost: sonnetCost,
|
|
4214
|
+
multiplier: 3,
|
|
4203
4215
|
releaseDate: "2025-06-19"
|
|
4204
4216
|
}),
|
|
4205
4217
|
"claude-opus-4-5": defineModel({
|
|
@@ -4210,6 +4222,7 @@ var defaultModels = {
|
|
|
4210
4222
|
context: 1e6,
|
|
4211
4223
|
output: 16384,
|
|
4212
4224
|
cost: opusCost,
|
|
4225
|
+
multiplier: 5,
|
|
4213
4226
|
releaseDate: "2025-04-14"
|
|
4214
4227
|
}),
|
|
4215
4228
|
"claude-opus-4-6": defineModel({
|
|
@@ -4220,6 +4233,7 @@ var defaultModels = {
|
|
|
4220
4233
|
context: 1e6,
|
|
4221
4234
|
output: 16384,
|
|
4222
4235
|
cost: opusCost,
|
|
4236
|
+
multiplier: 5,
|
|
4223
4237
|
releaseDate: "2025-06-19"
|
|
4224
4238
|
}),
|
|
4225
4239
|
"claude-opus-4-7": defineModel({
|
|
@@ -4230,6 +4244,7 @@ var defaultModels = {
|
|
|
4230
4244
|
context: 1e6,
|
|
4231
4245
|
output: 16384,
|
|
4232
4246
|
cost: opusCost,
|
|
4247
|
+
multiplier: 5,
|
|
4233
4248
|
releaseDate: "2025-07-16"
|
|
4234
4249
|
}),
|
|
4235
4250
|
"claude-opus-4-8": defineModel({
|
|
@@ -4240,7 +4255,34 @@ var defaultModels = {
|
|
|
4240
4255
|
context: 1e6,
|
|
4241
4256
|
output: 16384,
|
|
4242
4257
|
cost: opusCost,
|
|
4258
|
+
multiplier: 5,
|
|
4243
4259
|
releaseDate: "2026-05-28"
|
|
4260
|
+
}),
|
|
4261
|
+
"claude-fable-5": defineModel({
|
|
4262
|
+
id: "claude-fable-5",
|
|
4263
|
+
name: "Claude Fable 5",
|
|
4264
|
+
family: "fable",
|
|
4265
|
+
reasoning: true,
|
|
4266
|
+
context: 1e6,
|
|
4267
|
+
output: 16384,
|
|
4268
|
+
cost: fableCost,
|
|
4269
|
+
multiplier: 10,
|
|
4270
|
+
releaseDate: "2026-06-09"
|
|
4271
|
+
}),
|
|
4272
|
+
// Mythos 5 shares Fable 5's capabilities and pricing without the safety
|
|
4273
|
+
// classifiers; limited availability via Project Glasswing. `claude --model
|
|
4274
|
+
// claude-mythos-5` simply errors for accounts without access, so it's safe to
|
|
4275
|
+
// register unconditionally.
|
|
4276
|
+
"claude-mythos-5": defineModel({
|
|
4277
|
+
id: "claude-mythos-5",
|
|
4278
|
+
name: "Claude Mythos 5",
|
|
4279
|
+
family: "mythos",
|
|
4280
|
+
reasoning: true,
|
|
4281
|
+
context: 1e6,
|
|
4282
|
+
output: 16384,
|
|
4283
|
+
cost: fableCost,
|
|
4284
|
+
multiplier: 10,
|
|
4285
|
+
releaseDate: "2026-06-09"
|
|
4244
4286
|
})
|
|
4245
4287
|
};
|
|
4246
4288
|
|