@raindrop-ai/opencode-plugin 0.0.7 → 0.0.8

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 CHANGED
@@ -66,7 +66,7 @@ function loadConfig(projectDirectory) {
66
66
  // package.json
67
67
  var package_default = {
68
68
  name: "@raindrop-ai/opencode-plugin",
69
- version: "0.0.7",
69
+ version: "0.0.8",
70
70
  description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
71
71
  type: "module",
72
72
  main: "dist/index.cjs",
@@ -131,7 +131,7 @@ var package_default = {
131
131
  var PLUGIN_NAME = package_default.name;
132
132
  var PLUGIN_VERSION = package_default.version;
133
133
 
134
- // ../core/dist/chunk-H6VSZSLN.js
134
+ // ../core/dist/chunk-4UCYIEH4.js
135
135
  function getCrypto() {
136
136
  const c = globalThis.crypto;
137
137
  return c;
@@ -570,11 +570,28 @@ var EventShipper = class {
570
570
  }
571
571
  }
572
572
  };
573
+ var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
574
+ function resolveLocalDebuggerBaseUrl(baseUrl) {
575
+ var _a, _b, _c;
576
+ 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;
577
+ return resolved ? (_c = formatEndpoint(resolved)) != null ? _c : null : null;
578
+ }
579
+ function mirrorTraceExportToLocalDebugger(body, options = {}) {
580
+ var _a;
581
+ const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
582
+ if (!baseUrl) return;
583
+ void postJson(`${baseUrl}traces`, body, {}, {
584
+ maxAttempts: 1,
585
+ debug: (_a = options.debug) != null ? _a : false,
586
+ sdkName: options.sdkName
587
+ }).catch(() => {
588
+ });
589
+ }
573
590
  var TraceShipper = class {
574
591
  constructor(opts) {
575
592
  this.queue = [];
576
593
  this.inFlight = /* @__PURE__ */ new Set();
577
- var _a, _b, _c, _d, _e, _f, _g, _h;
594
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
578
595
  this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
579
596
  this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
580
597
  this.enabled = opts.enabled !== false;
@@ -587,6 +604,13 @@ var TraceShipper = class {
587
604
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
588
605
  this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
589
606
  this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
607
+ const localDebugger = typeof process !== "undefined" ? (_i = process.env) == null ? void 0 : _i.RAINDROP_LOCAL_DEBUGGER : void 0;
608
+ if (localDebugger) {
609
+ this.localDebuggerUrl = (_j = resolveLocalDebuggerBaseUrl(localDebugger)) != null ? _j : void 0;
610
+ if (this.debug) {
611
+ console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
612
+ }
613
+ }
590
614
  }
591
615
  isDebugEnabled() {
592
616
  return this.debug;
@@ -603,7 +627,25 @@ var TraceShipper = class {
603
627
  attrString("ai.operationId", args.operationId)
604
628
  ];
605
629
  if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
606
- return { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
630
+ const span = { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
631
+ if (this.localDebuggerUrl) {
632
+ const openSpan = buildOtlpSpan({
633
+ ids: span.ids,
634
+ name: span.name,
635
+ startTimeUnixNano: span.startTimeUnixNano,
636
+ endTimeUnixNano: span.startTimeUnixNano,
637
+ // placeholder — will be updated on endSpan
638
+ attributes: span.attributes,
639
+ status: { code: SpanStatusCode.UNSET }
640
+ });
641
+ const body = buildExportTraceServiceRequest([openSpan], this.serviceName, this.serviceVersion);
642
+ mirrorTraceExportToLocalDebugger(body, {
643
+ baseUrl: this.localDebuggerUrl,
644
+ debug: false,
645
+ sdkName: this.sdkName
646
+ });
647
+ }
648
+ return span;
607
649
  }
608
650
  endSpan(span, extra) {
609
651
  var _a, _b;
@@ -626,6 +668,14 @@ var TraceShipper = class {
626
668
  status
627
669
  });
628
670
  this.enqueue(otlp);
671
+ if (this.localDebuggerUrl) {
672
+ const body = buildExportTraceServiceRequest([otlp], this.serviceName, this.serviceVersion);
673
+ mirrorTraceExportToLocalDebugger(body, {
674
+ baseUrl: this.localDebuggerUrl,
675
+ debug: false,
676
+ sdkName: this.sdkName
677
+ });
678
+ }
629
679
  }
630
680
  createSpan(args) {
631
681
  var _a;
@@ -643,6 +693,14 @@ var TraceShipper = class {
643
693
  status: args.status
644
694
  });
645
695
  this.enqueue(otlp);
696
+ if (this.localDebuggerUrl) {
697
+ const body = buildExportTraceServiceRequest([otlp], this.serviceName, this.serviceVersion);
698
+ mirrorTraceExportToLocalDebugger(body, {
699
+ baseUrl: this.localDebuggerUrl,
700
+ debug: false,
701
+ sdkName: this.sdkName
702
+ });
703
+ }
646
704
  }
647
705
  enqueue(span) {
648
706
  if (!this.enabled) return;
@@ -899,7 +957,7 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
899
957
  const props = event.properties;
900
958
  const info = props["info"];
901
959
  const sessionID = (_b = (_a = props["sessionID"]) != null ? _a : info == null ? void 0 : info["id"]) != null ? _b : props["id"];
902
- const sessionEventTypes = ["session.created", "session.idle", "session.deleted", "session.error"];
960
+ const sessionEventTypes = ["session.created", "session.compacted", "session.idle", "session.deleted", "session.error"];
903
961
  if (sessionEventTypes.includes(event.type) && (sessionID === void 0 || sessionID === "")) {
904
962
  throw new Error(`event ${event.type}: missing sessionID in properties`);
905
963
  }
@@ -914,6 +972,10 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
914
972
  }
915
973
  state.parentId = parentID;
916
974
  if (state.parentId) mapChildSessionToParent.set(sessionID, { parentId: state.parentId });
975
+ } else if (event.type === "session.compacted") {
976
+ const state = sessions.get(String(sessionID));
977
+ if (!state) return;
978
+ state.isCompacting = true;
917
979
  } else if (event.type === "message.part.updated") {
918
980
  const part = props["part"];
919
981
  if (part == null || typeof part !== "object")
@@ -1023,6 +1085,7 @@ type: ${name != null ? name : "UnknownError"}`;
1023
1085
  attrString("ai.response.text", reasoningText),
1024
1086
  attrString("gen_ai.system", providerID),
1025
1087
  attrString("gen_ai.request.model", modelID),
1088
+ attrString("gen_ai.response.model", modelID),
1026
1089
  attrInt("gen_ai.usage.input_tokens", inputTokens),
1027
1090
  attrInt("gen_ai.usage.output_tokens", outputTokens)
1028
1091
  ];
@@ -1051,6 +1114,7 @@ type: ${name != null ? name : "UnknownError"}`;
1051
1114
  }
1052
1115
  if (outputText === void 0) return;
1053
1116
  const rootSpan = state.currentRootSpan;
1117
+ const isCompaction = state.isCompacting === true;
1054
1118
  if (state.parentId) {
1055
1119
  const llmAttrs = [
1056
1120
  attrString("ai.operationId", "generateText"),
@@ -1058,6 +1122,7 @@ type: ${name != null ? name : "UnknownError"}`;
1058
1122
  attrString("ai.response.text", outputText),
1059
1123
  attrString("gen_ai.system", providerID),
1060
1124
  attrString("gen_ai.request.model", modelID),
1125
+ attrString("gen_ai.response.model", modelID),
1061
1126
  attrInt("gen_ai.usage.input_tokens", inputTokens),
1062
1127
  attrInt("gen_ai.usage.output_tokens", outputTokens)
1063
1128
  ];
@@ -1097,16 +1162,20 @@ type: ${name != null ? name : "UnknownError"}`;
1097
1162
  error: errorForSpan
1098
1163
  });
1099
1164
  } else {
1100
- rootSpan.name = modelName;
1165
+ rootSpan.name = isCompaction ? "ai.compaction" : modelName;
1101
1166
  const rootAttrs = [
1102
1167
  attrString("ai.operationId", "generateText"),
1103
1168
  attrString("ai.prompt", state.currentInput),
1104
1169
  attrString("ai.response.text", outputText),
1105
1170
  attrString("gen_ai.system", providerID),
1106
1171
  attrString("gen_ai.request.model", modelID),
1172
+ attrString("gen_ai.response.model", modelID),
1107
1173
  attrInt("gen_ai.usage.input_tokens", inputTokens),
1108
1174
  attrInt("gen_ai.usage.output_tokens", outputTokens)
1109
1175
  ];
1176
+ if (isCompaction) {
1177
+ rootAttrs.push(attrString("is_compaction", "true"));
1178
+ }
1110
1179
  if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
1111
1180
  rootAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
1112
1181
  }
@@ -1120,6 +1189,9 @@ type: ${name != null ? name : "UnknownError"}`;
1120
1189
  attributes: rootAttrs,
1121
1190
  error: errorForSpan
1122
1191
  });
1192
+ if (isCompaction) {
1193
+ state.isCompacting = false;
1194
+ }
1123
1195
  }
1124
1196
  state.currentRootSpan = void 0;
1125
1197
  const hasAssistantResponse = outputText.trim().length > 0;
@@ -1134,7 +1206,8 @@ type: ${name != null ? name : "UnknownError"}`;
1134
1206
  model: modelName,
1135
1207
  output: outputText,
1136
1208
  properties: {
1137
- plugin_version: PLUGIN_VERSION
1209
+ plugin_version: PLUGIN_VERSION,
1210
+ ...isCompaction ? { is_compaction: true } : {}
1138
1211
  }
1139
1212
  });
