@khalilgharbaoui/opencode-claude-code-plugin 0.53.1 → 0.53.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/dist/index.d.ts CHANGED
@@ -1364,7 +1364,7 @@ declare class ClaudeCodeLanguageModel implements LanguageModelV3 {
1364
1364
  private effectiveMcpConfig;
1365
1365
  /** Resolve ProxyToolDef[] for the configured proxyTools names. */
1366
1366
  private resolvedProxyTools;
1367
- /** Resolve ProxyToolDef[] for opencode's MCP-backed tools. */
1367
+ /** Resolve ProxyToolDef[] for opencode's MCP-backed tools, and route the rest. */
1368
1368
  private resolvedProxyMcpTools;
1369
1369
  /** One `client.tool.list()` fetch, shaped for this turn's gates. */
1370
1370
  private fetchLiveToolInfo;
package/dist/index.js CHANGED
@@ -4044,7 +4044,13 @@ var TASK_INPUT_PROPERTIES = {
4044
4044
  },
4045
4045
  background: {
4046
4046
  type: "boolean",
4047
- description: 'Run the subagent in the background and return immediately with a `<task id="..." state="running">` envelope instead of its answer. You are notified automatically when it completes. Do NOT sleep, poll or proactively check on its progress.'
4047
+ // Both majors, for the reason the `task_id` field names both: a model
4048
+ // told to look for only V1's envelope finds nothing on opencode 2, where
4049
+ // a background dispatch answers in prose, and then has no task_id to pass
4050
+ // to task_status or task_cancel. This constant is shared by `task` and by
4051
+ // every `task_batch` item and is built with no dialect in hand, so it
4052
+ // names both rather than being rewritten per host.
4053
+ description: 'Run the subagent in the background and return immediately instead of its answer: opencode 1.x answers with a `<task id="..." state="running">` envelope, opencode 2 with `The subagent is working in the background (sessionID: ses_...)`. You are notified automatically when it completes. Do NOT sleep, poll or proactively check on its progress.'
4048
4054
  }
4049
4055
  };
