@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 +168 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/skills/claude-code-plugin/SKILL.md +20 -3
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
|
-
|
|
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 (
|
|
252
|
-
|
|
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
|
-
|
|
14131
|
+
const client = input.client;
|
|
14132
|
+
setOpencodeClient(client);
|
|
14133
|
+
registerOpencodeLogSink(client);
|
|
13970
14134
|
}
|
|
13971
14135
|
setOpencodeProjectDirectory(pickOpencodeDirectory(input));
|
|
13972
14136
|
return {
|