@raindrop-ai/opencode-plugin 0.0.5 → 0.0.7

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.
Files changed (3) hide show
  1. package/dist/index.cjs +164 -96
  2. package/dist/index.js +164 -96
  3. package/package.json +7 -7
package/dist/index.cjs CHANGED
@@ -29,7 +29,7 @@ var import_node_fs = require("fs");
29
29
  var import_node_os = require("os");
30
30
  var import_node_path = require("path");
31
31
  function loadConfig(projectDirectory) {
32
- var _a, _b, _c, _d, _e, _f;
32
+ var _a, _b, _c, _d, _e, _f, _g;
33
33
  let merged = {};
34
34
  const configPaths = [
35
35
  (0, import_node_path.join)((0, import_node_os.homedir)(), ".config", "opencode", "raindrop.json"),
@@ -45,15 +45,93 @@ function loadConfig(projectDirectory) {
45
45
  } catch (e) {
46
46
  }
47
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
+ }
48
56
  return {
49
57
  writeKey: (_b = (_a = process.env["RAINDROP_WRITE_KEY"]) != null ? _a : merged.write_key) != null ? _b : "",
50
58
  endpoint: (_d = (_c = process.env["RAINDROP_API_URL"]) != null ? _c : merged.api_url) != null ? _d : "https://api.raindrop.ai/v1",
51
59
  eventName: (_e = merged.event_name) != null ? _e : "opencode_session",
52
- debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_f = merged.debug) != null ? _f : false
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
53
63
  };
54
64
  }
55
65
 
