@khalilgharbaoui/opencode-claude-code-plugin 0.34.0 → 0.35.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khalilgharbaoui/opencode-claude-code-plugin",
3
- "version": "0.34.0",
3
+ "version": "0.35.0",
4
4
  "description": "Claude Code CLI provider plugin for opencode",
5
5
  "author": "Khalil Gharbaoui",
6
6
  "type": "module",
@@ -21,7 +21,8 @@
21
21
  "build": "tsup",
22
22
  "dev": "tsup --watch",
23
23
  "typecheck": "tsc --noEmit",
24
- "test": "OPENCODE_CLAUDE_CODE_LOG_FILE=0 tsx --test test-bridge.ts test-broker.ts test-proxy-mcp.ts test-proxy-task.ts test-auto-continue.ts test-has-new-user-content.ts test-get-claude-user-message.ts test-logger.ts test-cli-args.ts test-permission-presets.ts test-session-manager.ts test-compaction-model.ts test-tool-mapping.ts test-cwd-resolution.ts test-todo-ledger.ts test-session-affinity.ts test-config-models.ts test-ask-user-question.ts test-claude-session-wrapper.ts test-spawn-env.ts test-respawn.ts test-startup-diagnostics.ts test-subagent-hint.ts test-exit-plan-mode-question.ts test-compress-tool.ts test-agent-models.ts test-side-question.ts test-btw-command.ts test-effort-sessions.ts test-tool-block-index.ts test-context-usage.ts test-skill-bridge.ts test-turn-stats.ts test-cli-events.ts test-cli-events-stream.ts test-result-fallback.ts test-doctor.ts test-configure-skill.ts test-unattended-replay.ts test-process-lifecycle.ts test-account-failover.ts test-host-tools.ts test-v2-entrypoint.ts test-v2-client.ts test-tmp-dir.ts test-cleanup-stale.ts test-account-wrapper.ts test-runtime-status-sessions.ts test-index-hooks.ts test-silent-turn.ts test-mcp-tool-result-name.ts test-model-fallback.ts test-do-generate.ts test-interactive-usage.ts test-background-subagents.ts test-interactive-result.ts test-cli-probe-cache.ts test-mcp-late-connect.ts"
24
+ "test": "OPENCODE_CLAUDE_CODE_LOG_FILE=0 tsx --test test-bridge.ts test-broker.ts test-proxy-mcp.ts test-proxy-task.ts test-auto-continue.ts test-has-new-user-content.ts test-get-claude-user-message.ts test-logger.ts test-cli-args.ts test-permission-presets.ts test-session-manager.ts test-compaction-model.ts test-tool-mapping.ts test-cwd-resolution.ts test-todo-ledger.ts test-session-affinity.ts test-config-models.ts test-ask-user-question.ts test-claude-session-wrapper.ts test-spawn-env.ts test-respawn.ts test-startup-diagnostics.ts test-subagent-hint.ts test-exit-plan-mode-question.ts test-compress-tool.ts test-agent-models.ts test-side-question.ts test-btw-command.ts test-effort-sessions.ts test-tool-block-index.ts test-context-usage.ts test-skill-bridge.ts test-turn-stats.ts test-cli-events.ts test-cli-events-stream.ts test-result-fallback.ts test-doctor.ts test-configure-skill.ts test-unattended-replay.ts test-process-lifecycle.ts test-account-failover.ts test-host-tools.ts test-v2-entrypoint.ts test-v2-client.ts test-tmp-dir.ts test-cleanup-stale.ts test-account-wrapper.ts test-runtime-status-sessions.ts test-index-hooks.ts test-silent-turn.ts test-mcp-tool-result-name.ts test-model-fallback.ts test-do-generate.ts test-interactive-usage.ts test-background-subagents.ts test-interactive-result.ts test-cli-probe-cache.ts test-mcp-late-connect.ts test-prologue-abort.ts test-diagnostic-bundle.ts",
25
+ "generate:log-messages": "tsx scripts/generate-log-messages.ts"
25
26
  },