1140
1213
  }
@@ -1151,6 +1224,7 @@ type: ${name != null ? name : "UnknownError"}`;
1151
1224
  if (state.currentEventId) {
1152
1225
  state.currentEventId = void 0;
1153
1226
  }
1227
+ state.isCompacting = false;
1154
1228
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
1155
1229
  if (state.parentId) {
1156
1230
  cleanupSessionParentMap(String(sessionID));
@@ -1278,7 +1352,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1278
1352
  }
1279
1353
  state.currentEventId = generateId();
1280
1354
  state.currentRootSpan = traceShipper.startSpan({
1281
- name: "ai.event",
1355
+ name: state.isCompacting ? "ai.compaction" : "ai.event",
1282
1356
  eventId: state.currentEventId,
1283
1357
  attributes: [
1284
1358
  attrString("workspace", worktree),
@@ -1436,6 +1510,23 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1436
1510
  }
1437
1511
  },
1438
1512
  // ------------------------------------------------------------------
1513
+ // experimental.session.compacting — fires before compaction LLM call
1514
+ // ------------------------------------------------------------------
1515
+ "experimental.session.compacting": async (input, _output) => {
1516
+ try {
1517
+ const sessionID = input.sessionID;
1518
+ if (!sessionID) return;
1519
+ const state = sessions.get(sessionID);
1520
+ if (state) {
1521
+ state.isCompacting = true;
1522
+ }
1523
+ } catch (err) {
1524
+ console.log(
1525
+ `[raindrop-ai/opencode-plugin] [error] Error in experimental.session.compacting hook: ${err instanceof Error ? err.message : String(err)}`
1526
+ );
1527
+ }
1528
+ },
1529
+ // ------------------------------------------------------------------
1439
1530
  // experimental.chat.system.transform — capture system prompt (read-only)
1440
1531
  // ------------------------------------------------------------------
1441
1532
  "experimental.chat.system.transform": async (input, output) => {
package/dist/index.js CHANGED
@@ -47,7 +47,7 @@ function loadConfig(projectDirectory) {
47
47
  // package.json
48
48
  var package_default = {
49
49
  name: "@raindrop-ai/opencode-plugin",
50
- version: "0.0.7",
50
+ version: "0.0.8",
51
51
  description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
52
52
  type: "module",
53
53
  main: "dist/index.cjs",
@@ -112,7 +112,7 @@ var package_default = {
112
112
  var PLUGIN_NAME = package_default.name;
113
113
  var PLUGIN_VERSION = package_default.version;
114
114
 
115
- // ../core/dist/chunk-H6VSZSLN.js
115
+ // ../core/dist/chunk-4UCYIEH4.js
116
116
  function getCrypto() {
117
117
  const c = globalThis.crypto;
118
118
  return c;
@@ -551,11 +551,28 @@ var EventShipper = class {
551
551
  }
552
552
  }
553
553
  };
554
+ var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
555
+ function resolveLocalDebuggerBaseUrl(baseUrl) {
556
+ var _a, _b, _c;
557
+ 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;
558
+ return resolved ? (_c = formatEndpoint(resolved)) != null ? _c : null : null;
559
+ }
560
+ function mirrorTraceExportToLocalDebugger(body, options = {}) {
561
+ var _a;
562
+ const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
563
+ if (!baseUrl) return;
564
+ void postJson(`${baseUrl}traces`, body, {}, {
565
+ maxAttempts: 1,
566
+ debug: (_a = options.debug) != null ? _a : false,
567
+ sdkName: options.sdkName
568
+ }).catch(() => {
569
+ });
570
+ }
554
571
  var TraceShipper = class {
555
572
  constructor(opts) {
556
573
  this.queue = [];
557
574
  this.inFlight = /* @__PURE__ */ new Set();
558
- var _a, _b, _c, _d, _e, _f, _g, _h;
575
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
559
576
  this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
560
577
  this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
561
578
  this.enabled = opts.enabled !== false;
@@ -568,6 +585,13 @@ var TraceShipper = class {
568
585
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
569
586
  this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
570
587
  this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
588
+ const localDebugger = typeof process !== "undefined" ? (_i = process.env) == null ? void 0 : _i.RAINDROP_LOCAL_DEBUGGER : void 0;
589
+ if (localDebugger) {
590
+ this.localDebuggerUrl = (_j = resolveLocalDebuggerBaseUrl(localDebugger)) != null ? _j : void 0;
591
+ if (this.debug) {
592
+ console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
593
+ }
594
+ }
571
595
  }
572
596
  isDebugEnabled() {
573
597
  return this.debug;
@@ -584,7 +608,25 @@ var TraceShipper = class {
584
608
  attrString("ai.operationId", args.operationId)
585
609
  ];
586
610
  if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
587
- return { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
611
+ const span = { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
612
+ if (this.localDebuggerUrl) {
613
+ const openSpan = buildOtlpSpan({
614
+ ids: span.ids,
615
+ name: span.name,
616
+ startTimeUnixNano: span.startTimeUnixNano,
617
+ endTimeUnixNano: span.startTimeUnixNano,
618
+ // placeholder — will be updated on endSpan
619
+ attributes: span.attributes,
620
+ status: { code: SpanStatusCode.UNSET }
621
+ });
622
+ const body = buildExportTraceServiceRequest([openSpan], this.serviceName, this.serviceVersion);
623
+ mirrorTraceExportToLocalDebugger(body, {
624
+ baseUrl: this.localDebuggerUrl,
625
+ debug: false,
626
+ sdkName: this.sdkName
627
+ });
628
+ }
629
+ return span;
588
630
  }
589
631
  endSpan(span, extra) {
590
632
  var _a, _b;
@@ -607,6 +649,14 @@ var TraceShipper = class {
607
649
  status
608
650
  });
609
651
  this.enqueue(otlp);
652
+ if (this.localDebuggerUrl) {
653
+ const body = buildExportTraceServiceRequest([otlp], this.serviceName, this.serviceVersion);
654
+ mirrorTraceExportToLocalDebugger(body, {
655
+ baseUrl: this.localDebuggerUrl,
656
+ debug: false,
657
+ sdkName: this.sdkName
658
+ });
659
+ }
610
660
  }
611
661
  createSpan(args) {
612
662
  var _a;
@@ -624,6 +674,14 @@ var TraceShipper = class {
624
674
  status: args.status
625
675
  });
626
676
  this.enqueue(otlp);
677
+ if (this.localDebuggerUrl) {
678
+ const body = buildExportTraceServiceRequest([otlp], this.serviceName, this.serviceVersion);
679
+ mirrorTraceExportToLocalDebugger(body, {
680
+ baseUrl: this.localDebuggerUrl,
681
+ debug: false,
682
+ sdkName: this.sdkName
683
+ });
684
+ }
627
685
  }
628
686
  enqueue(span) {
629
687
  if (!this.enabled) return;
@@ -880,7 +938,7 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
880
938
  const props = event.properties;
881
939
  const info = props["info"];
882
940
  const sessionID = (_b = (_a = props["sessionID"]) != null ? _a : info == null ? void 0 : info["id"]) != null ? _b : props["id"];
883
- const sessionEventTypes = ["session.created", "session.idle", "session.deleted", "session.error"];
941
+ const sessionEventTypes = ["session.created", "session.compacted", "session.idle", "session.deleted", "session.error"];
884
942
  if (sessionEventTypes.includes(event.type) && (sessionID === void 0 || sessionID === "")) {
885
943
  throw new Error(`event ${event.type}: missing sessionID in properties`);
886
944
  }
@@ -895,6 +953,10 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
895
953
  }
896
954
  state.parentId = parentID;
897
955
  if (state.parentId) mapChildSessionToParent.set(sessionID, { parentId: state.parentId });
956
+ } else if (event.type === "session.compacted") {
957
+ const state = sessions.get(String(sessionID));
958
+ if (!state) return;
959
+ state.isCompacting = true;
898
960
  } else if (event.type === "message.part.updated") {
899
961
  const part = props["part"];
900
962
  if (part == null || typeof part !== "object")
@@ -1004,6 +1066,7 @@ type: ${name != null ? name : "UnknownError"}`;
1004
1066
  attrString("ai.response.text", reasoningText),
