@khalilgharbaoui/opencode-claude-code-plugin 0.37.0 → 0.37.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/dist/index.js CHANGED
@@ -149,6 +149,7 @@ import path from "path";
149
149
  import { appendFileSync, mkdirSync, renameSync, statSync } from "fs";
150
150
  import { homedir } from "os";
151
151
  import { dirname, join } from "path";
152
+ import { isMainThread } from "worker_threads";
152
153
  var LEVEL_RANK = {
153
154
  debug: 0,
154
155
  info: 1,
@@ -241,15 +242,110 @@ function fmt(level, msg, data) {
241
242
  function shouldEmit(level) {
242
243
  return LEVEL_RANK[level] >= LEVEL_RANK[activeConfig.level];
243
244
  }
244
- function shouldTui(level) {
245
+ var tuiHostOverride;
246
+ function isTuiHost() {
247
+ return tuiHostOverride ?? !isMainThread;
248
+ }
249
+ var MAX_BUFFERED_SINK_ENTRIES = 50;
250
+ var MAX_TOASTED_MESSAGES = 200;
251
+ var toastBurstLimit = 3;
252
+ var toastBurstWindowMs = 2e3;
253
+ var activeSink = null;
254
+ var bufferedEntries = [];
255
+ var droppedBeforeSink = 0;
256
+ var toastedMessages = /* @__PURE__ */ new Set();
257
+ var burstWindowStart = 0;
258
+ var burstCount = 0;
259
+ var burstSuppressed = 0;
260
+ var burstSummaryTimer = null;
261
+ function setLogSink(sink) {
262
+ activeSink = sink;
263
+ if (!sink) return;
264
+ const pending = bufferedEntries;
265
+ const dropped = droppedBeforeSink;
266
+ bufferedEntries = [];
267
+ droppedBeforeSink = 0;
268
+ for (const entry of pending) deliverToSink(entry);
269
+ if (dropped > 0) {
270
+ const message = `${dropped} earlier log line(s) were dropped before opencode's log channel was available`;
271
+ deliverToSink({
272
+ level: "warn",
273
+ message,
274
+ line: fmt("WARN", message)
275
+ });
276
+ }
277
+ }
278
+ function routeToSink(entry) {
279
+ if (!activeSink) {
280
+ if (bufferedEntries.length >= MAX_BUFFERED_SINK_ENTRIES) {
281
+ droppedBeforeSink += 1;
282
+ return;
283
+ }
284
+ bufferedEntries.push(entry);
285
+ return;
286
+ }
287
+ deliverToSink(entry);
288
+ }
289
+ function deliverToSink(entry) {
290
+ const sink = activeSink;
291
+ if (!sink) return;
292
+ try {
293
+ sink.log(entry);
294
+ } catch {
295
+ }
296
+ if (entry.level !== "warn" && entry.level !== "error") return;
297
+ if (toastedMessages.has(entry.message)) return;
298
+ if (toastedMessages.size < MAX_TOASTED_MESSAGES) toastedMessages.add(entry.message);
299
+ if (!allowToastNow()) return;
300
+ sendToast(sink, entry);
301
+ }
302
+ function sendToast(sink, entry) {
303
+ try {
304
+ sink.toast(entry);
305
+ } catch {
306
+ }
307
+ }
308
+ function allowToastNow() {
309
+ const now = Date.now();
310
+ if (now - burstWindowStart >= toastBurstWindowMs) {
311
+ burstWindowStart = now;
312
+ burstCount = 0;
313
+ }
314
+ if (burstCount < toastBurstLimit) {
315
+ burstCount += 1;
316
+ return true;
317
+ }
318
+ burstSuppressed += 1;
319
+ armBurstSummary();
320
+ return false;
321
+ }
322
+ function armBurstSummary() {
323
+ if (burstSummaryTimer) return;
324
+ burstSummaryTimer = setTimeout(() => {
325
+ burstSummaryTimer = null;
326
+ const suppressed = burstSuppressed;
327
+ burstSuppressed = 0;
328
+ if (suppressed <= 0) return;
329
+ const sink = activeSink;
330
+ if (!sink) return;
331
+ const message = `${suppressed} more claude-code warning(s) were not shown; the full text is in opencode's log`;
332
+ sendToast(sink, { level: "warn", message, line: fmt("WARN", message) });
333
+ }, toastBurstWindowMs);
334
+ burstSummaryTimer.unref?.();
335
+ }
336
+ function shouldSurface(level) {
245
337
  if (level === "warn" || level === "error") return true;
246
338
  return activeConfig.mode === "debug";
247
339
  }
248
340
  function emit(level, msg, data) {
249
341
  if (!shouldEmit(level)) return;
250
342
  const line = fmt(level.toUpperCase(), msg, data);
251
- if (shouldTui(level)) {
252
- console.error(line);
343
+ if (shouldSurface(level)) {
344
+ if (isTuiHost()) {
345
+ routeToSink({ level, message: msg, data, line });
346
+ } else {
347
+ console.error(line);
348
+ }
253
349
  }
254
350
  writeToFile(line);
255
351
  }
@@ -13142,6 +13238,72 @@ function cleanupOne(cacheRoot, ourDir) {
13142
13238
  }
13143
13239
  }
13144
13240
 
13241
+ // src/tui-log-sink.ts
13242
+ var LOG_SERVICE_NAME = "opencode-claude-code";
13243
+ var TOAST_TITLE = "claude-code";
13244
+ var TOAST_DURATION_MS = 1e4;
13245
+ var MAX_TOAST_CHARS = 240;
13246
+ var APP_LOG_LEVEL = {
13247
+ debug: "debug",
13248
+ info: "info",
13249
+ notice: "info",
13250
+ warn: "warn",
13251
+ error: "error"
13252
+ };
13253
+ function toastMessage(message) {
13254
+ const flat = message.replace(/\s+/g, " ").trim();
13255
+ if (flat.length <= MAX_TOAST_CHARS) return flat;
13256
+ return `${flat.slice(0, MAX_TOAST_CHARS - 1)}\u2026`;
13257
+ }
13258
+ function appLogBody(entry) {
13259
+ return {
13260
+ service: LOG_SERVICE_NAME,
13261
+ level: APP_LOG_LEVEL[entry.level],
13262
+ message: entry.message,
13263
+ ...entry.data && Object.keys(entry.data).length > 0 ? { extra: entry.data } : {}
13264
+ };
13265
+ }
13266
+ function toastBody(entry) {
13267
+ return {
13268
+ title: TOAST_TITLE,
13269
+ message: toastMessage(entry.message),
13270
+ variant: entry.level === "error" ? "error" : "warning",
13271
+ duration: TOAST_DURATION_MS
13272
+ };
13273
+ }
13274
+ function fireAndForget(call) {
13275
+ try {
13276
+ const result = call();
13277
+ if (result && typeof result.catch === "function") {
13278
+ void result.catch(() => void 0);
13279
+ }
13280
+ } catch {
13281
+ }
13282
+ }
13283
+ function createOpencodeLogSink(client) {
13284
+ if (!client || typeof client !== "object") return null;
13285
+ const sdk = client;
13286
+ const canLog = typeof sdk.app?.log === "function";
13287
+ const canToast = typeof sdk.tui?.showToast === "function";
13288
+ if (!canLog && !canToast) return null;
13289
+ return {
13290
+ log(entry) {
13291
+ if (!canLog) return;
13292
+ fireAndForget(() => sdk.app.log({ body: appLogBody(entry) }));
13293
+ },
13294
+ toast(entry) {
13295
+ if (!canToast) return;
13296
+ fireAndForget(() => sdk.tui.showToast({ body: toastBody(entry) }));
13297
+ }
13298
+ };
13299
+ }
13300
+ function registerOpencodeLogSink(client) {
13301
+ const sink = createOpencodeLogSink(client);
13302
+ if (!sink) return false;
13303
+ setLogSink(sink);
13304
+ return true;
13305
+ }
13306
+
13145
13307
  // src/v2-client.ts
13146
13308
  import path10 from "path";
13147
13309
  function formatAgentTypeList(agents) {
@@ -13966,7 +14128,9 @@ var server = async (input) => {
13966
14128
  ensureProcessExitCleanup();
13967
14129
  const opencodeVersion = pickOpencodeVersion(input);
13968
14130
  if (input && typeof input === "object" && "client" in input) {
13969
- setOpencodeClient(input.client);
14131
+ const client = input.client;
14132
+ setOpencodeClient(client);
14133
+ registerOpencodeLogSink(client);
13970
14134
  }
13971
14135
  setOpencodeProjectDirectory(pickOpencodeDirectory(input));
13972
14136
  return {