26
27
  "dependencies": {
27
28
  "@ai-sdk/provider": "^3.0.8",
@@ -131,7 +131,7 @@ Defaults below describe normal headless opencode use when the key is absent.
131
131
  | `mcpConfig` | string or string[] | unset | Extra `--mcp-config` paths or inline JSON passed alongside the bridged config. |
132
132
  | `strictMcpConfig` | boolean | `false` | Headless `--strict-mcp-config`: use only explicitly supplied MCP configs, ignoring other MCP sources, not all settings/credentials/hooks. The interactive wrapper adds it whenever it passes MCP paths, independently of this option. |
133
133
  | `hotReloadMcp` | boolean | `true` | With bridging on, compare merged MCP config/status at turn start and respawn on drift, so a server enabled, disabled or finished connecting since the spawn reaches the model. Keeps the session via headless `--resume`. Acts only at a safe boundary: never during compaction, never on the interactive transport, and never while a proxied call is pending, a turn is in flight or a plan-mode approval is outstanding. Logs the joined and left server names at INFO. One respawn per conversation per `CLAUDE_CODE_MCP_HOT_RELOAD_COOLDOWN_MS` (default 60000) so a flapping server cannot respawn every turn. Does not reload arbitrary provider options or watch explicit `mcpConfig` contents. |
134
- | `mcpConnectWaitMs` | number | `3000` | How long the first turn waits for MCP servers the host reports as still connecting before planning the spawn without them. Only opencode 2 reports that state (`pending`); opencode 1's status call blocks until every server decides, so this is a no-op there and costs one status call as before. `0` disables the wait; negative or non-numeric values fall back to the default. A server slower than the budget is still bridged (pending is not read as disabled) and `hotReloadMcp` brings a later one in on the next turn. |
134
+ | `mcpConnectWaitMs` | number | `3000` | How long the first turn waits for MCP servers the host reports as still connecting before planning the spawn without them. Only opencode 2 reports that state (`pending`); opencode 1's status call blocks until every server decides, so this is a no-op there and costs one status call as before. `0` disables the wait; negative or non-numeric values fall back to the default. Aborting the turn ends the wait at once, and the turn then spawns nothing. A server slower than the budget is still bridged (pending is not read as disabled) and `hotReloadMcp` brings a later one in on the next turn. |
135
135
  | `proxyOpencodeMcpTools` | boolean | `false` | Route opencode's MCP-backed tools through opencode's executor instead of Claude's own `--mcp-config` child, so each call is permission-prompted and rendered as an opencode tool row. Default changed `true` to `false` here, with no behaviour change: at `true` it routed nothing, because discovery read opencode's tool registry, which never contains MCP tools. Discovery now reads the model tool set opencode passes the provider, verified live on opencode 1.18.31 / Claude Code 2.1.263. **Tell the user to set `strictMcpConfig: true` alongside it**: a server also present in Claude Code's own config is reached directly and the proxy is bypassed, which looks exactly like the option doing nothing. A routed call runs with the calling agent's permissions. Servers whose tools are not found stay on the direct bridge and log a warning. Inert with `bridgeOpencodeMcp: false`, which leaves no bridged server list to match names against. Do not promise exactly-once side effects across failures, retries or opencode versions; verify routing before using write-capable tools. |
136
136
  | `proxyOpencodeTools` | string[] | `[]` | Forward explicitly named opencode tools (case-insensitive): V1 resolves registry ids; V2 resolves the current model tool snapshot and its actual JSON Schema, including synthesized Code Mode `execute`, without re-exposing tools absent from that snapshot. Covers plugin-declared tools such as DCP's `compress` and V2 Code Mode. Same broker as other proxies; collisions and unknown names warn. Explicit allowlist only, because calls run in opencode with the agent's permissions. `execute` grants access to the session's whole Code Mode catalog, not just MCP, and is refused by the read-only preset. |
137
137
  | `stripContextReminders` | boolean | `false` | Strip opencode-dcp `<dcp-system-reminder>` blocks from user/assistant message text, including the fresh-session rebuild. Only when no `compress` is proxied via `proxyTools` or `proxyOpencodeTools`; reachable compress makes it inert. Resolved from config, so a configured-but-unregistered name still counts as reachable. Leaves opencode's own `<system-reminder>` blocks alone. |
@@ -679,6 +679,8 @@ configured/env directory). INFO is enough for startup diagnostics. Add
679
679
  `"level": "debug"` only if needed for lower-level events; `mode: "debug"` alone does
680
680
  not do that. Capture a bounded, redacted excerpt, then disable temporary logging and
681
681
  restart. Logs rotate above 5 MB to `plugin.log.1`, which can also contain private data.
