@raindrop-ai/opencode-plugin 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/v2.d.ts CHANGED
@@ -1,11 +1,19 @@
1
1
  import { Plugin } from '@opencode/plugin';
2
- import { I as IdentifyInput, S as SignalInput, A as AppGitOptions } from './index.d-vgBcEZbX.js';
2
+ import { I as IdentifyInput, c as SignalInput, A as AppGitOptions, S as SelfDiagnosticsOptions, P as PromptToolsOverride } from './self-diagnostics-CLW6h4zB.js';
3
+ export { a as SelfDiagnosticsSignalDefinition, b as SelfDiagnosticsSignalDefinitions } from './self-diagnostics-CLW6h4zB.js';
3
4
 
4
5
  interface RaindropOpencodeV2Options {
5
6
  /** Application Git identity override. false disables enrichment. */
6
7
  appGit?: AppGitOptions | false;
7
8
  /** Config directory override; defaults to the first instance's ctx.location.directory. */
8
9
  directory?: string;
10
+ /** Built-in self-diagnostics: injects a `__raindrop_report` tool when enabled. */
11
+ selfDiagnostics?: SelfDiagnosticsOptions;
12
+ /**
13
+ * Overrides the tool catalog recorded as `ai.prompt.tools` on every model
14
+ * span; skips the OpenCode `ctx.tool.list()` lookup entirely.
15
+ */
16
+ tools?: PromptToolsOverride;
9
17
  }
10
18
  /**
11
19
  * The Raindrop control handle exposed on the v2 plugin. Unlike v1 (where the
@@ -38,4 +46,4 @@ interface RaindropOpencodePluginV2 extends Plugin.Plugin {
38
46
  */
39
47
  declare function raindrop(opts?: RaindropOpencodeV2Options): RaindropOpencodePluginV2;
40
48
 
41
- export { IdentifyInput, type RaindropOpencodePluginV2, type RaindropOpencodeV2Handle, type RaindropOpencodeV2Options, SignalInput, raindrop as default };
49
+ export { IdentifyInput, type RaindropOpencodePluginV2, type RaindropOpencodeV2Handle, type RaindropOpencodeV2Options, SelfDiagnosticsOptions, SignalInput, raindrop as default };
package/dist/v2.js CHANGED
@@ -2,16 +2,22 @@ import {
2
2
  EventShipper,
3
3
  PLUGIN_NAME,
4
4
  PLUGIN_VERSION,
5
+ SELF_DIAGNOSTICS_ACK,
5
6
  TraceShipper,
6
7
  attrString,
7
8
  boundedStringify,
8
9
  buildLlmGenAiAttributes,
9
10
  capText,
10
11
  createAppGitContext,
12
+ createToolCatalog,
11
13
  generateId,
12
14
  loadConfig,
13
- resolveLocalDebuggerBaseUrl
14
- } from "./chunk-4DAI6CYK.js";
15
+ normalizeSelfDiagnosticsConfig,
16
+ promptToolsAttributes,
17
+ resolveLocalDebuggerBaseUrl,
18
+ selfDiagnosticsInputJsonSchema,
19
+ trackSelfDiagnosticsSignal
20
+ } from "./chunk-ZG47FVK7.js";
15
21
 
16
22
  // src/v2.ts
17
23
  import { Plugin } from "@opencode/plugin";
