@khalilgharbaoui/opencode-claude-code-plugin 0.63.1 → 0.63.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khalilgharbaoui/opencode-claude-code-plugin",
3
- "version": "0.63.1",
3
+ "version": "0.63.3",
4
4
  "description": "Claude Code CLI provider plugin for opencode",
5
5
  "homepage": "https://opencode-claude-code-plugin.dev/",
6
6
  "funding": {
@@ -159,7 +159,7 @@ Defaults below describe normal headless opencode use when the key is absent.
159
159
  | `turnStats` | boolean | `false` | Append one `▌ **stats:**` line to each finished turn: cost, wall duration, CLI turn count, input/output/cache-read/cache-write tokens, and a permission-denial count when the turn had any, taken from the CLI's own `result`. Never on a compaction turn or a turn that ended in error. Its own text part, stripped from transcripts rebuilt for the CLI, so the model never sees it. The same numbers are logged at INFO regardless, and `modelUsage` plus `permission_denials` always reach `providerMetadata`. The cost is THIS turn's: the CLI reports the Claude session's running total, and the footer prints the difference from that session's previous total (the INFO line carries both, `costUsd` and `turnCostUsd`). The first turn of a session resumed after an opencode restart, or of a fork, prints no cost, because `--resume` restores the running total and there is nothing to subtract; the next turn has it again. Not a billing guarantee. |
160
160
  | `forkSessions` | boolean | `false` | When a new opencode session turns out to be a fork of one this provider already served, branch the parent's Claude conversation with `claude --resume <parent> --fork-session` instead of re-rendering the whole thread as text into the first message. Measured on CLI 2.1.280 with haiku 4.5 over a ~13k-token thread: 814 cache tokens written and 39,710 read, against 22,355 written and 17,385 read for the replay, so $0.0058 against $0.0467 for that turn; the parent's transcript is byte-identical afterwards. Neither opencode major tells a provider that a session is a fork, so the parent is found by matching this prompt's history against what each sibling session key was last asked to continue. Off by default because a resumed Claude conversation reuses the system prompt recorded on its FIRST request (`--system-prompt-snapshot`, default `on`), so a forked session answers under the parent's appended system prompt rather than this turn's; measured directly, a parent seeded with codename ZEBRA and forked while passing QUAIL answered ZEBRA. Falls back to the replay, unchanged, for: another account, an unknown or released parent session id, a busy parent (live process, proxied call in flight, unanswered plan-mode question), a fork cut mid-conversation, a fork taken mid tool round trip, a different cwd / model / agent / effort / prompt-cache TTL, compaction, an account-failover switch, and a `claude` whose `--help` does not advertise `--fork-session`. Recording costs nothing while the option is off. |
161
161
  | `resumeAfterRestart` | boolean | `true` | After an opencode restart, resume the conversation's Claude session (`--resume`) instead of replaying the thread as text. Persists session id + conversation digest per session key in `$XDG_STATE_HOME/opencode-claude-code-plugin/claude-sessions.json` (0600, 256 entries, 30 days) after each successful turn. Resumes only on the same session key and binary, with the transcript on disk and the history equal to the recorded conversation plus Claude's reply; anything else (edit, revert, compaction, account switch, open tool round trip) replays. opencode-dcp's `<dcp-message-id>` references (and its `@12@` compact form) are not part of the digest: dcp renumbers them on every opencode restart, so after an undo the same message came back under another number and the conversation was refused as `conversation-changed`. Records carry a digest `version`; one without it (written by an older plugin) is compared the old way. Not on compaction. Log: `resuming the claude session from before the restart` (NOTICE) or `not resuming ...` with a reason (INFO). `false` disables reading and writing. |
162
- | `resumeAcrossModelChanges` | boolean | `true` | When the operator changes a conversation's model or reasoning effort mid-conversation, continue the same Claude session (`--resume <id> --model <new>`) instead of replaying the thread as text. Both are in the session key, so changing either used to start a fresh Claude conversation (issue #91); neither needs one, because `--model` and `CLAUDE_CODE_EFFORT_LEVEL` are spawn-time and the CLI applies either to a resumed transcript (measured on 2.1.288). The session is MOVED off the old key, so one Claude conversation has exactly one owner. Refused on every term `resumeAfterRestart` is refused on (another account, a transcript that is gone, a conversation that changed) plus two more: a sibling whose transcript may still be written to, and anything that is not the same cwd, request scope, opencode session, agent and prompt-cache TTL. Not on compaction, not on an account-failover switch. It reads the record `resumeAfterRestart` writes, so `resumeAfterRestart: false` turns it off too. Log: `continuing this conversation's claude session under the new model or effort` (NOTICE). |
162
+ | `resumeAcrossModelChanges` | boolean | `true` | When the operator changes a conversation's model or reasoning effort mid-conversation, continue the same Claude session (`--resume <id> --model <new>`) instead of replaying the thread as text. Both are in the session key, so changing either used to start a fresh Claude conversation (issue #91); neither needs one, because `--model` and `CLAUDE_CODE_EFFORT_LEVEL` are spawn-time and the CLI applies either to a resumed transcript (measured on 2.1.288). The session is MOVED off the old key, so one Claude conversation has exactly one owner. Refused on every term `resumeAfterRestart` is refused on (another account, a transcript that is gone, a conversation that changed) plus two more: a sibling whose transcript may still be written to (that turn is served on the sibling instead and the change applies at the next turn that finds it idle, h #g271), and anything that is not the same cwd, request scope, opencode session, agent and prompt-cache TTL. Not on compaction, not on an account-failover switch. It reads the record `resumeAfterRestart` writes, so `resumeAfterRestart: false` turns it off too. Log: `continuing this conversation's claude session under the new model or effort` (NOTICE). |
163
163
  | `crossAccountResume` | boolean | `true` | On any account switch (a by-hand pick of another account's model in the same session, the switch form, and the switch back when the override expires), and only between accounts in the same `accountGroups` group, continue the same Claude conversation on the other account instead of replaying the thread as text. An account is a `CLAUDE_CONFIG_DIR` and a conversation is one `projects/<encoded cwd>/<id>.jsonl` inside it, so the switch copies that file into the target account's own projects dir (0600, dir 0700) and keeps the session id for the `--resume` both transports already build. Measured on CLI 2.1.288: a copied transcript resumes under another config dir with its context intact, the CLI resolves a session by FILENAME (not the `sessionId` in the records), it appends to the copy it found rather than to the cwd's path, the source comes out byte-identical, and no record holds a user, org or account id. Never overwrites: an older copy already at the target path (what a switch back finds) makes the carry take a fresh session id, and the live copy is the longest one. Refuses on nothing to carry, a non-file at the target path, or a failed copy, and each refusal falls back to the replay. Not on compaction, and inert with one account. Log: `carried this conversation's claude transcript to the other account` or `replaying this conversation as text on the other account` with a reason (both NOTICE). What is NOT verified live is a different Anthropic login answering another's conversation; `false` keeps the replay. |
164
164
  | `usageWarnThresholds` | number[] | `[50, 75, 90, 95]` | Percent levels of a usage window at which a SERVED turn ends with one `▌ **usage:**` note (its own text part, stripped from rebuilt transcripts): account, window, utilization, reset in local time. Read from every headless `rate_limit_event` (not only a rejected one), whose `utilization` is a FRACTION (`0.9` is 90%) and is ABSENT on an `allowed` event with headroom, which is unknown, never zero, and crosses nothing. The same event's `unifiedWindows` carries every window's own utilization and reset (measured on CLI 2.1.293), and each listed window is recorded, so the 7-day window has readings and notes while the 5-hour one limits. Readings persist per account per window in `$XDG_STATE_HOME/opencode-claude-code-plugin/account-usage.json` (`0600`, names, numbers and times only), and so does the dedup: each threshold is said once per account per window across reused processes, sessions and restarts, again only after the window's reset. A crossing in a `/compact` turn or a child session is not said there and is said by the next ordinary turn on the account. Never on `doGenerate`, never turns a served turn into a failure. `[]` turns the notes off but keeps the readings. The single-account name is `default`. Interactive transport: no event, so only a limit reply is recorded (`limited`). Log: `claude account usage crossed a warning threshold` (NOTICE). |
165
165
  | `usageSwitchAt` | number / `false` | `90` | Percent at which work leaves an account BEFORE the wall, when another `failoverCandidates` account (same `accountGroups` group) exists and is not itself at that level per the store. `accountFailover: "auto"`: sets the existing account override (keyed on the account, until the window's reset; in memory, lost on restart) so the NEXT turn spawns on the other account, carried like a limit switch; the note says `New turns move to the "<account>" account until HH:MM`. `"ask"` / `"off"`: nothing moves and no form (the form only ends a FAILED turn); the note names the other account to pick a model from. The turn that crossed finishes as served. Also a threshold in its own right, so the switch is said exactly once per window. `false` or `0` never. Log: `claude account is near its usage limit; new turns move to another account until the window resets` (WARN). |
@@ -1462,7 +1462,7 @@ Prefer the doctor: it needs no logging change and no restart.
1462
1462
  | `proxy call still waiting` in the log, or a `task` that looks stuck | Expected: `task`/`task_batch` carry no default deadline, and the line is a status report | `/claude-code-doctor` lists pending calls with tool, age and deadline. Tell a working subagent from a wedged one there before proposing any timeout change; see the note under "Proxy tool names" |
1463
1463
  | An MCP server's tool returns nothing useful, and `plugin.log` carries `MCP server asked for operator input and was declined` | That server raised an MCP **elicitation**, a mid-call request for the operator to type or choose something. The Claude Code session the plugin drives is headless, so there is nobody to ask: the plugin answers `{"action":"decline"}` under the CLI's documented schema and warns once per server. The tool call still returns and the turn continues | Not configurable, and deliberately so: accepting would mean inventing the answer the server asked for. Run that server's flow in Claude Code directly, where its own dialog can take the input, or configure the server so that path does not elicit |
1464
1464
  | An MCP server's tools are simply absent | Claude Code could not connect that server | Read the once-per-process WARN at session start, and the doctor's **MCP config entries Claude Code skipped** section for one the CLI refused outright. `mcpServers` in the ready block is disk discovery, not live connectivity; fix the server where it is configured |
1465
- | `MCP server "<name>" is needs-auth in Claude Code`, for a remote server that works in opencode | Whether the user authenticated it through opencode's own OAuth flow. opencode holds that token; the bridged config carries no credential, so the CLI cannot connect and the server is dead for the whole session | On opencode **1**, `bridgeMcpOauthTokens: true` hands the CLI the token opencode already has. Tell the user what it does before suggesting it: it copies a credential out of opencode's own store into the bridged `0600` config. On opencode **2** there is no such file and the option finds nothing, so the fix is configuring that server for Claude Code directly |
1465
+ | `MCP server "<name>" is needs-auth in Claude Code` (or `N MCP servers are needs-auth ...` listing several), for a remote server that works in opencode. A `claude.ai` connector the account never connected (not in the CLI's `claudeAiMcpEverConnected`) is never warned about: it is logged at INFO and listed in `/claude-code-doctor` | Whether the user authenticated it through opencode's own OAuth flow. opencode holds that token; the bridged config carries no credential, so the CLI cannot connect and the server is dead for the whole session | On opencode **1**, `bridgeMcpOauthTokens: true` hands the CLI the token opencode already has. Tell the user what it does before suggesting it: it copies a credential out of opencode's own store into the bridged `0600` config. On opencode **2** there is no such file and the option finds nothing, so the fix is configuring that server for Claude Code directly |
1466
1466
  | An MCP server opencode has configured is missing on the FIRST turn of a fresh `opencode run`, but present in the TUI | Not a config fault, and mostly fixed. The bridge reads opencode's live MCP status when the turn plans its spawn. On opencode 2 a server still connecting is reported `pending`, which the bridge no longer reads as disabled, and the turn waits up to `mcpConnectWaitMs` (3 s) for the host to decide; opencode 1 cannot reach this state, because its own status call blocks until every server resolves. If the server is slower than the budget it is still bridged, and if it genuinely joins later `hotReloadMcp` moves the conversation onto a process that has it on the next turn, logging `opencode MCP servers changed, respawning claude` with the joined names | Nothing, usually. For a very slow server raise `mcpConnectWaitMs`. Check `plugin.log` for `waited for opencode MCP servers to finish connecting` and for the respawn line; if neither appears and the server is still absent, the status the host reported was a real refusal (`failed`, `needs_auth`), which is opencode's to fix |
1467
1467
  | `permissionPreset` set but nothing about the session looks restricted | The option never reached that provider, or the name is not one the plugin knows (only `read-only` exists) | Read the `permissionPreset` row in `/claude-code-doctor`, or `permissionPresets` in the ready block, for the provider the conversation is on: `none` means it is not configured there (each account is its own provider id), `applied: false` with a name means an unrecognised name applied nothing, and `overrides` lists what an applied preset replaced |
1468
1468
  | `permissionPreset: "read-only"` set, but reads are unconfined or something still prompts | `--restricted` needs CLI 2.1.258 and `--permission-prompts none` needs 2.1.263; below those the preset falls back to `--disallowedTools` plus the plugin's own deny and WARNs naming what is lost | `claude --version`. Below 2.1.258 the working-directory confinement on reads is gone; below 2.1.263 the denial happens in the plugin instead of the CLI. The preset still holds, with one layer fewer |