682
+ Never hand either file to anyone: for anything shared, use `/claude-code-doctor bundle`,
683
+ which is redacted by allowlist (see "Filing an issue" below).
682
684
 
683
685
  ### Upgrade the plugin
684
686
 
@@ -814,6 +816,16 @@ warned about content that did not load. Read it whenever bridged skills are miss
814
816
  `opencode-skills@...` row is the skill bridge itself, which is a plugin bug to report,
815
817
  not something to fix in the user's config.
816
818
 
819
+ A **Hooks Claude Code ran that failed** section appears only when one did. These are the
820
+ user's own Claude Code hooks (`hook_response` with `outcome: "error"` or a non-zero
821
+ `exit_code`), not opencode's. A failing `SessionStart` hook is otherwise invisible: the
822
+ CLI drops its contribution and the turn succeeds, so the context it was meant to add is
823
+ missing from every turn on that process. Read it whenever a hook's effect is absent. The
824
+ first failure is also a WARN in the terminal. Only the hook's `stderr` is shown, capped
825
+ at 200 characters, because its stdout is spliced into the model's context. The plugin
826
+ never passes `--include-hook-events`, so only `SessionStart` (and `Setup`) hooks are
827
+ reported at all; `cancelled` is not a failure, since an abort produces it.
828
+
817
829
  A **Background subagents** section is always printed: whether `background` was offered
818
830
  to Claude and `task_status` / `task_cancel` registered, the opencode major, what decided
819
831
  it, and the background tasks this process collected or cancelled. It reads
@@ -832,6 +844,37 @@ runs the user's `SessionStart` hooks and takes a few seconds; say that when sugg
832
844
  it. Do not propose `--bare` to skip the hooks: it never reads OAuth, so it reports
833
845
  nothing about a subscription.
834
846
 
847
+ ### Filing an issue: /claude-code-doctor bundle
848
+
849
+ `/claude-code-doctor bundle` is what to tell a user to paste into a GitHub issue. It
850
+ returns the normal report plus this process's recent `NOTICE`/`WARN`/`ERROR` lines from
851
+ `plugin.log`, redacted. Unlike `usage` it starts no process, so it stays instant.
852
+ **Never ask a user to attach `plugin.log` itself**: it has no redaction guarantee and
853
+ can hold whole system prompts, spawn argv with `--settings` JSON, bridged MCP config
854
+ paths and session ids. The same applies to the rotated `plugin.log.1`.
855
+
856
+ The redaction is an allowlist, not a filter. Per line it keeps the timestamp, the level,
857
+ the message **only** when it is one of the message literals extracted from the plugin's
858
+ own source (`src/log-messages.ts`, generated by `npm run generate:log-messages`), and
859
+ only data fields whose key is on an explicit allowlist and whose value is then the kind
860
+ that entry declares: versions, counts, booleans, enums, durations, exit codes, model /
861
+ tool / server names, paths and the loopback proxy URL. The allowlist applies at every
862
+ nesting depth. Everything else, every unknown key included, becomes
863
+ `[redacted, N chars]`, which keeps the shape without the content. Session ids become a
864
+ per-bundle salted hash, so lines correlate inside one paste and nowhere else, and the
865
+ home directory becomes `~` across the whole report including the table.
866
+
867
+ Never in a bundle: prompt or reply text, system prompts, tool inputs or outputs, file
868
+ contents, environment values, bearer tokens, the proxy `authToken`, API keys,
869
+ `Authorization` headers, MCP server env or headers, URL credentials or query strings,
870
+ or the raw spawn argv (option names are kept, every value is replaced).
871
+
872
+ Capped at 120 lines and 24,000 bytes, newest first, with a line saying how many were
873
+ left out. With file logging off the section says so, tells the user to relaunch under
874
+ `OPENCODE_CLAUDE_CODE_LOG_FILE=1` or set `logging.file`, and the report is still
875
+ returned. A message a maintainer cannot read in a bundle means that warning's text is
876
+ built at runtime; its data fields still carry the diagnosis.
877
+
835
878
  Claude Code stream events the plugin now surfaces without debug logging: a rate-limit
836
879
  rejection, a context compaction the CLI did on its own, a `result` subtype other than
837
880
  `success` (which now finishes the turn as an error, not a clean stop), and a failed