1005
1067
  attrString("gen_ai.system", providerID),
1006
1068
  attrString("gen_ai.request.model", modelID),
1069
+ attrString("gen_ai.response.model", modelID),
1007
1070
  attrInt("gen_ai.usage.input_tokens", inputTokens),
1008
1071
  attrInt("gen_ai.usage.output_tokens", outputTokens)
1009
1072
  ];
@@ -1032,6 +1095,7 @@ type: ${name != null ? name : "UnknownError"}`;
1032
1095
  }
1033
1096
  if (outputText === void 0) return;
1034
1097
  const rootSpan = state.currentRootSpan;
1098
+ const isCompaction = state.isCompacting === true;
1035
1099
  if (state.parentId) {
1036
1100
  const llmAttrs = [
1037
1101
  attrString("ai.operationId", "generateText"),
@@ -1039,6 +1103,7 @@ type: ${name != null ? name : "UnknownError"}`;
1039
1103
  attrString("ai.response.text", outputText),
1040
1104
  attrString("gen_ai.system", providerID),
1041
1105
  attrString("gen_ai.request.model", modelID),
1106
+ attrString("gen_ai.response.model", modelID),
1042
1107
  attrInt("gen_ai.usage.input_tokens", inputTokens),
1043
1108
  attrInt("gen_ai.usage.output_tokens", outputTokens)
