@raindrop-ai/opencode-plugin 0.2.0 → 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/README.md +39 -0
- package/dist/{chunk-4DAI6CYK.js → chunk-FCORH4YS.js} +217 -2
- package/dist/index.cjs +266 -23
- package/dist/index.d.cts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +78 -23
- package/dist/{index.d-vgBcEZbX.d.cts → self-diagnostics-NiAq-SZ8.d.cts} +34 -1
- package/dist/{index.d-vgBcEZbX.d.ts → self-diagnostics-NiAq-SZ8.d.ts} +34 -1
- package/dist/v2.cjs +253 -3
- package/dist/v2.d.cts +5 -2
- package/dist/v2.d.ts +5 -2
- package/dist/v2.js +46 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -23,6 +23,7 @@ __export(index_exports, {
|
|
|
23
23
|
default: () => plugin
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
var import_plugin = require("@opencode-ai/plugin");
|
|
26
27
|
|
|
27
28
|
// ../core/dist/chunk-BYBMRLZM.js
|
|
28
29
|
var EVAL_CORRELATION_ID_ATTRIBUTE = "raindrop.eval_correlation_id";
|
|
@@ -2308,9 +2309,41 @@ function loadConfig(projectDirectory) {
|
|
|
2308
2309
|
captureSystemPrompt: process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] !== void 0 ? process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] === "true" : (_h = merged.capture_system_prompt) != null ? _h : false,
|
|
2309
2310
|
eventMetadata,
|
|
2310
2311
|
localWorkshopUrl: resolveLocalWorkshopUrl(merged.local_workshop_url),
|
|
2311
|
-
appGit: mapAppGit(merged.app_git)
|
|
2312
|
+
appGit: mapAppGit(merged.app_git),
|
|
2313
|
+
selfDiagnostics: mapSelfDiagnostics(merged.self_diagnostics)
|
|
2312
2314
|
};
|
|
2313
2315
|
}
|
|
2316
|
+
function isRecord(value) {
|
|
2317
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2318
|
+
}
|
|
2319
|
+
function mapSelfDiagnostics(value) {
|
|
2320
|
+
const env = process.env["RAINDROP_SELF_DIAGNOSTICS"];
|
|
2321
|
+
const record = isRecord(value) ? value : {};
|
|
2322
|
+
const enabled = env !== void 0 ? env === "true" : typeof record["enabled"] === "boolean" ? record["enabled"] : void 0;
|
|
2323
|
+
const signals = mapSelfDiagnosticsSignals(record["signals"]);
|
|
2324
|
+
const options = {
|
|
2325
|
+
...enabled !== void 0 ? { enabled } : {},
|
|
2326
|
+
...signals ? { signals } : {},
|
|
2327
|
+
...typeof record["guidance"] === "string" ? { guidance: record["guidance"] } : {},
|
|
2328
|
+
...typeof record["tool_name"] === "string" ? { toolName: record["tool_name"] } : {}
|
|
2329
|
+
};
|
|
2330
|
+
return Object.keys(options).length > 0 ? options : void 0;
|
|
2331
|
+
}
|
|
2332
|
+
function mapSelfDiagnosticsSignals(value) {
|
|
2333
|
+
if (!isRecord(value)) return void 0;
|
|
2334
|
+
const out = {};
|
|
2335
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
2336
|
+
if (!isRecord(entry)) continue;
|
|
2337
|
+
const definition = entry;
|
|
2338
|
+
if (typeof definition["description"] !== "string") continue;
|
|
2339
|
+
const sentiment = definition["sentiment"];
|
|
2340
|
+
out[key] = {
|
|
2341
|
+
description: definition["description"],
|
|
2342
|
+
...sentiment === "POSITIVE" || sentiment === "NEGATIVE" ? { sentiment } : {}
|
|
2343
|
+
};
|
|
2344
|
+
}
|
|
2345
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
2346
|
+
}
|
|
2314
2347
|
function mapAppGit(value) {
|
|
2315
2348
|
if (value === false) return false;
|
|
2316
2349
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
@@ -2337,7 +2370,7 @@ function resolveLocalWorkshopUrl(fileValue) {
|
|
|
2337
2370
|
// package.json
|
|
2338
2371
|
var package_default = {
|
|
2339
2372
|
name: "@raindrop-ai/opencode-plugin",
|
|
2340
|
-
version: "0.
|
|
2373
|
+
version: "0.3.0",
|
|
2341
2374
|
description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
|
|
2342
2375
|
type: "module",
|
|
2343
2376
|
main: "dist/index.js",
|
|
@@ -2426,6 +2459,167 @@ var package_default = {
|
|
|
2426
2459
|
var PLUGIN_NAME = package_default.name;
|
|
2427
2460
|
var PLUGIN_VERSION = package_default.version;
|
|
2428
2461
|
|
|
2462
|
+
// src/self-diagnostics.ts
|
|
2463
|
+
var SELF_DIAGNOSTICS_TOOL_NAME_DEFAULT = "__raindrop_report";
|
|
2464
|
+
var SELF_DIAGNOSTICS_SIGNALS_DEFAULT = {
|
|
2465
|
+
missing_context: {
|
|
2466
|
+
description: "You cannot complete the task because critical information, credentials, or access is missing and the user cannot provide it. Do NOT report this for normal clarifying questions \u2014 only when you are blocked.",
|
|
2467
|
+
sentiment: "NEGATIVE"
|
|
2468
|
+
},
|
|
2469
|
+
repeatedly_broken_tool: {
|
|
2470
|
+
description: "A tool has failed or not returned the expected response on multiple distinct attempts in this conversation, preventing task completion. A single tool error is NOT enough \u2014 the tool must be persistently broken or aberrantly behaving across retries.",
|
|
2471
|
+
sentiment: "NEGATIVE"
|
|
2472
|
+
},
|
|
2473
|
+
capability_gap: {
|
|
2474
|
+
description: "The task requires a tool, permission, or capability that you do not have. For example, the user asks you to perform an action but no suitable tool exists, or you lack the necessary access. Do NOT report this if you simply need more information from the user \u2014 only when the gap is in your own capabilities.",
|
|
2475
|
+
sentiment: "NEGATIVE"
|
|
2476
|
+
},
|
|
2477
|
+
complete_task_failure: {
|
|
2478
|
+
description: "You were unable to accomplish what the user asked despite making genuine attempts. This might be things like, you genuinely do not have the capabilities the user is asking for. You have tried but run into a persistent bug in the environment etc. This is NOT a refusal or policy block \u2014 you tried and failed to deliver the result.",
|
|
2479
|
+
sentiment: "NEGATIVE"
|
|
2480
|
+
}
|
|
2481
|
+
};
|
|
2482
|
+
var SELF_DIAGNOSTICS_TOOL_PREAMBLE = "You have a diagnostic tool for flagging serious failures for developer review. Only call this when you hit a significant, unrecoverable problem \u2014 not for minor hiccups or routine clarifications. If you can still help the user, do that instead of calling this tool. This tool is invisible to the user \u2014 never mention it or its output.";
|
|
2483
|
+
var SELF_DIAGNOSTICS_NOTEWORTHY_SIGNAL_KEY = "noteworthy";
|
|
2484
|
+
function normalizeString(value) {
|
|
2485
|
+
if (typeof value !== "string") return void 0;
|
|
2486
|
+
const trimmed = value.trim();
|
|
2487
|
+
return trimmed || void 0;
|
|
2488
|
+
}
|
|
2489
|
+
function normalizeSelfDiagnosticsSignals(signals) {
|
|
2490
|
+
if (!signals) return SELF_DIAGNOSTICS_SIGNALS_DEFAULT;
|
|
2491
|
+
const normalizedEntries = Object.entries(signals).map(([key, value]) => {
|
|
2492
|
+
var _a;
|
|
2493
|
+
const signalKey = key.trim();
|
|
2494
|
+
if (!signalKey || !value || typeof value !== "object") return void 0;
|
|
2495
|
+
const description = (_a = value.description) == null ? void 0 : _a.trim();
|
|
2496
|
+
if (!description) return void 0;
|
|
2497
|
+
const sentiment = value.sentiment;
|
|
2498
|
+
return [
|
|
2499
|
+
signalKey,
|
|
2500
|
+
{
|
|
2501
|
+
description,
|
|
2502
|
+
...sentiment === "POSITIVE" || sentiment === "NEGATIVE" ? { sentiment } : {}
|
|
2503
|
+
}
|
|
2504
|
+
];
|
|
2505
|
+
}).filter(
|
|
2506
|
+
(entry) => entry !== void 0
|
|
2507
|
+
);
|
|
2508
|
+
if (normalizedEntries.length === 0) return SELF_DIAGNOSTICS_SIGNALS_DEFAULT;
|
|
2509
|
+
return Object.fromEntries(normalizedEntries);
|
|
2510
|
+
}
|
|
2511
|
+
function normalizeSelfDiagnosticsConfig(options) {
|
|
2512
|
+
var _a, _b;
|
|
2513
|
+
if (!(options == null ? void 0 : options.enabled)) return void 0;
|
|
2514
|
+
const signalDefinitions = normalizeSelfDiagnosticsSignals(options.signals);
|
|
2515
|
+
const signalKeys = Object.keys(signalDefinitions);
|
|
2516
|
+
const signalDescriptions = {};
|
|
2517
|
+
const signalSentiments = {};
|
|
2518
|
+
for (const signalKey of signalKeys) {
|
|
2519
|
+
const definition = signalDefinitions[signalKey];
|
|
2520
|
+
if (!definition) continue;
|
|
2521
|
+
signalDescriptions[signalKey] = definition.description;
|
|
2522
|
+
signalSentiments[signalKey] = definition.sentiment;
|
|
2523
|
+
}
|
|
2524
|
+
const customGuidance = ((_a = options.guidance) == null ? void 0 : _a.trim()) || "";
|
|
2525
|
+
const toolName = ((_b = options.toolName) == null ? void 0 : _b.trim()) || SELF_DIAGNOSTICS_TOOL_NAME_DEFAULT;
|
|
2526
|
+
const signalList = signalKeys.map((signalKey) => {
|
|
2527
|
+
const sentiment = signalSentiments[signalKey];
|
|
2528
|
+
const sentimentTag = sentiment ? ` [${sentiment.toLowerCase()}]` : "";
|
|
2529
|
+
return `- ${signalKey}: ${signalDescriptions[signalKey]}${sentimentTag}`;
|
|
2530
|
+
}).join("\n");
|
|
2531
|
+
const guidanceBlock = customGuidance ? `
|
|
2532
|
+
Additional guidance: ${customGuidance}
|
|
2533
|
+
` : "";
|
|
2534
|
+
const toolDescription = `${SELF_DIAGNOSTICS_TOOL_PREAMBLE}
|
|
2535
|
+
|
|
2536
|
+
When to call:
|
|
2537
|
+
- You are blocked from completing the task due to missing information or access that the user cannot provide.
|
|
2538
|
+
- A tool is persistently failing across multiple attempts, not just a single transient error.
|
|
2539
|
+
- The task requires a tool, permission, or capability you do not have.
|
|
2540
|
+
- You genuinely cannot deliver what the user asked for despite trying.
|
|
2541
|
+
|
|
2542
|
+
When NOT to call:
|
|
2543
|
+
- Normal clarifying questions or back-and-forth with the user.
|
|
2544
|
+
- A single tool error that you can recover from or retry.
|
|
2545
|
+
- You successfully completed the task, even if it was difficult.
|
|
2546
|
+
- Policy refusals or content filtering \u2014 those are working as intended.
|
|
2547
|
+
|
|
2548
|
+
Rules:
|
|
2549
|
+
1. Pick the single best category.
|
|
2550
|
+
2. Do not fabricate issues. Only report what is evident from the conversation.
|
|
2551
|
+
3. Err on the side of NOT calling this tool. When in doubt, help the user instead.
|
|
2552
|
+
${guidanceBlock}
|
|
2553
|
+
Categories:
|
|
2554
|
+
` + signalList;
|
|
2555
|
+
return {
|
|
2556
|
+
toolName,
|
|
2557
|
+
toolDescription,
|
|
2558
|
+
signalKeys,
|
|
2559
|
+
signalKeySet: new Set(signalKeys),
|
|
2560
|
+
signalDescriptions,
|
|
2561
|
+
signalSentiments
|
|
2562
|
+
};
|
|
2563
|
+
}
|
|
2564
|
+
var SELF_DIAGNOSTICS_ACK = '{"acknowledged":true}';
|
|
2565
|
+
function isRecord2(value) {
|
|
2566
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2567
|
+
}
|
|
2568
|
+
async function trackSelfDiagnosticsSignal(toolInput, config, eventShipper, eventId, debug) {
|
|
2569
|
+
var _a, _b;
|
|
2570
|
+
try {
|
|
2571
|
+
const input = isRecord2(toolInput) ? toolInput : void 0;
|
|
2572
|
+
const fallbackCategory = (_a = config.signalKeys[0]) != null ? _a : "unknown";
|
|
2573
|
+
const categoryCandidate = normalizeString(input == null ? void 0 : input["category"]);
|
|
2574
|
+
const category = categoryCandidate && config.signalKeySet.has(categoryCandidate) ? categoryCandidate : fallbackCategory;
|
|
2575
|
+
const detail = (_b = normalizeString(input == null ? void 0 : input["detail"])) != null ? _b : "";
|
|
2576
|
+
if (!eventId) {
|
|
2577
|
+
if (debug) {
|
|
2578
|
+
console.warn(
|
|
2579
|
+
"[raindrop-ai/opencode-plugin] self diagnostics signal skipped: no open event for this session."
|
|
2580
|
+
);
|
|
2581
|
+
}
|
|
2582
|
+
return;
|
|
2583
|
+
}
|
|
2584
|
+
if (category === SELF_DIAGNOSTICS_NOTEWORTHY_SIGNAL_KEY) {
|
|
2585
|
+
await eventShipper.trackSignal({
|
|
2586
|
+
eventId,
|
|
2587
|
+
name: "self diagnostics - noteworthy",
|
|
2588
|
+
type: "agent_internal",
|
|
2589
|
+
properties: {
|
|
2590
|
+
source: "agent_flag_event_tool",
|
|
2591
|
+
reason: detail,
|
|
2592
|
+
severity: "medium",
|
|
2593
|
+
sdk: "opencode-plugin",
|
|
2594
|
+
sdk_version: PLUGIN_VERSION
|
|
2595
|
+
}
|
|
2596
|
+
});
|
|
2597
|
+
return;
|
|
2598
|
+
}
|
|
2599
|
+
await eventShipper.trackSignal({
|
|
2600
|
+
eventId,
|
|
2601
|
+
name: `self diagnostics - ${category}`,
|
|
2602
|
+
type: "agent",
|
|
2603
|
+
sentiment: config.signalSentiments[category],
|
|
2604
|
+
properties: {
|
|
2605
|
+
source: "agent_reporting_tool",
|
|
2606
|
+
category,
|
|
2607
|
+
signal_description: config.signalDescriptions[category],
|
|
2608
|
+
sdk: "opencode-plugin",
|
|
2609
|
+
sdk_version: PLUGIN_VERSION,
|
|
2610
|
+
...detail ? { detail } : {}
|
|
2611
|
+
}
|
|
2612
|
+
});
|
|
2613
|
+
} catch (err) {
|
|
2614
|
+
if (debug) {
|
|
2615
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2616
|
+
console.warn(
|
|
2617
|
+
`[raindrop-ai/opencode-plugin] selfDiagnostics signal dispatch failed: ${message}`
|
|
2618
|
+
);
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2429
2623
|
// src/shipper.ts
|
|
2430
2624
|
var EventShipper3 = class extends EventShipper2 {
|
|
2431
2625
|
constructor(opts) {
|
|
@@ -2697,7 +2891,7 @@ function markTaskCallFinished(sessionID, callID) {
|
|
|
2697
2891
|
running.delete(callID);
|
|
2698
2892
|
if (running.size === 0) runningTaskCallsBySession.delete(sessionID);
|
|
2699
2893
|
}
|
|
2700
|
-
function endPendingToolSpanWithError(state2, callID,
|
|
2894
|
+
function endPendingToolSpanWithError(state2, callID, tool2, toolCallArgs, errorMessage, traceShipper) {
|
|
2701
2895
|
const startInfo = state2.toolSpanStarts.get(callID);
|
|
2702
2896
|
if (!startInfo) return false;
|
|
2703
2897
|
state2.toolSpanStarts.delete(callID);
|
|
@@ -2719,7 +2913,7 @@ function endPendingToolSpanWithError(state2, callID, tool, toolCallArgs, errorMe
|
|
|
2719
2913
|
startTimeUnixNano: startInfo.startTimeUnixNano,
|
|
2720
2914
|
attributes: [
|
|
2721
2915
|
attrString("ai.operationId", "ai.toolCall"),
|
|
2722
|
-
attrString("ai.toolCall.name",
|
|
2916
|
+
attrString("ai.toolCall.name", tool2),
|
|
2723
2917
|
attrString("ai.toolCall.id", callID)
|
|
2724
2918
|
]
|
|
2725
2919
|
});
|
|
@@ -2756,7 +2950,7 @@ function getHostname() {
|
|
|
2756
2950
|
return h;
|
|
2757
2951
|
}
|
|
2758
2952
|
}
|
|
2759
|
-
function
|
|
2953
|
+
function createTracing(config, worktree, directory, eventShipper, traceShipper) {
|
|
2760
2954
|
function log(msg, data) {
|
|
2761
2955
|
if (!config.debug) return;
|
|
2762
2956
|
const prefix = `[raindrop-ai/opencode-plugin] [info] ${msg}`;
|
|
@@ -2782,7 +2976,7 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
2782
2976
|
callKey,
|
|
2783
2977
|
log
|
|
2784
2978
|
});
|
|
2785
|
-
|
|
2979
|
+
const hooks = {
|
|
2786
2980
|
// ------------------------------------------------------------------
|
|
2787
2981
|
// event — session lifecycle + streaming parts
|
|
2788
2982
|
// ------------------------------------------------------------------
|
|
@@ -2827,14 +3021,14 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
2827
3021
|
if (partObj["type"] === "text" && typeof partObj["text"] === "string") {
|
|
2828
3022
|
state2.outputParts.set(messageId, capText2(partObj["text"]));
|
|
2829
3023
|
} else if (partObj["type"] === "tool" && messageId) {
|
|
2830
|
-
const
|
|
3024
|
+
const tool2 = partObj["tool"];
|
|
2831
3025
|
const callID = partObj["callID"];
|
|
2832
3026
|
const partState = partObj["state"];
|
|
2833
3027
|
if (callID == null || callID === "")
|
|
2834
3028
|
throw new Error("message.part.updated: part.callID is required for tool part");
|
|
2835
3029
|
if (partState == null || typeof partState !== "object")
|
|
2836
3030
|
throw new Error("message.part.updated: part.state is required for tool part");
|
|
2837
|
-
if (
|
|
3031
|
+
if (tool2 === "task") {
|
|
2838
3032
|
const metadata = partState["metadata"];
|
|
2839
3033
|
const childSessionId = metadata != null && typeof metadata === "object" ? metadata["sessionId"] : void 0;
|
|
2840
3034
|
if (childSessionId != null && childSessionId !== "") {
|
|
@@ -2859,11 +3053,11 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
2859
3053
|
if (endPendingToolSpanWithError(
|
|
2860
3054
|
state2,
|
|
2861
3055
|
callID,
|
|
2862
|
-
|
|
3056
|
+
tool2,
|
|
2863
3057
|
toolCallArgs,
|
|
2864
3058
|
errorMessage,
|
|
2865
3059
|
traceShipper
|
|
2866
|
-
) &&
|
|
3060
|
+
) && tool2 === "task") {
|
|
2867
3061
|
markTaskCallFinished(partSessionID, callID);
|
|
2868
3062
|
}
|
|
2869
3063
|
}
|
|
@@ -3240,20 +3434,20 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3240
3434
|
"tool.execute.before": async (toolInput, _output) => {
|
|
3241
3435
|
var _a, _b, _c;
|
|
3242
3436
|
try {
|
|
3243
|
-
const { tool, sessionID, callID } = toolInput;
|
|
3437
|
+
const { tool: tool2, sessionID, callID } = toolInput;
|
|
3244
3438
|
const state2 = sessions.get(sessionID);
|
|
3245
3439
|
if (!state2 || !state2.currentEventId) return;
|
|
3246
3440
|
const spanParent = state2.parentId && state2.parentTaskSpanIds ? state2.parentTaskSpanIds : (_a = state2.currentRootSpan) == null ? void 0 : _a.ids;
|
|
3247
3441
|
if (!spanParent) return;
|
|
3248
3442
|
const startTimeUnixNano = nowUnixNanoString();
|
|
3249
|
-
if (
|
|
3443
|
+
if (tool2 === "task") {
|
|
3250
3444
|
const liveTaskSpan = traceShipper.startSpan({
|
|
3251
3445
|
name: "ai.toolCall",
|
|
3252
3446
|
parent: spanParent,
|
|
3253
3447
|
eventId: state2.currentEventId,
|
|
3254
3448
|
attributes: [
|
|
3255
3449
|
attrString("ai.operationId", "ai.toolCall"),
|
|
3256
|
-
attrString("ai.toolCall.name",
|
|
3450
|
+
attrString("ai.toolCall.name", tool2),
|
|
3257
3451
|
attrString("ai.toolCall.id", callID)
|
|
3258
3452
|
]
|
|
3259
3453
|
});
|
|
@@ -3278,7 +3472,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3278
3472
|
startTimeUnixNano,
|
|
3279
3473
|
parent: spanParent,
|
|
3280
3474
|
eventId: state2.currentEventId,
|
|
3281
|
-
name:
|
|
3475
|
+
name: tool2,
|
|
3282
3476
|
liveSpan: liveTaskSpan
|
|
3283
3477
|
});
|
|
3284
3478
|
} else {
|
|
@@ -3286,7 +3480,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3286
3480
|
startTimeUnixNano,
|
|
3287
3481
|
parent: spanParent,
|
|
3288
3482
|
eventId: state2.currentEventId,
|
|
3289
|
-
name:
|
|
3483
|
+
name: tool2
|
|
3290
3484
|
});
|
|
3291
3485
|
}
|
|
3292
3486
|
} catch (err) {
|
|
@@ -3301,7 +3495,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3301
3495
|
// ------------------------------------------------------------------
|
|
3302
3496
|
"tool.execute.after": async (toolInput, result) => {
|
|
3303
3497
|
try {
|
|
3304
|
-
const { tool, sessionID, callID, args } = toolInput;
|
|
3498
|
+
const { tool: tool2, sessionID, callID, args } = toolInput;
|
|
3305
3499
|
const state2 = sessions.get(sessionID);
|
|
3306
3500
|
if (!state2 || !state2.currentEventId) return;
|
|
3307
3501
|
if (args === void 0 || args === null)
|
|
@@ -3311,7 +3505,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3311
3505
|
state2.toolSpanStarts.delete(callID);
|
|
3312
3506
|
const resultMetadata = result.metadata;
|
|
3313
3507
|
const childSessionId = resultMetadata == null ? void 0 : resultMetadata["sessionId"];
|
|
3314
|
-
if (
|
|
3508
|
+
if (tool2 === "task" && childSessionId) {
|
|
3315
3509
|
mapChildSessionToParent.set(childSessionId, { parentId: sessionID });
|
|
3316
3510
|
attachChildSessionToParentTask(childSessionId, sessionID, callID, "tool.execute.after");
|
|
3317
3511
|
}
|
|
@@ -3336,7 +3530,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3336
3530
|
endTimeUnixNano,
|
|
3337
3531
|
attributes: [
|
|
3338
3532
|
attrString("ai.operationId", "ai.toolCall"),
|
|
3339
|
-
attrString("ai.toolCall.name",
|
|
3533
|
+
attrString("ai.toolCall.name", tool2),
|
|
3340
3534
|
attrString("ai.toolCall.id", callID),
|
|
3341
3535
|
attrString("ai.toolCall.args", toolCallArgs),
|
|
3342
3536
|
attrString("ai.toolCall.result", toolResult)
|
|
@@ -3344,7 +3538,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3344
3538
|
});
|
|
3345
3539
|
}
|
|
3346
3540
|
}
|
|
3347
|
-
if (
|
|
3541
|
+
if (tool2 === "task") {
|
|
3348
3542
|
markTaskCallFinished(sessionID, callID);
|
|
3349
3543
|
}
|
|
3350
3544
|
} catch (err) {
|
|
@@ -3397,16 +3591,24 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3397
3591
|
}
|
|
3398
3592
|
}
|
|
3399
3593
|
};
|
|
3594
|
+
return {
|
|
3595
|
+
hooks,
|
|
3596
|
+
currentEventId(sessionID) {
|
|
3597
|
+
var _a;
|
|
3598
|
+
return (_a = sessions.get(sessionID)) == null ? void 0 : _a.currentEventId;
|
|
3599
|
+
}
|
|
3600
|
+
};
|
|
3400
3601
|
}
|
|
3401
3602
|
|
|
3402
3603
|
// src/index.ts
|
|
3403
|
-
function createRaindropHandle(eventShipper, traceShipper, appGitContext) {
|
|
3604
|
+
function createRaindropHandle(eventShipper, traceShipper, appGitContext, currentEventId) {
|
|
3404
3605
|
return {
|
|
3405
3606
|
users: {
|
|
3406
3607
|
async identify(users) {
|
|
3407
3608
|
await eventShipper.identify(users);
|
|
3408
3609
|
}
|
|
3409
3610
|
},
|
|
3611
|
+
currentEventId,
|
|
3410
3612
|
async flush() {
|
|
3411
3613
|
await Promise.all([eventShipper.flush(), traceShipper.flush()]);
|
|
3412
3614
|
},
|
|
@@ -3423,7 +3625,7 @@ function createRaindropHandle(eventShipper, traceShipper, appGitContext) {
|
|
|
3423
3625
|
};
|
|
3424
3626
|
}
|
|
3425
3627
|
async function plugin(input, opts = {}) {
|
|
3426
|
-
var _a, _b, _c;
|
|
3628
|
+
var _a, _b, _c, _d;
|
|
3427
3629
|
const config = loadConfig(input.directory);
|
|
3428
3630
|
function appLog(level, message) {
|
|
3429
3631
|
console.log(`[raindrop-ai/opencode-plugin] [${level}] ${message}`);
|
|
@@ -3467,12 +3669,53 @@ async function plugin(input, opts = {}) {
|
|
|
3467
3669
|
appGitContext
|
|
3468
3670
|
});
|
|
3469
3671
|
const worktree = (_c = input.worktree) != null ? _c : input.directory;
|
|
3470
|
-
const
|
|
3672
|
+
const tracing = createTracing(
|
|
3471
3673
|
config,
|
|
3472
3674
|
worktree,
|
|
3473
3675
|
input.directory,
|
|
3474
3676
|
eventShipper,
|
|
3475
3677
|
traceShipper
|
|
3476
3678
|
);
|
|
3477
|
-
|
|
3679
|
+
const hooks = tracing.hooks;
|
|
3680
|
+
const selfDiagnostics = normalizeSelfDiagnosticsConfig(
|
|
3681
|
+
(_d = opts.selfDiagnostics) != null ? _d : config.selfDiagnostics
|
|
3682
|
+
);
|
|
3683
|
+
if (selfDiagnostics && !config.writeKey.trim()) {
|
|
3684
|
+
appLog(
|
|
3685
|
+
"warn",
|
|
3686
|
+
`selfDiagnostics enabled but RAINDROP_WRITE_KEY is not set \u2014 the ${selfDiagnostics.toolName} tool is not registered (signals require the cloud destination).`
|
|
3687
|
+
);
|
|
3688
|
+
}
|
|
3689
|
+
const [firstSignalKey, ...restSignalKeys] = config.writeKey.trim() && selfDiagnostics ? selfDiagnostics.signalKeys : [];
|
|
3690
|
+
if (selfDiagnostics && firstSignalKey !== void 0) {
|
|
3691
|
+
const cfg = selfDiagnostics;
|
|
3692
|
+
hooks.tool = {
|
|
3693
|
+
[cfg.toolName]: (0, import_plugin.tool)({
|
|
3694
|
+
description: cfg.toolDescription,
|
|
3695
|
+
args: {
|
|
3696
|
+
category: import_plugin.tool.schema.enum([firstSignalKey, ...restSignalKeys]),
|
|
3697
|
+
detail: import_plugin.tool.schema.string()
|
|
3698
|
+
},
|
|
3699
|
+
async execute(args, ctx) {
|
|
3700
|
+
await trackSelfDiagnosticsSignal(
|
|
3701
|
+
args,
|
|
3702
|
+
cfg,
|
|
3703
|
+
eventShipper,
|
|
3704
|
+
tracing.currentEventId(ctx.sessionID),
|
|
3705
|
+
config.debug
|
|
3706
|
+
);
|
|
3707
|
+
return SELF_DIAGNOSTICS_ACK;
|
|
3708
|
+
}
|
|
3709
|
+
})
|
|
3710
|
+
};
|
|
3711
|
+
}
|
|
3712
|
+
return {
|
|
3713
|
+
...hooks,
|
|
3714
|
+
raindrop: createRaindropHandle(
|
|
3715
|
+
eventShipper,
|
|
3716
|
+
traceShipper,
|
|
3717
|
+
appGitContext,
|
|
3718
|
+
tracing.currentEventId
|
|
3719
|
+
)
|
|
3720
|
+
};
|
|
3478
3721
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { I as IdentifyInput, A as AppGitOptions } from './
|
|
1
|
+
import { I as IdentifyInput, A as AppGitOptions, S as SelfDiagnosticsOptions } from './self-diagnostics-NiAq-SZ8.cjs';
|
|
2
|
+
export { a as SelfDiagnosticsSignalDefinition, b as SelfDiagnosticsSignalDefinitions } from './self-diagnostics-NiAq-SZ8.cjs';
|
|
2
3
|
import { Hooks, PluginInput } from '@opencode-ai/plugin';
|
|
3
4
|
|
|
4
5
|
interface RaindropOpencodeOptions {
|
|
5
6
|
/** Application Git identity override. false disables enrichment. */
|
|
6
7
|
appGit?: AppGitOptions | false;
|
|
8
|
+
/** Built-in self-diagnostics: injects a `__raindrop_report` tool when enabled. */
|
|
9
|
+
selfDiagnostics?: SelfDiagnosticsOptions;
|
|
7
10
|
}
|
|
8
11
|
/**
|
|
9
12
|
* The Raindrop control handle exposed alongside the OpenCode hooks.
|
|
@@ -25,6 +28,8 @@ interface RaindropOpencodeHandle {
|
|
|
25
28
|
*/
|
|
26
29
|
identify(users: IdentifyInput | IdentifyInput[]): Promise<void>;
|
|
27
30
|
};
|
|
31
|
+
/** Raindrop eventId of the turn currently open for this OpenCode session, if any. */
|
|
32
|
+
currentEventId(sessionID: string): string | undefined;
|
|
28
33
|
/** Drain the buffered event + trace shippers. */
|
|
29
34
|
flush(): Promise<void>;
|
|
30
35
|
/** Flush and tear down the shippers (also wired into session teardown). */
|
|
@@ -53,4 +58,4 @@ type RaindropOpencodeHooks = Hooks & {
|
|
|
53
58
|
*/
|
|
54
59
|
declare function plugin(input: PluginInput, opts?: RaindropOpencodeOptions): Promise<RaindropOpencodeHooks>;
|
|
55
60
|
|
|
56
|
-
export { IdentifyInput, type RaindropOpencodeHandle, type RaindropOpencodeHooks, type RaindropOpencodeOptions, plugin as default };
|
|
61
|
+
export { IdentifyInput, type RaindropOpencodeHandle, type RaindropOpencodeHooks, type RaindropOpencodeOptions, SelfDiagnosticsOptions, plugin as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { I as IdentifyInput, A as AppGitOptions } from './
|
|
1
|
+
import { I as IdentifyInput, A as AppGitOptions, S as SelfDiagnosticsOptions } from './self-diagnostics-NiAq-SZ8.js';
|
|
2
|
+
export { a as SelfDiagnosticsSignalDefinition, b as SelfDiagnosticsSignalDefinitions } from './self-diagnostics-NiAq-SZ8.js';
|
|
2
3
|
import { Hooks, PluginInput } from '@opencode-ai/plugin';
|
|
3
4
|
|
|
4
5
|
interface RaindropOpencodeOptions {
|
|
5
6
|
/** Application Git identity override. false disables enrichment. */
|
|
6
7
|
appGit?: AppGitOptions | false;
|
|
8
|
+
/** Built-in self-diagnostics: injects a `__raindrop_report` tool when enabled. */
|
|
9
|
+
selfDiagnostics?: SelfDiagnosticsOptions;
|
|
7
10
|
}
|
|
8
11
|
/**
|
|
9
12
|
* The Raindrop control handle exposed alongside the OpenCode hooks.
|
|
@@ -25,6 +28,8 @@ interface RaindropOpencodeHandle {
|
|
|
25
28
|
*/
|
|
26
29
|
identify(users: IdentifyInput | IdentifyInput[]): Promise<void>;
|
|
27
30
|
};
|
|
31
|
+
/** Raindrop eventId of the turn currently open for this OpenCode session, if any. */
|
|
32
|
+
currentEventId(sessionID: string): string | undefined;
|
|
28
33
|
/** Drain the buffered event + trace shippers. */
|
|
29
34
|
flush(): Promise<void>;
|
|
30
35
|
/** Flush and tear down the shippers (also wired into session teardown). */
|
|
@@ -53,4 +58,4 @@ type RaindropOpencodeHooks = Hooks & {
|
|
|
53
58
|
*/
|
|
54
59
|
declare function plugin(input: PluginInput, opts?: RaindropOpencodeOptions): Promise<RaindropOpencodeHooks>;
|
|
55
60
|
|
|
56
|
-
export { IdentifyInput, type RaindropOpencodeHandle, type RaindropOpencodeHooks, type RaindropOpencodeOptions, plugin as default };
|
|
61
|
+
export { IdentifyInput, type RaindropOpencodeHandle, type RaindropOpencodeHooks, type RaindropOpencodeOptions, SelfDiagnosticsOptions, plugin as default };
|