@khalilgharbaoui/opencode-claude-code-plugin 0.12.1 → 0.13.1

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
@@ -181,7 +181,8 @@ The account model IDs are internally suffixed, for example `claude-sonnet-4-6@wo
181
181
  | `cwd` | string | `process.cwd()` | Working directory for the spawned CLI. Resolved **lazily per request**, so opencode's project switching works. |
182
182
  | `skipPermissions` | boolean | `true` | Pass `--dangerously-skip-permissions` to `claude`. Ignored when `proxyTools` is set — the proxy handles permissions through opencode instead. |
183
183
  | `permissionMode` | `acceptEdits` \| `auto` \| `bypassPermissions` \| `default` \| `dontAsk` \| `plan` | – | Forwarded to `claude --permission-mode`. |
184
- | `proxyTools` | string[] | `["Bash", "Edit", "Write", "WebFetch", "Task"]` | Claude built-in tools to route through opencode's executor + permission UI. See [Selective tool proxy](#selective-tool-proxy). |
184
+ | `proxyTools` | string[] | `["Bash", "Edit", "Write", "WebFetch", "Task"]` | Claude built-in tools to route through opencode's executor + permission UI. Opt-in extras: `"Question"`, `"Compress"`. See [Selective tool proxy](#selective-tool-proxy). |
185
+ | `extraDisallowedTools` | string[] | – | Extra Claude built-ins to switch off with `--disallowedTools`, on top of what `proxyTools` implies. Claude's names, e.g. `["NotebookEdit"]`. See [Closing a tool with no proxy](#closing-a-tool-with-no-proxy). |
185
186
  | `proxyToolTimeoutMs` | `Record<string, number>` | – | Per-tool proxy call deadline in ms, keyed by proxy tool name (`bash`, `task`, …). Defaults: 10 min flat, `task` → 60 min. For `bash`, the call's own `input.timeout` is honoured on top (`max(resolved, input.timeout)`). See [Selective tool proxy](#selective-tool-proxy). |
186
187
  | `planModeQuestion` | boolean | `false` | Route `ExitPlanMode` approval through opencode's native `question` tool instead of a text "(yes/no)" prompt. Off because opencode's question form is currently broken upstream. See [Plan mode](#plan-mode). |
187
188
  | `controlRequestBehavior` | `allow` \| `deny` | `allow` | Default response when `skipPermissions: false` and Claude sends a `can_use_tool` control request. |
@@ -273,6 +274,7 @@ By default, the plugin proxies `Bash`, `Edit`, `Write`, `WebFetch`, and `Task`.
273
274
  | `"WebFetch"` | `WebFetch` | `mcp__opencode_proxy__webfetch` |
274
275
  | `"Task"` | `Agent` | `mcp__opencode_proxy__task` |
275
276
  | `"Question"` | `AskUserQuestion` | `mcp__opencode_proxy__question` |
277
+ | `"Compress"` | none | `mcp__opencode_proxy__compress` |
276
278
 
277
279
  ### OpenCode-native subagents
278
280
 
@@ -297,7 +299,35 @@ recovery step for harnesses that defer MCP tool schemas. Both apply per Claude
297
299
  process at spawn, and provider options are read once at opencode startup, so
298
300
  `proxyTools` changes need a full opencode restart.
299
301
 
300
- Only those six values are actually proxied; anything else you put in `proxyTools` is ignored. Proxying `Edit` also disables `MultiEdit` — opencode has no batched-edit equivalent, so Claude is forced to fan out into single `Edit` calls that each flow through the permission UI. The `"Question"` proxy is version-gated on opencode's built-in `question` tool: on builds that lack the registry entry the def is silently dropped (a forwarded call would otherwise render as `⚙ invalid`), so add it only on opencode versions that ship the `question` tool.
302
+ ### Closing a tool with no proxy
303
+
304
+ `proxyTools` only reaches built-ins the plugin can replace. A built-in with no opencode equivalent, `NotebookEdit` today and whatever Claude Code ships next, stays enabled and unmediated no matter what you put in that list. `extraDisallowedTools` names them directly:
305
+
306
+ ```json
307
+ "options": {
308
+ "extraDisallowedTools": ["NotebookEdit"]
309
+ }
310
+ ```
311
+
312
+ These go straight to `claude --disallowedTools`, so use Claude's tool names rather than opencode's. There is no replacement: the capability goes away rather than being routed through opencode, which is the point, but the model then has to work without it.
313
+
314
+ Unknown entries in `proxyTools` are logged as a warning at spawn rather than passing silently, so a typo shows up as "ignoring unknown proxyTools entries" in the plugin log instead of quietly leaving the matching built-in unmediated.
315
+
316
+ ### Context compression
317
+
318
+ `"Compress"` is off by default. Add it when you run a harness that expects the model to manage its own context (opencode-dcp injects exactly those instructions), and the plugin exposes `mcp__opencode_proxy__compress`:
319
+
320
+ ```json
321
+ "options": {
322
+ "proxyTools": ["Bash", "Edit", "Write", "WebFetch", "Task", "Compress"]
323
+ }
324
+ ```
325
+
326
+ It is the one proxy tool opencode never sees. The call is answered inside the plugin: the model passes a `summary`, the plugin stores it, and the turn continues normally. At the start of the **next** turn the Claude Code session is discarded and a fresh `claude` starts with that summary prepended to its system prompt, and nothing else. The earlier conversation is not replayed, so a thin summary means real lost context. The reset waits if the incoming turn is carrying tool results for the running process.
327
+
328
+ Without it, the appended system prompt tells the model that `compress` is unavailable and to ignore instructions that ask for it, which is the right answer when nothing implements it.
329
+
330
+ Only those seven values are actually proxied; anything else you put in `proxyTools` is ignored. Proxying `Edit` also disables `MultiEdit` — opencode has no batched-edit equivalent, so Claude is forced to fan out into single `Edit` calls that each flow through the permission UI. The `"Question"` proxy is version-gated on opencode's built-in `question` tool: on builds that lack the registry entry the def is silently dropped (a forwarded call would otherwise render as `⚙ invalid`), so add it only on opencode versions that ship the `question` tool.
301
331
 
302
332
  Without `"Task"` in `proxyTools`, Claude's built-in `Agent` tool stays enabled and Claude orchestrates subagents internally with no opencode child-session visibility. To opt out of all proxying, including Task, use an explicit empty list:
303
333
 
package/dist/index.d.ts CHANGED
@@ -161,6 +161,7 @@ interface ClaudeCodeConfig {
161
161
  controlRequestToolBehaviors?: Record<string, ControlRequestBehavior>;
162
162
  controlRequestDenyMessage?: string;
163
163
  proxyTools?: string[];
164
+ extraDisallowedTools?: string[];
164
165
  proxyToolTimeoutMs?: Record<string, number>;
165
166
  /**
166
167
  * Route `ExitPlanMode` through opencode's native `question` tool so plan
@@ -283,6 +284,20 @@ interface ClaudeCodeProviderSettings {
283
284
  * entry, in which case the deny/markdown fallback applies.
284
285
  */
285
286
  proxyTools?: string[];
287
+ /**
288
+ * Extra Claude Code built-ins to switch off with `--disallowedTools`,
289
+ * on top of the ones implied by `proxyTools`.
290
+ *
291
+ * `proxyTools` can only disable built-ins the plugin knows how to
292
+ * replace, so a built-in with no proxy equivalent (`NotebookEdit`, and
293
+ * anything Claude Code adds after this release) has no off switch
294
+ * otherwise. Names are Claude's, not opencode's: `["NotebookEdit"]`.
295
+ *
296
+ * Disabling a tool with no replacement removes the capability rather
297
+ * than routing it through opencode — that is the point, but it does mean
298
+ * the model has to work without it.
299
+ */
300
+ extraDisallowedTools?: string[];
286
301
  /**
287
302
  * Per-tool proxy call timeouts in milliseconds, keyed by the proxy tool
288
303
  * name (`bash`, `edit`, `write`, `webfetch`, `task`, `question` —
@@ -655,6 +670,7 @@ interface ClaudeCodeProvider {
655
670
  (modelId: string): LanguageModelV3;
656
671
  languageModel(modelId: string): LanguageModelV3;
657
672
  }
673
+ declare const DEFAULT_PROXY_TOOL_NAMES: string[];
658
674
  declare function createClaudeCode(settings?: ClaudeCodeProviderSettings): ClaudeCodeProvider;
659
675
  /**
660
676
  * Build models in OpenCode's config schema format (flat properties like
@@ -673,4 +689,4 @@ declare const _default: {
673
689
  server: OpenCodePlugin;
674
690
  };
675
691
 
676
- export { type ClaudeCodeConfig, ClaudeCodeLanguageModel, type ClaudeCodeProvider, type ClaudeCodeProviderSettings, type ClaudeStreamMessage, type OpenCodeHooks, type OpenCodeModel, type OpenCodePlugin, bridgeOpencodeMcp, claudeCodeProviders, configModelsForProvider, createClaudeCode, _default as default, defaultModels };
692
+ export { type ClaudeCodeConfig, ClaudeCodeLanguageModel, type ClaudeCodeProvider, type ClaudeCodeProviderSettings, type ClaudeStreamMessage, DEFAULT_PROXY_TOOL_NAMES, type OpenCodeHooks, type OpenCodeModel, type OpenCodePlugin, bridgeOpencodeMcp, claudeCodeProviders, configModelsForProvider, createClaudeCode, _default as default, defaultModels };
package/dist/index.js CHANGED
@@ -294,6 +294,9 @@ var CLAUDE_INTERNAL_TOOLS = /* @__PURE__ */ new Set([
294
294
  "TaskGet",
295
295
  "TaskStop"
296
296
  ]);
297
+ function singleQuoteForShell(value) {
298
+ return `'${value.replace(/'/g, `'\\''`)}'`;
299
+ }
297
300
  function emitTodoWrite(todos) {
298
301
  return {
299
302
  name: "todowrite",
@@ -348,7 +351,7 @@ function mapTool(name, input, opts) {
348
351
  return {
349
352
  name: "bash",
350
353
  input: {
351
- command: `echo "TASK OUTPUT: ${String(output).replace(/"/g, '\\"')}"`,
354
+ command: `printf '%s\\n' ${singleQuoteForShell(`TASK OUTPUT: ${String(output)}`)}`,
352
355
  description: "Displaying task output"
353
356
  },
354
357
  executed: false
@@ -2212,6 +2215,31 @@ function spawnInteractiveProcess(opts) {
2212
2215
  };
2213
2216
  }
2214
2217
 
2218
+ // src/compression-store.ts
2219
+ var MAX_COMPRESSION_ENTRIES = 32;
2220
+ var compressions = /* @__PURE__ */ new Map();
2221
+ function storeCompressionSummary(sessionKey2, summary) {
2222
+ compressions.set(sessionKey2, { summary, restartPending: true });
2223
+ while (compressions.size > MAX_COMPRESSION_ENTRIES) {
2224
+ const oldest = compressions.keys().next();
2225
+ if (oldest.done) break;
2226
+ compressions.delete(oldest.value);
2227
+ log.info("compression store evicted oldest entry", { sessionKey: oldest.value });
2228
+ }
2229
+ }
2230
+ function getCompressionSummary(sessionKey2) {
2231
+ return compressions.get(sessionKey2)?.summary;
2232
+ }
2233
+ function consumeCompressionRestart(sessionKey2) {
2234
+ const state = compressions.get(sessionKey2);
2235
+ if (!state?.restartPending) return false;
2236
+ state.restartPending = false;
2237
+ return true;
2238
+ }
2239
+ function clearCompression(sessionKey2) {
2240
+ compressions.delete(sessionKey2);
2241
+ }
2242
+
2215
2243
  // src/proxy-mcp.ts
2216
2244
  import { createServer } from "http";
2217
2245
  import * as fs4 from "fs";
@@ -2279,6 +2307,7 @@ var TASK_PROXY_NOTE = "This is the ONLY tool that dispatches opencode subagents
2279
2307
  var AGENT_TYPES_HEADING = "Available agent types";
2280
2308
  var AGENT_BLURB_LIMIT = 140;
2281
2309
  var QUESTION_PROXY_NOTE = "This routes structured questions through opencode's native `question` tool, which renders a TUI form with the options you provide and blocks until the operator answers. Claude Code's built-in AskUserQuestion is disabled in this environment; this proxy is the ONLY way to ask the operator for a decision or clarification. Answers come back as arrays of selected labels (set `multiple: true` to allow more than one). If the operator dismisses the form the call returns an error \u2014 treat that as 'no answer' and stop, do not guess. Question calls get a 30-minute proxy deadline by default (configurable via proxyToolTimeoutMs); for long-AFK scenarios prefer fewer, high-signal questions.";
2310
+ var COMPRESS_PROXY_NOTE = "The current turn continues normally after this call \u2014 finish what you are doing. The reset happens at the START of the next turn: the Claude Code session is discarded and a fresh one begins with your summary as its only prior context. Everything else, including tool output and files you read, is gone, so write the summary as the authoritative record. Call this once per compression, when older resolved work no longer needs full detail.";
2282
2311
  function extractAgentTypeList(liveDescription) {
2283
2312
  const live = liveDescription?.trim();
2284
2313
  if (!live) return void 0;
@@ -2493,9 +2522,23 @@ var DEFAULT_PROXY_TOOLS = [
2493
2522
  },
2494
2523
  required: ["questions"]
2495
2524
  }
2525
+ },
2526
+ {
2527
+ name: "compress",
2528
+ description: "Replace older conversation detail with a summary you write, then continue in a fresh Claude Code session. Handled inside the plugin, so it never prompts the operator. " + COMPRESS_PROXY_NOTE,
2529
+ inputSchema: {
2530
+ type: "object",
2531
+ properties: {
2532
+ summary: {
2533
+ type: "string",
2534
+ description: "Dense technical summary of the work being compressed: decisions made, files changed, commands run and their outcomes, and what is still open. This is the ONLY prior context that survives, so anything omitted is lost."
2535
+ }
2536
+ },
2537
+ required: ["summary"]
2538
+ }
2496
2539
  }
2497
2540
  ];
2498
- async function createProxyMcpServer(tools = DEFAULT_PROXY_TOOLS, timeoutOverrides) {
2541
+ async function createProxyMcpServer(tools = DEFAULT_PROXY_TOOLS, timeoutOverrides, interceptors) {
2499
2542
  const calls = new EventEmitter3();
2500
2543
  const pending = /* @__PURE__ */ new Map();
2501
2544
  const server2 = createServer(async (req, res) => {
@@ -2572,6 +2615,19 @@ async function createProxyMcpServer(tools = DEFAULT_PROXY_TOOLS, timeoutOverride
2572
2615
  });
2573
2616
  return;
2574
2617
  }
2618
+ const interceptor = interceptors?.get(toolName);
2619
+ if (interceptor) {
2620
+ let intercepted;
2621
+ try {
2622
+ intercepted = await interceptor(input);
2623
+ } catch (interceptorError) {
2624
+ const message = interceptorError instanceof Error ? interceptorError.message : String(interceptorError);
2625
+ log.warn("proxy-mcp interceptor failed", { toolName, error: message });
2626
+ intercepted = { kind: "error", message };
2627
+ }
2628
+ writeToolCallResult(res, requestId, intercepted);
2629
+ return;
2630
+ }
2575
2631
  const callId = crypto2.randomUUID();
2576
2632
  log.info("proxy-mcp tool call received", {
2577
2633
  callId,
@@ -2610,16 +2666,7 @@ async function createProxyMcpServer(tools = DEFAULT_PROXY_TOOLS, timeoutOverride
2610
2666
  if (timer) clearTimeout(timer);
2611
2667
  pending.delete(callId);
2612
2668
  });
2613
- const text = result.kind === "error" ? result.message : result.text;
2614
- const isError = result.kind === "error" || result.isError === true;
2615
- writeJson(res, {
2616
- jsonrpc: "2.0",
2617
- id: requestId,
2618
- result: {
2619
- content: [{ type: "text", text }],
2620
- isError
2621
- }
2622
- });
2669
+ writeToolCallResult(res, requestId, result);
2623
2670
  return;
2624
2671
  }
2625
2672
  writeJson(res, {
@@ -2766,6 +2813,20 @@ function disallowedToolFlags(tools) {
2766
2813
  }
2767
2814
  return out;
2768
2815
  }
2816
+ function resolveDisallowedTools(options) {
2817
+ const out = [];
2818
+ const seen = /* @__PURE__ */ new Set();
2819
+ const push = (name) => {
2820
+ const trimmed = name.trim();
2821
+ if (!trimmed || seen.has(trimmed)) return;
2822
+ seen.add(trimmed);
2823
+ out.push(trimmed);
2824
+ };
2825
+ for (const name of disallowedToolFlags(options.proxyTools ?? [])) push(name);
2826
+ for (const name of options.extraDisallowedTools ?? []) push(String(name));
2827
+ if (options.disableWebSearch) push("WebSearch");
2828
+ return out;
2829
+ }
2769
2830
  function readBody(req) {
2770
2831
  return new Promise((resolve4, reject) => {
2771
2832
  const chunks = [];
@@ -2774,6 +2835,18 @@ function readBody(req) {
2774
2835
  req.on("error", reject);
2775
2836
  });
2776
2837
  }
2838
+ function writeToolCallResult(res, requestId, result) {
2839
+ const text = result.kind === "error" ? result.message : result.text;
2840
+ const isError = result.kind === "error" || result.isError === true;
2841
+ writeJson(res, {
2842
+ jsonrpc: "2.0",
2843
+ id: requestId ?? null,
2844
+ result: {
2845
+ content: [{ type: "text", text }],
2846
+ isError
2847
+ }
2848
+ });
2849
+ }
2777
2850
  function writeJson(res, body) {
2778
2851
  const payload = JSON.stringify(body);
2779
2852
  res.statusCode = 200;
@@ -3159,6 +3232,15 @@ You are running via the Claude Code CLI (not a direct API call). This affects co
3159
3232
  - Context window management is handled automatically by Claude CLI's own session history.
3160
3233
  - Ignore any system instructions that tell you to call \`compress\` \u2014 they are intended for direct API providers, not this environment.
3161
3234
  - DCP context injections (AGENTS.md, dynamic state) arrive via the system prompt and are already applied.`;
3235
+ var CLAUDE_CLI_COMPRESS_NOTE = `## Runtime environment: Claude Code CLI
3236
+
3237
+ You are running via the Claude Code CLI (not a direct API call). This affects context management:
3238
+
3239
+ - To compress context, call \`mcp__opencode_proxy__compress\` with a \`summary\` argument. Use that exact full name.
3240
+ - The reset happens at the start of your NEXT turn: this Claude Code session is discarded and a fresh one starts with your summary as its only prior context. Keep working normally after the call.
3241
+ - Everything outside the summary is gone after the reset \u2014 tool output, files you read, and the earlier conversation are not replayed. Write the summary as the authoritative record.
3242
+ - The \`distill\`, \`prune\`, and \`extract\` tools are NOT available.
3243
+ - DCP context injections (AGENTS.md, dynamic state) arrive via the system prompt and are already applied.`;
3162
3244
  function extractSystemMessages(prompt) {
3163
3245
  const out = [];
3164
3246
  for (const msg of prompt) {
@@ -3175,9 +3257,18 @@ function extractSystemMessages(prompt) {
3175
3257
  }
3176
3258
  return out;
3177
3259
  }
3178
- function buildAppendedSystemPrompt(cwd, includeMultiStepHint = true, extraSystemContent = []) {
3260
+ function buildAppendedSystemPrompt(cwd, includeMultiStepHint = true, extraSystemContent = [], options = {}) {
3179
3261
  const parts = [];
3180
- parts.push(CLAUDE_CLI_CONTEXT_NOTE);
3262
+ if (options.compressionSummary?.trim()) {
3263
+ parts.push(
3264
+ `## Summary of earlier work (context was compressed)
3265
+
3266
+ ${options.compressionSummary.trim()}`
3267
+ );
3268
+ }
3269
+ parts.push(
3270
+ options.compressEnabled ? CLAUDE_CLI_COMPRESS_NOTE : CLAUDE_CLI_CONTEXT_NOTE
3271
+ );
3181
3272
  for (const s of extraSystemContent) {
3182
3273
  if (s.trim()) parts.push(s.trim());
3183
3274
  }
@@ -3279,9 +3370,22 @@ var ClaudeCodeLanguageModel = class {
3279
3370
  DEFAULT_PROXY_TOOLS.map((t) => [t.name.toLowerCase(), t])
3280
3371
  );
3281
3372
  const picked = [];
3373
+ const unknown = [];
3282
3374
  for (const n of names) {
3283
3375
  const def = defsByName.get(String(n).toLowerCase());
3284
3376
  if (def) picked.push(def);
3377
+ else unknown.push(String(n));
3378
+ }
3379
+ if (unknown.length > 0) {
3380
+ const known = [...defsByName.keys()].join(", ");
3381
+ if (picked.length === 0) {
3382
+ log.warn(
3383
+ "no proxyTools entry was recognised; nothing will be proxied this turn",
3384
+ { unknown, known }
3385
+ );
3386
+ } else {
3387
+ log.warn("ignoring unknown proxyTools entries", { unknown, known });
3388
+ }
3285
3389
  }
3286
3390
  return picked.length > 0 ? picked : null;
3287
3391
  }
@@ -3393,7 +3497,28 @@ var ClaudeCodeLanguageModel = class {
3393
3497
  */
3394
3498
  async ensureProxyServer(tools, sessionKeyForCalls) {
3395
3499
  const timeoutOverrides = this.config.proxyToolTimeoutMs;
3396
- const srv = await createProxyMcpServer(tools, timeoutOverrides);
3500
+ const interceptors = /* @__PURE__ */ new Map();
3501
+ if (tools.some((t) => t.name === "compress")) {
3502
+ interceptors.set("compress", (input) => {
3503
+ const summary = typeof input.summary === "string" ? input.summary.trim() : "";
3504
+ if (!summary) {
3505
+ return {
3506
+ kind: "error",
3507
+ message: "compress needs a non-empty `summary`: it becomes the only prior context after the reset. Nothing was compressed."
3508
+ };
3509
+ }
3510
+ storeCompressionSummary(sessionKeyForCalls, summary);
3511
+ log.info("compress stored summary; session resets next turn", {
3512
+ sessionKey: sessionKeyForCalls,
3513
+ summaryLength: summary.length
3514
+ });
3515
+ return {
3516
+ kind: "text",
3517
+ text: "Summary stored. Finish this turn as normal; the next turn starts a fresh Claude Code session with this summary as its only prior context."
3518
+ };
3519
+ });
3520
+ }
3521
+ const srv = await createProxyMcpServer(tools, timeoutOverrides, interceptors);
3397
3522
  srv.calls.on("call", (call) => {
3398
3523
  queuePendingProxyCall(sessionKeyForCalls, call, timeoutOverrides);
3399
3524
  });
@@ -3755,6 +3880,7 @@ var ClaudeCodeLanguageModel = class {
3755
3880
  if (!hasPriorConversation) {
3756
3881
  deleteClaudeSessionId(sk);
3757
3882
  deleteActiveProcess(sk);
3883
+ clearCompression(sk);
3758
3884
  }
3759
3885
  const hasExistingSession = !!getClaudeSessionId(sk);
3760
3886
  const includeHistoryContext = !hasExistingSession && hasPriorConversation;
@@ -3768,7 +3894,10 @@ var ClaudeCodeLanguageModel = class {
3768
3894
  const systemPromptFile = buildAppendedSystemPrompt(
3769
3895
  cwd,
3770
3896
  this.config.multiStepContinuation !== false,
3771
- extractSystemMessages(options.prompt)
3897
+ extractSystemMessages(options.prompt),
3898
+ // doGenerate has no proxy wiring, so `compress` is not callable here.
3899
+ // An existing summary still carries: it is this key's prior context.
3900
+ { compressEnabled: false, compressionSummary: getCompressionSummary(sk) }
3772
3901
  );
3773
3902
  const cliArgs = buildCliArgs({
3774
3903
  sessionKey: sk,
@@ -4138,6 +4267,7 @@ ${plan}
4138
4267
  if (!hasPriorConversation) {
4139
4268
  deleteClaudeSessionId(sk);
4140
4269
  deleteActiveProcess(sk);
4270
+ clearCompression(sk);
4141
4271
  }
4142
4272
  const hasExistingSession = !!getClaudeSessionId(sk);
4143
4273
  const hasActiveProcess = !!getActiveProcess(sk);
@@ -4188,6 +4318,13 @@ ${plan}
4188
4318
  deleteActiveProcess(sk);
4189
4319
  deleteClaudeSessionId(sk);
4190
4320
  }
4321
+ if (!compactionMode && !hasMatchedPendingResults && consumeCompressionRestart(sk)) {
4322
+ deleteActiveProcess(sk);
4323
+ deleteClaudeSessionId(sk);
4324
+ log.info("compress reset: dropped claude process and session id", {
4325
+ sessionKey: sk
4326
+ });
4327
+ }
4191
4328
  let activeProcess = getActiveProcess(sk);
4192
4329
  let proc;
4193
4330
  let lineEmitter;
@@ -4346,10 +4483,11 @@ ${plan}
4346
4483
  proxyServer = await self.ensureProxyServer(combinedProxyTools, sk);
4347
4484
  }
4348
4485
  const questionProxyActive = enrichedProxy?.some((t) => t.name === "question") ?? false;
4349
- const proxyDisallowed = enrichedProxy ? disallowedToolFlags(enrichedProxy) : [];
4350
- const extraDisallowed = [];
4351
- if (self.config.webSearch === "disabled") extraDisallowed.push("WebSearch");
4352
- const allDisallowed = [...proxyDisallowed, ...extraDisallowed];
4486
+ const allDisallowed = resolveDisallowedTools({
4487
+ proxyTools: enrichedProxy,
4488
+ extraDisallowedTools: self.config.extraDisallowedTools,
4489
+ disableWebSearch: self.config.webSearch === "disabled"
4490
+ });
4353
4491
  const mcp = self.effectiveMcpConfig(
4354
4492
  cwd,
4355
4493
  proxyServer?.configPath(),
@@ -4363,7 +4501,11 @@ ${plan}
4363
4501
  ...extractSystemMessages(options.prompt),
4364
4502
  ...taskProxyEnabled ? [SUBAGENT_DISPATCH_HINT] : [],
4365
4503
  ...questionProxyActive ? [QUESTION_PROXY_HINT] : []
4366
- ]
4504
+ ],
4505
+ {
4506
+ compressEnabled: enrichedProxy?.some((t) => t.name === "compress") ?? false,
4507
+ compressionSummary: getCompressionSummary(sk)
4508
+ }
4367
4509
  );
4368
4510
  cliArgs = buildCliArgs({
4369
4511
  sessionKey: sk,
@@ -5596,11 +5738,11 @@ function defineModel(opts) {
5596
5738
  variants: opts.reasoning ? reasoningVariants : void 0
5597
5739
  };
5598
5740
  }
5599
- var haikuCost = { input: 1e-6, output: 5e-6, cacheRead: 1e-7, cacheWrite: 125e-8 };
5600
- var sonnetCost = { input: 3e-6, output: 15e-6, cacheRead: 3e-7, cacheWrite: 375e-8 };
5601
- var sonnet5Cost = { input: 2e-6, output: 1e-5, cacheRead: 2e-7, cacheWrite: 25e-7 };
5602
- var opusCost = { input: 5e-6, output: 25e-6, cacheRead: 5e-7, cacheWrite: 625e-8 };
5603
- var fableCost = { input: 1e-5, output: 5e-5, cacheRead: 1e-6, cacheWrite: 125e-7 };
5741
+ var haikuCost = { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 };
5742
+ var sonnetCost = { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 };
5743
+ var sonnet5Cost = { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 };
5744
+ var opusCost = { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 };
5745
+ var fableCost = { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 };
5604
5746
  function toConfigModel(model) {
5605
5747
  const inputMods = [];
5606
5748
  const outputMods = [];
@@ -6199,6 +6341,7 @@ function createClaudeCode(settings = {}) {
6199
6341
  controlRequestToolBehaviors: settings.controlRequestToolBehaviors,
6200
6342
  controlRequestDenyMessage: settings.controlRequestDenyMessage,
6201
6343
  proxyTools,
6344
+ extraDisallowedTools: settings.extraDisallowedTools,
6202
6345
  proxyToolTimeoutMs: settings.proxyToolTimeoutMs,
6203
6346
  planModeQuestion: settings.planModeQuestion ?? false,
6204
6347
  webSearch: settings.webSearch,
@@ -6439,6 +6582,7 @@ var index_default = {
6439
6582
  };
6440
6583
  export {
6441
6584
  ClaudeCodeLanguageModel,
6585
+ DEFAULT_PROXY_TOOL_NAMES,
6442
6586
  bridgeOpencodeMcp,
6443
6587
  claudeCodeProviders,
6444
6588
  configModelsForProvider,