1044
1109
  ];
@@ -1078,16 +1143,20 @@ type: ${name != null ? name : "UnknownError"}`;
1078
1143
  error: errorForSpan
1079
1144
  });
1080
1145
  } else {
1081
- rootSpan.name = modelName;
1146
+ rootSpan.name = isCompaction ? "ai.compaction" : modelName;
1082
1147
  const rootAttrs = [
1083
1148
  attrString("ai.operationId", "generateText"),
1084
1149
  attrString("ai.prompt", state.currentInput),
1085
1150
  attrString("ai.response.text", outputText),
1086
1151
  attrString("gen_ai.system", providerID),
1087
1152
  attrString("gen_ai.request.model", modelID),
1153
+ attrString("gen_ai.response.model", modelID),
1088
1154
  attrInt("gen_ai.usage.input_tokens", inputTokens),
1089
1155
  attrInt("gen_ai.usage.output_tokens", outputTokens)
1090
1156
  ];
1157
+ if (isCompaction) {
1158
+ rootAttrs.push(attrString("is_compaction", "true"));
1159
+ }
1091
1160
  if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
1092
1161
  rootAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
1093
1162
  }
@@ -1101,6 +1170,9 @@ type: ${name != null ? name : "UnknownError"}`;
1101
1170
  attributes: rootAttrs,