56
- // ../core/dist/chunk-FTBZHS25.js
66
+ // package.json
67
+ var package_default = {
68
+ name: "@raindrop-ai/opencode-plugin",
69
+ version: "0.0.7",
70
+ description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
71
+ type: "module",
72
+ main: "dist/index.cjs",
73
+ module: "dist/index.js",
74
+ types: "dist/index.d.ts",
75
+ exports: {
76
+ ".": {
77
+ types: "./dist/index.d.ts",
78
+ import: "./dist/index.js",
79
+ require: "./dist/index.cjs"
80
+ }
81
+ },
82
+ sideEffects: false,
83
+ files: [
84
+ "dist/**"
85
+ ],
86
+ scripts: {
87
+ build: "tsup",
88
+ dev: "tsup --watch",
89
+ clean: "rm -rf dist",
90
+ test: "cd tests && pnpm test"
91
+ },
92
+ peerDependencies: {
93
+ "@opencode-ai/plugin": ">=1.3.0",
94
+ "@opencode-ai/sdk": ">=1.3.0"
95
+ },
96
+ peerDependenciesMeta: {
97
+ "@opencode-ai/sdk": {
98
+ optional: true
99
+ }
100
+ },
101
+ devDependencies: {
102
+ "@raindrop-ai/core": "workspace:*",
103
+ "@opencode-ai/plugin": "^1.3.3",
104
+ "@opencode-ai/sdk": "^1.3.3",
105
+ "@types/node": "^20.11.17",
106
+ tsup: "^8.4.0",
107
+ typescript: "^5.3.3"
108
+ },
109
+ tsup: {
110
+ entry: [
111
+ "src/index.ts"
112
+ ],
113
+ format: [
114
+ "cjs",
115
+ "esm"
116
+ ],
117
+ dts: {
118
+ resolve: true
119
+ },
120
+ clean: true,
121
+ noExternal: [
122
+ "@raindrop-ai/core"
123
+ ]
124
+ },
125
+ publishConfig: {
126
+ access: "public"
127
+ }
128
+ };
129
+
130
+ // src/package-info.ts
131
+ var PLUGIN_NAME = package_default.name;
132
+ var PLUGIN_VERSION = package_default.version;
133
+
134
+ // ../core/dist/chunk-H6VSZSLN.js
57
135
  function getCrypto() {
58
136
  const c = globalThis.crypto;
59
137
  return c;
@@ -298,6 +376,7 @@ var EventShipper = class {
298
376
  console.log(`${this.prefix} queue patch`, {
299
377
  eventId,
300
378
  userId: patch.userId,
379
+ convoId: patch.convoId,
301
380
  eventName: patch.eventName,
302
381
  hasInput: typeof patch.input === "string" && patch.input.length > 0,
303
382
  hasOutput: typeof patch.output === "string" && patch.output.length > 0,
@@ -426,16 +505,18 @@ var EventShipper = class {
426
505
  return;
427
506
  }
428
507
  const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
508
+ const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
509
+ const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
429
510
  const payload = {
430
511
  event_id: eventId,
431
512
  user_id: userId,
432
513
  event: eventName,
433
- timestamp: (_f = accumulated.timestamp) != null ? _f : (/* @__PURE__ */ new Date()).toISOString(),
514
+ timestamp: (_i = accumulated.timestamp) != null ? _i : (/* @__PURE__ */ new Date()).toISOString(),
434
515
  ai_data: {
435
516
  input: accumulated.input,
436
517
  output: accumulated.output,
437
518
  model: accumulated.model,
438
- convo_id: (_g = accumulated.convoId) != null ? _g : sticky.convoId
519
+ convo_id: convoId
439
520
  },
440
521
  properties: {
441
522
  ...restProperties,
@@ -443,7 +524,7 @@ var EventShipper = class {
443
524
  $context: this.context
444
525
  },
445
526
  attachments: accumulated.attachments,
446
- is_pending: ((_i = (_h = accumulated.isPending) != null ? _h : sticky.isPending) != null ? _i : true) !== false
527
+ is_pending: isPending
447
528
  };
448
529
  const url = `${this.baseUrl}events/track_partial`;
449
530
  if (this.debug) {
@@ -451,7 +532,8 @@ var EventShipper = class {
451
532
  eventId,
452
533
  eventName,
453
534
  userId,
454
- isPending: payload.is_pending,
535
+ convoId,
536
+ isPending,
455
537
  inputPreview: typeof accumulated.input === "string" ? accumulated.input.slice(0, 120) : void 0,
456
538
  outputPreview: typeof accumulated.output === "string" ? accumulated.output.slice(0, 120) : void 0,
457
539
  attachments: (_k = (_j = accumulated.attachments) == null ? void 0 : _j.length) != null ? _k : 0,
@@ -483,7 +565,6 @@ var EventShipper = class {
483
565
  } finally {
484
566
  this.inFlight.delete(p);
485
567
  }
486
- const isPending = payload.is_pending;
487
568
  if (!isPending) {
488
569
  this.sticky.delete(eventId);
489
570
  }
@@ -636,69 +717,9 @@ var TraceShipper = class {
636
717
  }
637
718
  };
638
719
 
639
- // package.json
640
- var package_default = {
641
- name: "@raindrop-ai/opencode-plugin",
642
- version: "0.0.5",
643
- description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
644
- type: "module",
645
- main: "dist/index.cjs",
646
- module: "dist/index.js",
647
- types: "dist/index.d.ts",
648
- exports: {
649
- ".": {
650
- types: "./dist/index.d.ts",
651
- import: "./dist/index.js",
652
- require: "./dist/index.cjs"
653
- }
654
- },
655
- sideEffects: false,
656
- files: [
657
- "dist/**"
658
- ],
659
- scripts: {
660
- build: "tsup",
661
- dev: "tsup --watch",
662
- clean: "rm -rf dist",
663
- test: "cd tests && yarn test"
664
- },
665
- peerDependencies: {
666
- "@opencode-ai/plugin": ">=1.2.0",
667
- "@opencode-ai/sdk": ">=1.2.0"
668
- },
669
- peerDependenciesMeta: {
670
- "@opencode-ai/sdk": {
671
- optional: true
672
- }
673
- },
674
- devDependencies: {
675
- "@raindrop-ai/core": "*",
676
- "@opencode-ai/plugin": "^1.2.0",
677
- "@opencode-ai/sdk": "^1.2.0",
678
- "@types/node": "^20.11.17",
679
- tsup: "^8.4.0",
680
- typescript: "^5.3.3"
681
- },
682
- tsup: {
683
- entry: [
684
- "src/index.ts"
685
- ],
686
- format: [
687
- "cjs",
688
- "esm"
689
- ],
690
- dts: {
691
- resolve: true
692
- },
693
- clean: true,
694
- noExternal: [
695
- "@raindrop-ai/core"
696
- ]
697
- },
698
- publishConfig: {
699
- access: "public"
700
- }
701
- };
720
+ // ../core/dist/index.node.js
721
+ var import_async_hooks = require("async_hooks");
722
+ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = import_async_hooks.AsyncLocalStorage;
702
723
 
703
724
  // src/shipper.ts
704
725
  var EventShipper2 = class extends EventShipper {
@@ -707,8 +728,8 @@ var EventShipper2 = class extends EventShipper {
707
728
  super({
708
729
  ...opts,
709
730
  sdkName: (_a = opts.sdkName) != null ? _a : "opencode-plugin",
710
- libraryName: (_b = opts.libraryName) != null ? _b : package_default.name,
711
- libraryVersion: (_c = opts.libraryVersion) != null ? _c : package_default.version,
731
+ libraryName: (_b = opts.libraryName) != null ? _b : PLUGIN_NAME,
732
+ libraryVersion: (_c = opts.libraryVersion) != null ? _c : PLUGIN_VERSION,
712
733
  defaultEventName: (_d = opts.defaultEventName) != null ? _d : "opencode_session"
713
734
  });
714
735
  }
@@ -720,7 +741,7 @@ var TraceShipper2 = class extends TraceShipper {
720
741
  ...opts,
721
742
  sdkName: (_a = opts.sdkName) != null ? _a : "opencode-plugin",
722
743
  serviceName: (_b = opts.serviceName) != null ? _b : "raindrop.opencode-plugin",
723
- serviceVersion: (_c = opts.serviceVersion) != null ? _c : package_default.version
744
+ serviceVersion: (_c = opts.serviceVersion) != null ? _c : PLUGIN_VERSION
724
745
  });
725
746
  }
726
747
  enqueue(span) {
@@ -820,8 +841,6 @@ var pendingChildSessionsByCallKey = /* @__PURE__ */ new Map();
820
841
  function createSessionState(sessionId) {
821
842
  return {
822
843
  sessionId,
823
- turnNumber: 0,
824
- toolCount: 0,
825
844
  currentInput: "",
826
845
  outputParts: /* @__PURE__ */ new Map(),
827
846
  reasoningParts: /* @__PURE__ */ new Map(),
@@ -875,7 +894,7 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
875
894
  // event — session lifecycle + streaming parts
876
895
  // ------------------------------------------------------------------
877
896
  event: async ({ event }) => {
878
- var _a, _b, _c, _d, _e;
897
+ var _a, _b, _c, _d, _e, _f, _g;
879
898
  try {
880
899
  const props = event.properties;
881
900
  const info = props["info"];
@@ -1010,6 +1029,12 @@ type: ${name != null ? name : "UnknownError"}`;
1010
1029
  if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
1011
1030
  llmAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
1012
1031
  }
1032
+ if (state.currentSystemPrompt) {
1033
+ llmAttrs.push(
1034
+ attrString("gen_ai.prompt.0.role", "system"),
1035
+ attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
1036
+ );
1037
+ }
1013
1038
  const llmParent = state.parentId && state.parentTaskSpanIds ? state.parentTaskSpanIds : state.currentRootSpan.ids;
1014
1039
  const llmSpan = traceShipper.startSpan({
1015
1040
  name: modelName,
@@ -1039,6 +1064,12 @@ type: ${name != null ? name : "UnknownError"}`;
1039
1064
  if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
1040
1065
  llmAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
1041
1066
  }
1067
+ if (state.currentSystemPrompt) {
1068
+ llmAttrs.push(
1069
+ attrString("gen_ai.prompt.0.role", "system"),
1070
+ attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
1071
+ );
1072
+ }
1042
1073
  if (!state.parentTaskSpanIds) {
1043
1074
  traceShipper.endSpan(rootSpan, {
1044
1075
  error: "Missing strict parent task for child session"
@@ -1079,6 +1110,12 @@ type: ${name != null ? name : "UnknownError"}`;
1079
1110
  if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
1080
1111
  rootAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
1081
1112
  }
1113
+ if (state.currentSystemPrompt) {
1114
+ rootAttrs.push(
1115
+ attrString("gen_ai.prompt.0.role", "system"),
1116
+ attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
1117
+ );
1118
+ }
1082
1119
  traceShipper.endSpan(rootSpan, {
1083
1120
  attributes: rootAttrs,
1084
1121
  error: errorForSpan
@@ -1093,12 +1130,11 @@ type: ${name != null ? name : "UnknownError"}`;
1093
1130
  }
1094
1131
  if (!state.parentId) {
1095
1132
  await eventShipper.finish(state.currentEventId, {
1096
- userId: state.sessionId,
1133
+ userId: (_d = (_c = state.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state.sessionId,
1097
1134
  model: modelName,
1098
1135
  output: outputText,
1099
1136
  properties: {
1100
- turn_count: state.turnNumber,
1101
- tool_count: state.toolCount
1137
+ plugin_version: PLUGIN_VERSION
1102
1138
  }
1103
1139
  });
1104
1140
  }
@@ -1136,7 +1172,7 @@ type: ${name != null ? name : "UnknownError"}`;
1136
1172
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
1137
1173
  sessions.delete(String(sessionID));
1138
1174
  } else if (event.type === "session.error") {
1139
- const errorSessionID = (_c = props["sessionID"]) != null ? _c : sessionID;
1175
+ const errorSessionID = (_e = props["sessionID"]) != null ? _e : sessionID;
1140
1176
  if (errorSessionID === void 0 || errorSessionID === "")
1141
1177
  throw new Error("session.error: missing sessionID");
1142
1178
  const state = sessions.get(String(errorSessionID));
@@ -1144,7 +1180,7 @@ type: ${name != null ? name : "UnknownError"}`;
1144
1180
  const errorObj = props["error"];
1145
1181
  if (errorObj == null) throw new Error("session.error: missing error object");
1146
1182
  const errorName = errorObj.name;
1147
- const errorMessage = (_e = (_d = errorObj.data) == null ? void 0 : _d.message) != null ? _e : errorObj.name;
1183
+ const errorMessage = (_g = (_f = errorObj.data) == null ? void 0 : _f.message) != null ? _g : errorObj.name;
1148
1184
  if (errorName == null && errorMessage == null)
1149
1185
  throw new Error("session.error: error object must have name or data.message");
1150
1186
  const errorStr = `${errorMessage != null ? errorMessage : errorName}
@@ -1171,6 +1207,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1171
1207
  // chat.message — user sent a message; start a new turn with a fresh event ID
1172
1208
  // ------------------------------------------------------------------
1173
1209
  "chat.message": async (messageInput, output) => {
1210
+ var _a, _b, _c, _d, _e, _f, _g;
1174
1211
  try {
1175
1212
  const { sessionID } = messageInput;
1176
1213
  let state = sessions.get(sessionID);
@@ -1183,15 +1220,24 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1183
1220
  traceShipper.endSpan(state.currentRootSpan);
1184
1221
  state.currentRootSpan = void 0;
1185
1222
  }
1186
- state.turnNumber++;
1187
1223
  if (output == null) throw new Error("chat.message: output is required");
1188
1224
  const parts = output.parts;
1189
1225
  if (parts == null) throw new Error("chat.message: output.parts is required");
1190
1226
  const textParts = [];
1191
1227
  const newAttachments = [];
1228
+ const baseMeta = { ...config.eventMetadata };
1229
+ const promptMeta = {};
1192
1230
  for (const part of parts) {
1193
1231
  if (part["type"] === "text" && typeof part["text"] === "string") {
1194
1232
  textParts.push(part["text"]);
1233
+ const meta = part["metadata"];
1234
+ if (meta != null && typeof meta === "object") {
1235
+ const m = meta;
1236
+ if (typeof m["userId"] === "string") promptMeta.userId = m["userId"];
1237
+ if (typeof m["eventName"] === "string") promptMeta.eventName = m["eventName"];
1238
+ if (m["properties"] != null && typeof m["properties"] === "object")
1239
+ promptMeta.properties = m["properties"];
1240
+ }
1195
1241
  } else if (part["type"] === "file") {
1196
1242
  const mimeType = part["mediaType"];
1197
1243
  const filename = part["filename"];
@@ -1203,6 +1249,11 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1203
1249
  }
1204
1250
  }
1205
1251
  }
1252
+ state.eventMetadata = {
1253
+ ...baseMeta,
1254
+ ...promptMeta,
1255
+ properties: baseMeta.properties || promptMeta.properties ? { ...(_a = baseMeta.properties) != null ? _a : {}, ...(_b = promptMeta.properties) != null ? _b : {} } : void 0
1256
+ };
1206
1257
  const userText = textParts.join("\n");
1207
1258
  state.currentInput = userText;
1208
1259
  if (state.parentId) {
@@ -1238,9 +1289,9 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1238
1289
  });
1239
1290
  await eventShipper.patch(state.currentEventId, {
1240
1291
  isPending: true,
1241
- userId: state.sessionId,
1292
+ userId: (_d = (_c = state.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state.sessionId,
1242
1293
  convoId: state.sessionId,
1243
- eventName: config.eventName,
1294
+ eventName: (_f = (_e = state.eventMetadata) == null ? void 0 : _e.eventName) != null ? _f : config.eventName,
1244
1295
  input: userText,
1245
1296
  ...newAttachments.length > 0 ? { attachments: newAttachments } : {},
1246
1297
  properties: {
@@ -1248,8 +1299,8 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1248
1299
  directory,
1249
1300
  hostname,
1250
1301
  os,
1251
- turn_count: state.turnNumber,
1252
- tool_count: state.toolCount
1302
+ plugin_version: PLUGIN_VERSION,
1303
+ ...(_g = state.eventMetadata) == null ? void 0 : _g.properties
1253
1304
  }
1254
1305
  });
1255
1306
  } catch (err) {
@@ -1260,7 +1311,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1260
1311
  // For child sessions, tool spans are parented directly to the parent task span.
1261
1312
  // ------------------------------------------------------------------
1262
1313
  "tool.execute.before": async (toolInput, _output) => {
1263
- var _a;
1314
+ var _a, _b, _c;
1264
1315
  try {
1265
1316
  const { tool, sessionID, callID } = toolInput;
1266
1317
  const state = sessions.get(sessionID);
@@ -1284,7 +1335,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1284
1335
  ids: liveTaskSpan.ids,
1285
1336
  eventContext: {
1286
1337
  eventId: state.currentEventId,
1287
- userId: state.sessionId,
1338
+ userId: (_c = (_b = state.eventMetadata) == null ? void 0 : _b.userId) != null ? _c : state.sessionId,
1288
1339
  convoId: state.sessionId
1289
1340
  }
1290
1341
  };
@@ -1325,7 +1376,6 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1325
1376
  const { tool, sessionID, callID, args } = toolInput;
1326
1377
  const state = sessions.get(sessionID);
1327
1378
  if (!state || !state.currentEventId) return;
1328
- state.toolCount++;
1329
1379
  if (args === void 0 || args === null)
1330
1380
  throw new Error("tool.execute.after: args is required");
1331
1381
  const toolCallArgs = typeof args === "string" ? args : JSON.stringify(args);
@@ -1379,17 +1429,34 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1379
1429
  if (running.size === 0) runningTaskCallsBySession.delete(sessionID);
1380
1430
  }
1381
1431
  }
1382
- if (!state.parentId) {
1383
- await eventShipper.patch(state.currentEventId, {
1384
- userId: state.sessionId,
1385
- properties: { tool_count: state.toolCount }
1386
- });
1387
- }
1388
1432
  } catch (err) {
1389
1433
  console.log(
1390
1434
  `[raindrop-ai/opencode-plugin] [error] Error in tool.execute.after hook: ${err instanceof Error ? err.message : String(err)}`
1391
1435
  );
1392
1436
  }
1437
+ },
1438
+ // ------------------------------------------------------------------
1439
+ // experimental.chat.system.transform — capture system prompt (read-only)
1440
+ // ------------------------------------------------------------------
1441
+ "experimental.chat.system.transform": async (input, output) => {
1442
+ try {
1443
+ if (!config.captureSystemPrompt) return;
1444
+ const sessionID = input.sessionID;
1445
+ if (!sessionID) return;
1446
+ let state = sessions.get(sessionID);
1447
+ if (!state) {
1448
+ state = createSessionState(sessionID);
1449
+ sessions.set(sessionID, state);
1450
+ }
1451
+ const MAX_SYSTEM_PROMPT_LENGTH = 32768;
1452
+ const TRUNCATION_MARKER = "\n...[truncated]";
1453
+ const joined = output.system.join("\n\n");
1454
+ state.currentSystemPrompt = joined.length > MAX_SYSTEM_PROMPT_LENGTH ? joined.slice(0, MAX_SYSTEM_PROMPT_LENGTH - TRUNCATION_MARKER.length) + TRUNCATION_MARKER : joined;
1455
+ } catch (err) {
1456
+ console.log(
1457
+ `[raindrop-ai/opencode-plugin] [error] Error in experimental.chat.system.transform hook: ${err instanceof Error ? err.message : String(err)}`
1458
+ );
1459
+ }
1393
1460
  }
1394
1461
  };
1395
1462
  }
@@ -1401,6 +1468,7 @@ async function plugin(input) {
1401
1468
  function appLog(level, message) {
1402
1469
  console.log(`[raindrop-ai/opencode-plugin] [${level}] ${message}`);
1403
1470
  }
1471
+ appLog("info", `Loading ${PLUGIN_NAME} v${PLUGIN_VERSION}`);
1404
1472
  if (!config.writeKey) {
1405
1473
  appLog(
1406
1474
  "warn",
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import { existsSync, readFileSync } from "fs";
10
10
  import { homedir } from "os";
11
11
  import { join } from "path";
12
12
  function loadConfig(projectDirectory) {
13
- var _a, _b, _c, _d, _e, _f;
13
+ var _a, _b, _c, _d, _e, _f, _g;
14
14
  let merged = {};
15
15
  const configPaths = [
16
16
  join(homedir(), ".config", "opencode", "raindrop.json"),
@@ -26,15 +26,93 @@ function loadConfig(projectDirectory) {
26
26
  } catch (e) {
27
27
  }
28
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
+ }
29
37
  return {
30
38
  writeKey: (_b = (_a = process.env["RAINDROP_WRITE_KEY"]) != null ? _a : merged.write_key) != null ? _b : "",
31
39
  endpoint: (_d = (_c = process.env["RAINDROP_API_URL"]) != null ? _c : merged.api_url) != null ? _d : "https://api.raindrop.ai/v1",
32
40
  eventName: (_e = merged.event_name) != null ? _e : "opencode_session",
33
- debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_f = merged.debug) != null ? _f : false
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
34
44
  };
35
45
  }
36
46
 
37
- // ../core/dist/chunk-FTBZHS25.js
47
+ // package.json
48
+ var package_default = {
49
+ name: "@raindrop-ai/opencode-plugin",
50
+ version: "0.0.7",
51
+ description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
52
+ type: "module",
53
+ main: "dist/index.cjs",
54
+ module: "dist/index.js",
55
+ types: "dist/index.d.ts",
56
+ exports: {
57
+ ".": {
58
+ types: "./dist/index.d.ts",
59
+ import: "./dist/index.js",
60
+ require: "./dist/index.cjs"
61
+ }
62
+ },
63
+ sideEffects: false,
64
+ files: [
65
+ "dist/**"
66
+ ],
67
+ scripts: {
68
+ build: "tsup",
69
+ dev: "tsup --watch",
70
+ clean: "rm -rf dist",
71
+ test: "cd tests && pnpm test"
72
+ },
73
+ peerDependencies: {
74
+ "@opencode-ai/plugin": ">=1.3.0",
75
+ "@opencode-ai/sdk": ">=1.3.0"
76
+ },
77
+ peerDependenciesMeta: {
78
+ "@opencode-ai/sdk": {
79
+ optional: true
80
+ }
81
+ },
82
+ devDependencies: {
83
+ "@raindrop-ai/core": "workspace:*",
84
+ "@opencode-ai/plugin": "^1.3.3",
85
+ "@opencode-ai/sdk": "^1.3.3",
86
+ "@types/node": "^20.11.17",
87
+ tsup: "^8.4.0",
88
+ typescript: "^5.3.3"
89
+ },
90
+ tsup: {
91
+ entry: [
92
+ "src/index.ts"
93
+ ],
94
+ format: [
95
+ "cjs",
96
+ "esm"
97
+ ],
98
+ dts: {
99
+ resolve: true
100
+ },
101
+ clean: true,
102
+ noExternal: [
103
+ "@raindrop-ai/core"
104
+ ]
105
+ },
106
+ publishConfig: {
107
+ access: "public"
108
+ }
109
+ };
110
+
111
+ // src/package-info.ts
112
+ var PLUGIN_NAME = package_default.name;
113
+ var PLUGIN_VERSION = package_default.version;
114
+
115
+ // ../core/dist/chunk-H6VSZSLN.js
38
116
  function getCrypto() {
39
117
  const c = globalThis.crypto;
40
118
  return c;
@@ -279,6 +357,7 @@ var EventShipper = class {
279
357
  console.log(`${this.prefix} queue patch`, {
280
358
  eventId,
281
359
  userId: patch.userId,
360
+ convoId: patch.convoId,
282
361
  eventName: patch.eventName,
283
362
  hasInput: typeof patch.input === "string" && patch.input.length > 0,
284
363
  hasOutput: typeof patch.output === "string" && patch.output.length > 0,
@@ -407,16 +486,18 @@ var EventShipper = class {
407
486
  return;
408
487
  }
409
488
  const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
489
+ const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
490
+ const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
410
491
  const payload = {
411
492
  event_id: eventId,
412
493
  user_id: userId,
413
494
  event: eventName,
414
- timestamp: (_f = accumulated.timestamp) != null ? _f : (/* @__PURE__ */ new Date()).toISOString(),
495
+ timestamp: (_i = accumulated.timestamp) != null ? _i : (/* @__PURE__ */ new Date()).toISOString(),
415
496
  ai_data: {
416
497
  input: accumulated.input,
417
498
  output: accumulated.output,
418
499
  model: accumulated.model,
419
- convo_id: (_g = accumulated.convoId) != null ? _g : sticky.convoId
500
+ convo_id: convoId
420
501
  },
421
502
  properties: {
422
503
  ...restProperties,
@@ -424,7 +505,7 @@ var EventShipper = class {
424
505
  $context: this.context
425
506
  },
426
507
  attachments: accumulated.attachments,
427
- is_pending: ((_i = (_h = accumulated.isPending) != null ? _h : sticky.isPending) != null ? _i : true) !== false
508
+ is_pending: isPending
428
509
  };
429
510
  const url = `${this.baseUrl}events/track_partial`;
430
511
  if (this.debug) {
@@ -432,7 +513,8 @@ var EventShipper = class {
432
513
  eventId,
433
514
  eventName,
434
515
  userId,
435
- isPending: payload.is_pending,
516
+ convoId,
517
+ isPending,
436
518
  inputPreview: typeof accumulated.input === "string" ? accumulated.input.slice(0, 120) : void 0,
437
519
  outputPreview: typeof accumulated.output === "string" ? accumulated.output.slice(0, 120) : void 0,
438
520
  attachments: (_k = (_j = accumulated.attachments) == null ? void 0 : _j.length) != null ? _k : 0,
@@ -464,7 +546,6 @@ var EventShipper = class {
464
546
  } finally {
465
547
  this.inFlight.delete(p);
466
548
  }
467
- const isPending = payload.is_pending;
468
549
  if (!isPending) {
469
550
  this.sticky.delete(eventId);
470
551
  }
@@ -617,69 +698,9 @@ var TraceShipper = class {
617
698
  }
618
699
  };
619
700
 
620
- // package.json
621
- var package_default = {
622
- name: "@raindrop-ai/opencode-plugin",
623
- version: "0.0.5",
624
- description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
625
- type: "module",
626
- main: "dist/index.cjs",
627
- module: "dist/index.js",
628
- types: "dist/index.d.ts",
629
- exports: {
630
- ".": {
631
- types: "./dist/index.d.ts",
632
- import: "./dist/index.js",
633
- require: "./dist/index.cjs"
634
- }
635
- },
636
- sideEffects: false,
637
- files: [
638
- "dist/**"
639
- ],
640
- scripts: {
641
- build: "tsup",
642
- dev: "tsup --watch",
643
- clean: "rm -rf dist",
644
- test: "cd tests && yarn test"
645
- },
646
- peerDependencies: {
647
- "@opencode-ai/plugin": ">=1.2.0",
648
- "@opencode-ai/sdk": ">=1.2.0"
649
- },
650
- peerDependenciesMeta: {
651
- "@opencode-ai/sdk": {
652
- optional: true
653
- }
654
- },
655
- devDependencies: {
656
- "@raindrop-ai/core": "*",
657
- "@opencode-ai/plugin": "^1.2.0",
658
- "@opencode-ai/sdk": "^1.2.0",
659
- "@types/node": "^20.11.17",
660
- tsup: "^8.4.0",
661
- typescript: "^5.3.3"
662
- },
663
- tsup: {
664
- entry: [
665
- "src/index.ts"
666
- ],
667
- format: [
668
- "cjs",
669
- "esm"
670
- ],
671
- dts: {
672
- resolve: true
673
- },
674
- clean: true,
675
- noExternal: [
676
- "@raindrop-ai/core"
677
- ]
678
- },
679
- publishConfig: {
680
- access: "public"
681
- }
682
- };
701
+ // ../core/dist/index.node.js
702
+ import { AsyncLocalStorage } from "async_hooks";
703
+ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = AsyncLocalStorage;
683
704
 
684
705
  // src/shipper.ts
685
706
  var EventShipper2 = class extends EventShipper {
@@ -688,8 +709,8 @@ var EventShipper2 = class extends EventShipper {
688
709
  super({
689
710
  ...opts,
690
711
  sdkName: (_a = opts.sdkName) != null ? _a : "opencode-plugin",
691
- libraryName: (_b = opts.libraryName) != null ? _b : package_default.name,
692
- libraryVersion: (_c = opts.libraryVersion) != null ? _c : package_default.version,
712
+ libraryName: (_b = opts.libraryName) != null ? _b : PLUGIN_NAME,
713
+ libraryVersion: (_c = opts.libraryVersion) != null ? _c : PLUGIN_VERSION,
693
714
  defaultEventName: (_d = opts.defaultEventName) != null ? _d : "opencode_session"
694
715
  });
695
716
  }
@@ -701,7 +722,7 @@ var TraceShipper2 = class extends TraceShipper {
701
722
  ...opts,
702
723
  sdkName: (_a = opts.sdkName) != null ? _a : "opencode-plugin",
703
724
  serviceName: (_b = opts.serviceName) != null ? _b : "raindrop.opencode-plugin",
704
- serviceVersion: (_c = opts.serviceVersion) != null ? _c : package_default.version
725
+ serviceVersion: (_c = opts.serviceVersion) != null ? _c : PLUGIN_VERSION
705
726
  });
706
727
  }
707
728
  enqueue(span) {
@@ -801,8 +822,6 @@ var pendingChildSessionsByCallKey = /* @__PURE__ */ new Map();
801
822
  function createSessionState(sessionId) {
802
823
  return {
803
824
  sessionId,
804
- turnNumber: 0,
805
- toolCount: 0,
806
825
  currentInput: "",
807
826
  outputParts: /* @__PURE__ */ new Map(),
808
827
  reasoningParts: /* @__PURE__ */ new Map(),
@@ -856,7 +875,7 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
856
875
  // event — session lifecycle + streaming parts
857
876
  // ------------------------------------------------------------------
858
877
  event: async ({ event }) => {
859
- var _a, _b, _c, _d, _e;
878
+ var _a, _b, _c, _d, _e, _f, _g;
860
879
  try {
861
880
  const props = event.properties;
862
881
  const info = props["info"];
@@ -991,6 +1010,12 @@ type: ${name != null ? name : "UnknownError"}`;
991
1010
  if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
992
1011
  llmAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
993
1012
  }
1013
+ if (state.currentSystemPrompt) {
1014
+ llmAttrs.push(
1015
+ attrString("gen_ai.prompt.0.role", "system"),
1016
+ attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
1017
+ );
1018
+ }
994
1019
  const llmParent = state.parentId && state.parentTaskSpanIds ? state.parentTaskSpanIds : state.currentRootSpan.ids;
995
1020
  const llmSpan = traceShipper.startSpan({
996
1021
  name: modelName,
@@ -1020,6 +1045,12 @@ type: ${name != null ? name : "UnknownError"}`;
1020
1045
  if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
1021
1046
  llmAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
1022
1047
  }
1048
+ if (state.currentSystemPrompt) {
1049
+ llmAttrs.push(
1050
+ attrString("gen_ai.prompt.0.role", "system"),
1051
+ attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
1052
+ );
1053
+ }
1023
1054
  if (!state.parentTaskSpanIds) {
1024
1055
  traceShipper.endSpan(rootSpan, {
1025
1056
  error: "Missing strict parent task for child session"
@@ -1060,6 +1091,12 @@ type: ${name != null ? name : "UnknownError"}`;
1060
1091
  if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
1061
1092
  rootAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
1062
1093
  }
1094
+ if (state.currentSystemPrompt) {
1095
+ rootAttrs.push(
1096
+ attrString("gen_ai.prompt.0.role", "system"),
1097
+ attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
1098
+ );
1099
+ }
1063
1100
  traceShipper.endSpan(rootSpan, {
1064
1101
  attributes: rootAttrs,
1065
1102
  error: errorForSpan
@@ -1074,12 +1111,11 @@ type: ${name != null ? name : "UnknownError"}`;
1074
1111
  }
1075
1112
  if (!state.parentId) {
1076
1113
  await eventShipper.finish(state.currentEventId, {
1077
- userId: state.sessionId,
1114
+ userId: (_d = (_c = state.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state.sessionId,
1078
1115
  model: modelName,
1079
1116
  output: outputText,
1080
1117
  properties: {
1081
- turn_count: state.turnNumber,
1082
- tool_count: state.toolCount
1118
+ plugin_version: PLUGIN_VERSION
1083
1119
  }
1084
1120
  });
1085
1121
  }
@@ -1117,7 +1153,7 @@ type: ${name != null ? name : "UnknownError"}`;
1117
1153
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
1118
1154
  sessions.delete(String(sessionID));
1119
1155
  } else if (event.type === "session.error") {
1120
- const errorSessionID = (_c = props["sessionID"]) != null ? _c : sessionID;
1156
+ const errorSessionID = (_e = props["sessionID"]) != null ? _e : sessionID;
1121
1157
  if (errorSessionID === void 0 || errorSessionID === "")
1122
1158
  throw new Error("session.error: missing sessionID");
1123
1159
  const state = sessions.get(String(errorSessionID));
@@ -1125,7 +1161,7 @@ type: ${name != null ? name : "UnknownError"}`;
1125
1161
  const errorObj = props["error"];
1126
1162
  if (errorObj == null) throw new Error("session.error: missing error object");
1127
1163
  const errorName = errorObj.name;
1128
- const errorMessage = (_e = (_d = errorObj.data) == null ? void 0 : _d.message) != null ? _e : errorObj.name;
1164
+ const errorMessage = (_g = (_f = errorObj.data) == null ? void 0 : _f.message) != null ? _g : errorObj.name;
1129
1165
  if (errorName == null && errorMessage == null)
1130
1166
  throw new Error("session.error: error object must have name or data.message");
1131
1167
  const errorStr = `${errorMessage != null ? errorMessage : errorName}
@@ -1152,6 +1188,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1152
1188
  // chat.message — user sent a message; start a new turn with a fresh event ID
1153
1189
  // ------------------------------------------------------------------
1154
1190
  "chat.message": async (messageInput, output) => {
1191
+ var _a, _b, _c, _d, _e, _f, _g;
1155
1192
  try {
1156
1193
  const { sessionID } = messageInput;
1157
1194
  let state = sessions.get(sessionID);
@@ -1164,15 +1201,24 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1164
1201
  traceShipper.endSpan(state.currentRootSpan);
1165
1202
  state.currentRootSpan = void 0;
1166
1203
  }
1167
- state.turnNumber++;
1168
1204
  if (output == null) throw new Error("chat.message: output is required");
1169
1205
  const parts = output.parts;
1170
1206
  if (parts == null) throw new Error("chat.message: output.parts is required");
1171
1207
  const textParts = [];
1172
1208
  const newAttachments = [];
1209
+ const baseMeta = { ...config.eventMetadata };
1210
+ const promptMeta = {};
1173
1211
  for (const part of parts) {
1174
1212
  if (part["type"] === "text" && typeof part["text"] === "string") {
1175
1213
  textParts.push(part["text"]);
1214
+ const meta = part["metadata"];
1215
+ if (meta != null && typeof meta === "object") {
1216
+ const m = meta;
1217
+ if (typeof m["userId"] === "string") promptMeta.userId = m["userId"];
1218
+ if (typeof m["eventName"] === "string") promptMeta.eventName = m["eventName"];
1219
+ if (m["properties"] != null && typeof m["properties"] === "object")
1220
+ promptMeta.properties = m["properties"];
1221
+ }
1176
1222
  } else if (part["type"] === "file") {
1177
1223
  const mimeType = part["mediaType"];
1178
1224
  const filename = part["filename"];
@@ -1184,6 +1230,11 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1184
1230
  }
1185
1231
  }
1186
1232
  }
1233
+ state.eventMetadata = {
1234
+ ...baseMeta,
1235
+ ...promptMeta,
1236
+ properties: baseMeta.properties || promptMeta.properties ? { ...(_a = baseMeta.properties) != null ? _a : {}, ...(_b = promptMeta.properties) != null ? _b : {} } : void 0
1237
+ };
1187
1238
  const userText = textParts.join("\n");
1188
1239
  state.currentInput = userText;
1189
1240
  if (state.parentId) {
@@ -1219,9 +1270,9 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1219
1270
  });
1220
1271
  await eventShipper.patch(state.currentEventId, {
1221
1272
  isPending: true,
1222
- userId: state.sessionId,
1273
+ userId: (_d = (_c = state.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state.sessionId,
1223
1274
  convoId: state.sessionId,
1224
- eventName: config.eventName,
1275
+ eventName: (_f = (_e = state.eventMetadata) == null ? void 0 : _e.eventName) != null ? _f : config.eventName,
1225
1276
  input: userText,
1226
1277
  ...newAttachments.length > 0 ? { attachments: newAttachments } : {},
1227
1278
  properties: {
@@ -1229,8 +1280,8 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1229
1280
  directory,
1230
1281
  hostname,
1231
1282
  os,
1232
- turn_count: state.turnNumber,
1233
- tool_count: state.toolCount
1283
+ plugin_version: PLUGIN_VERSION,
1284
+ ...(_g = state.eventMetadata) == null ? void 0 : _g.properties
1234
1285
  }
1235
1286
  });
1236
1287
  } catch (err) {
@@ -1241,7 +1292,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1241
1292
  // For child sessions, tool spans are parented directly to the parent task span.
1242
1293
  // ------------------------------------------------------------------
1243
1294
  "tool.execute.before": async (toolInput, _output) => {
1244
- var _a;
1295
+ var _a, _b, _c;
1245
1296
  try {
1246
1297
  const { tool, sessionID, callID } = toolInput;
1247
1298
  const state = sessions.get(sessionID);
@@ -1265,7 +1316,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1265
1316
  ids: liveTaskSpan.ids,
1266
1317
  eventContext: {
1267
1318
  eventId: state.currentEventId,
1268
- userId: state.sessionId,
1319
+ userId: (_c = (_b = state.eventMetadata) == null ? void 0 : _b.userId) != null ? _c : state.sessionId,
1269
1320
  convoId: state.sessionId
1270
1321
  }
1271
1322
  };
@@ -1306,7 +1357,6 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1306
1357
  const { tool, sessionID, callID, args } = toolInput;
1307
1358
  const state = sessions.get(sessionID);
1308
1359
  if (!state || !state.currentEventId) return;
1309
- state.toolCount++;
1310
1360
  if (args === void 0 || args === null)
1311
1361
  throw new Error("tool.execute.after: args is required");
1312
1362
  const toolCallArgs = typeof args === "string" ? args : JSON.stringify(args);
@@ -1360,17 +1410,34 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1360
1410
  if (running.size === 0) runningTaskCallsBySession.delete(sessionID);
1361
1411
  }
1362
1412
  }
1363
- if (!state.parentId) {
1364
- await eventShipper.patch(state.currentEventId, {
1365
- userId: state.sessionId,
1366
- properties: { tool_count: state.toolCount }
1367
- });
1368
- }
1369
1413
  } catch (err) {
1370
1414
  console.log(
1371
1415
  `[raindrop-ai/opencode-plugin] [error] Error in tool.execute.after hook: ${err instanceof Error ? err.message : String(err)}`
1372
1416
  );
1373
1417
  }
1418
+ },
1419
+ // ------------------------------------------------------------------
1420
+ // experimental.chat.system.transform — capture system prompt (read-only)
1421
+ // ------------------------------------------------------------------
1422
+ "experimental.chat.system.transform": async (input, output) => {
1423
+ try {
1424
+ if (!config.captureSystemPrompt) return;
1425
+ const sessionID = input.sessionID;
1426
+ if (!sessionID) return;
1427
+ let state = sessions.get(sessionID);
1428
+ if (!state) {
1429
+ state = createSessionState(sessionID);
1430
+ sessions.set(sessionID, state);
1431
+ }
1432
+ const MAX_SYSTEM_PROMPT_LENGTH = 32768;
1433
+ const TRUNCATION_MARKER = "\n...[truncated]";
1434
+ const joined = output.system.join("\n\n");
1435
+ state.currentSystemPrompt = joined.length > MAX_SYSTEM_PROMPT_LENGTH ? joined.slice(0, MAX_SYSTEM_PROMPT_LENGTH - TRUNCATION_MARKER.length) + TRUNCATION_MARKER : joined;
1436
+ } catch (err) {
1437
+ console.log(
1438
+ `[raindrop-ai/opencode-plugin] [error] Error in experimental.chat.system.transform hook: ${err instanceof Error ? err.message : String(err)}`
1439
+ );
1440
+ }
1374
1441
  }
1375
1442
  };
1376
1443
  }
@@ -1382,6 +1449,7 @@ async function plugin(input) {
1382
1449
  function appLog(level, message) {
1383
1450
  console.log(`[raindrop-ai/opencode-plugin] [${level}] ${message}`);
1384
1451
  }
1452
+ appLog("info", `Loading ${PLUGIN_NAME} v${PLUGIN_VERSION}`);
1385
1453
  if (!config.writeKey) {
1386
1454
  appLog(
1387
1455
  "warn",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raindrop-ai/opencode-plugin",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "Raindrop observability plugin for OpenCode — automatic session/event/span tracing",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -21,11 +21,11 @@
21
21
  "build": "tsup",
22
22
  "dev": "tsup --watch",
23
23
  "clean": "rm -rf dist",
24
- "test": "cd tests && yarn test"
24
+ "test": "cd tests && pnpm test"
25
25
  },
26
26
  "peerDependencies": {
27
- "@opencode-ai/plugin": ">=1.2.0",
28
- "@opencode-ai/sdk": ">=1.2.0"
27
+ "@opencode-ai/plugin": ">=1.3.0",
28
+ "@opencode-ai/sdk": ">=1.3.0"
29
29
  },
30
30
  "peerDependenciesMeta": {
31
31
  "@opencode-ai/sdk": {
@@ -33,9 +33,9 @@
33
33
  }
34
34
  },
35
35
  "devDependencies": {
36
- "@raindrop-ai/core": "*",
37
- "@opencode-ai/plugin": "^1.2.0",
38
- "@opencode-ai/sdk": "^1.2.0",
36
+ "@raindrop-ai/core": "workspace:*",
37
+ "@opencode-ai/plugin": "^1.3.3",
38
+ "@opencode-ai/sdk": "^1.3.3",
39
39
  "@types/node": "^20.11.17",
40
40
  "tsup": "^8.4.0",
41
41
  "typescript": "^5.3.3"