@khalilgharbaoui/opencode-claude-code-plugin 0.4.18 → 0.4.20

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
@@ -173,6 +173,7 @@ The account model IDs are internally suffixed, for example `claude-sonnet-4-6@wo
173
173
  | `webSearch` | `"claude"` \| `"disabled"` \| `<tool>` | `"claude"` | Routing for Claude's built-in `WebSearch`. See [WebSearch routing](#websearch-routing). |
174
174
  | `multiStepContinuation` | boolean | `true` | Append a system-prompt hint nudging Claude to chain tool calls within one turn instead of pausing between subtasks. Each opencode turn boundary requires the user to manually press "continue", so for multi-step tasks this reduces friction. Set `false` to disable. |
175
175
  | `autoContinueIncompleteTurns` | boolean \| `"smart"` | `"smart"` | Smartly continue incomplete Claude CLI results inside the same opencode turn. Reduces manual "continue" presses when Claude ends after reasoning/tool activity without a useful final answer. Set `false` to disable. |
176
+ | `compactionModel` | string | `"claude-haiku-4-5"` | Model used when opencode invokes `/compact`. Override per-process via the `CLAUDE_CODE_COMPACTION_MODEL` env var (env wins over config). See [Compaction](#compaction). |
176
177
 
177
178
  ### Overriding model metadata
178
179
 
@@ -309,6 +310,50 @@ Set `permissionMode: "plan"` to forward `--permission-mode plan` to Claude. The
309
310
 
310
311
  ---
311
312
 
313
+ ## Compaction
314
+
315
+ When you run `/compact` in opencode, the plugin handles it on a short-lived dedicated Claude CLI spawn instead of routing it through your main conversation process. Three reasons:
316
+
317
+ 1. **Cost.** The summarizer reads your entire transcript every time. Routing through a smaller model keeps `/compact` from burning your Opus budget.
318
+ 2. **Latency.** Claude Haiku 4.5 hits ~150 tok/s with a hard 8k output cap, so compaction completes predictably (~30s for a long transcript).
319
+ 3. **Cleanliness.** The compaction spawn skips MCP servers, the tool proxy, and the multi-step continuation hint. It's a one-shot text-out call; the rest is overhead.
320
+
321
+ The transcript itself is serialized rich: tool inputs and tool results are both included (each clipped at 10k chars), with oldest entries dropped first when the aggregate exceeds 180k chars. The summarizer sees actual tool activity rather than placeholders.
322
+
323
+ ### Picking a different compaction model
324
+
325
+ | Source | How | Wins over |
326
+ |---|---|---|
327
+ | Env var (per-process) | `CLAUDE_CODE_COMPACTION_MODEL=claude-sonnet-4-6 opencode` | config, default |
328
+ | `opencode.json` (per-project) | `"compactionModel": "claude-sonnet-4-6"` under `provider.claude-code.options` | default |
329
+ | Default | `claude-haiku-4-5` | – |
330
+
331
+ Anything Claude Code's `--model` accepts works as a value.
332
+
333
+ ---
334
+
335
+ ## Extended thinking
336
+
337
+ The plugin forwards Claude's thinking blocks (`thinking_delta` stream events) to opencode as reasoning parts, so the "Thinking" row in the chat panel shows whenever the model uses extended thinking. This works across every Claude 4 family model the CLI supports.
338
+
339
+ What you see is a **summary** of the model's thinking, not the raw chain-of-thought. Anthropic [stopped exposing raw thinking on the Claude 4 family](https://platform.claude.com/docs/en/build-with-claude/extended-thinking#summarized-thinking) and ships a server-generated digest instead. For Claude Opus 4.7 specifically, [thinking content is omitted from responses by default](https://platform.claude.com/docs/en/about-claude/models/whats-new-claude-4-7#thinking-content-omitted-by-default); the plugin opts back in by passing `--thinking-display summarized` on every spawn. Claude Code CLI 2.1.142+ is required for that flag to take effect; older CLIs skip it silently.
340
+
341
+ ### Reasoning effort variants
342
+
343
+ Each model exposes `low` / `medium` / `high` / `xhigh` / `max` variants. Picking one injects the corresponding Claude CLI thinking keyword (e.g. `(ultrathink)` for `max`) into the user message. Compaction calls skip this injection so the full output budget goes to the summary.
344
+
345
+ ### Env-var overrides
346
+
347
+ The plugin respects the standard Claude Code thinking env vars. If you set them in your shell, they pass through to the spawned process untouched.
348
+
349
+ | Env var | Effect |
350
+ |---|---|
351
+ | `CLAUDE_CODE_DISABLE_THINKING=1` | Disable thinking entirely. |
352
+ | `CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING=1` | Disable adaptive thinking only. |
353
+ | `CLAUDE_CODE_SHOW_THINKING_SUMMARIES=0` | Suppress summaries (the plugin sets this to `1` by default when unset). |
354
+
355
+ ---
356
+
312
357
  ## Quirks worth knowing
313
358
 
314
359
  - **Empty text blocks are dropped.** Claude sometimes opens a `content_block_start` for text but never sends a delta. The plugin no longer emits the empty block (which was triggering Anthropic 400s like `cache_control cannot be set for empty text blocks`).
@@ -385,8 +430,8 @@ plugin internals.
385
430
  ## Known limitations
386
431
 
387
432
  - No streaming of tool inputs as they're being constructed (Anthropic's `input_json_delta`); the plugin emits them once complete.
388
- - No interleaved thinking Claude Code CLI doesn't expose reasoning tokens to the SDK.
389
- - The CLI must be a recent enough version to support `--mcp-config` and `--disallowedTools`. If something breaks after a Claude Code update, that's the first thing to check.
433
+ - Raw chain-of-thought is not available. Claude 4 family models ship summarized thinking only. See [Extended thinking](#extended-thinking) for the full picture.
434
+ - Recommended Claude Code CLI: **2.1.142+**. Older CLIs work for everything else but skip the `--thinking-display` flag, so Claude Opus 4.7 turns may render empty Thinking rows. If something breaks after a Claude Code update, the CLI version is the first thing to check.
390
435
 
391
436
  ---
392
437
 
@@ -405,9 +450,11 @@ src/
405
450
  index.ts # opencode plugin entry, config + provider hooks
406
451
  models.ts # default models + variants
407
452
  claude-code-language-model.ts # AI-SDK provider that drives `claude`
453
+ message-builder.ts # AI-SDK prompt → Claude CLI user message
408
454
  proxy-mcp.ts # in-process MCP server for proxied tools
409
455
  mcp-bridge.ts # opencode → Claude --mcp-config translator
410
456
  session-manager.ts # LRU cache of CLI subprocesses
457
+ cli-version.ts # detect Claude CLI version, gate optional flags
411
458
  logger.ts # DEBUG=opencode-claude-code stderr logger
412
459
  types.ts # public option types
413
460
  opencode-types.ts # mirrored opencode types
package/dist/index.d.ts CHANGED
@@ -84,6 +84,34 @@ type OpenCodeEvent = {
84
84
  };
85
85
  [key: string]: unknown;
86
86
  };
87
+ /**
88
+ * Input shape for the `chat.params` hook. opencode passes the agent name
89
+ * for the current call ("default", "compaction", "title", etc.), the
90
+ * resolved model, and the user message. Output is the mutable params bag
91
+ * the hook can adjust before opencode forwards them to the LM.
92
+ */
93
+ type OpenCodeChatParamsInput = {
94
+ sessionID?: string;
95
+ agent?: string;
96
+ model?: OpenCodeModel & {
97
+ providerID: ProviderID;
98
+ };
99
+ provider?: {
100
+ source?: string;
101
+ info?: {
102
+ id?: ProviderID;
103
+ };
104
+ options?: Record<string, unknown>;
105
+ };
106
+ message?: unknown;
107
+ };
108
+ type OpenCodeChatParamsOutput = {
109
+ temperature?: number;
110
+ topP?: number;
111
+ topK?: number;
112
+ maxOutputTokens?: number;
113
+ options?: Record<string, unknown>;
114
+ };
87
115
  type OpenCodeHooks = {
88
116
  config?: (input: OpenCodeConfig) => Promise<void>;
89
117
  provider?: {
@@ -93,6 +121,7 @@ type OpenCodeHooks = {
93
121
  event?: (input: {
94
122
  event: OpenCodeEvent;
95
123
  }) => Promise<void>;
124
+ "chat.params"?: (input: OpenCodeChatParamsInput, output: OpenCodeChatParamsOutput) => Promise<void>;
96
125
  };
97
126
  type OpenCodePlugin = (input: unknown, options?: Record<string, unknown>) => Promise<OpenCodeHooks>;
98
127
 
@@ -120,6 +149,7 @@ interface ClaudeCodeConfig {
120
149
  proxyOpencodeMcpTools?: boolean;
121
150
  multiStepContinuation?: boolean;
122
151
  autoContinueIncompleteTurns?: boolean | "smart";
152
+ compactionModel?: string;
123
153
  logging?: LoggingConfig;
124
154
  }
125
155
  interface LoggingConfig {
@@ -265,6 +295,14 @@ interface ClaudeCodeProviderSettings {
265
295
  * Set to `false` to disable.
266
296
  */
267
297
  autoContinueIncompleteTurns?: boolean | "smart";
298
+ /**
299
+ * Model id used when opencode invokes `/compact`. Defaults to
300
+ * `claude-haiku-4-5` — fast, cheap, strong structured summarizer. Set
301
+ * to override per-project in `opencode.json` / `opencode.jsonc`; the
302
+ * `CLAUDE_CODE_COMPACTION_MODEL` env var overrides this in turn for
303
+ * one-off runs without editing config.
304
+ */
305
+ compactionModel?: string;
268
306
  /**
269
307
  * Logger configuration. See `LoggingConfig` for fields. Env vars
270
308
  * (`OPENCODE_CLAUDE_CODE_LOG_FILE`, `OPENCODE_CLAUDE_CODE_LOG_DIR`,
@@ -419,6 +457,16 @@ declare class ClaudeCodeLanguageModel implements LanguageModelV3 {
419
457
  */
420
458
  private handleControlRequest;
421
459
  private getReasoningEffort;
460
+ private getOpencodeAgent;
461
+ private isCompactionCall;
462
+ /**
463
+ * Pick the model used to handle /compact. Precedence:
464
+ * 1. `CLAUDE_CODE_COMPACTION_MODEL` env var (per-process override)
465
+ * 2. `compactionModel` provider setting (opencode.json / .jsonc)
466
+ * 3. Built-in default (claude-haiku-4-5)
467
+ */
468
+ private resolveCompactionModel;
469
+ private thinkingCliOptions;
422
470
  private latestUserText;
423
471
  private synthesizeTitle;
424
472
  private doGenerateViaStream;