1102
1171
  error: errorForSpan
1103
1172
  });
1173
+ if (isCompaction) {
1174
+ state.isCompacting = false;
1175
+ }
1104
1176
  }
1105
1177
  state.currentRootSpan = void 0;
1106
1178
  const hasAssistantResponse = outputText.trim().length > 0;
@@ -1115,7 +1187,8 @@ type: ${name != null ? name : "UnknownError"}`;
1115
1187
  model: modelName,
1116
1188
  output: outputText,
1117
1189
  properties: {
1118
- plugin_version: PLUGIN_VERSION
1190
+ plugin_version: PLUGIN_VERSION,
1191
+ ...isCompaction ? { is_compaction: true } : {}
1119
1192
  }
1120
1193
  });
1121
1194
  }
@@ -1132,6 +1205,7 @@ type: ${name != null ? name : "UnknownError"}`;
1132
1205
  if (state.currentEventId) {
1133
1206
  state.currentEventId = void 0;
1134
1207
  }
1208
+ state.isCompacting = false;
1135
1209
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
1136
1210
  if (state.parentId) {
1137
1211
  cleanupSessionParentMap(String(sessionID));
@@ -1259,7 +1333,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1259
1333
  }
1260
1334
  state.currentEventId = generateId();
1261
1335
  state.currentRootSpan = traceShipper.startSpan({
1262
- name: "ai.event",
1336
+ name: state.isCompacting ? "ai.compaction" : "ai.event",
1263
1337
  eventId: state.currentEventId,
1264
1338
  attributes: [
1265
1339
  attrString("workspace", worktree),
@@ -1417,6 +1491,23 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
1417
1491
  }
1418
1492
  },
1419
1493
  // ------------------------------------------------------------------
1494
+ // experimental.session.compacting — fires before compaction LLM call
1495
+ // ------------------------------------------------------------------
1496
+ "experimental.session.compacting": async (input, _output) => {
1497
+ try {
1498
+ const sessionID = input.sessionID;
1499
+ if (!sessionID) return;
1500
+ const state = sessions.get(sessionID);
1501
+ if (state) {
1502
+ state.isCompacting = true;
1503
+ }
1504
+ } catch (err) {
1505
+ console.log(
1506
+ `[raindrop-ai/opencode-plugin] [error] Error in experimental.session.compacting hook: ${err instanceof Error ? err.message : String(err)}`
1507
+ );
1508
+ }
1509
+ },
1510
+ // ------------------------------------------------------------------
1420
1511
  // experimental.chat.system.transform — capture system prompt (read-only)
1421
1512
  // ------------------------------------------------------------------
1422
1513
  "experimental.chat.system.transform": async (input, output) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raindrop-ai/opencode-plugin",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "Raindrop observability plugin for OpenCode — automatic session/event/span tracing",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",