@@ -66,7 +72,7 @@ function errorString(error) {
66
72
 
67
73
  type: ${error.type}`;
68
74
  }
69
- function createV2Tracing(config, eventShipper, traceShipper, sessionLookup) {
75
+ function createV2Tracing(config, eventShipper, traceShipper, sessionLookup, toolCatalog) {
70
76
  const sessions = /* @__PURE__ */ new Map();
71
77
  const admittedPrompts = /* @__PURE__ */ new Map();
72
78
  const subagentLinks = /* @__PURE__ */ new Map();
@@ -106,7 +112,7 @@ function createV2Tracing(config, eventShipper, traceShipper, sessionLookup) {
106
112
  async function finalizeTurn(state, error) {
107
113
  var _a, _b, _c;
108
114
  for (const step of state.stepSpans.values()) {
109
- traceShipper.endSpan(step.span);
115
+ traceShipper.endSpan(step.span, { attributes: promptToolsAttributes(await step.promptTools) });
110
116
  }
111
117
  state.stepSpans.clear();
112
118
  if (state.compactionSpan) {
@@ -361,7 +367,13 @@ function createV2Tracing(config, eventShipper, traceShipper, sessionLookup) {
361
367
  state.stepSpans.set(data.assistantMessageID, {
362
368
  span,
363
369
  providerID: data.model.providerID,
364
- modelID: data.model.id
370
+ modelID: data.model.id,
371
+ // Kicked off here, awaited when the step closes: the lookup (bounded
372
+ // by its timeout) never delays the events streamed during the step.
373
+ promptTools: toolCatalog ? toolCatalog.resolve(data.sessionID, {
374
+ provider: data.model.providerID,
375
+ model: data.model.id
376
+ }) : Promise.resolve(void 0)
365
377
  });
366
378
  break;
367
379
  }
@@ -392,6 +404,7 @@ function createV2Tracing(config, eventShipper, traceShipper, sessionLookup) {
392
404
  if (reasoning !== void 0) {
393
405
  attrs.push(attrString("ai.reasoning.text", reasoning));
394
406
  }
407
+ attrs.push(...promptToolsAttributes(await step.promptTools));
395
408
  traceShipper.endSpan(step.span, { attributes: attrs });
396
409
  break;
397
410
  }
@@ -401,7 +414,10 @@ function createV2Tracing(config, eventShipper, traceShipper, sessionLookup) {
401
414
  const step = state == null ? void 0 : state.stepSpans.get(data.assistantMessageID);
402
415
  if (!state || !step) return;
403
416
  state.stepSpans.delete(data.assistantMessageID);
404
- traceShipper.endSpan(step.span, { error: errorString(data.error) });
417
+ traceShipper.endSpan(step.span, {
418
+ error: errorString(data.error),
419
+ attributes: promptToolsAttributes(await step.promptTools)
420
+ });
405
421
  break;
406
422
  }
407
423
  case "session.text.ended": {
@@ -577,6 +593,7 @@ function createV2Tracing(config, eventShipper, traceShipper, sessionLookup) {
577
593
  }
578
594
  }
579
595
  sessions.delete(event.data.sessionID);
596
+ toolCatalog == null ? void 0 : toolCatalog.forget(event.data.sessionID);
580
597
  break;
581
598
  }
582
599
  }
@@ -654,7 +671,7 @@ function raindrop(opts = {}) {
654
671
  }
655
672
  }
656
673
  function createShared(ctx) {
657
- var _a, _b, _c;
674
+ var _a, _b, _c, _d, _e;
658
675
  const config = loadConfig((_a = opts.directory) != null ? _a : ctx.location.directory);
659
676
  const resolvedLocalUrl = resolveLocalDebuggerBaseUrl(config.localWorkshopUrl);
660
677
  const hasLocalDestination = resolvedLocalUrl !== null;
@@ -687,18 +704,41 @@ function raindrop(opts = {}) {
687
704
  };
688
705
  const eventShipper = new EventShipper(shipperOptions);
689
706
  const traceShipper = new TraceShipper(shipperOptions);
707
+ const selfDiagnostics = normalizeSelfDiagnosticsConfig(
708
+ (_d = opts.selfDiagnostics) != null ? _d : config.selfDiagnostics
709
+ );
710
+ if (selfDiagnostics && !config.writeKey.trim()) {
711
+ appLog(
712
+ "warn",
713
+ `selfDiagnostics enabled but RAINDROP_WRITE_KEY is not set \u2014 the ${selfDiagnostics.toolName} tool is not registered (signals require the cloud destination).`
714
+ );
715
+ }
690
716
  const s = {
691
717
  eventShipper,
692
718
  traceShipper,
719
+ config,
720
+ selfDiagnostics: config.writeKey.trim() ? selfDiagnostics : void 0,
693
721
  appGitContext,
694
722
  abort: new AbortController(),
695
723
  instances: /* @__PURE__ */ new Set(),
696
- runtime: createV2Tracing(config, eventShipper, traceShipper, async (sessionID) => {
697
- const instance = firstInstance(s);
698
- if (!instance) return void 0;
699
- const info = await instance.ctx.session.get({ sessionID });
700
- return { parentID: info.parentID };
701
- })
724
+ runtime: createV2Tracing(
725
+ config,
726
+ eventShipper,
727
+ traceShipper,
728
+ async (sessionID) => {
729
+ const instance = firstInstance(s);
730
+ if (!instance) return void 0;
731
+ const info = await instance.ctx.session.get({ sessionID });
732
+ return { parentID: info.parentID };
733
+ },
734
+ createToolCatalog({
735
+ override: (_e = opts.tools) != null ? _e : config.tools,
736
+ // v2 exposes no per-model catalog endpoint; the registered tool list
737
+ // (after every plugin transform) is the closest observable catalog.
738
+ fetch: () => ctx.tool.list(),
739
+ debug: config.debug
740
+ })
741
+ )
702
742
  };
703
743
  return s;
704
744
  }
@@ -741,6 +781,34 @@ function raindrop(opts = {}) {
741
781
  const directory = ctx.location.directory;
742
782
  instance.disposables.push(await ctx.session.hook("prompt", (e) => runtime.onPrompt(e, directory)));
743
783
  instance.disposables.push(await ctx.session.hook("context", (e) => runtime.onContext(e)));
784
+ const selfDiagnostics = s.selfDiagnostics;
785
+ if (selfDiagnostics) {
786
+ const cfg = selfDiagnostics;
787
+ const eventShipper = s.eventShipper;
788
+ const debug = s.config.debug;
789
+ instance.disposables.push(
790
+ await ctx.tool.transform(
791
+ (editor) => editor.add({
792
+ name: cfg.toolName,
793
+ description: cfg.toolDescription,
794
+ input: selfDiagnosticsInputJsonSchema(cfg),
795
+ // Direct tool — the host routes everything else through the
796
+ // codemode `execute` wrapper, where this name isn't callable.
797
+ options: { codemode: false },
798
+ async execute(input, context) {
799
+ await trackSelfDiagnosticsSignal(
800
+ input,
801
+ cfg,
802
+ eventShipper,
803
+ runtime.currentEventId(context.sessionID),
804
+ debug
805
+ );
806
+ return { content: SELF_DIAGNOSTICS_ACK };
807
+ }
808
+ })
809
+ )
810
+ );
811
+ }
744
812
  if (isFirst) void runEventLoop(s);
745
813
  const owner = s;
746
814
  return async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raindrop-ai/opencode-plugin",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Raindrop observability plugin for OpenCode — automatic session/event/span tracing",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -55,7 +55,7 @@
55
55
  "@types/node": "^20.11.17",
56
56
  "tsup": "^8.4.0",
57
57
  "typescript": "^5.3.3",
58
- "@raindrop-ai/core": "0.3.0"
58
+ "@raindrop-ai/core": "0.3.1"
59
59
  },
60
60
  "tsup": {
61
61
  "entry": [