@khalilgharbaoui/opencode-claude-code-plugin 0.2.5 → 0.3.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/dist/index.d.ts CHANGED
@@ -201,6 +201,7 @@ interface ClaudeStreamMessage {
201
201
  type: string;
202
202
  subtype?: string;
203
203
  request_id?: string;
204
+ event?: ClaudeStreamMessage;
204
205
  request?: {
205
206
  subtype?: string;
206
207
  tool_name?: string;
package/dist/index.js CHANGED
@@ -145,7 +145,7 @@ function mapTool(name, input, opts) {
145
145
  const toolName = parts.slice(1).join("_");
146
146
  const openCodeName = `${serverName}_${toolName}`;
147
147
  log.debug("mapping MCP tool", { original: name, mapped: openCodeName });
148
- return { name: openCodeName, input, executed: false };
148
+ return { name: openCodeName, input, executed: true };
149
149
  }
150
150
  }
151
151
  if (OPENCODE_HANDLED_TOOLS.has(name)) {
@@ -825,10 +825,12 @@ function buildCliArgs(opts) {
825
825
  appendSystemPromptFile
826
826
  } = opts;
827
827
  const args = [
828
+ "--print",
828
829
  "--output-format",
829
830
  "stream-json",
830
831
  "--input-format",
831
832
  "stream-json",
833
+ "--include-partial-messages",
832
834
  "--verbose"
833
835
  ];
834
836
  if (model) {
@@ -1267,6 +1269,25 @@ import { unlink as unlink2 } from "fs/promises";
1267
1269
  import { homedir as homedir2, tmpdir as tmpdir3 } from "os";
1268
1270
  import { randomUUID as randomUUID2 } from "crypto";
1269
1271
  import { dirname as dirname2, join as join3 } from "path";
1272
+ function hasNewUserContent(prompt) {
1273
+ for (let i = prompt.length - 1; i >= 0; i--) {
1274
+ const msg = prompt[i];
1275
+ if (msg.role === "assistant") return false;
1276
+ if (msg.role !== "user") continue;
1277
+ const content = msg.content;
1278
+ if (typeof content === "string") {
1279
+ if (content.trim()) return true;
1280
+ continue;
1281
+ }
1282
+ if (Array.isArray(content)) {
1283
+ for (const part of content) {
1284
+ if (part.type === "text" && part.text && part.text.trim()) return true;
1285
+ if (part.type === "tool-result") return true;
1286
+ }
1287
+ }
1288
+ }
1289
+ return false;
1290
+ }
1270
1291
  function readPromptFileIfPresent(path4) {
1271
1292
  try {
1272
1293
  const content = readFileSync2(path4, "utf8").trim();
@@ -1692,6 +1713,24 @@ var ClaudeCodeLanguageModel = class {
1692
1713
  warnings
1693
1714
  };
1694
1715
  }
1716
+ if (!hasNewUserContent(options.prompt)) {
1717
+ log.info("doGenerate short-circuit: no new user content");
1718
+ return {
1719
+ content: [],
1720
+ finishReason: this.toFinishReason("stop"),
1721
+ usage: this.toUsage({ input_tokens: 0, output_tokens: 0 }),
1722
+ request: { body: { text: "" } },
1723
+ response: {
1724
+ id: generateId(),
1725
+ timestamp: /* @__PURE__ */ new Date(),
1726
+ modelId: this.modelId
1727
+ },
1728
+ providerMetadata: {
1729
+ "claude-code": { synthetic: true, path: "no-new-user-content" }
1730
+ },
1731
+ warnings
1732
+ };
1733
+ }
1695
1734
  const hasPriorConversation = options.prompt.filter((m) => m.role === "user" || m.role === "assistant").length > 1;
1696
1735
  if (!hasPriorConversation) {
1697
1736
  deleteClaudeSessionId(sk);
@@ -1743,11 +1782,16 @@ var ClaudeCodeLanguageModel = class {
1743
1782
  let thinkingText = "";
1744
1783
  let resultMeta = {};
1745
1784
  const toolCalls = [];
1785
+ let gotPartialEvents = false;
1746
1786
  const result = await new Promise((resolve3, reject) => {
1747
1787
  rl.on("line", (line) => {
1748
1788
  if (!line.trim()) return;
1749
1789
  try {
1750
- const msg = JSON.parse(line);
1790
+ const outer = JSON.parse(line);
1791
+ const msg = outer.type === "stream_event" && outer.event ? { ...outer.event, session_id: outer.session_id } : outer;
1792
+ if (outer.type === "stream_event") {
1793
+ gotPartialEvents = true;
1794
+ }
1751
1795
  if (this.handleControlRequest(msg, proc)) {
1752
1796
  return;
1753
1797
  }
@@ -1756,7 +1800,7 @@ var ClaudeCodeLanguageModel = class {
1756
1800
  setClaudeSessionId(sk, msg.session_id);
1757
1801
  }
1758
1802
  }
1759
- if (msg.type === "assistant" && msg.message?.content) {
1803
+ if (msg.type === "assistant" && msg.message?.content && !gotPartialEvents) {
1760
1804
  for (const block of msg.message.content) {
1761
1805
  if (block.type === "text" && block.text) {
1762
1806
  responseText += block.text;
@@ -1975,6 +2019,24 @@ ${plan}
1975
2019
  request: { body: { text: "" } }
1976
2020
  };
1977
2021
  }
2022
+ if (!hasNewUserContent(options.prompt)) {
2023
+ log.info("doStream short-circuit: no new user content");
2024
+ const stream2 = new ReadableStream({
2025
+ start(controller) {
2026
+ controller.enqueue({ type: "stream-start", warnings });
2027
+ controller.enqueue({
2028
+ type: "finish",
2029
+ finishReason: toFinishReason("stop"),
2030
+ usage: toUsage({ input_tokens: 0, output_tokens: 0 }),
2031
+ providerMetadata: {
2032
+ "claude-code": { synthetic: true, path: "no-new-user-content" }
2033
+ }
2034
+ });
2035
+ controller.close();
2036
+ }
2037
+ });
2038
+ return { stream: stream2, request: { body: { text: "" } } };
2039
+ }
1978
2040
  const hasPriorConversation = options.prompt.filter((m) => m.role === "user" || m.role === "assistant").length > 1;
1979
2041
  if (!hasPriorConversation) {
1980
2042
  deleteClaudeSessionId(sk);
@@ -2096,14 +2158,16 @@ ${plan}
2096
2158
  resultFallbackTimer = null;
2097
2159
  }
2098
2160
  };
2099
- const startResultFallback = () => {
2161
+ const startResultFallback = (delayMs = 6e4) => {
2100
2162
  clearFallbackTimer();
2101
2163
  if (!hasReceivedContent || controllerClosed) return;
2102
2164
  resultFallbackTimer = setTimeout(() => {
2103
2165
  if (controllerClosed) return;
2104
- log.warn("result fallback timer fired \u2014 closing stream without result event");
2166
+ log.warn("result fallback timer fired \u2014 closing stream without result event", {
2167
+ delayMs
2168
+ });
2105
2169
  closeHandler();
2106
- }, 5e3);
2170
+ }, delayMs);
2107
2171
  };
2108
2172
  const toolCallMap = /* @__PURE__ */ new Map();
2109
2173
  const skipResultForIds = /* @__PURE__ */ new Set();
@@ -2139,11 +2203,17 @@ ${plan}
2139
2203
  } catch {
2140
2204
  }
2141
2205
  };
2206
+ let gotPartialEvents = false;
2142
2207
  const lineHandler = (line) => {
2143
2208
  if (!line.trim()) return;
2144
2209
  if (controllerClosed) return;
2210
+ startResultFallback();
2145
2211
  try {
2146
- const msg = JSON.parse(line);
2212
+ const outer = JSON.parse(line);
2213
+ const msg = outer.type === "stream_event" && outer.event ? { ...outer.event, session_id: outer.session_id } : outer;
2214
+ if (outer.type === "stream_event") {
2215
+ gotPartialEvents = true;
2216
+ }
2147
2217
  if (handleControlRequest(msg, proc)) {
2148
2218
  return;
2149
2219
  }
@@ -2172,7 +2242,6 @@ ${plan}
2172
2242
  reasoningStarted.set(idx, true);
2173
2243
  }
2174
2244
  if (block.type === "text") {
2175
- clearFallbackTimer();
2176
2245
  textBlockIndices.add(idx);
2177
2246
  if (block.text) {
2178
2247
  if (!currentTextId) startTextBlock();
@@ -2185,7 +2254,6 @@ ${plan}
2185
2254
  }
2186
2255
  }
2187
2256
  if (block.type === "tool_use" && block.id && block.name) {
2188
- clearFallbackTimer();
2189
2257
  toolCallMap.set(idx, {
2190
2258
  id: block.id,
2191
2259
  name: block.name,
@@ -2260,7 +2328,6 @@ ${plan}
2260
2328
  if (textBlockIndices.has(idx)) {
2261
2329
  endTextBlock();
2262
2330
  textBlockIndices.delete(idx);
2263
- startResultFallback();
2264
2331
  }
2265
2332
  const tc = toolCallMap.get(idx);
2266
2333
  if (tc) {
@@ -2338,7 +2405,7 @@ ${plan}
2338
2405
  }
2339
2406
  }
2340
2407
  }
2341
- if (msg.type === "assistant" && msg.message?.content) {
2408
+ if (msg.type === "assistant" && msg.message?.content && !gotPartialEvents) {
2342
2409
  const hasText = msg.message.content.some(
2343
2410
  (b) => b.type === "text" && b.text
2344
2411
  );
@@ -2637,7 +2704,7 @@ ${plan}
2637
2704
  "abort signal received mid-turn, starting grace period",
2638
2705
  { cwd }
2639
2706
  );
2640
- startResultFallback();
2707
+ startResultFallback(5e3);
2641
2708
  });
2642
2709
  }
2643
2710
  if (pendingProxyCall && pendingProxyResult) {