@raindrop-ai/opencode-plugin 0.0.10 → 0.0.12
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.cjs +343 -163
- package/dist/index.js +343 -163
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -24,124 +24,7 @@ __export(index_exports, {
|
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(index_exports);
|
|
26
26
|
|
|
27
|
-
//
|
|
28
|
-
var import_node_fs = require("fs");
|
|
29
|
-
var import_node_os = require("os");
|
|
30
|
-
var import_node_path = require("path");
|
|
31
|
-
function loadConfig(projectDirectory) {
|
|
32
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
33
|
-
let merged = {};
|
|
34
|
-
const configPaths = [
|
|
35
|
-
(0, import_node_path.join)((0, import_node_os.homedir)(), ".config", "opencode", "raindrop.json"),
|
|
36
|
-
(0, import_node_path.join)(projectDirectory, ".opencode", "raindrop.json")
|
|
37
|
-
];
|
|
38
|
-
for (const configPath of configPaths) {
|
|
39
|
-
try {
|
|
40
|
-
if ((0, import_node_fs.existsSync)(configPath)) {
|
|
41
|
-
const content = (0, import_node_fs.readFileSync)(configPath, "utf-8");
|
|
42
|
-
const parsed = JSON.parse(content);
|
|
43
|
-
merged = { ...merged, ...parsed };
|
|
44
|
-
}
|
|
45
|
-
} catch (e) {
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
let eventMetadata;
|
|
49
|
-
const envMeta = process.env["RAINDROP_EVENT_METADATA"];
|
|
50
|
-
if (envMeta) {
|
|
51
|
-
try {
|
|
52
|
-
eventMetadata = JSON.parse(envMeta);
|
|
53
|
-
} catch (e) {
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return {
|
|
57
|
-
writeKey: (_b = (_a = process.env["RAINDROP_WRITE_KEY"]) != null ? _a : merged.write_key) != null ? _b : "",
|
|
58
|
-
endpoint: (_d = (_c = process.env["RAINDROP_API_URL"]) != null ? _c : merged.api_url) != null ? _d : "https://api.raindrop.ai/v1",
|
|
59
|
-
eventName: (_e = merged.event_name) != null ? _e : "opencode_session",
|
|
60
|
-
debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_f = merged.debug) != null ? _f : false,
|
|
61
|
-
captureSystemPrompt: process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] !== void 0 ? process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] === "true" : (_g = merged.capture_system_prompt) != null ? _g : false,
|
|
62
|
-
eventMetadata
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// package.json
|
|
67
|
-
var package_default = {
|
|
68
|
-
name: "@raindrop-ai/opencode-plugin",
|
|
69
|
-
version: "0.0.10",
|
|
70
|
-
description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
|
|
71
|
-
type: "module",
|
|
72
|
-
main: "dist/index.js",
|
|
73
|
-
module: "dist/index.js",
|
|
74
|
-
types: "dist/index.d.ts",
|
|
75
|
-
license: "MIT",
|
|
76
|
-
repository: {
|
|
77
|
-
type: "git",
|
|
78
|
-
url: "git+https://github.com/raindrop-ai/raindrop-js.git",
|
|
79
|
-
directory: "packages/opencode-plugin"
|
|
80
|
-
},
|
|
81
|
-
homepage: "https://github.com/raindrop-ai/raindrop-js/tree/main/packages/opencode-plugin#readme",
|
|
82
|
-
bugs: {
|
|
83
|
-
url: "https://github.com/raindrop-ai/raindrop-js/issues"
|
|
84
|
-
},
|
|
85
|
-
exports: {
|
|
86
|
-
".": {
|
|
87
|
-
types: "./dist/index.d.ts",
|
|
88
|
-
import: "./dist/index.js",
|
|
89
|
-
require: "./dist/index.cjs"
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
sideEffects: false,
|
|
93
|
-
files: [
|
|
94
|
-
"dist/**"
|
|
95
|
-
],
|
|
96
|
-
scripts: {
|
|
97
|
-
build: "tsup",
|
|
98
|
-
dev: "tsup --watch",
|
|
99
|
-
clean: "rm -rf dist",
|
|
100
|
-
test: "cd tests && pnpm test"
|
|
101
|
-
},
|
|
102
|
-
peerDependencies: {
|
|
103
|
-
"@opencode-ai/plugin": ">=1.3.0",
|
|
104
|
-
"@opencode-ai/sdk": ">=1.3.0"
|
|
105
|
-
},
|
|
106
|
-
peerDependenciesMeta: {
|
|
107
|
-
"@opencode-ai/sdk": {
|
|
108
|
-
optional: true
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
devDependencies: {
|
|
112
|
-
"@raindrop-ai/core": "workspace:*",
|
|
113
|
-
"@opencode-ai/plugin": "^1.3.3",
|
|
114
|
-
"@opencode-ai/sdk": "^1.3.3",
|
|
115
|
-
"@types/node": "^20.11.17",
|
|
116
|
-
tsup: "^8.4.0",
|
|
117
|
-
typescript: "^5.3.3"
|
|
118
|
-
},
|
|
119
|
-
tsup: {
|
|
120
|
-
entry: [
|
|
121
|
-
"src/index.ts"
|
|
122
|
-
],
|
|
123
|
-
format: [
|
|
124
|
-
"cjs",
|
|
125
|
-
"esm"
|
|
126
|
-
],
|
|
127
|
-
dts: {
|
|
128
|
-
resolve: true
|
|
129
|
-
},
|
|
130
|
-
clean: true,
|
|
131
|
-
noExternal: [
|
|
132
|
-
"@raindrop-ai/core"
|
|
133
|
-
]
|
|
134
|
-
},
|
|
135
|
-
publishConfig: {
|
|
136
|
-
access: "public"
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
// src/package-info.ts
|
|
141
|
-
var PLUGIN_NAME = package_default.name;
|
|
142
|
-
var PLUGIN_VERSION = package_default.version;
|
|
143
|
-
|
|
144
|
-
// ../core/dist/chunk-4UCYIEH4.js
|
|
27
|
+
// ../core/dist/chunk-OLYXZCOK.js
|
|
145
28
|
function getCrypto() {
|
|
146
29
|
const c = globalThis.crypto;
|
|
147
30
|
return c;
|
|
@@ -334,6 +217,91 @@ function buildExportTraceServiceRequest(spans, serviceName = "raindrop.core", se
|
|
|
334
217
|
]
|
|
335
218
|
};
|
|
336
219
|
}
|
|
220
|
+
var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
|
|
221
|
+
var WORKSHOP_ENV_VAR = "RAINDROP_WORKSHOP";
|
|
222
|
+
var DEFAULT_LOCAL_WORKSHOP_URL = "http://localhost:5899/v1/";
|
|
223
|
+
function readEnvVar(name) {
|
|
224
|
+
var _a;
|
|
225
|
+
try {
|
|
226
|
+
const env = (_a = globalThis == null ? void 0 : globalThis.process) == null ? void 0 : _a.env;
|
|
227
|
+
if (env && typeof env[name] === "string" && env[name].length > 0) {
|
|
228
|
+
return env[name];
|
|
229
|
+
}
|
|
230
|
+
} catch (e) {
|
|
231
|
+
}
|
|
232
|
+
return void 0;
|
|
233
|
+
}
|
|
234
|
+
function readWorkshopEnv() {
|
|
235
|
+
const raw = readEnvVar(WORKSHOP_ENV_VAR);
|
|
236
|
+
if (raw === void 0) return void 0;
|
|
237
|
+
const trimmed = raw.trim();
|
|
238
|
+
if (trimmed.length === 0) return void 0;
|
|
239
|
+
if (/^https?:\/\//i.test(trimmed)) return { url: trimmed };
|
|
240
|
+
if (/^(1|true|yes|on)$/i.test(trimmed)) return "enable";
|
|
241
|
+
if (/^(0|false|no|off)$/i.test(trimmed)) return "disable";
|
|
242
|
+
return void 0;
|
|
243
|
+
}
|
|
244
|
+
function isLocalDevHost(hostname) {
|
|
245
|
+
if (!hostname) return false;
|
|
246
|
+
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "::1") {
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
if (hostname.endsWith(".localhost")) return true;
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
function readRuntimeHostname() {
|
|
253
|
+
try {
|
|
254
|
+
const loc = globalThis == null ? void 0 : globalThis.location;
|
|
255
|
+
if (loc && typeof loc.hostname === "string" && loc.hostname.length > 0) {
|
|
256
|
+
return loc.hostname;
|
|
257
|
+
}
|
|
258
|
+
} catch (e) {
|
|
259
|
+
}
|
|
260
|
+
return void 0;
|
|
261
|
+
}
|
|
262
|
+
function shouldAutoEnableLocalWorkshop() {
|
|
263
|
+
if (isLocalDevHost(readRuntimeHostname())) return true;
|
|
264
|
+
if (readEnvVar("NODE_ENV") === "development") return true;
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
function resolveLocalDebuggerBaseUrl(baseUrl) {
|
|
268
|
+
var _a, _b, _c;
|
|
269
|
+
if (baseUrl === null) return null;
|
|
270
|
+
if (typeof baseUrl === "string" && baseUrl.length > 0) {
|
|
271
|
+
return (_a = formatEndpoint(baseUrl)) != null ? _a : null;
|
|
272
|
+
}
|
|
273
|
+
const explicitUrlEnv = readEnvVar(LOCAL_DEBUGGER_ENV_VAR);
|
|
274
|
+
if (explicitUrlEnv) return (_b = formatEndpoint(explicitUrlEnv)) != null ? _b : null;
|
|
275
|
+
const workshopEnv = readWorkshopEnv();
|
|
276
|
+
if (workshopEnv === "disable") return null;
|
|
277
|
+
if (workshopEnv === "enable") return DEFAULT_LOCAL_WORKSHOP_URL;
|
|
278
|
+
if (workshopEnv && "url" in workshopEnv) return (_c = formatEndpoint(workshopEnv.url)) != null ? _c : null;
|
|
279
|
+
if (shouldAutoEnableLocalWorkshop()) return DEFAULT_LOCAL_WORKSHOP_URL;
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
function mirrorTraceExportToLocalDebugger(body, options = {}) {
|
|
283
|
+
var _a;
|
|
284
|
+
const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
|
|
285
|
+
if (!baseUrl) return;
|
|
286
|
+
void postJson(`${baseUrl}traces`, body, {}, {
|
|
287
|
+
maxAttempts: 1,
|
|
288
|
+
debug: (_a = options.debug) != null ? _a : false,
|
|
289
|
+
sdkName: options.sdkName
|
|
290
|
+
}).catch(() => {
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
function mirrorPartialEventToLocalDebugger(event, options = {}) {
|
|
294
|
+
var _a;
|
|
295
|
+
const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
|
|
296
|
+
if (!baseUrl) return;
|
|
297
|
+
const headers = options.writeKey ? { Authorization: `Bearer ${options.writeKey}` } : {};
|
|
298
|
+
void postJson(`${baseUrl}events/track_partial`, event, headers, {
|
|
299
|
+
maxAttempts: 1,
|
|
300
|
+
debug: (_a = options.debug) != null ? _a : false,
|
|
301
|
+
sdkName: options.sdkName
|
|
302
|
+
}).catch(() => {
|
|
303
|
+
});
|
|
304
|
+
}
|
|
337
305
|
function mergePatches(target, source) {
|
|
338
306
|
var _a, _b, _c, _d;
|
|
339
307
|
const out = { ...target, ...source };
|
|
@@ -351,7 +319,7 @@ var EventShipper = class {
|
|
|
351
319
|
this.sticky = /* @__PURE__ */ new Map();
|
|
352
320
|
this.timers = /* @__PURE__ */ new Map();
|
|
353
321
|
this.inFlight = /* @__PURE__ */ new Set();
|
|
354
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
322
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
355
323
|
this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
|
|
356
324
|
this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
|
|
357
325
|
this.enabled = opts.enabled !== false;
|
|
@@ -360,11 +328,15 @@ var EventShipper = class {
|
|
|
360
328
|
this.sdkName = (_d = opts.sdkName) != null ? _d : "core";
|
|
361
329
|
this.prefix = `[raindrop-ai/${this.sdkName}]`;
|
|
362
330
|
this.defaultEventName = (_e = opts.defaultEventName) != null ? _e : "ai_generation";
|
|
331
|
+
this.localDebuggerUrl = (_f = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _f : void 0;
|
|
332
|
+
if (this.debug && this.localDebuggerUrl) {
|
|
333
|
+
console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
|
|
334
|
+
}
|
|
363
335
|
const isNode = typeof process !== "undefined" && typeof process.version === "string";
|
|
364
336
|
this.context = {
|
|
365
337
|
library: {
|
|
366
|
-
name: (
|
|
367
|
-
version: (
|
|
338
|
+
name: (_g = opts.libraryName) != null ? _g : "@raindrop-ai/core",
|
|
339
|
+
version: (_h = opts.libraryVersion) != null ? _h : "0.0.0"
|
|
368
340
|
},
|
|
369
341
|
metadata: {
|
|
370
342
|
jsRuntime: isNode ? "node" : "web",
|
|
@@ -450,6 +422,7 @@ var EventShipper = class {
|
|
|
450
422
|
}
|
|
451
423
|
}
|
|
452
424
|
];
|
|
425
|
+
if (!this.writeKey) return;
|
|
453
426
|
const url = `${this.baseUrl}signals/track`;
|
|
454
427
|
try {
|
|
455
428
|
await postJson(url, body, this.authHeaders(), {
|
|
@@ -480,6 +453,7 @@ var EventShipper = class {
|
|
|
480
453
|
traits: (_a = user.traits) != null ? _a : {}
|
|
481
454
|
};
|
|
482
455
|
});
|
|
456
|
+
if (!this.writeKey) return;
|
|
483
457
|
if (body.length === 0) return;
|
|
484
458
|
const url = `${this.baseUrl}users/identify`;
|
|
485
459
|
try {
|
|
@@ -556,6 +530,18 @@ var EventShipper = class {
|
|
|
556
530
|
endpoint: url
|
|
557
531
|
});
|
|
558
532
|
}
|
|
533
|
+
if (this.localDebuggerUrl) {
|
|
534
|
+
mirrorPartialEventToLocalDebugger(payload, {
|
|
535
|
+
baseUrl: this.localDebuggerUrl,
|
|
536
|
+
writeKey: this.writeKey,
|
|
537
|
+
debug: this.debug,
|
|
538
|
+
sdkName: this.sdkName
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
if (!this.writeKey) {
|
|
542
|
+
if (!isPending) this.sticky.delete(eventId);
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
559
545
|
const p = postJson(url, payload, this.authHeaders(), {
|
|
560
546
|
maxAttempts: 3,
|
|
561
547
|
debug: this.debug,
|
|
@@ -580,28 +566,11 @@ var EventShipper = class {
|
|
|
580
566
|
}
|
|
581
567
|
}
|
|
582
568
|
};
|
|
583
|
-
var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
|
|
584
|
-
function resolveLocalDebuggerBaseUrl(baseUrl) {
|
|
585
|
-
var _a, _b, _c;
|
|
586
|
-
const resolved = (_b = baseUrl != null ? baseUrl : typeof process !== "undefined" ? (_a = process.env) == null ? void 0 : _a[LOCAL_DEBUGGER_ENV_VAR] : void 0) != null ? _b : null;
|
|
587
|
-
return resolved ? (_c = formatEndpoint(resolved)) != null ? _c : null : null;
|
|
588
|
-
}
|
|
589
|
-
function mirrorTraceExportToLocalDebugger(body, options = {}) {
|
|
590
|
-
var _a;
|
|
591
|
-
const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
|
|
592
|
-
if (!baseUrl) return;
|
|
593
|
-
void postJson(`${baseUrl}traces`, body, {}, {
|
|
594
|
-
maxAttempts: 1,
|
|
595
|
-
debug: (_a = options.debug) != null ? _a : false,
|
|
596
|
-
sdkName: options.sdkName
|
|
597
|
-
}).catch(() => {
|
|
598
|
-
});
|
|
599
|
-
}
|
|
600
569
|
var TraceShipper = class {
|
|
601
570
|
constructor(opts) {
|
|
602
571
|
this.queue = [];
|
|
603
572
|
this.inFlight = /* @__PURE__ */ new Set();
|
|
604
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i
|
|
573
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
605
574
|
this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
|
|
606
575
|
this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
|
|
607
576
|
this.enabled = opts.enabled !== false;
|
|
@@ -614,12 +583,9 @@ var TraceShipper = class {
|
|
|
614
583
|
this.prefix = `[raindrop-ai/${this.sdkName}]`;
|
|
615
584
|
this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
|
|
616
585
|
this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
|
|
617
|
-
|
|
618
|
-
if (
|
|
619
|
-
this.
|
|
620
|
-
if (this.debug) {
|
|
621
|
-
console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
|
|
622
|
-
}
|
|
586
|
+
this.localDebuggerUrl = (_i = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _i : void 0;
|
|
587
|
+
if (this.debug && this.localDebuggerUrl) {
|
|
588
|
+
console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
|
|
623
589
|
}
|
|
624
590
|
}
|
|
625
591
|
isDebugEnabled() {
|
|
@@ -747,6 +713,7 @@ var TraceShipper = class {
|
|
|
747
713
|
}
|
|
748
714
|
while (this.queue.length > 0) {
|
|
749
715
|
const batch = this.queue.splice(0, this.maxBatchSize);
|
|
716
|
+
if (!this.writeKey) continue;
|
|
750
717
|
const body = buildExportTraceServiceRequest(batch, this.serviceName, this.serviceVersion);
|
|
751
718
|
const url = `${this.baseUrl}traces`;
|
|
752
719
|
if (this.debug) {
|
|
@@ -789,6 +756,134 @@ var TraceShipper = class {
|
|
|
789
756
|
var import_async_hooks = require("async_hooks");
|
|
790
757
|
globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = import_async_hooks.AsyncLocalStorage;
|
|
791
758
|
|
|
759
|
+
// src/config.ts
|
|
760
|
+
var import_node_fs = require("fs");
|
|
761
|
+
var import_node_os = require("os");
|
|
762
|
+
var import_node_path = require("path");
|
|
763
|
+
function loadConfig(projectDirectory) {
|
|
764
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
765
|
+
let merged = {};
|
|
766
|
+
const configPaths = [
|
|
767
|
+
(0, import_node_path.join)((0, import_node_os.homedir)(), ".config", "opencode", "raindrop.json"),
|
|
768
|
+
(0, import_node_path.join)(projectDirectory, ".opencode", "raindrop.json")
|
|
769
|
+
];
|
|
770
|
+
for (const configPath of configPaths) {
|
|
771
|
+
try {
|
|
772
|
+
if ((0, import_node_fs.existsSync)(configPath)) {
|
|
773
|
+
const content = (0, import_node_fs.readFileSync)(configPath, "utf-8");
|
|
774
|
+
const parsed = JSON.parse(content);
|
|
775
|
+
merged = { ...merged, ...parsed };
|
|
776
|
+
}
|
|
777
|
+
} catch (e) {
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
let eventMetadata;
|
|
781
|
+
const envMeta = process.env["RAINDROP_EVENT_METADATA"];
|
|
782
|
+
if (envMeta) {
|
|
783
|
+
try {
|
|
784
|
+
eventMetadata = JSON.parse(envMeta);
|
|
785
|
+
} catch (e) {
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
return {
|
|
789
|
+
writeKey: (_b = (_a = process.env["RAINDROP_WRITE_KEY"]) != null ? _a : merged.write_key) != null ? _b : "",
|
|
790
|
+
endpoint: (_d = (_c = process.env["RAINDROP_API_URL"]) != null ? _c : merged.api_url) != null ? _d : "https://api.raindrop.ai/v1",
|
|
791
|
+
eventName: (_e = merged.event_name) != null ? _e : "opencode_session",
|
|
792
|
+
debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_f = merged.debug) != null ? _f : false,
|
|
793
|
+
captureSystemPrompt: process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] !== void 0 ? process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] === "true" : (_g = merged.capture_system_prompt) != null ? _g : false,
|
|
794
|
+
eventMetadata,
|
|
795
|
+
localWorkshopUrl: resolveLocalWorkshopUrl(merged.local_workshop_url)
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
function resolveLocalWorkshopUrl(fileValue) {
|
|
799
|
+
const envValue = process.env["RAINDROP_LOCAL_WORKSHOP_URL"];
|
|
800
|
+
if (envValue !== void 0) {
|
|
801
|
+
if (envValue === "" || envValue.toLowerCase() === "null" || envValue.toLowerCase() === "false") {
|
|
802
|
+
return null;
|
|
803
|
+
}
|
|
804
|
+
return envValue;
|
|
805
|
+
}
|
|
806
|
+
return fileValue;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
// package.json
|
|
810
|
+
var package_default = {
|
|
811
|
+
name: "@raindrop-ai/opencode-plugin",
|
|
812
|
+
version: "0.0.12",
|
|
813
|
+
description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
|
|
814
|
+
type: "module",
|
|
815
|
+
main: "dist/index.js",
|
|
816
|
+
module: "dist/index.js",
|
|
817
|
+
types: "dist/index.d.ts",
|
|
818
|
+
license: "MIT",
|
|
819
|
+
repository: {
|
|
820
|
+
type: "git",
|
|
821
|
+
url: "git+https://github.com/raindrop-ai/raindrop-js.git",
|
|
822
|
+
directory: "packages/opencode-plugin"
|
|
823
|
+
},
|
|
824
|
+
homepage: "https://github.com/raindrop-ai/raindrop-js/tree/main/packages/opencode-plugin#readme",
|
|
825
|
+
bugs: {
|
|
826
|
+
url: "https://github.com/raindrop-ai/raindrop-js/issues"
|
|
827
|
+
},
|
|
828
|
+
exports: {
|
|
829
|
+
".": {
|
|
830
|
+
types: "./dist/index.d.ts",
|
|
831
|
+
import: "./dist/index.js",
|
|
832
|
+
require: "./dist/index.cjs"
|
|
833
|
+
}
|
|
834
|
+
},
|
|
835
|
+
sideEffects: false,
|
|
836
|
+
files: [
|
|
837
|
+
"dist/**"
|
|
838
|
+
],
|
|
839
|
+
scripts: {
|
|
840
|
+
build: "tsup",
|
|
841
|
+
dev: "tsup --watch",
|
|
842
|
+
clean: "rm -rf dist",
|
|
843
|
+
test: "cd tests && pnpm test"
|
|
844
|
+
},
|
|
845
|
+
peerDependencies: {
|
|
846
|
+
"@opencode-ai/plugin": ">=1.3.0",
|
|
847
|
+
"@opencode-ai/sdk": ">=1.3.0"
|
|
848
|
+
},
|
|
849
|
+
peerDependenciesMeta: {
|
|
850
|
+
"@opencode-ai/sdk": {
|
|
851
|
+
optional: true
|
|
852
|
+
}
|
|
853
|
+
},
|
|
854
|
+
devDependencies: {
|
|
855
|
+
"@raindrop-ai/core": "workspace:*",
|
|
856
|
+
"@opencode-ai/plugin": "^1.3.3",
|
|
857
|
+
"@opencode-ai/sdk": "^1.3.3",
|
|
858
|
+
"@types/node": "^20.11.17",
|
|
859
|
+
tsup: "^8.4.0",
|
|
860
|
+
typescript: "^5.3.3"
|
|
861
|
+
},
|
|
862
|
+
tsup: {
|
|
863
|
+
entry: [
|
|
864
|
+
"src/index.ts"
|
|
865
|
+
],
|
|
866
|
+
format: [
|
|
867
|
+
"cjs",
|
|
868
|
+
"esm"
|
|
869
|
+
],
|
|
870
|
+
dts: {
|
|
871
|
+
resolve: true
|
|
872
|
+
},
|
|
873
|
+
clean: true,
|
|
874
|
+
noExternal: [
|
|
875
|
+
"@raindrop-ai/core"
|
|
876
|
+
]
|
|
877
|
+
},
|
|
878
|
+
publishConfig: {
|
|
879
|
+
access: "public"
|
|
880
|
+
}
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
// src/package-info.ts
|
|
884
|
+
var PLUGIN_NAME = package_default.name;
|
|
885
|
+
var PLUGIN_VERSION = package_default.version;
|
|
886
|
+
|
|
792
887
|
// src/shipper.ts
|
|
793
888
|
var EventShipper2 = class extends EventShipper {
|
|
794
889
|
constructor(opts) {
|
|
@@ -919,6 +1014,59 @@ function createSessionState(sessionId) {
|
|
|
919
1014
|
function callKey(sessionId, callId) {
|
|
920
1015
|
return `${sessionId}:${callId}`;
|
|
921
1016
|
}
|
|
1017
|
+
function markTaskCallFinished(sessionID, callID) {
|
|
1018
|
+
const running = runningTaskCallsBySession.get(sessionID);
|
|
1019
|
+
if (!running) return;
|
|
1020
|
+
running.delete(callID);
|
|
1021
|
+
if (running.size === 0) runningTaskCallsBySession.delete(sessionID);
|
|
1022
|
+
}
|
|
1023
|
+
function endPendingToolSpanWithError(state, callID, tool, toolCallArgs, errorMessage, traceShipper) {
|
|
1024
|
+
const startInfo = state.toolSpanStarts.get(callID);
|
|
1025
|
+
if (!startInfo) return false;
|
|
1026
|
+
state.toolSpanStarts.delete(callID);
|
|
1027
|
+
const error = new Error(errorMessage);
|
|
1028
|
+
const endAttrs = [
|
|
1029
|
+
attrString("ai.toolCall.args", toolCallArgs),
|
|
1030
|
+
attrString("error.message", errorMessage)
|
|
1031
|
+
];
|
|
1032
|
+
if (startInfo.liveSpan) {
|
|
1033
|
+
traceShipper.endSpan(startInfo.liveSpan, {
|
|
1034
|
+
attributes: endAttrs,
|
|
1035
|
+
error
|
|
1036
|
+
});
|
|
1037
|
+
} else {
|
|
1038
|
+
const toolSpan = traceShipper.startSpan({
|
|
1039
|
+
name: "ai.toolCall",
|
|
1040
|
+
parent: startInfo.parent,
|
|
1041
|
+
eventId: startInfo.eventId,
|
|
1042
|
+
startTimeUnixNano: startInfo.startTimeUnixNano,
|
|
1043
|
+
attributes: [
|
|
1044
|
+
attrString("ai.operationId", "ai.toolCall"),
|
|
1045
|
+
attrString("ai.toolCall.name", tool),
|
|
1046
|
+
attrString("ai.toolCall.id", callID)
|
|
1047
|
+
]
|
|
1048
|
+
});
|
|
1049
|
+
traceShipper.endSpan(toolSpan, {
|
|
1050
|
+
attributes: endAttrs,
|
|
1051
|
+
error,
|
|
1052
|
+
endTimeUnixNano: nowUnixNanoString()
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
return true;
|
|
1056
|
+
}
|
|
1057
|
+
function unwrapQuotes(s) {
|
|
1058
|
+
if (s.length < 2) return s;
|
|
1059
|
+
const first = s[0];
|
|
1060
|
+
const last = s[s.length - 1];
|
|
1061
|
+
if ((first === '"' || first === "'") && first === last) return s.slice(1, -1);
|
|
1062
|
+
return s;
|
|
1063
|
+
}
|
|
1064
|
+
function buildPromptMessages(systemPrompt, userInput) {
|
|
1065
|
+
const messages = [];
|
|
1066
|
+
if (systemPrompt) messages.push({ role: "system", content: systemPrompt });
|
|
1067
|
+
messages.push({ role: "user", content: unwrapQuotes(userInput) });
|
|
1068
|
+
return JSON.stringify(messages);
|
|
1069
|
+
}
|
|
922
1070
|
function getHostname() {
|
|
923
1071
|
var _a;
|
|
924
1072
|
try {
|
|
@@ -1003,13 +1151,13 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
1003
1151
|
state.outputParts.set(messageId, partObj["text"]);
|
|
1004
1152
|
} else if (partObj["type"] === "tool" && messageId) {
|
|
1005
1153
|
const tool = partObj["tool"];
|
|
1154
|
+
const callID = partObj["callID"];
|
|
1155
|
+
const partState = partObj["state"];
|
|
1156
|
+
if (callID == null || callID === "")
|
|
1157
|
+
throw new Error("message.part.updated: part.callID is required for tool part");
|
|
1158
|
+
if (partState == null || typeof partState !== "object")
|
|
1159
|
+
throw new Error("message.part.updated: part.state is required for tool part");
|
|
1006
1160
|
if (tool === "task") {
|
|
1007
|
-
const callID = partObj["callID"];
|
|
1008
|
-
const partState = partObj["state"];
|
|
1009
|
-
if (callID == null || callID === "")
|
|
1010
|
-
throw new Error("message.part.updated: part.callID is required for tool part");
|
|
1011
|
-
if (partState == null || typeof partState !== "object")
|
|
1012
|
-
throw new Error("message.part.updated: part.state is required for tool part");
|
|
1013
1161
|
const metadata = partState["metadata"];
|
|
1014
1162
|
const childSessionId = metadata != null && typeof metadata === "object" ? metadata["sessionId"] : void 0;
|
|
1015
1163
|
if (childSessionId != null && childSessionId !== "") {
|
|
@@ -1024,6 +1172,24 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
1024
1172
|
);
|
|
1025
1173
|
}
|
|
1026
1174
|
}
|
|
1175
|
+
const toolState = partState;
|
|
1176
|
+
if (toolState["status"] === "error") {
|
|
1177
|
+
const errorMessage = toolState["error"];
|
|
1178
|
+
if (typeof errorMessage !== "string" || errorMessage === "")
|
|
1179
|
+
throw new Error("message.part.updated: error tool state must have error string");
|
|
1180
|
+
const input = toolState["input"];
|
|
1181
|
+
const toolCallArgs = input === void 0 ? void 0 : typeof input === "string" ? input : JSON.stringify(input);
|
|
1182
|
+
if (endPendingToolSpanWithError(
|
|
1183
|
+
state,
|
|
1184
|
+
callID,
|
|
1185
|
+
tool,
|
|
1186
|
+
toolCallArgs,
|
|
1187
|
+
errorMessage,
|
|
1188
|
+
traceShipper
|
|
1189
|
+
) && tool === "task") {
|
|
1190
|
+
markTaskCallFinished(partSessionID, callID);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1027
1193
|
} else if (partObj["type"] === "reasoning" && typeof partObj["text"] === "string") {
|
|
1028
1194
|
state.reasoningParts.set(messageId, partObj["text"]);
|
|
1029
1195
|
}
|
|
@@ -1126,9 +1292,14 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1126
1292
|
const rootSpan = state.currentRootSpan;
|
|
1127
1293
|
const isCompaction = state.isCompacting === true;
|
|
1128
1294
|
if (state.parentId) {
|
|
1295
|
+
const userInput = unwrapQuotes(state.currentInput);
|
|
1129
1296
|
const llmAttrs = [
|
|
1130
1297
|
attrString("ai.operationId", "generateText"),
|
|
1131
|
-
attrString("ai.prompt",
|
|
1298
|
+
attrString("ai.prompt", userInput),
|
|
1299
|
+
attrString(
|
|
1300
|
+
"ai.prompt.messages",
|
|
1301
|
+
buildPromptMessages(state.currentSystemPrompt, state.currentInput)
|
|
1302
|
+
),
|
|
1132
1303
|
attrString("ai.response.text", outputText),
|
|
1133
1304
|
attrString("gen_ai.system", providerID),
|
|
1134
1305
|
attrString("gen_ai.request.model", modelID),
|
|
@@ -1173,9 +1344,14 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1173
1344
|
});
|
|
1174
1345
|
} else {
|
|
1175
1346
|
rootSpan.name = isCompaction ? "ai.compaction" : modelName;
|
|
1347
|
+
const userInput = unwrapQuotes(state.currentInput);
|
|
1176
1348
|
const rootAttrs = [
|
|
1177
1349
|
attrString("ai.operationId", "generateText"),
|
|
1178
|
-
attrString("ai.prompt",
|
|
1350
|
+
attrString("ai.prompt", userInput),
|
|
1351
|
+
attrString(
|
|
1352
|
+
"ai.prompt.messages",
|
|
1353
|
+
buildPromptMessages(state.currentSystemPrompt, state.currentInput)
|
|
1354
|
+
),
|
|
1179
1355
|
attrString("ai.response.text", outputText),
|
|
1180
1356
|
attrString("gen_ai.system", providerID),
|
|
1181
1357
|
attrString("gen_ai.request.model", modelID),
|
|
@@ -1507,11 +1683,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1507
1683
|
}
|
|
1508
1684
|
}
|
|
1509
1685
|
if (tool === "task") {
|
|
1510
|
-
|
|
1511
|
-
if (running) {
|
|
1512
|
-
running.delete(callID);
|
|
1513
|
-
if (running.size === 0) runningTaskCallsBySession.delete(sessionID);
|
|
1514
|
-
}
|
|
1686
|
+
markTaskCallFinished(sessionID, callID);
|
|
1515
1687
|
}
|
|
1516
1688
|
} catch (err) {
|
|
1517
1689
|
console.log(
|
|
@@ -1570,25 +1742,33 @@ async function plugin(input) {
|
|
|
1570
1742
|
console.log(`[raindrop-ai/opencode-plugin] [${level}] ${message}`);
|
|
1571
1743
|
}
|
|
1572
1744
|
appLog("info", `Loading ${PLUGIN_NAME} v${PLUGIN_VERSION}`);
|
|
1573
|
-
|
|
1745
|
+
const resolvedLocalUrl = resolveLocalDebuggerBaseUrl(config.localWorkshopUrl);
|
|
1746
|
+
const hasLocalDestination = resolvedLocalUrl !== null;
|
|
1747
|
+
if (!config.writeKey && !hasLocalDestination) {
|
|
1574
1748
|
appLog(
|
|
1575
1749
|
"warn",
|
|
1576
|
-
"RAINDROP_WRITE_KEY not set \u2014 Raindrop tracing disabled. Set
|
|
1750
|
+
"RAINDROP_WRITE_KEY not set and no local Workshop daemon detected \u2014 Raindrop tracing disabled. Set RAINDROP_WRITE_KEY for cloud, or RAINDROP_LOCAL_WORKSHOP_URL / RAINDROP_LOCAL_DEBUGGER for local-only mode."
|
|
1577
1751
|
);
|
|
1578
1752
|
return {};
|
|
1579
1753
|
}
|
|
1580
1754
|
if (config.debug) {
|
|
1581
|
-
|
|
1755
|
+
const destinations = [
|
|
1756
|
+
config.writeKey ? `cloud (${config.endpoint})` : null,
|
|
1757
|
+
resolvedLocalUrl ? `local Workshop (${resolvedLocalUrl})` : null
|
|
1758
|
+
].filter(Boolean);
|
|
1759
|
+
appLog("info", `Raindrop tracing enabled \u2014 destinations: ${destinations.join(", ")}`);
|
|
1582
1760
|
}
|
|
1583
1761
|
const eventShipper = new EventShipper2({
|
|
1584
1762
|
writeKey: config.writeKey,
|
|
1585
1763
|
endpoint: config.endpoint,
|
|
1586
|
-
debug: config.debug
|
|
1764
|
+
debug: config.debug,
|
|
1765
|
+
localDebuggerUrl: config.localWorkshopUrl
|
|
1587
1766
|
});
|
|
1588
1767
|
const traceShipper = new TraceShipper2({
|
|
1589
1768
|
writeKey: config.writeKey,
|
|
1590
1769
|
endpoint: config.endpoint,
|
|
1591
|
-
debug: config.debug
|
|
1770
|
+
debug: config.debug,
|
|
1771
|
+
localDebuggerUrl: config.localWorkshopUrl
|
|
1592
1772
|
});
|
|
1593
1773
|
const worktree = (_a = input.worktree) != null ? _a : input.directory;
|
|
1594
1774
|
const hooks = createHooks(
|
package/dist/index.js
CHANGED
|
@@ -5,124 +5,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
5
5
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
6
|
});
|
|
7
7
|
|
|
8
|
-
//
|
|
9
|
-
import { existsSync, readFileSync } from "fs";
|
|
10
|
-
import { homedir } from "os";
|
|
11
|
-
import { join } from "path";
|
|
12
|
-
function loadConfig(projectDirectory) {
|
|
13
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
14
|
-
let merged = {};
|
|
15
|
-
const configPaths = [
|
|
16
|
-
join(homedir(), ".config", "opencode", "raindrop.json"),
|
|
17
|
-
join(projectDirectory, ".opencode", "raindrop.json")
|
|
18
|
-
];
|
|
19
|
-
for (const configPath of configPaths) {
|
|
20
|
-
try {
|
|
21
|
-
if (existsSync(configPath)) {
|
|
22
|
-
const content = readFileSync(configPath, "utf-8");
|
|
23
|
-
const parsed = JSON.parse(content);
|
|
24
|
-
merged = { ...merged, ...parsed };
|
|
25
|
-
}
|
|
26
|
-
} catch (e) {
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
let eventMetadata;
|
|
30
|
-
const envMeta = process.env["RAINDROP_EVENT_METADATA"];
|
|
31
|
-
if (envMeta) {
|
|
32
|
-
try {
|
|
33
|
-
eventMetadata = JSON.parse(envMeta);
|
|
34
|
-
} catch (e) {
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return {
|
|
38
|
-
writeKey: (_b = (_a = process.env["RAINDROP_WRITE_KEY"]) != null ? _a : merged.write_key) != null ? _b : "",
|
|
39
|
-
endpoint: (_d = (_c = process.env["RAINDROP_API_URL"]) != null ? _c : merged.api_url) != null ? _d : "https://api.raindrop.ai/v1",
|
|
40
|
-
eventName: (_e = merged.event_name) != null ? _e : "opencode_session",
|
|
41
|
-
debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_f = merged.debug) != null ? _f : false,
|
|
42
|
-
captureSystemPrompt: process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] !== void 0 ? process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] === "true" : (_g = merged.capture_system_prompt) != null ? _g : false,
|
|
43
|
-
eventMetadata
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// package.json
|
|
48
|
-
var package_default = {
|
|
49
|
-
name: "@raindrop-ai/opencode-plugin",
|
|
50
|
-
version: "0.0.10",
|
|
51
|
-
description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
|
|
52
|
-
type: "module",
|
|
53
|
-
main: "dist/index.js",
|
|
54
|
-
module: "dist/index.js",
|
|
55
|
-
types: "dist/index.d.ts",
|
|
56
|
-
license: "MIT",
|
|
57
|
-
repository: {
|
|
58
|
-
type: "git",
|
|
59
|
-
url: "git+https://github.com/raindrop-ai/raindrop-js.git",
|
|
60
|
-
directory: "packages/opencode-plugin"
|
|
61
|
-
},
|
|
62
|
-
homepage: "https://github.com/raindrop-ai/raindrop-js/tree/main/packages/opencode-plugin#readme",
|
|
63
|
-
bugs: {
|
|
64
|
-
url: "https://github.com/raindrop-ai/raindrop-js/issues"
|
|
65
|
-
},
|
|
66
|
-
exports: {
|
|
67
|
-
".": {
|
|
68
|
-
types: "./dist/index.d.ts",
|
|
69
|
-
import: "./dist/index.js",
|
|
70
|
-
require: "./dist/index.cjs"
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
sideEffects: false,
|
|
74
|
-
files: [
|
|
75
|
-
"dist/**"
|
|
76
|
-
],
|
|
77
|
-
scripts: {
|
|
78
|
-
build: "tsup",
|
|
79
|
-
dev: "tsup --watch",
|
|
80
|
-
clean: "rm -rf dist",
|
|
81
|
-
test: "cd tests && pnpm test"
|
|
82
|
-
},
|
|
83
|
-
peerDependencies: {
|
|
84
|
-
"@opencode-ai/plugin": ">=1.3.0",
|
|
85
|
-
"@opencode-ai/sdk": ">=1.3.0"
|
|
86
|
-
},
|
|
87
|
-
peerDependenciesMeta: {
|
|
88
|
-
"@opencode-ai/sdk": {
|
|
89
|
-
optional: true
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
devDependencies: {
|
|
93
|
-
"@raindrop-ai/core": "workspace:*",
|
|
94
|
-
"@opencode-ai/plugin": "^1.3.3",
|
|
95
|
-
"@opencode-ai/sdk": "^1.3.3",
|
|
96
|
-
"@types/node": "^20.11.17",
|
|
97
|
-
tsup: "^8.4.0",
|
|
98
|
-
typescript: "^5.3.3"
|
|
99
|
-
},
|
|
100
|
-
tsup: {
|
|
101
|
-
entry: [
|
|
102
|
-
"src/index.ts"
|
|
103
|
-
],
|
|
104
|
-
format: [
|
|
105
|
-
"cjs",
|
|
106
|
-
"esm"
|
|
107
|
-
],
|
|
108
|
-
dts: {
|
|
109
|
-
resolve: true
|
|
110
|
-
},
|
|
111
|
-
clean: true,
|
|
112
|
-
noExternal: [
|
|
113
|
-
"@raindrop-ai/core"
|
|
114
|
-
]
|
|
115
|
-
},
|
|
116
|
-
publishConfig: {
|
|
117
|
-
access: "public"
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
// src/package-info.ts
|
|
122
|
-
var PLUGIN_NAME = package_default.name;
|
|
123
|
-
var PLUGIN_VERSION = package_default.version;
|
|
124
|
-
|
|
125
|
-
// ../core/dist/chunk-4UCYIEH4.js
|
|
8
|
+
// ../core/dist/chunk-OLYXZCOK.js
|
|
126
9
|
function getCrypto() {
|
|
127
10
|
const c = globalThis.crypto;
|
|
128
11
|
return c;
|
|
@@ -315,6 +198,91 @@ function buildExportTraceServiceRequest(spans, serviceName = "raindrop.core", se
|
|
|
315
198
|
]
|
|
316
199
|
};
|
|
317
200
|
}
|
|
201
|
+
var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
|
|
202
|
+
var WORKSHOP_ENV_VAR = "RAINDROP_WORKSHOP";
|
|
203
|
+
var DEFAULT_LOCAL_WORKSHOP_URL = "http://localhost:5899/v1/";
|
|
204
|
+
function readEnvVar(name) {
|
|
205
|
+
var _a;
|
|
206
|
+
try {
|
|
207
|
+
const env = (_a = globalThis == null ? void 0 : globalThis.process) == null ? void 0 : _a.env;
|
|
208
|
+
if (env && typeof env[name] === "string" && env[name].length > 0) {
|
|
209
|
+
return env[name];
|
|
210
|
+
}
|
|
211
|
+
} catch (e) {
|
|
212
|
+
}
|
|
213
|
+
return void 0;
|
|
214
|
+
}
|
|
215
|
+
function readWorkshopEnv() {
|
|
216
|
+
const raw = readEnvVar(WORKSHOP_ENV_VAR);
|
|
217
|
+
if (raw === void 0) return void 0;
|
|
218
|
+
const trimmed = raw.trim();
|
|
219
|
+
if (trimmed.length === 0) return void 0;
|
|
220
|
+
if (/^https?:\/\//i.test(trimmed)) return { url: trimmed };
|
|
221
|
+
if (/^(1|true|yes|on)$/i.test(trimmed)) return "enable";
|
|
222
|
+
if (/^(0|false|no|off)$/i.test(trimmed)) return "disable";
|
|
223
|
+
return void 0;
|
|
224
|
+
}
|
|
225
|
+
function isLocalDevHost(hostname) {
|
|
226
|
+
if (!hostname) return false;
|
|
227
|
+
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "::1") {
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
if (hostname.endsWith(".localhost")) return true;
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
function readRuntimeHostname() {
|
|
234
|
+
try {
|
|
235
|
+
const loc = globalThis == null ? void 0 : globalThis.location;
|
|
236
|
+
if (loc && typeof loc.hostname === "string" && loc.hostname.length > 0) {
|
|
237
|
+
return loc.hostname;
|
|
238
|
+
}
|
|
239
|
+
} catch (e) {
|
|
240
|
+
}
|
|
241
|
+
return void 0;
|
|
242
|
+
}
|
|
243
|
+
function shouldAutoEnableLocalWorkshop() {
|
|
244
|
+
if (isLocalDevHost(readRuntimeHostname())) return true;
|
|
245
|
+
if (readEnvVar("NODE_ENV") === "development") return true;
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
function resolveLocalDebuggerBaseUrl(baseUrl) {
|
|
249
|
+
var _a, _b, _c;
|
|
250
|
+
if (baseUrl === null) return null;
|
|
251
|
+
if (typeof baseUrl === "string" && baseUrl.length > 0) {
|
|
252
|
+
return (_a = formatEndpoint(baseUrl)) != null ? _a : null;
|
|
253
|
+
}
|
|
254
|
+
const explicitUrlEnv = readEnvVar(LOCAL_DEBUGGER_ENV_VAR);
|
|
255
|
+
if (explicitUrlEnv) return (_b = formatEndpoint(explicitUrlEnv)) != null ? _b : null;
|
|
256
|
+
const workshopEnv = readWorkshopEnv();
|
|
257
|
+
if (workshopEnv === "disable") return null;
|
|
258
|
+
if (workshopEnv === "enable") return DEFAULT_LOCAL_WORKSHOP_URL;
|
|
259
|
+
if (workshopEnv && "url" in workshopEnv) return (_c = formatEndpoint(workshopEnv.url)) != null ? _c : null;
|
|
260
|
+
if (shouldAutoEnableLocalWorkshop()) return DEFAULT_LOCAL_WORKSHOP_URL;
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
function mirrorTraceExportToLocalDebugger(body, options = {}) {
|
|
264
|
+
var _a;
|
|
265
|
+
const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
|
|
266
|
+
if (!baseUrl) return;
|
|
267
|
+
void postJson(`${baseUrl}traces`, body, {}, {
|
|
268
|
+
maxAttempts: 1,
|
|
269
|
+
debug: (_a = options.debug) != null ? _a : false,
|
|
270
|
+
sdkName: options.sdkName
|
|
271
|
+
}).catch(() => {
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
function mirrorPartialEventToLocalDebugger(event, options = {}) {
|
|
275
|
+
var _a;
|
|
276
|
+
const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
|
|
277
|
+
if (!baseUrl) return;
|
|
278
|
+
const headers = options.writeKey ? { Authorization: `Bearer ${options.writeKey}` } : {};
|
|
279
|
+
void postJson(`${baseUrl}events/track_partial`, event, headers, {
|
|
280
|
+
maxAttempts: 1,
|
|
281
|
+
debug: (_a = options.debug) != null ? _a : false,
|
|
282
|
+
sdkName: options.sdkName
|
|
283
|
+
}).catch(() => {
|
|
284
|
+
});
|
|
285
|
+
}
|
|
318
286
|
function mergePatches(target, source) {
|
|
319
287
|
var _a, _b, _c, _d;
|
|
320
288
|
const out = { ...target, ...source };
|
|
@@ -332,7 +300,7 @@ var EventShipper = class {
|
|
|
332
300
|
this.sticky = /* @__PURE__ */ new Map();
|
|
333
301
|
this.timers = /* @__PURE__ */ new Map();
|
|
334
302
|
this.inFlight = /* @__PURE__ */ new Set();
|
|
335
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
303
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
336
304
|
this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
|
|
337
305
|
this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
|
|
338
306
|
this.enabled = opts.enabled !== false;
|
|
@@ -341,11 +309,15 @@ var EventShipper = class {
|
|
|
341
309
|
this.sdkName = (_d = opts.sdkName) != null ? _d : "core";
|
|
342
310
|
this.prefix = `[raindrop-ai/${this.sdkName}]`;
|
|
343
311
|
this.defaultEventName = (_e = opts.defaultEventName) != null ? _e : "ai_generation";
|
|
312
|
+
this.localDebuggerUrl = (_f = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _f : void 0;
|
|
313
|
+
if (this.debug && this.localDebuggerUrl) {
|
|
314
|
+
console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
|
|
315
|
+
}
|
|
344
316
|
const isNode = typeof process !== "undefined" && typeof process.version === "string";
|
|
345
317
|
this.context = {
|
|
346
318
|
library: {
|
|
347
|
-
name: (
|
|
348
|
-
version: (
|
|
319
|
+
name: (_g = opts.libraryName) != null ? _g : "@raindrop-ai/core",
|
|
320
|
+
version: (_h = opts.libraryVersion) != null ? _h : "0.0.0"
|
|
349
321
|
},
|
|
350
322
|
metadata: {
|
|
351
323
|
jsRuntime: isNode ? "node" : "web",
|
|
@@ -431,6 +403,7 @@ var EventShipper = class {
|
|
|
431
403
|
}
|
|
432
404
|
}
|
|
433
405
|
];
|
|
406
|
+
if (!this.writeKey) return;
|
|
434
407
|
const url = `${this.baseUrl}signals/track`;
|
|
435
408
|
try {
|
|
436
409
|
await postJson(url, body, this.authHeaders(), {
|
|
@@ -461,6 +434,7 @@ var EventShipper = class {
|
|
|
461
434
|
traits: (_a = user.traits) != null ? _a : {}
|
|
462
435
|
};
|
|
463
436
|
});
|
|
437
|
+
if (!this.writeKey) return;
|
|
464
438
|
if (body.length === 0) return;
|
|
465
439
|
const url = `${this.baseUrl}users/identify`;
|
|
466
440
|
try {
|
|
@@ -537,6 +511,18 @@ var EventShipper = class {
|
|
|
537
511
|
endpoint: url
|
|
538
512
|
});
|
|
539
513
|
}
|
|
514
|
+
if (this.localDebuggerUrl) {
|
|
515
|
+
mirrorPartialEventToLocalDebugger(payload, {
|
|
516
|
+
baseUrl: this.localDebuggerUrl,
|
|
517
|
+
writeKey: this.writeKey,
|
|
518
|
+
debug: this.debug,
|
|
519
|
+
sdkName: this.sdkName
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
if (!this.writeKey) {
|
|
523
|
+
if (!isPending) this.sticky.delete(eventId);
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
540
526
|
const p = postJson(url, payload, this.authHeaders(), {
|
|
541
527
|
maxAttempts: 3,
|
|
542
528
|
debug: this.debug,
|
|
@@ -561,28 +547,11 @@ var EventShipper = class {
|
|
|
561
547
|
}
|
|
562
548
|
}
|
|
563
549
|
};
|
|
564
|
-
var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
|
|
565
|
-
function resolveLocalDebuggerBaseUrl(baseUrl) {
|
|
566
|
-
var _a, _b, _c;
|
|
567
|
-
const resolved = (_b = baseUrl != null ? baseUrl : typeof process !== "undefined" ? (_a = process.env) == null ? void 0 : _a[LOCAL_DEBUGGER_ENV_VAR] : void 0) != null ? _b : null;
|
|
568
|
-
return resolved ? (_c = formatEndpoint(resolved)) != null ? _c : null : null;
|
|
569
|
-
}
|
|
570
|
-
function mirrorTraceExportToLocalDebugger(body, options = {}) {
|
|
571
|
-
var _a;
|
|
572
|
-
const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
|
|
573
|
-
if (!baseUrl) return;
|
|
574
|
-
void postJson(`${baseUrl}traces`, body, {}, {
|
|
575
|
-
maxAttempts: 1,
|
|
576
|
-
debug: (_a = options.debug) != null ? _a : false,
|
|
577
|
-
sdkName: options.sdkName
|
|
578
|
-
}).catch(() => {
|
|
579
|
-
});
|
|
580
|
-
}
|
|
581
550
|
var TraceShipper = class {
|
|
582
551
|
constructor(opts) {
|
|
583
552
|
this.queue = [];
|
|
584
553
|
this.inFlight = /* @__PURE__ */ new Set();
|
|
585
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i
|
|
554
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
586
555
|
this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
|
|
587
556
|
this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
|
|
588
557
|
this.enabled = opts.enabled !== false;
|
|
@@ -595,12 +564,9 @@ var TraceShipper = class {
|
|
|
595
564
|
this.prefix = `[raindrop-ai/${this.sdkName}]`;
|
|
596
565
|
this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
|
|
597
566
|
this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
|
|
598
|
-
|
|
599
|
-
if (
|
|
600
|
-
this.
|
|
601
|
-
if (this.debug) {
|
|
602
|
-
console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
|
|
603
|
-
}
|
|
567
|
+
this.localDebuggerUrl = (_i = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _i : void 0;
|
|
568
|
+
if (this.debug && this.localDebuggerUrl) {
|
|
569
|
+
console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
|
|
604
570
|
}
|
|
605
571
|
}
|
|
606
572
|
isDebugEnabled() {
|
|
@@ -728,6 +694,7 @@ var TraceShipper = class {
|
|
|
728
694
|
}
|
|
729
695
|
while (this.queue.length > 0) {
|
|
730
696
|
const batch = this.queue.splice(0, this.maxBatchSize);
|
|
697
|
+
if (!this.writeKey) continue;
|
|
731
698
|
const body = buildExportTraceServiceRequest(batch, this.serviceName, this.serviceVersion);
|
|
732
699
|
const url = `${this.baseUrl}traces`;
|
|
733
700
|
if (this.debug) {
|
|
@@ -770,6 +737,134 @@ var TraceShipper = class {
|
|
|
770
737
|
import { AsyncLocalStorage } from "async_hooks";
|
|
771
738
|
globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = AsyncLocalStorage;
|
|
772
739
|
|
|
740
|
+
// src/config.ts
|
|
741
|
+
import { existsSync, readFileSync } from "fs";
|
|
742
|
+
import { homedir } from "os";
|
|
743
|
+
import { join } from "path";
|
|
744
|
+
function loadConfig(projectDirectory) {
|
|
745
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
746
|
+
let merged = {};
|
|
747
|
+
const configPaths = [
|
|
748
|
+
join(homedir(), ".config", "opencode", "raindrop.json"),
|
|
749
|
+
join(projectDirectory, ".opencode", "raindrop.json")
|
|
750
|
+
];
|
|
751
|
+
for (const configPath of configPaths) {
|
|
752
|
+
try {
|
|
753
|
+
if (existsSync(configPath)) {
|
|
754
|
+
const content = readFileSync(configPath, "utf-8");
|
|
755
|
+
const parsed = JSON.parse(content);
|
|
756
|
+
merged = { ...merged, ...parsed };
|
|
757
|
+
}
|
|
758
|
+
} catch (e) {
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
let eventMetadata;
|
|
762
|
+
const envMeta = process.env["RAINDROP_EVENT_METADATA"];
|
|
763
|
+
if (envMeta) {
|
|
764
|
+
try {
|
|
765
|
+
eventMetadata = JSON.parse(envMeta);
|
|
766
|
+
} catch (e) {
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
return {
|
|
770
|
+
writeKey: (_b = (_a = process.env["RAINDROP_WRITE_KEY"]) != null ? _a : merged.write_key) != null ? _b : "",
|
|
771
|
+
endpoint: (_d = (_c = process.env["RAINDROP_API_URL"]) != null ? _c : merged.api_url) != null ? _d : "https://api.raindrop.ai/v1",
|
|
772
|
+
eventName: (_e = merged.event_name) != null ? _e : "opencode_session",
|
|
773
|
+
debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_f = merged.debug) != null ? _f : false,
|
|
774
|
+
captureSystemPrompt: process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] !== void 0 ? process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] === "true" : (_g = merged.capture_system_prompt) != null ? _g : false,
|
|
775
|
+
eventMetadata,
|
|
776
|
+
localWorkshopUrl: resolveLocalWorkshopUrl(merged.local_workshop_url)
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
function resolveLocalWorkshopUrl(fileValue) {
|
|
780
|
+
const envValue = process.env["RAINDROP_LOCAL_WORKSHOP_URL"];
|
|
781
|
+
if (envValue !== void 0) {
|
|
782
|
+
if (envValue === "" || envValue.toLowerCase() === "null" || envValue.toLowerCase() === "false") {
|
|
783
|
+
return null;
|
|
784
|
+
}
|
|
785
|
+
return envValue;
|
|
786
|
+
}
|
|
787
|
+
return fileValue;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// package.json
|
|
791
|
+
var package_default = {
|
|
792
|
+
name: "@raindrop-ai/opencode-plugin",
|
|
793
|
+
version: "0.0.12",
|
|
794
|
+
description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
|
|
795
|
+
type: "module",
|
|
796
|
+
main: "dist/index.js",
|
|
797
|
+
module: "dist/index.js",
|
|
798
|
+
types: "dist/index.d.ts",
|
|
799
|
+
license: "MIT",
|
|
800
|
+
repository: {
|
|
801
|
+
type: "git",
|
|
802
|
+
url: "git+https://github.com/raindrop-ai/raindrop-js.git",
|
|
803
|
+
directory: "packages/opencode-plugin"
|
|
804
|
+
},
|
|
805
|
+
homepage: "https://github.com/raindrop-ai/raindrop-js/tree/main/packages/opencode-plugin#readme",
|
|
806
|
+
bugs: {
|
|
807
|
+
url: "https://github.com/raindrop-ai/raindrop-js/issues"
|
|
808
|
+
},
|
|
809
|
+
exports: {
|
|
810
|
+
".": {
|
|
811
|
+
types: "./dist/index.d.ts",
|
|
812
|
+
import: "./dist/index.js",
|
|
813
|
+
require: "./dist/index.cjs"
|
|
814
|
+
}
|
|
815
|
+
},
|
|
816
|
+
sideEffects: false,
|
|
817
|
+
files: [
|
|
818
|
+
"dist/**"
|
|
819
|
+
],
|
|
820
|
+
scripts: {
|
|
821
|
+
build: "tsup",
|
|
822
|
+
dev: "tsup --watch",
|
|
823
|
+
clean: "rm -rf dist",
|
|
824
|
+
test: "cd tests && pnpm test"
|
|
825
|
+
},
|
|
826
|
+
peerDependencies: {
|
|
827
|
+
"@opencode-ai/plugin": ">=1.3.0",
|
|
828
|
+
"@opencode-ai/sdk": ">=1.3.0"
|
|
829
|
+
},
|
|
830
|
+
peerDependenciesMeta: {
|
|
831
|
+
"@opencode-ai/sdk": {
|
|
832
|
+
optional: true
|
|
833
|
+
}
|
|
834
|
+
},
|
|
835
|
+
devDependencies: {
|
|
836
|
+
"@raindrop-ai/core": "workspace:*",
|
|
837
|
+
"@opencode-ai/plugin": "^1.3.3",
|
|
838
|
+
"@opencode-ai/sdk": "^1.3.3",
|
|
839
|
+
"@types/node": "^20.11.17",
|
|
840
|
+
tsup: "^8.4.0",
|
|
841
|
+
typescript: "^5.3.3"
|
|
842
|
+
},
|
|
843
|
+
tsup: {
|
|
844
|
+
entry: [
|
|
845
|
+
"src/index.ts"
|
|
846
|
+
],
|
|
847
|
+
format: [
|
|
848
|
+
"cjs",
|
|
849
|
+
"esm"
|
|
850
|
+
],
|
|
851
|
+
dts: {
|
|
852
|
+
resolve: true
|
|
853
|
+
},
|
|
854
|
+
clean: true,
|
|
855
|
+
noExternal: [
|
|
856
|
+
"@raindrop-ai/core"
|
|
857
|
+
]
|
|
858
|
+
},
|
|
859
|
+
publishConfig: {
|
|
860
|
+
access: "public"
|
|
861
|
+
}
|
|
862
|
+
};
|
|
863
|
+
|
|
864
|
+
// src/package-info.ts
|
|
865
|
+
var PLUGIN_NAME = package_default.name;
|
|
866
|
+
var PLUGIN_VERSION = package_default.version;
|
|
867
|
+
|
|
773
868
|
// src/shipper.ts
|
|
774
869
|
var EventShipper2 = class extends EventShipper {
|
|
775
870
|
constructor(opts) {
|
|
@@ -900,6 +995,59 @@ function createSessionState(sessionId) {
|
|
|
900
995
|
function callKey(sessionId, callId) {
|
|
901
996
|
return `${sessionId}:${callId}`;
|
|
902
997
|
}
|
|
998
|
+
function markTaskCallFinished(sessionID, callID) {
|
|
999
|
+
const running = runningTaskCallsBySession.get(sessionID);
|
|
1000
|
+
if (!running) return;
|
|
1001
|
+
running.delete(callID);
|
|
1002
|
+
if (running.size === 0) runningTaskCallsBySession.delete(sessionID);
|
|
1003
|
+
}
|
|
1004
|
+
function endPendingToolSpanWithError(state, callID, tool, toolCallArgs, errorMessage, traceShipper) {
|
|
1005
|
+
const startInfo = state.toolSpanStarts.get(callID);
|
|
1006
|
+
if (!startInfo) return false;
|
|
1007
|
+
state.toolSpanStarts.delete(callID);
|
|
1008
|
+
const error = new Error(errorMessage);
|
|
1009
|
+
const endAttrs = [
|
|
1010
|
+
attrString("ai.toolCall.args", toolCallArgs),
|
|
1011
|
+
attrString("error.message", errorMessage)
|
|
1012
|
+
];
|
|
1013
|
+
if (startInfo.liveSpan) {
|
|
1014
|
+
traceShipper.endSpan(startInfo.liveSpan, {
|
|
1015
|
+
attributes: endAttrs,
|
|
1016
|
+
error
|
|
1017
|
+
});
|
|
1018
|
+
} else {
|
|
1019
|
+
const toolSpan = traceShipper.startSpan({
|
|
1020
|
+
name: "ai.toolCall",
|
|
1021
|
+
parent: startInfo.parent,
|
|
1022
|
+
eventId: startInfo.eventId,
|
|
1023
|
+
startTimeUnixNano: startInfo.startTimeUnixNano,
|
|
1024
|
+
attributes: [
|
|
1025
|
+
attrString("ai.operationId", "ai.toolCall"),
|
|
1026
|
+
attrString("ai.toolCall.name", tool),
|
|
1027
|
+
attrString("ai.toolCall.id", callID)
|
|
1028
|
+
]
|
|
1029
|
+
});
|
|
1030
|
+
traceShipper.endSpan(toolSpan, {
|
|
1031
|
+
attributes: endAttrs,
|
|
1032
|
+
error,
|
|
1033
|
+
endTimeUnixNano: nowUnixNanoString()
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
return true;
|
|
1037
|
+
}
|
|
1038
|
+
function unwrapQuotes(s) {
|
|
1039
|
+
if (s.length < 2) return s;
|
|
1040
|
+
const first = s[0];
|
|
1041
|
+
const last = s[s.length - 1];
|
|
1042
|
+
if ((first === '"' || first === "'") && first === last) return s.slice(1, -1);
|
|
1043
|
+
return s;
|
|
1044
|
+
}
|
|
1045
|
+
function buildPromptMessages(systemPrompt, userInput) {
|
|
1046
|
+
const messages = [];
|
|
1047
|
+
if (systemPrompt) messages.push({ role: "system", content: systemPrompt });
|
|
1048
|
+
messages.push({ role: "user", content: unwrapQuotes(userInput) });
|
|
1049
|
+
return JSON.stringify(messages);
|
|
1050
|
+
}
|
|
903
1051
|
function getHostname() {
|
|
904
1052
|
var _a;
|
|
905
1053
|
try {
|
|
@@ -984,13 +1132,13 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
984
1132
|
state.outputParts.set(messageId, partObj["text"]);
|
|
985
1133
|
} else if (partObj["type"] === "tool" && messageId) {
|
|
986
1134
|
const tool = partObj["tool"];
|
|
1135
|
+
const callID = partObj["callID"];
|
|
1136
|
+
const partState = partObj["state"];
|
|
1137
|
+
if (callID == null || callID === "")
|
|
1138
|
+
throw new Error("message.part.updated: part.callID is required for tool part");
|
|
1139
|
+
if (partState == null || typeof partState !== "object")
|
|
1140
|
+
throw new Error("message.part.updated: part.state is required for tool part");
|
|
987
1141
|
if (tool === "task") {
|
|
988
|
-
const callID = partObj["callID"];
|
|
989
|
-
const partState = partObj["state"];
|
|
990
|
-
if (callID == null || callID === "")
|
|
991
|
-
throw new Error("message.part.updated: part.callID is required for tool part");
|
|
992
|
-
if (partState == null || typeof partState !== "object")
|
|
993
|
-
throw new Error("message.part.updated: part.state is required for tool part");
|
|
994
1142
|
const metadata = partState["metadata"];
|
|
995
1143
|
const childSessionId = metadata != null && typeof metadata === "object" ? metadata["sessionId"] : void 0;
|
|
996
1144
|
if (childSessionId != null && childSessionId !== "") {
|
|
@@ -1005,6 +1153,24 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
1005
1153
|
);
|
|
1006
1154
|
}
|
|
1007
1155
|
}
|
|
1156
|
+
const toolState = partState;
|
|
1157
|
+
if (toolState["status"] === "error") {
|
|
1158
|
+
const errorMessage = toolState["error"];
|
|
1159
|
+
if (typeof errorMessage !== "string" || errorMessage === "")
|
|
1160
|
+
throw new Error("message.part.updated: error tool state must have error string");
|
|
1161
|
+
const input = toolState["input"];
|
|
1162
|
+
const toolCallArgs = input === void 0 ? void 0 : typeof input === "string" ? input : JSON.stringify(input);
|
|
1163
|
+
if (endPendingToolSpanWithError(
|
|
1164
|
+
state,
|
|
1165
|
+
callID,
|
|
1166
|
+
tool,
|
|
1167
|
+
toolCallArgs,
|
|
1168
|
+
errorMessage,
|
|
1169
|
+
traceShipper
|
|
1170
|
+
) && tool === "task") {
|
|
1171
|
+
markTaskCallFinished(partSessionID, callID);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1008
1174
|
} else if (partObj["type"] === "reasoning" && typeof partObj["text"] === "string") {
|
|
1009
1175
|
state.reasoningParts.set(messageId, partObj["text"]);
|
|
1010
1176
|
}
|
|
@@ -1107,9 +1273,14 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1107
1273
|
const rootSpan = state.currentRootSpan;
|
|
1108
1274
|
const isCompaction = state.isCompacting === true;
|
|
1109
1275
|
if (state.parentId) {
|
|
1276
|
+
const userInput = unwrapQuotes(state.currentInput);
|
|
1110
1277
|
const llmAttrs = [
|
|
1111
1278
|
attrString("ai.operationId", "generateText"),
|
|
1112
|
-
attrString("ai.prompt",
|
|
1279
|
+
attrString("ai.prompt", userInput),
|
|
1280
|
+
attrString(
|
|
1281
|
+
"ai.prompt.messages",
|
|
1282
|
+
buildPromptMessages(state.currentSystemPrompt, state.currentInput)
|
|
1283
|
+
),
|
|
1113
1284
|
attrString("ai.response.text", outputText),
|
|
1114
1285
|
attrString("gen_ai.system", providerID),
|
|
1115
1286
|
attrString("gen_ai.request.model", modelID),
|
|
@@ -1154,9 +1325,14 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1154
1325
|
});
|
|
1155
1326
|
} else {
|
|
1156
1327
|
rootSpan.name = isCompaction ? "ai.compaction" : modelName;
|
|
1328
|
+
const userInput = unwrapQuotes(state.currentInput);
|
|
1157
1329
|
const rootAttrs = [
|
|
1158
1330
|
attrString("ai.operationId", "generateText"),
|
|
1159
|
-
attrString("ai.prompt",
|
|
1331
|
+
attrString("ai.prompt", userInput),
|
|
1332
|
+
attrString(
|
|
1333
|
+
"ai.prompt.messages",
|
|
1334
|
+
buildPromptMessages(state.currentSystemPrompt, state.currentInput)
|
|
1335
|
+
),
|
|
1160
1336
|
attrString("ai.response.text", outputText),
|
|
1161
1337
|
attrString("gen_ai.system", providerID),
|
|
1162
1338
|
attrString("gen_ai.request.model", modelID),
|
|
@@ -1488,11 +1664,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1488
1664
|
}
|
|
1489
1665
|
}
|
|
1490
1666
|
if (tool === "task") {
|
|
1491
|
-
|
|
1492
|
-
if (running) {
|
|
1493
|
-
running.delete(callID);
|
|
1494
|
-
if (running.size === 0) runningTaskCallsBySession.delete(sessionID);
|
|
1495
|
-
}
|
|
1667
|
+
markTaskCallFinished(sessionID, callID);
|
|
1496
1668
|
}
|
|
1497
1669
|
} catch (err) {
|
|
1498
1670
|
console.log(
|
|
@@ -1551,25 +1723,33 @@ async function plugin(input) {
|
|
|
1551
1723
|
console.log(`[raindrop-ai/opencode-plugin] [${level}] ${message}`);
|
|
1552
1724
|
}
|
|
1553
1725
|
appLog("info", `Loading ${PLUGIN_NAME} v${PLUGIN_VERSION}`);
|
|
1554
|
-
|
|
1726
|
+
const resolvedLocalUrl = resolveLocalDebuggerBaseUrl(config.localWorkshopUrl);
|
|
1727
|
+
const hasLocalDestination = resolvedLocalUrl !== null;
|
|
1728
|
+
if (!config.writeKey && !hasLocalDestination) {
|
|
1555
1729
|
appLog(
|
|
1556
1730
|
"warn",
|
|
1557
|
-
"RAINDROP_WRITE_KEY not set \u2014 Raindrop tracing disabled. Set
|
|
1731
|
+
"RAINDROP_WRITE_KEY not set and no local Workshop daemon detected \u2014 Raindrop tracing disabled. Set RAINDROP_WRITE_KEY for cloud, or RAINDROP_LOCAL_WORKSHOP_URL / RAINDROP_LOCAL_DEBUGGER for local-only mode."
|
|
1558
1732
|
);
|
|
1559
1733
|
return {};
|
|
1560
1734
|
}
|
|
1561
1735
|
if (config.debug) {
|
|
1562
|
-
|
|
1736
|
+
const destinations = [
|
|
1737
|
+
config.writeKey ? `cloud (${config.endpoint})` : null,
|
|
1738
|
+
resolvedLocalUrl ? `local Workshop (${resolvedLocalUrl})` : null
|
|
1739
|
+
].filter(Boolean);
|
|
1740
|
+
appLog("info", `Raindrop tracing enabled \u2014 destinations: ${destinations.join(", ")}`);
|
|
1563
1741
|
}
|
|
1564
1742
|
const eventShipper = new EventShipper2({
|
|
1565
1743
|
writeKey: config.writeKey,
|
|
1566
1744
|
endpoint: config.endpoint,
|
|
1567
|
-
debug: config.debug
|
|
1745
|
+
debug: config.debug,
|
|
1746
|
+
localDebuggerUrl: config.localWorkshopUrl
|
|
1568
1747
|
});
|
|
1569
1748
|
const traceShipper = new TraceShipper2({
|
|
1570
1749
|
writeKey: config.writeKey,
|
|
1571
1750
|
endpoint: config.endpoint,
|
|
1572
|
-
debug: config.debug
|
|
1751
|
+
debug: config.debug,
|
|
1752
|
+
localDebuggerUrl: config.localWorkshopUrl
|
|
1573
1753
|
});
|
|
1574
1754
|
const worktree = (_a = input.worktree) != null ? _a : input.directory;
|
|
1575
1755
|
const hooks = createHooks(
|