4050
4056
  var TASK_INPUT_PROPERTIES_NO_BACKGROUND = Object.fromEntries(
@@ -4673,7 +4679,11 @@ function resolveProxyOpencodeToolDefs(options) {
4673
4679
  return out;
4674
4680
  }
4675
4681
  function resolveMcpProxyToolDefs(options) {
4676
- const empty = { defs: [], coveredServers: /* @__PURE__ */ new Set() };
4682
+ const empty = {
4683
+ defs: [],
4684
+ coveredServers: /* @__PURE__ */ new Set(),
4685
+ matchedServers: /* @__PURE__ */ new Set()
4686
+ };
4677
4687
  const serverNames = options.serverNames ?? [];
4678
4688
  if (serverNames.length === 0) return empty;
4679
4689
  const tools = options.tools;
@@ -4682,6 +4692,7 @@ function resolveMcpProxyToolDefs(options) {
4682
4692
  const taken = options.taken ?? /* @__PURE__ */ new Set();
4683
4693
  const defs = [];
4684
4694
  const coveredServers = /* @__PURE__ */ new Set();
4695
+ const matchedServers = /* @__PURE__ */ new Set();
4685
4696
  const seen = /* @__PURE__ */ new Set();
4686
4697
  const collided = [];
4687
4698
  for (const tool of tools) {
@@ -4693,6 +4704,7 @@ function resolveMcpProxyToolDefs(options) {
4693
4704
  (server2) => name === server2 || name.startsWith(`${server2}_`)
4694
4705
  );
4695
4706
  if (!matchedServer) continue;
4707
+ matchedServers.add(matchedServer);
4696
4708
  if (seen.has(name)) continue;
4697
4709
  if (taken.has(name)) {
4698
4710
  collided.push(name);
@@ -4712,7 +4724,7 @@ function resolveMcpProxyToolDefs(options) {
4712
4724
  { collided }
4713
4725
  );
4714
4726
  }
4715
- return { defs, coveredServers };
4727
+ return { defs, coveredServers, matchedServers };
4716
4728
  }
4717
4729
  function readBody(req) {
4718
4730
  return new Promise((resolve6, reject) => {
@@ -5701,7 +5713,7 @@ async function fetchSessionRunState(sessionID, directory) {
5701
5713
  async function settleSessionRunState(sessionID, options = {}) {
5702
5714
  const pollMs = options.pollMs ?? 150;
5703
5715
  const windowMs = options.windowMs ?? 1500;
5704
- const started = Date.now();
5716
+ const started2 = Date.now();
5705
5717
  let last = "unknown";
5706
5718
  let directory = options.directory;
5707
5719
  for (; ; ) {
@@ -5709,7 +5721,7 @@ async function settleSessionRunState(sessionID, options = {}) {
5709
5721
  const state = await fetchSessionRunState(sessionID, directory ?? "");
5710
5722
  if (state === "busy") return "busy";
5711
5723
  if (state !== "unknown") last = state;
5712
- if (Date.now() - started >= windowMs) return last;
5724
+ if (Date.now() - started2 >= windowMs) return last;
5713
5725
  await new Promise((resolve6) => setTimeout(resolve6, pollMs));
5714
5726
  }
5715
5727
  }
@@ -5759,9 +5771,9 @@ async function waitForPendingMcpServers(first, budgetMs, signal) {
5759
5771
  let current = first;
5760
5772
  const waitedFor = pendingMcpServers(current);
5761
5773
  if (waitedFor.length === 0) return current;
5762
- const started = Date.now();
5774
+ const started2 = Date.now();
5763
5775
  for (; ; ) {
5764
- if (Date.now() - started >= budgetMs) break;
5776
+ if (Date.now() - started2 >= budgetMs) break;
5765
5777
  if (signal?.aborted) break;
5766
5778
  await new Promise((resolve6) => setTimeout(resolve6, MCP_CONNECT_POLL_MS));
5767
5779
  if (signal?.aborted) break;
@@ -5775,7 +5787,7 @@ async function waitForPendingMcpServers(first, budgetMs, signal) {
5775
5787
  waitedFor,
5776
5788
  stillPending,
5777
5789
  budgetMs,
5778
- elapsedMs: Date.now() - started,
5790
+ elapsedMs: Date.now() - started2,
5779
5791
  aborted: signal?.aborted === true
5780
5792
  });
5781
5793
  return current;
@@ -5903,6 +5915,56 @@ function clearBackgroundTasks(sessionKey2) {
5903
5915
  collected.delete(sessionKey2);
5904
5916
  cancelled.delete(sessionKey2);
5905
5917
  }
5918
+ var MAX_STARTED = 128;
5919
+ var started = /* @__PURE__ */ new Map();
5920
+ function backgroundTaskIdsIn(text) {
5921
+ const ids = /* @__PURE__ */ new Set();
5922
+ for (const match of text.matchAll(/<task id="([^"\s]+)" state="running">/g)) {
5923
+ ids.add(match[1]);
5924
+ }
5925
+ for (const match of text.matchAll(/in the background \(sessionID: ([^)\s]+)\)/g)) {
5926
+ ids.add(match[1]);
5927
+ }
5928
+ return [...ids];
5929
+ }
5930
+ function noteBackgroundDispatchResult(sessionKey2, result, now = Date.now()) {
5931
+ if (result.kind !== "text" || result.isError === true) return;
5932
+ for (const taskId of backgroundTaskIdsIn(result.text)) {
5933
+ started.delete(taskId);
5934
+ started.set(taskId, { sessionKey: sessionKey2, at: now });
5935
+ while (started.size > MAX_STARTED) {
5936
+ const oldest = started.keys().next();
5937
+ if (oldest.done) break;
5938
+ started.delete(oldest.value);
5939
+ }
5940
+ }
5941
+ }
5942
+ async function countRunningBackgroundTasks() {
5943
+ const entries = [...started.entries()];
5944
+ const cancelledIds = /* @__PURE__ */ new Set();
5945
+ for (const ids of cancelled.values()) for (const id of ids) cancelledIds.add(id);
5946
+ const states = await Promise.all(
5947
+ entries.map(async ([taskId]) => {
5948
+ if (cancelledIds.has(taskId)) return "stopped";
5949
+ try {
5950
+ const runState = await fetchSessionRunState(taskId);
5951
+ if (runState !== "unknown") {
5952
+ return isBackgroundTaskRunning(runState, []) ? "running" : "stopped";
5953
+ }
5954
+ const replies = await fetchSessionReplies(taskId);
5955
+ if (replies === void 0) return "unreadable";
5956
+ return isBackgroundTaskRunning(runState, replies) ? "running" : "stopped";
5957
+ } catch {
5958
+ return "unreadable";
5959
+ }
5960
+ })
5961
+ );
5962
+ return {
5963
+ running: states.filter((state) => state === "running").length,
5964
+ started: entries.length,
5965
+ unreadable: states.filter((state) => state === "unreadable").length
5966
+ };
5967
+ }
5906
5968
  var lastGate;
5907
5969
  function recordBackgroundSubagentGate(gate, now = Date.now()) {
5908
5970
  lastGate = { ...gate, at: now };
@@ -7629,21 +7691,21 @@ async function sessionStatus(client, sessionID) {
7629
7691
  async function waitForSessionIdle(client, sessionID, options = {}) {
7630
7692
  const pollMs = options.pollMs ?? IDLE_POLL_MS;
7631
7693
  const timeoutMs = options.timeoutMs ?? IDLE_WAIT_MAX_MS;
7632
- const started = Date.now();
7694
+ const started2 = Date.now();
7633
7695
  for (; ; ) {
7634
7696
  if (options.stop?.()) return true;
7635
7697
  if (await sessionStatus(client, sessionID) !== "busy") return true;
7636
- if (Date.now() - started >= timeoutMs) return false;
7698
+ if (Date.now() - started2 >= timeoutMs) return false;
7637
7699
  await new Promise((resolve6) => setTimeout(resolve6, pollMs));
7638
7700
  }
7639
7701
  }
7640
7702
  async function deliverAsideInline(client, sessionID, text, options = {}) {
7641
7703
  const pollMs = options.inlinePollMs ?? INLINE_POLL_MS;
7642
7704
  const timeoutMs = options.inlineWaitMs ?? INLINE_WAIT_MAX_MS;
7643
- const started = Date.now();
7705
+ const started2 = Date.now();
7644
7706
  for (; ; ) {
7645
7707
  if (emitAsideInline(sessionID, text)) return true;
7646
- if (Date.now() - started >= timeoutMs) return false;
7708
+ if (Date.now() - started2 >= timeoutMs) return false;
7647
7709
  if (await sessionStatus(client, sessionID) !== "busy") return false;
7648
7710
  await new Promise((resolve6) => setTimeout(resolve6, pollMs));
7649
7711
  }
@@ -7652,12 +7714,12 @@ async function waitForAsideProcess(client, sessionID, options = {}) {
7652
7714
  const pollMs = options.pollMs ?? IDLE_POLL_MS;
7653
7715
  const settleMs = options.settleMs ?? BUSY_SETTLE_MS;
7654
7716
  const spawnWaitMs = options.spawnWaitMs ?? SPAWN_WAIT_MAX_MS;
7655
- const started = Date.now();
7717
+ const started2 = Date.now();
7656
7718
  for (; ; ) {
7657
7719
  const active = findActiveProcessBySessionId(sessionID);
7658
7720
  if (active) return active;
7659
7721
  const busy = await sessionStatus(client, sessionID) === "busy";
7660
- const waitedMs = Date.now() - started;
7722
+ const waitedMs = Date.now() - started2;
7661
7723
  if (!busy && waitedMs >= settleMs) {
7662
7724
  log.info("btw: no live claude process for session, leaving it to the turn", { sessionID, waitedMs });
7663
7725
  return void 0;
@@ -7672,12 +7734,12 @@ async function waitForAsideProcess(client, sessionID, options = {}) {
7672
7734
  async function settleSessionBusy(client, sessionID, active, options = {}) {
7673
7735
  const pollMs = options.pollMs ?? IDLE_POLL_MS;
7674
7736
  const settleMs = options.settleMs ?? BUSY_SETTLE_MS;
7675
- const started = Date.now();
7737
+ const started2 = Date.now();
7676
7738
  for (; ; ) {
7677
7739
  const status = await sessionStatus(client, sessionID);
7678
7740
  if (status === "busy") return true;
7679
7741
  if (status === "unknown") return isProcessBusy(active);
7680
- if (Date.now() - started >= settleMs) return false;
7742
+ if (Date.now() - started2 >= settleMs) return false;
7681
7743
  await new Promise((resolve6) => setTimeout(resolve6, pollMs));
7682
7744
  }
7683
7745
  }
@@ -7781,7 +7843,7 @@ async function handleBtwCommand(client, input, options = {}) {
7781
7843
  );
7782
7844
  }
7783
7845
  if (!busy) return;
7784
- const started = Date.now();
7846
+ const started2 = Date.now();
7785
7847
  const outcome = await Promise.race([
7786
7848
  inlineDelivered,
7787
7849
  waitForSessionIdle(client, input.sessionID, { ...options, stop: () => inlineDone }).then(
@@ -7791,14 +7853,14 @@ async function handleBtwCommand(client, input, options = {}) {
7791
7853
  if (outcome === "inline") {
7792
7854
  log.info("btw: answered inside the running turn, dropping the /btw message", {
7793
7855
  sessionID: input.sessionID,
7794
- waitedMs: Date.now() - started
7856
+ waitedMs: Date.now() - started2
7795
7857
  });
7796
7858
  throw new BtwHandledError(BTW_INLINE_HANDLED_MESSAGE);
7797
7859
  }
7798
7860
  log.info("btw: turn over, releasing the /btw message", {
7799
7861
  sessionID: input.sessionID,
7800
7862
  idle: outcome === "idle",
7801
- waitedMs: Date.now() - started
7863
+ waitedMs: Date.now() - started2
7802
7864
  });
7803
7865
  if (outcome === "timeout") {
7804
7866
  showToast(client, { title: "btw", message: BTW_TURN_TOO_LONG_MESSAGE, variant: "warning", duration: 8e3 });
@@ -7927,6 +7989,7 @@ var PLUGIN_LOG_MESSAGES = /* @__PURE__ */ new Set([
7927
7989
  "proxy-mcp interceptor failed",
7928
7990
  "proxy-mcp rejected a request",
7929
7991
  "proxy-mcp tool call timed out",
7992
+ "proxyOpencodeMcpTools cannot route V2 Code Mode's MCP tools, which reach the model through execute; for Code Mode, explicitly allowlist execute in proxyOpencodeTools and use bridgeOpencodeMcp: false with strictMcpConfig: true",
7930
7993
  "proxyOpencodeTools entry dropped: a proxy tool already holds that name, and it keeps it",
7931
7994
  "proxyOpencodeTools is set but opencode's tool registry did not answer; forwarding nothing this spawn",
7932
7995
  "refusing the pid-named scratch directory",
@@ -9162,6 +9225,10 @@ function formatDoctorReport(report) {
9162
9225
  }
9163
9226
  function formatBackgroundSubagents(state) {
9164
9227
  const lines = [];
9228
+ if (state.running) {
9229
+ lines.push(...formatRunningCount(state.running));
9230
+ lines.push("");
9231
+ }
9165
9232
  const gate = state.gate;
9166
9233
  if (!gate) {
9167
9234
  lines.push(
@@ -9207,6 +9274,19 @@ function formatBackgroundSubagents(state) {
9207
9274
  }
9208
9275
  return lines;
9209
9276
  }
9277
+ function formatRunningCount(count) {
9278
+ if (count.started === 0) {
9279
+ return ["running now: 0 (none started by this process)"];
9280
+ }
9281
+ const lines = [`running now: ${count.running} (of ${count.started} started by this process)`];
9282
+ if (count.unreadable > 0) {
9283
+ lines.push("");
9284
+ lines.push(
9285
+ `${count.unreadable} could not be read from opencode (deleted, or no session route on this build) and are not counted as running.`
9286
+ );
9287
+ }
9288
+ return lines;
9289
+ }
9210
9290
  function describeBackgroundGateSource(gate) {
9211
9291
  if (gate.hostApi === "v2") {
9212
9292
  return "opencode 2 offers `background` unconditionally, so the registry is not consulted";
@@ -9291,7 +9371,8 @@ async function gatherDoctorReport(options) {
9291
9371
  planUsage,
9292
9372
  backgroundSubagents: {
9293
9373
  gate: snapshotBackgroundSubagentGate(),
9294
- ledgers: snapshotBackgroundTasks()
9374
+ ledgers: snapshotBackgroundTasks(),
9375
+ running: await countRunningBackgroundTasks().catch(() => void 0)
9295
9376
  }
9296
9377
  };
9297
9378
  }
@@ -11962,12 +12043,12 @@ function spawnInteractiveProcess(opts) {
11962
12043
  }
11963
12044
  }
11964
12045
  closeProxyServer();
11965
- const started = startPromise !== null;
12046
+ const started2 = startPromise !== null;
11966
12047
  try {
11967
12048
  session.dispose();
11968
12049
  } catch {
11969
12050
  }
11970
- if (!started && proc.exitCode === null && proc.signalCode === null) {
12051
+ if (!started2 && proc.exitCode === null && proc.signalCode === null) {
11971
12052
  proc.signalCode = "SIGTERM";
11972
12053
  proc.emit("exit", null, "SIGTERM");
11973
12054
  proc.emit("close", null, "SIGTERM");
@@ -12120,6 +12201,17 @@ This opencode host runs background subagents, so \`mcp__opencode_proxy__task\` t
12120
12201
  - After starting one, keep working on something that does not overlap it, then end your turn normally. When the subagent finishes, opencode delivers its result into this conversation as a new message on its own. Do not sleep, poll, or ask the operator to wait.
12121
12202
  - The \`id\` in that envelope is the task_id. \`mcp__opencode_proxy__task_status\` reads a result back if the automatic delivery did not arrive (an interrupted or errored turn); \`mcp__opencode_proxy__task_cancel\` stops a background subagent you no longer want. Neither is a progress poll.
12122
12203
  - Foreground is still the default and still the right choice when you need the answer before you can continue. Use background only for work that genuinely runs alongside yours.`;
12204
+ var BACKGROUND_SUBAGENT_HINT_V2 = `## Background subagents
12205
+
12206
+ This opencode host runs background subagents, so \`mcp__opencode_proxy__task\` takes \`background: true\`.
12207
+
12208
+ - A background dispatch returns at once with \`The subagent is working in the background (sessionID: ses_...)\` instead of the subagent's answer. That is success, not a truncated result.
12209
+ - After starting one, keep working on something that does not overlap it, then end your turn normally. When the subagent finishes, opencode delivers its result into this conversation on its own, as a \`<subagent sessionID="..." state="completed">\` message. Do not sleep, poll, or ask the operator to wait.
12210
+ - That \`sessionID\` is the task_id. \`mcp__opencode_proxy__task_status\` reads a result back if the automatic delivery did not arrive (an interrupted or errored turn); \`mcp__opencode_proxy__task_cancel\` stops a background subagent you no longer want. Neither is a progress poll.
12211
+ - Foreground is still the default and still the right choice when you need the answer before you can continue. Use background only for work that genuinely runs alongside yours.`;
12212
+ function backgroundSubagentHint(dialect) {
12213
+ return dialect === "v2" ? BACKGROUND_SUBAGENT_HINT_V2 : BACKGROUND_SUBAGENT_HINT;
12214
+ }
12123
12215
  var QUESTION_PROXY_HINT = `## Asking the operator questions
12124
12216
 
12125
12217
  Structured questions in this environment go through exactly one tool: \`mcp__opencode_proxy__question\`.
@@ -12720,7 +12812,13 @@ function resolvedProxyTools(config) {
12720
12812
  }
12721
12813
  return picked.length > 0 ? picked : null;
12722
12814
  }
12723
- function resolvedProxyMcpTools(config, allEnabledServerNames, modelTools, taken) {
12815
+ function decideMcpServerRoute(input) {
12816
+ if (input.covered) return "proxy";
12817
+ if (input.inToolSet) return "bridge";
12818
+ if (input.toolSetKnown && input.status === "connected") return "withhold";
12819
+ return "bridge";
12820
+ }
12821
+ function resolvedProxyMcpTools(config, allEnabledServerNames, modelTools, taken, runtimeStatus) {
12724
12822
  if (config.proxyOpencodeMcpTools !== true) return null;
12725
12823
  if (config.bridgeOpencodeMcp === false) return null;
12726
12824
  if (allEnabledServerNames.length === 0) return null;
@@ -12729,18 +12827,47 @@ function resolvedProxyMcpTools(config, allEnabledServerNames, modelTools, taken)
12729
12827
  tools: modelTools,
12730
12828
  taken
12731
12829
  });
12732
- if (resolution.defs.length === 0) {
12830
+ const codeMode = config.hostApi === "v2" && (modelTools?.some((tool) => tool.name === "execute") ?? false);
12831
+ const toolSetKnown = (modelTools?.length ?? 0) > 0 && !codeMode;
12832
+ const withheld = [];
12833
+ const bridged = [];
12834
+ for (const server2 of allEnabledServerNames) {
12835
+ const route = decideMcpServerRoute({
12836
+ covered: resolution.coveredServers.has(server2),
12837
+ inToolSet: resolution.matchedServers.has(server2),
12838
+ status: runtimeStatus?.[server2],
12839
+ toolSetKnown
12840
+ });
12841
+ if (route === "withhold") withheld.push(server2);
12842
+ else if (route === "bridge") bridged.push(server2);
12843
+ }
12844
+ if (codeMode && resolution.defs.length === 0) {
12733
12845
  log.warn(
12734
- "proxyOpencodeMcpTools is on but no MCP tool was found in opencode's tool set; those servers stay on the direct bridge this spawn" + (config.hostApi === "v2" && modelTools?.some((tool) => tool.name === "execute") ? ". For V2 Code Mode, explicitly allowlist execute in proxyOpencodeTools and use bridgeOpencodeMcp: false with strictMcpConfig: true" : ""),
12735
- { servers: allEnabledServerNames, modelTools: modelTools?.length ?? 0 }
12846
+ "proxyOpencodeMcpTools cannot route V2 Code Mode's MCP tools, which reach the model through execute; for Code Mode, explicitly allowlist execute in proxyOpencodeTools and use bridgeOpencodeMcp: false with strictMcpConfig: true",
12847
+ { servers: allEnabledServerNames }
12736
12848
  );
12737
- return null;
12738
12849
  }
12739
- log.debug("routing opencode MCP tools through the proxy", {
12740
- servers: [...resolution.coveredServers],
12741
- tools: resolution.defs.map((def) => def.name)
12742
- });
12743
- return resolution;
12850
+ if (withheld.length > 0 || bridged.length > 0) {
12851
+ log.info("proxyOpencodeMcpTools: MCP servers outside this agent's tool set", {
12852
+ proxied: [...resolution.coveredServers],
12853
+ withheld,
12854
+ bridged,
12855
+ modelTools: modelTools?.length ?? 0,
12856
+ statusKnown: runtimeStatus !== void 0
12857
+ });
12858
+ } else {
12859
+ log.debug("routing opencode MCP tools through the proxy", {
12860
+ servers: [...resolution.coveredServers],
12861
+ tools: resolution.defs.map((def) => def.name)
12862
+ });
12863
+ }
12864
+ const exclude = /* @__PURE__ */ new Set([...resolution.coveredServers, ...withheld]);
12865
+ return {
12866
+ resolution,
12867
+ withheld,
12868
+ bridged,
12869
+ excludeServers: exclude.size > 0 ? exclude : void 0
12870
+ };
12744
12871
  }
12745
12872
  async function fetchLiveToolInfo(config, modelId) {
12746
12873
  const items = await fetchOpencodeToolList(
@@ -14667,13 +14794,14 @@ var ClaudeCodeLanguageModel = class {
14667
14794
  resolvedProxyTools() {
14668
14795
  return resolvedProxyTools(this.config);
14669
14796
  }
14670
- /** Resolve ProxyToolDef[] for opencode's MCP-backed tools. */
14671
- resolvedProxyMcpTools(allEnabledServerNames, modelTools, taken) {
14797
+ /** Resolve ProxyToolDef[] for opencode's MCP-backed tools, and route the rest. */
14798
+ resolvedProxyMcpTools(allEnabledServerNames, modelTools, taken, runtimeStatus) {
14672
14799
  return resolvedProxyMcpTools(
14673
14800
  this.config,
14674
14801
  allEnabledServerNames,
14675
14802
  modelTools,
14676
- taken
14803
+ taken,
14804
+ runtimeStatus
14677
14805
  );
14678
14806
  }
14679
14807
  /** One `client.tool.list()` fetch, shaped for this turn's gates. */
@@ -15982,13 +16110,14 @@ var ClaudeCodeLanguageModel = class {
15982
16110
  void 0,
15983
16111
  runtimeStatus
15984
16112
  );
15985
- const mcpResolution = self.resolvedProxyMcpTools(
16113
+ const mcpRouting = self.resolvedProxyMcpTools(
15986
16114
  discovery.allEnabledServerNames,
15987
16115
  options.tools,
15988
- new Set((resolvedProxy ?? []).map((def) => def.name))
16116
+ new Set((resolvedProxy ?? []).map((def) => def.name)),
16117
+ runtimeStatus
15989
16118
  );
15990
- const proxyMcpTools = mcpResolution?.defs ?? null;
15991
- const excludeServers = mcpResolution ? mcpResolution.coveredServers : void 0;
16119
+ const proxyMcpTools = mcpRouting && mcpRouting.resolution.defs.length > 0 ? mcpRouting.resolution.defs : null;
16120
+ const excludeServers = mcpRouting?.excludeServers;
15992
16121
  const taskProxyEnabled = resolvedProxy?.some((t) => t.name === "task") ?? false;
15993
16122
  const questionProxyEnabled = resolvedProxy?.some((t) => t.name === "question") ?? false;
15994
16123
  const opencodeToolsRequested = (self.config.proxyOpencodeTools?.length ?? 0) > 0;
@@ -16005,6 +16134,7 @@ var ClaudeCodeLanguageModel = class {
16005
16134
  };
16006
16135
  let enrichedProxy = resolvedProxy;
16007
16136
  let backgroundSubagentsSupported = false;
16137
+ const hostDialect = self.config.hostApi === "v2" ? "v2" : "v1";
16008
16138
  if (enrichedProxy && taskProxyEnabled) {
16009
16139
  enrichedProxy = overlayTaskProxyDescription(
16010
16140
  enrichedProxy,
@@ -16019,7 +16149,6 @@ var ClaudeCodeLanguageModel = class {
16019
16149
  )
16020
16150
  )
16021
16151
  });
16022
- const hostDialect = self.config.hostApi === "v2" ? "v2" : "v1";
16023
16152
  backgroundSubagentsSupported = liveTaskSupportsBackground(
16024
16153
  liveToolInfo.taskParameters,
16025
16154
  hostDialect
@@ -16096,6 +16225,7 @@ var ClaudeCodeLanguageModel = class {
16096
16225
  excludeServers,
16097
16226
  taskProxyEnabled,
16098
16227
  backgroundSubagentsSupported,
16228
+ hostDialect,
16099
16229
  questionProxyActive,
16100
16230
  opencodeToolDefs,
16101
16231
  pluginCompressEnabled,
@@ -16161,7 +16291,7 @@ var ClaudeCodeLanguageModel = class {
16161
16291
  // dispatch instead of calling the proxy (h #g74).
16162
16292
  [
16163
16293
  ...wiring.taskProxyEnabled ? [SUBAGENT_DISPATCH_HINT] : [],
16164
- ...wiring.backgroundSubagentsSupported ? [BACKGROUND_SUBAGENT_HINT] : [],
16294
+ ...wiring.backgroundSubagentsSupported ? [backgroundSubagentHint(wiring.hostDialect)] : [],
16165
16295
  ...wiring.questionProxyActive ? [QUESTION_PROXY_HINT] : []
16166
16296
  ],
16167
16297
  {
@@ -16275,6 +16405,7 @@ var ClaudeCodeLanguageModel = class {
16275
16405
  excludeServers,
16276
16406
  taskProxyEnabled,
16277
16407
  backgroundSubagentsSupported,
16408
+ hostDialect,
16278
16409
  questionProxyActive,
16279
16410
  opencodeToolDefs,
16280
16411
  pluginCompressEnabled,
@@ -16292,7 +16423,7 @@ var ClaudeCodeLanguageModel = class {
16292
16423
  [
16293
16424
  ...extractSystemMessages(options.prompt),
16294
16425
  ...taskProxyEnabled ? [SUBAGENT_DISPATCH_HINT] : [],
16295
- ...backgroundSubagentsSupported ? [BACKGROUND_SUBAGENT_HINT] : [],
16426
+ ...backgroundSubagentsSupported ? [backgroundSubagentHint(hostDialect)] : [],
16296
16427
  ...questionProxyActive ? [QUESTION_PROXY_HINT] : [],
16297
16428
  ...self.config.hostApi === "v2" && options.tools?.some((t) => t.name === "execute") ? [codeModeProxyHint(opencodeToolDefs.some((t) => t.name === "execute"))] : []
16298
16429
  ],
@@ -16842,6 +16973,9 @@ var ClaudeCodeLanguageModel = class {
16842
16973
  recoveryRequired: channelClosed || state.unattendedTurnEnded
16843
16974
  });
16844
16975
  }
16976
+ if (call.toolName === "task" || call.toolName === TASK_BATCH_TOOL_NAME) {
16977
+ noteBackgroundDispatchResult(sk, result);
16978
+ }
16845
16979
  resolvePendingProxyCallById(call.toolCallId, result);
16846
16980
  } else {
16847
16981
  log.info(