@raindrop-ai/claude-code 0.0.18 → 0.0.19

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
@@ -43,7 +43,7 @@ __export(src_exports, {
43
43
  });
44
44
  module.exports = __toCommonJS(src_exports);
45
45
 
46
- // ../core/dist/chunk-WKRW55KX.js
46
+ // ../core/dist/chunk-5PSWD267.js
47
47
  function getCrypto() {
48
48
  const c = globalThis.crypto;
49
49
  return c;
@@ -87,6 +87,20 @@ function base64Encode(bytes) {
87
87
  }
88
88
  return out;
89
89
  }
90
+ var HANDOFF_ATTRIBUTE_SUFFIXES = {
91
+ mode: "raindrop.handoff.mode",
92
+ childEventId: "raindrop.handoff.childEventId",
93
+ parentEventId: "raindrop.handoff.parentEventId",
94
+ parentSpanId: "raindrop.handoff.parentSpanId",
95
+ name: "raindrop.handoff.name",
96
+ terminal: "raindrop.handoff.terminal",
97
+ agentRole: "raindrop.agent.role"
98
+ };
99
+ var HANDOFF_TERMINAL_PROPERTY_KEY = HANDOFF_ATTRIBUTE_SUFFIXES.terminal;
100
+ var TRACEPARENT_HEADER = "traceparent";
101
+ var BAGGAGE_HEADER = "baggage";
102
+ var HANDOFF_HEADER = "x-raindrop-handoff";
103
+ var UNRESOLVED_CARRIER_WARNING = `[raindrop] resume: headers were supplied but no hand-off carrier was found on them (searched ${HANDOFF_HEADER}, ${TRACEPARENT_HEADER}, ${BAGGAGE_HEADER}). This run reports as an UNLINKED event, and the launcher that dispatched it will stay on "queued" forever because nothing ever references its child. Passing headers means a parent handed off, so no carrier on them is almost certainly a defect: a gateway or proxy stripping ${HANDOFF_HEADER}, a middleware overwriting ${BAGGAGE_HEADER}, a request forwarded without its headers, or a hand-built carrier whose field names do not match. Send every header the launcher's dispatch returned. Logged once per process; pass no headers for a directly-invoked sub-agent to silence it.`;
90
104
  function runWithTracingSuppressed(fn) {
91
105
  const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
92
106
  if (typeof hook !== "function") return fn();
@@ -377,26 +391,29 @@ function resolveLocalDebuggerBaseUrl(baseUrl) {
377
391
  if (shouldAutoEnableLocalWorkshop()) return DEFAULT_LOCAL_WORKSHOP_URL;
378
392
  return null;
379
393
  }
394
+ var LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS = 2e3;
380
395
  function mirrorTraceExportToLocalDebugger(body, options = {}) {
381
396
  var _a;
382
397
  const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
383
- if (!baseUrl) return;
384
- void postJson(`${baseUrl}traces`, body, {}, {
398
+ if (!baseUrl) return Promise.resolve();
399
+ return postJson(`${baseUrl}traces`, body, {}, {
385
400
  maxAttempts: 1,
386
401
  debug: (_a = options.debug) != null ? _a : false,
387
- sdkName: options.sdkName
402
+ sdkName: options.sdkName,
403
+ timeoutMs: LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS
388
404
  }).catch(() => {
389
405
  });
390
406
  }
391
407
  function mirrorPartialEventToLocalDebugger(event, options = {}) {
392
408
  var _a;
393
409
  const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
394
- if (!baseUrl) return;
410
+ if (!baseUrl) return Promise.resolve();
395
411
  const headers = options.writeKey ? { Authorization: `Bearer ${options.writeKey}` } : {};
396
- void postJson(`${baseUrl}events/track_partial`, event, headers, {
412
+ return postJson(`${baseUrl}events/track_partial`, event, headers, {
397
413
  maxAttempts: 1,
398
414
  debug: (_a = options.debug) != null ? _a : false,
399
- sdkName: options.sdkName
415
+ sdkName: options.sdkName,
416
+ timeoutMs: LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS
400
417
  }).catch(() => {
401
418
  });
402
419
  }
@@ -422,16 +439,52 @@ function projectIdHeaders(projectId) {
422
439
  var SHUTDOWN_DEADLINE_MS = 1e4;
423
440
  var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
424
441
  function mergePatches(target, source) {
425
- var _a, _b, _c, _d;
442
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
426
443
  const out = { ...target, ...source };
427
444
  if (target.properties || source.properties) {
428
445
  out.properties = { ...(_a = target.properties) != null ? _a : {}, ...(_b = source.properties) != null ? _b : {} };
429
446
  }
447
+ if (target.usage || source.usage) {
448
+ out.usage = { ...(_c = target.usage) != null ? _c : {} };
449
+ if (((_d = source.usage) == null ? void 0 : _d.promptTokens) !== void 0) {
450
+ out.usage.promptTokens = source.usage.promptTokens;
451
+ }
452
+ if (((_e = source.usage) == null ? void 0 : _e.completionTokens) !== void 0) {
453
+ out.usage.completionTokens = source.usage.completionTokens;
454
+ }
455
+ }
456
+ if (source.error === void 0) {
457
+ out.error = target.error;
458
+ }
459
+ if (target.featureFlags || source.featureFlags) {
460
+ out.featureFlags = { ...(_f = target.featureFlags) != null ? _f : {}, ...(_g = source.featureFlags) != null ? _g : {} };
461
+ }
430
462
  if (target.attachments || source.attachments) {
431
- out.attachments = [...(_c = target.attachments) != null ? _c : [], ...(_d = source.attachments) != null ? _d : []];
463
+ out.attachments = [...(_h = target.attachments) != null ? _h : [], ...(_i = source.attachments) != null ? _i : []];
432
464
  }
433
465
  return out;
434
466
  }
467
+ function isErrorLike(value) {
468
+ return value !== null && typeof value === "object";
469
+ }
470
+ function eventTelemetryProperties(patch) {
471
+ var _a, _b;
472
+ const properties = {};
473
+ if (((_a = patch.usage) == null ? void 0 : _a.promptTokens) !== void 0 && Number.isFinite(patch.usage.promptTokens)) {
474
+ properties["ai.usage.prompt_tokens"] = patch.usage.promptTokens;
475
+ }
476
+ if (((_b = patch.usage) == null ? void 0 : _b.completionTokens) !== void 0 && Number.isFinite(patch.usage.completionTokens)) {
477
+ properties["ai.usage.completion_tokens"] = patch.usage.completionTokens;
478
+ }
479
+ if (patch.error !== void 0 && patch.error !== null) {
480
+ const constructorName = patch.error instanceof Error && patch.error.constructor !== Error ? patch.error.constructor.name : void 0;
481
+ const errorType = patch.error instanceof Error ? patch.error.name && patch.error.name !== "Error" ? patch.error.name : constructorName || patch.error.name || "Error" : isErrorLike(patch.error) && typeof patch.error.name === "string" && patch.error.name.length > 0 ? patch.error.name : "Error";
482
+ const errorMessage = patch.error instanceof Error ? patch.error.message : isErrorLike(patch.error) && typeof patch.error.message === "string" ? patch.error.message : String(patch.error);
483
+ properties["error.type"] = errorType;
484
+ properties["error.message"] = errorMessage;
485
+ }
486
+ return properties;
487
+ }
435
488
  var EventShipper = class {
436
489
  constructor(opts) {
437
490
  this.buffers = /* @__PURE__ */ new Map();
@@ -680,6 +733,11 @@ var EventShipper = class {
680
733
  return;
681
734
  }
682
735
  const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
736
+ let telemetryProperties = {};
737
+ try {
738
+ telemetryProperties = eventTelemetryProperties(accumulated);
739
+ } catch (e) {
740
+ }
683
741
  const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
684
742
  const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
685
743
  const payload = {
@@ -689,15 +747,17 @@ var EventShipper = class {
689
747
  timestamp: (_i = accumulated.timestamp) != null ? _i : (/* @__PURE__ */ new Date()).toISOString(),
690
748
  ai_data: {
691
749
  input: accumulated.input,
692
- output: accumulated.output,
750
+ output: accumulated.error !== void 0 && accumulated.error !== null ? void 0 : accumulated.output,
693
751
  model: accumulated.model,
694
752
  convo_id: convoId
695
753
  },
696
754
  properties: {
697
755
  ...restProperties,
756
+ ...telemetryProperties,
698
757
  ...wizardSession ? { "raindrop.wizardSession": wizardSession } : {},
699
758
  $context: this.context
700
759
  },
760
+ ...accumulated.featureFlags && Object.keys(accumulated.featureFlags).length > 0 ? { feature_flags: accumulated.featureFlags } : {},
701
761
  attachments: accumulated.attachments,
702
762
  is_pending: isPending
703
763
  };
@@ -721,29 +781,30 @@ var EventShipper = class {
721
781
  endpoint: url
722
782
  });
723
783
  }
724
- if (this.localDebuggerUrl) {
725
- mirrorPartialEventToLocalDebugger(payload, {
726
- baseUrl: this.localDebuggerUrl,
727
- writeKey: this.writeKey,
728
- debug: this.debug,
729
- sdkName: this.sdkName
730
- });
731
- }
784
+ const mirror = this.localDebuggerUrl ? mirrorPartialEventToLocalDebugger(payload, {
785
+ baseUrl: this.localDebuggerUrl,
786
+ writeKey: this.writeKey,
787
+ debug: this.debug,
788
+ sdkName: this.sdkName
789
+ }) : void 0;
732
790
  if (!this.writeKey) {
733
791
  if (!isPending) this.sticky.delete(eventId);
792
+ if (mirror) await mirror;
734
793
  return;
735
794
  }
736
795
  const opts = this.requestOpts();
737
796
  if (!opts) {
738
797
  this.warnShutdownDrop(`track_partial ${eventId}`);
739
798
  if (!isPending) this.sticky.delete(eventId);
799
+ if (mirror) await mirror;
740
800
  return;
741
801
  }
742
802
  const p = postJson(url, payload, this.requestHeaders(), opts);
743
- this.inFlight.add(p);
803
+ const combined = mirror ? Promise.all([mirror, p]).then(() => void 0) : p;
804
+ this.inFlight.add(combined);
744
805
  try {
745
806
  try {
746
- await p;
807
+ await combined;
747
808
  if (this.debug) {
748
809
  console.log(`${this.prefix} sent track_partial ${eventId} (${eventName})`);
749
810
  }
@@ -755,13 +816,156 @@ var EventShipper = class {
755
816
  );
756
817
  }
757
818
  } finally {
758
- this.inFlight.delete(p);
819
+ this.inFlight.delete(combined);
759
820
  }
760
821
  if (!isPending) {
761
822
  this.sticky.delete(eventId);
762
823
  }
763
824
  }
764
825
  };
826
+ var MODEL_USAGE_ATTRIBUTES = {
827
+ usageSource: "raindrop.usage.source",
828
+ providerName: "gen_ai.provider.name",
829
+ requestModel: "gen_ai.request.model",
830
+ responseModel: "gen_ai.response.model",
831
+ inputTokens: "gen_ai.usage.input_tokens",
832
+ outputTokens: "gen_ai.usage.output_tokens",
833
+ reasoningTokens: "gen_ai.usage.reasoning_tokens",
834
+ cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
835
+ cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
836
+ providerReportedCost: "gen_ai.usage.provider_reported_cost",
837
+ nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
838
+ nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
839
+ totalOutputTokens: "raindrop.usage.output_tokens.total",
840
+ reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
841
+ cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
842
+ cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
843
+ };
844
+ var MODEL_PROVIDER_NAMES = [
845
+ ["google.vertex.anthropic", "google-vertex"],
846
+ ["google.vertex_ai", "google-vertex"],
847
+ ["google.vertex", "google-vertex"],
848
+ ["gcp.vertex_ai", "google-vertex"],
849
+ ["gcp.gemini", "google"],
850
+ ["google_vertexai", "google-vertex"],
851
+ ["vertex.anthropic", "google-vertex"],
852
+ ["amazon-bedrock", "amazon-bedrock"],
853
+ ["aws.bedrock", "amazon-bedrock"],
854
+ ["bedrock", "amazon-bedrock"],
855
+ ["anthropic", "anthropic"],
856
+ ["openai", "openai"],
857
+ ["google", "google"],
858
+ ["az.ai.openai", "azure"],
859
+ ["azure", "azure"],
860
+ ["openrouter", "openrouter"]
861
+ ];
862
+ function canonicalModelProvider(provider) {
863
+ var _a;
864
+ const normalizedProvider = provider.trim().toLowerCase();
865
+ if (normalizedProvider === "gateway") return "vercel";
866
+ const match = MODEL_PROVIDER_NAMES.find(
867
+ ([family]) => normalizedProvider === family || normalizedProvider.startsWith(`${family}.`)
868
+ );
869
+ return (_a = match == null ? void 0 : match[1]) != null ? _a : normalizedProvider;
870
+ }
871
+ var STRING_ALIASES = {
872
+ [MODEL_USAGE_ATTRIBUTES.requestModel]: ["ai.model.id", "ai.model"]
873
+ };
874
+ var NUMBER_ALIASES = {
875
+ [MODEL_USAGE_ATTRIBUTES.inputTokens]: [
876
+ "gen_ai.usage.prompt_tokens",
877
+ "ai.usage.prompt_tokens",
878
+ "ai.usage.promptTokens",
879
+ "ai.usage.input_tokens",
880
+ "ai.usage.inputTokens"
881
+ ],
882
+ [MODEL_USAGE_ATTRIBUTES.outputTokens]: [
883
+ "gen_ai.usage.completion_tokens",
884
+ "ai.usage.completion_tokens",
885
+ "ai.usage.completionTokens",
886
+ "ai.usage.output_tokens",
887
+ "ai.usage.outputTokens"
888
+ ],
889
+ [MODEL_USAGE_ATTRIBUTES.reasoningTokens]: [
890
+ "gen_ai.usage.reasoning.output_tokens",
891
+ "ai.usage.reasoningTokens",
892
+ "ai.usage.thoughts_tokens"
893
+ ],
894
+ [MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens]: [
895
+ "gen_ai.usage.cache_read_tokens",
896
+ "gen_ai.usage.cache_read.input_tokens",
897
+ "ai.usage.cachedInputTokens",
898
+ "ai.usage.cached_tokens",
899
+ "ai.usage.cache_read_tokens",
900
+ "ai.usage.cache_read_input_tokens",
901
+ "ai.usage.cacheReadInputTokens"
902
+ ],
903
+ [MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens]: [
904
+ "gen_ai.usage.cache_creation_input_tokens",
905
+ "gen_ai.usage.cache_creation.input_tokens",
906
+ "ai.usage.cacheWriteInputTokens",
907
+ "ai.usage.cache_creation_input_tokens",
908
+ "ai.usage.cacheCreationInputTokens"
909
+ ]
910
+ };
911
+ function hasAttribute(attributes, key) {
912
+ return attributes.some((attribute) => attribute.key === key);
913
+ }
914
+ function findStringAttribute(attributes, keys) {
915
+ return attributes.find(
916
+ (attribute) => keys.includes(attribute.key) && typeof attribute.value.stringValue === "string" && attribute.value.stringValue.length > 0
917
+ );
918
+ }
919
+ function findNumberAttribute(attributes, keys) {
920
+ return attributes.find((attribute) => {
921
+ if (!keys.includes(attribute.key)) return false;
922
+ if (typeof attribute.value.doubleValue === "number" && Number.isSafeInteger(attribute.value.doubleValue) && attribute.value.doubleValue >= 0) {
923
+ return true;
924
+ }
925
+ const intValue = attribute.value.intValue;
926
+ return integerValue(intValue) !== void 0;
927
+ });
928
+ }
929
+ function integerValue(value) {
930
+ if (typeof value === "number") {
931
+ return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
932
+ }
933
+ if (typeof value !== "string") return void 0;
934
+ const parsed = Number(value);
935
+ return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
936
+ }
937
+ function appendAlias(attributes, target, source) {
938
+ if (!source || hasAttribute(attributes, target)) return attributes;
939
+ return [...attributes, { key: target, value: { ...source.value } }];
940
+ }
941
+ function appendProviderAlias(attributes) {
942
+ if (hasAttribute(attributes, MODEL_USAGE_ATTRIBUTES.providerName)) return attributes;
943
+ const source = findStringAttribute(attributes, ["gen_ai.system", "ai.model.provider"]);
944
+ if (!(source == null ? void 0 : source.value.stringValue)) return attributes;
945
+ const attribute = attrString(
946
+ MODEL_USAGE_ATTRIBUTES.providerName,
947
+ canonicalModelProvider(source.value.stringValue)
948
+ );
949
+ return attribute ? [...attributes, attribute] : attributes;
950
+ }
951
+ function normalizeModelUsageSpan(span) {
952
+ const original = span.attributes;
953
+ if (!original || original.length === 0) return span;
954
+ const responseModel = findStringAttribute(original, [
955
+ MODEL_USAGE_ATTRIBUTES.responseModel,
956
+ "ai.response.model"
957
+ ]);
958
+ if (!responseModel) return span;
959
+ let attributes = appendAlias(original, MODEL_USAGE_ATTRIBUTES.responseModel, responseModel);
960
+ attributes = appendProviderAlias(attributes);
961
+ for (const [target, aliases] of Object.entries(STRING_ALIASES)) {
962
+ attributes = appendAlias(attributes, target, findStringAttribute(attributes, aliases));
963
+ }
964
+ for (const [target, aliases] of Object.entries(NUMBER_ALIASES)) {
965
+ attributes = appendAlias(attributes, target, findNumberAttribute(attributes, aliases));
966
+ }
967
+ return attributes === original ? span : { ...span, attributes };
968
+ }
765
969
  var DEFAULT_SECRET_KEY_NAMES = [
766
970
  "apikey",
767
971
  "apisecret",
@@ -851,6 +1055,13 @@ function redactJsonAttributeValue(key, value) {
851
1055
  if (scrubbedJson === json) return void 0;
852
1056
  return { stringValue: scrubbedJson };
853
1057
  }
1058
+ function identityAttrs(args) {
1059
+ return [
1060
+ attrString("ai.telemetry.metadata.raindrop.ai.userId", args.userId),
1061
+ attrString("ai.telemetry.metadata.raindrop.convoId", args.convoId),
1062
+ attrString("ai.telemetry.metadata.raindrop.eventName", args.eventName)
1063
+ ];
1064
+ }
854
1065
  function applyOtelSpanAttributeLimit(limit) {
855
1066
  var _a, _b;
856
1067
  try {
@@ -955,6 +1166,10 @@ var TraceShipper = class {
955
1166
  return null;
956
1167
  }
957
1168
  }
1169
+ try {
1170
+ current = normalizeModelUsageSpan(current);
1171
+ } catch (e) {
1172
+ }
958
1173
  if (!this.disableDefaultRedaction) {
959
1174
  current = defaultTransformSpan(current);
960
1175
  }
@@ -975,6 +1190,7 @@ var TraceShipper = class {
975
1190
  const started = (_a = args.startTimeUnixNano) != null ? _a : nowUnixNanoString();
976
1191
  const attrs = [
977
1192
  attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
1193
+ ...identityAttrs(args),
978
1194
  attrString("ai.operationId", args.operationId)
979
1195
  ];
980
1196
  if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
@@ -997,11 +1213,15 @@ var TraceShipper = class {
997
1213
  const redacted = this.redactSpan(span);
998
1214
  if (redacted === null) return;
999
1215
  const body = buildExportTraceServiceRequest([redacted], this.serviceName, this.serviceVersion);
1000
- mirrorTraceExportToLocalDebugger(body, {
1216
+ const p = mirrorTraceExportToLocalDebugger(body, {
1001
1217
  baseUrl: this.localDebuggerUrl,
1002
1218
  debug: false,
1003
1219
  sdkName: this.sdkName
1004
1220
  });
1221
+ this.inFlight.add(p);
1222
+ void p.finally(() => {
1223
+ this.inFlight.delete(p);
1224
+ });
1005
1225
  }
1006
1226
  endSpan(span, extra) {
1007
1227
  var _a, _b;
@@ -1030,7 +1250,8 @@ var TraceShipper = class {
1030
1250
  var _a;
1031
1251
  const ids = createSpanIds(args.parent);
1032
1252
  const attrs = [
1033
- attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId)
1253
+ attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
1254
+ ...identityAttrs(args)
1034
1255
  ];
1035
1256
  if ((_a = args.attributes) == null ? void 0 : _a.length) attrs.push(...args.attributes);
1036
1257
  const otlp = buildOtlpSpan({
@@ -1074,7 +1295,11 @@ var TraceShipper = class {
1074
1295
  }
1075
1296
  }
1076
1297
  async flush() {
1077
- if (!this.enabled) return;
1298
+ if (!this.enabled) {
1299
+ await Promise.all([...this.inFlight].map((p) => p.catch(() => {
1300
+ })));
1301
+ return;
1302
+ }
1078
1303
  if (this.timer) {
1079
1304
  clearTimeout(this.timer);
1080
1305
  this.timer = void 0;
@@ -1195,9 +1420,81 @@ function installTracingSuppressionHook() {
1195
1420
  }
1196
1421
  installTracingSuppressionHook();
1197
1422
 
1423
+ // package.json
1424
+ var package_default = {
1425
+ name: "@raindrop-ai/claude-code",
1426
+ version: "0.0.19",
1427
+ description: "Raindrop observability for Claude Code CLI \u2014 automatic session, tool call, and prompt tracing via hooks",
1428
+ license: "MIT",
1429
+ homepage: "https://www.raindrop.ai/docs/integrations/claude-code/",
1430
+ bugs: {
1431
+ url: "https://www.raindrop.ai/docs/support/"
1432
+ },
1433
+ type: "module",
1434
+ main: "dist/index.cjs",
1435
+ module: "dist/index.js",
1436
+ types: "dist/index.d.ts",
1437
+ bin: {
1438
+ "raindrop-claude-code": "dist/cli.js"
1439
+ },
1440
+ exports: {
1441
+ ".": {
1442
+ import: {
1443
+ types: "./dist/index.d.ts",
1444
+ default: "./dist/index.js"
1445
+ },
1446
+ require: {
1447
+ types: "./dist/index.d.cts",
1448
+ default: "./dist/index.cjs"
1449
+ }
1450
+ }
1451
+ },
1452
+ sideEffects: false,
1453
+ files: [
1454
+ "dist/**",
1455
+ "README.md",
1456
+ ".claude-plugin/**",
1457
+ "hooks/**",
1458
+ ".mcp.json"
1459
+ ],
1460
+ keywords: [
1461
+ "raindrop",
1462
+ "claude-code",
1463
+ "claude",
1464
+ "anthropic",
1465
+ "observability",
1466
+ "tracing",
1467
+ "hooks",
1468
+ "cli"
1469
+ ],
1470
+ engines: {
1471
+ node: ">=18"
1472
+ },
1473
+ scripts: {
1474
+ build: "tsup",
1475
+ postbuild: "chmod +x ./dist/cli.js && node ./scripts/sync-plugin-version.mjs",
1476
+ prepack: "node ./scripts/sync-plugin-version.mjs",
1477
+ dev: "tsup --watch",
1478
+ clean: "rm -rf dist",
1479
+ test: "pnpm build && cd tests && pnpm test",
1480
+ "test:watch": "cd tests && pnpm test:watch"
1481
+ },
1482
+ devDependencies: {
1483
+ "@raindrop-ai/core": "workspace:*",
1484
+ "@types/node": "^20.11.17",
1485
+ msw: "^2.12.7",
1486
+ tsup: "^8.4.0",
1487
+ typescript: "^5.3.3",
1488
+ vitest: "^2.1.0"
1489
+ },
1490
+ publishConfig: {
1491
+ access: "public"
1492
+ }
1493
+ };
1494
+
1198
1495
  // src/package-info.ts
1199
1496
  var PACKAGE_NAME = "@raindrop-ai/claude-code";
1200
- var PACKAGE_VERSION = "0.0.13";
1497
+ var PACKAGE_VERSION = package_default.version;
1201
1498
 
1202
1499
  // src/shipper.ts
1203
1500
  var EventShipper2 = class extends EventShipper {
@@ -2247,7 +2544,6 @@ var import_node_path3 = require("path");
2247
2544
  var DEFAULT_PORT = 5899;
2248
2545
  var DEFAULT_URL = `http://localhost:${DEFAULT_PORT}/v1/`;
2249
2546
  var HEALTH_TIMEOUT_MS = 300;
2250
- var MIRROR_TIMEOUT_MS = 2e3;
2251
2547
  var CACHE_DIR = (0, import_node_path3.join)((0, import_node_os3.tmpdir)(), "raindrop-claude-code");
2252
2548
  var CACHE_FILE = (0, import_node_path3.join)(CACHE_DIR, "debugger_cache");
2253
2549
  var CACHE_TTL_MS = 5e3;
@@ -2309,20 +2605,22 @@ async function detectLocalDebugger(debug) {
2309
2605
  }
2310
2606
  return { url: detected, autoDetected: detected !== null };
2311
2607
  }
2312
- function mirrorEventToLocalDebugger(baseUrl, payload, debug) {
2608
+ async function mirrorEventToLocalDebugger(baseUrl, payload, debug) {
2313
2609
  const url = `${baseUrl}events/track_partial`;
2314
2610
  if (debug) {
2315
2611
  console.log(`[raindrop-ai/claude-code] Mirroring event to local debugger: ${url}`);
2316
2612
  }
2317
- void runWithTracingSuppressed(
2318
- () => fetch(url, {
2319
- method: "POST",
2320
- headers: { "Content-Type": "application/json" },
2321
- body: JSON.stringify(payload),
2322
- signal: AbortSignal.timeout(MIRROR_TIMEOUT_MS)
2323
- })
2324
- ).catch(() => {
2325
- });
2613
+ try {
2614
+ await runWithTracingSuppressed(
2615
+ () => fetch(url, {
2616
+ method: "POST",
2617
+ headers: { "Content-Type": "application/json" },
2618
+ body: JSON.stringify(payload),
2619
+ signal: AbortSignal.timeout(LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS)
2620
+ })
2621
+ );
2622
+ } catch (e) {
2623
+ }
2326
2624
  }
2327
2625
 
2328
2626
  // src/mcp-serve.ts
package/dist/index.d.cts CHANGED
@@ -45,6 +45,10 @@ type IdentifyInput = {
45
45
  userId: string;
46
46
  traits?: Record<string, unknown>;
47
47
  };
48
+ type EventUsage = {
49
+ promptTokens?: number;
50
+ completionTokens?: number;
51
+ };
48
52
  type Patch = {
49
53
  eventName?: string;
50
54
  userId?: string;
@@ -52,7 +56,10 @@ type Patch = {
52
56
  input?: string;
53
57
  output?: string;
54
58
  model?: string;
59
+ usage?: EventUsage;
60
+ error?: unknown;
55
61
  properties?: Record<string, unknown>;
62
+ featureFlags?: Record<string, string>;
56
63
  attachments?: Attachment[];
57
64
  isPending?: boolean;
58
65
  timestamp?: string;
@@ -149,12 +156,7 @@ declare class EventShipper$1 {
149
156
  */
150
157
  private requestOpts;
151
158
  patch(eventId: string, patch: Patch): Promise<void>;
152
- finish(eventId: string, patch: {
153
- output?: string;
154
- model?: string;
155
- properties?: Record<string, unknown>;
156
- userId?: string;
157
- }): Promise<void>;
159
+ finish(eventId: string, patch: Pick<Patch, "output" | "model" | "usage" | "error" | "properties" | "featureFlags" | "userId">): Promise<void>;
158
160
  flush(): Promise<void>;
159
161
  shutdown(): Promise<void>;
160
162
  trackSignal(signal: SignalInput): Promise<void>;
@@ -327,6 +329,9 @@ declare class TraceShipper$1 {
327
329
  spanIdB64: string;
328
330
  };
329
331
  eventId: string;
332
+ userId?: string;
333
+ convoId?: string;
334
+ eventName?: string;
330
335
  operationId?: string;
331
336
  attributes?: Array<OtlpKeyValue | undefined>;
332
337
  startTimeUnixNano?: string;
@@ -345,6 +350,9 @@ declare class TraceShipper$1 {
345
350
  spanIdB64: string;
346
351
  };
347
352
  eventId: string;
353
+ userId?: string;
354
+ convoId?: string;
355
+ eventName?: string;
348
356
  startTimeUnixNano: string;
349
357
  endTimeUnixNano: string;
350
358
  attributes?: Array<OtlpKeyValue | undefined>;
@@ -525,7 +533,7 @@ declare function mapHookToRaindrop(payload: HookPayload, config: MapperConfig, e
525
533
  declare function extractAppendSystemPrompt(args: string[]): string | undefined;
526
534
 
527
535
  declare const PACKAGE_NAME = "@raindrop-ai/claude-code";
528
- declare const PACKAGE_VERSION = "0.0.13";
536
+ declare const PACKAGE_VERSION: string;
529
537
 
530
538
  /** A tool call extracted from an assistant message content block. */
531
539
  interface LLMToolCall {
@@ -619,9 +627,11 @@ interface LocalDebuggerResult {
619
627
  declare function detectLocalDebugger(debug: boolean): Promise<LocalDebuggerResult>;
620
628
  /**
621
629
  * Mirror an event payload to the local debugger's track_partial endpoint.
622
- * Fire-and-forget — errors are silently swallowed.
630
+ * Must be awaited: Claude Code hooks call process.exit as soon as handleHook
631
+ * returns, so a fire-and-forget fetch is killed before it leaves the socket.
632
+ * Errors are swallowed — observability must never fail the hook.
623
633
  */
624
- declare function mirrorEventToLocalDebugger(baseUrl: string, payload: Record<string, unknown>, debug: boolean): void;
634
+ declare function mirrorEventToLocalDebugger(baseUrl: string, payload: Record<string, unknown>, debug: boolean): Promise<void>;
625
635
 
626
636
  interface ResolvedSignal {
627
637
  description: string;