@@ -865,6 +908,7 @@ Prefer the doctor: it needs no logging change and no restart.
865
908
  | No `claude-code` provider or model in the picker at all | The plugin never loaded, or it loaded and the CLI was not usable | Check for a `plugin ready` line first: absent means not loaded (wrong `plugin`/`plugins` key, a 2.x local install not pointing at `dist/`, or no full relaunch), present with `claudeCli.version: not detected` means the binary did not answer `--version`, which also disables every version-gated flag |
866
909
  | `Model unavailable` for a model id the user typed | The provider id is not what they assumed | Use the id the ready block's `providers` field lists. With no `accounts` configured on opencode 2 the id is `claude-code`, so `claude-code-default/<model>` fails while the plugin is healthy (measured on opencode 2.0.16, 2026-09-27). Declaring `accounts` is what creates `claude-code-default`; on 1.x with accounts the ids are `claude-code-default` / `claude-code-<name>` and never a bare `claude-code` |
867
910
  | `Tool result name changed`, turn aborts, on opencode 2 | Before 0.28.1 a CLI-executed tool's result reached opencode under a different name than its call, and 2.0.16 aborts the turn on the mismatch, breaking every Claude-side MCP server call | Upgrade to 0.28.1+ **and fully relaunch every opencode window**; plugin code is read once at process start, so upgrading the package under a running window changes nothing |
911
+ | A `SessionStart` hook the user configured has no visible effect | It exited non-zero and Claude Code discarded its contribution; the turn still succeeded | Read the **Hooks Claude Code ran that failed** section of `/claude-code-doctor` for the exit code and the hook's stderr. It is their Claude Code settings to fix, not the plugin's |
868
912
  | `plugin ready` missing from the log | Logging is off (the default), or the plugin genuinely did not load | Confirm `OPENCODE_CLAUDE_CODE_LOG_FILE=1` and a relaunch before concluding anything. `/claude-code-doctor` answers the same questions with no logging change |
869
913
  | "Failed to authenticate: OAuth session expired", one account, turns failing in milliseconds | That account's CLI login lapsed | `claude auth status` for it, then log in again with the command the `▌ **claude account:**` note prints (`CLAUDE_CONFIG_DIR=<that account's dir> claude auth login`). Restart opencode after: a switch taken from the failover form lasts until restart. Login is a user action, never a diagnostic probe |
870
914
  | A tool call reported as rejected although it ran | Two fixed causes: opencode 1.18.32 aborts the provider signal of every step ending in tool calls, read as an operator stop (0.26.1); and a call waiting on an unanswered permission prompt was rejected at the flat 10-minute deadline, after which the late approval cancelled Claude's next call (0.26.2) | Upgrade to 0.26.2+ and relaunch. Do NOT raise `proxyToolTimeoutMs` for this: a deadline now waits while opencode reports the session busy |
@@ -881,6 +925,7 @@ Prefer the doctor: it needs no logging change and no restart.
881
925
  | A `subtask: true` command's subagent output is "lost" | Bug fixed in 0.15.4 | Upgrade |
882
926
  | Two subagents run one after another | The CLI serialises MCP calls | Plugin 0.17.0+; the model must use `mcp__opencode_proxy__task_batch` |
883
927
  | Esc does not stop Claude; aborted turns keep running | Plugin older than 0.16.0 | Upgrade |
928
+ | Esc pressed in the first moment of a turn does nothing, and the turn runs and bills anyway | A turn prepares before it asks the CLI for anything (spawn directory, `claude --version`, opencode's MCP status and tool registry), and a stop that landed in that window used to be dropped. Fixed: the turn ends there, spawning nothing and writing nothing, and the reply is empty | Upgrade and fully relaunch every opencode window. Grep `plugin.log` for `abort while the turn was still being prepared` |
884
929
  | Under `opencode serve` or the web UI every project spawns Claude in the server's launch dir | Plugin older than 0.16.0 | Upgrade, or pin `cwd` |
885
930
  | 400 `Third-party apps now draw from your extra usage…` | Subscription/account usage gate, including disabled extra usage or an exhausted window | Explain waiting, account choice and billing options; do not enable paid usage, switch auth or change transport without approval |
886
931
  | Warning that a fast turn ran at standard speed | Fast mode ineligible (usage credits off, cooldown, not first-party) | Prefer non-fast id; paid usage changes require approval |