@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 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 Code Haiku 4.5 | 200k | 8,192 | – |
72
- | `claude-sonnet-4-5` | Claude Code Sonnet 4.5 | 1M | 16,384 | low/medium/high/xhigh/max |
73
- | `claude-sonnet-4-6` | Claude Code Sonnet 4.6 | 1M | 16,384 | low/medium/high/xhigh/max |
74
- | `claude-opus-4-5` | Claude Code Opus 4.5 | 1M | 16,384 | low/medium/high/xhigh/max |
75
- | `claude-opus-4-6` | Claude Code Opus 4.6 | 1M | 16,384 | low/medium/high/xhigh/max |
76
- | `claude-opus-4-7` | Claude Code Opus 4.7 | 1M | 16,384 | low/medium/high/xhigh/max |
77
- | `claude-opus-4-8` | Claude Code Opus 4.8 | 1M | 16,384 | low/medium/high/xhigh/max |
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 — or, if the run is non-interactive, to proceed with the single most reasonable option and state its assumption rather than stall.
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 = isAskUserQuestionTool(toolName) ? "Your question and its options have already been presented to the operator in full. Prefer to stop here and wait for their answer in the next message \u2014 do not silently guess. But if this is an automated or otherwise non-interactive run where no operator will reply, do not stall: proceed with the single most reasonable option and state, in one line, the assumption you made so it can be corrected later." : this.config.controlRequestDenyMessage ?? `Denied by opencode-claude-code policy for tool ${toolName}`;
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: 15e-6, output: 75e-6, cacheRead: 15e-7, cacheWrite: 1875e-8 };
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