@raindrop-ai/claude-code 0.0.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/index.cjs ADDED
@@ -0,0 +1,1039 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ EventShipper: () => EventShipper2,
24
+ PACKAGE_NAME: () => PACKAGE_NAME,
25
+ PACKAGE_VERSION: () => PACKAGE_VERSION,
26
+ TraceShipper: () => TraceShipper2,
27
+ getConfigPath: () => getConfigPath,
28
+ loadConfig: () => loadConfig,
29
+ mapHookToRaindrop: () => mapHookToRaindrop
30
+ });
31
+ module.exports = __toCommonJS(src_exports);
32
+
33
+ // ../core/dist/chunk-H6VSZSLN.js
34
+ function getCrypto() {
35
+ const c = globalThis.crypto;
36
+ return c;
37
+ }
38
+ function randomBytes(length) {
39
+ const cryptoObj = getCrypto();
40
+ const out = new Uint8Array(length);
41
+ if (cryptoObj && typeof cryptoObj.getRandomValues === "function") {
42
+ cryptoObj.getRandomValues(out);
43
+ return out;
44
+ }
45
+ for (let i = 0; i < out.length; i++) out[i] = Math.floor(Math.random() * 256);
46
+ return out;
47
+ }
48
+ function base64Encode(bytes) {
49
+ const maybeBuffer = globalThis.Buffer;
50
+ if (maybeBuffer) {
51
+ return maybeBuffer.from(bytes).toString("base64");
52
+ }
53
+ let binary = "";
54
+ for (let i2 = 0; i2 < bytes.length; i2++) {
55
+ binary += String.fromCharCode(bytes[i2]);
56
+ }
57
+ const btoaFn = globalThis.btoa;
58
+ if (typeof btoaFn === "function") return btoaFn(binary);
59
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
60
+ let out = "";
61
+ let i = 0;
62
+ while (i < binary.length) {
63
+ const c1 = binary.charCodeAt(i++) & 255;
64
+ const c2 = i < binary.length ? binary.charCodeAt(i++) & 255 : NaN;
65
+ const c3 = i < binary.length ? binary.charCodeAt(i++) & 255 : NaN;
66
+ const e1 = c1 >> 2;
67
+ const e2 = (c1 & 3) << 4 | (Number.isNaN(c2) ? 0 : c2 >> 4);
68
+ const e3 = Number.isNaN(c2) ? 64 : (c2 & 15) << 2 | (Number.isNaN(c3) ? 0 : c3 >> 6);
69
+ const e4 = Number.isNaN(c3) ? 64 : c3 & 63;
70
+ out += alphabet.charAt(e1);
71
+ out += alphabet.charAt(e2);
72
+ out += e3 === 64 ? "=" : alphabet.charAt(e3);
73
+ out += e4 === 64 ? "=" : alphabet.charAt(e4);
74
+ }
75
+ return out;
76
+ }
77
+ function wait(ms) {
78
+ return new Promise((resolve) => setTimeout(resolve, ms));
79
+ }
80
+ function formatEndpoint(endpoint) {
81
+ if (!endpoint) return void 0;
82
+ return endpoint.endsWith("/") ? endpoint : `${endpoint}/`;
83
+ }
84
+ function parseRetryAfter(headers) {
85
+ var _a;
86
+ const value = (_a = headers.get("Retry-After")) != null ? _a : headers.get("retry-after");
87
+ if (!value) return void 0;
88
+ const asNumber = Number(value);
89
+ if (value.trim() !== "" && !Number.isNaN(asNumber)) return asNumber * 1e3;
90
+ const asDate = new Date(value).getTime();
91
+ if (!Number.isNaN(asDate)) {
92
+ const delta = asDate - Date.now();
93
+ return delta > 0 ? delta : 0;
94
+ }
95
+ return void 0;
96
+ }
97
+ function getRetryDelayMs(attemptNumber, previousError) {
98
+ if (previousError && typeof previousError === "object" && previousError !== null && "retryAfterMs" in previousError) {
99
+ const v = previousError.retryAfterMs;
100
+ if (typeof v === "number") return Math.max(0, v);
101
+ }
102
+ if (attemptNumber <= 1) return 0;
103
+ const base = 500;
104
+ const factor = Math.pow(2, attemptNumber - 2);
105
+ return base * factor;
106
+ }
107
+ async function withRetry(operation, opName, opts) {
108
+ const prefix = opts.sdkName ? `[raindrop-ai/${opts.sdkName}]` : "[raindrop-ai/core]";
109
+ let lastError = void 0;
110
+ for (let attemptNumber = 1; attemptNumber <= opts.maxAttempts; attemptNumber++) {
111
+ if (attemptNumber > 1) {
112
+ const delay = getRetryDelayMs(attemptNumber, lastError);
113
+ if (opts.debug) {
114
+ console.warn(
115
+ `${prefix} ${opName} retry ${attemptNumber}/${opts.maxAttempts} in ${delay}ms`
116
+ );
117
+ }
118
+ if (delay > 0) await wait(delay);
119
+ } else if (opts.debug) {
120
+ console.log(`${prefix} ${opName} attempt ${attemptNumber}/${opts.maxAttempts}`);
121
+ }
122
+ try {
123
+ return await operation();
124
+ } catch (err) {
125
+ lastError = err;
126
+ if (opts.debug) {
127
+ const msg = err instanceof Error ? err.message : String(err);
128
+ console.warn(
129
+ `${prefix} ${opName} attempt ${attemptNumber} failed: ${msg}${attemptNumber === opts.maxAttempts ? " (no more retries)" : ""}`
130
+ );
131
+ }
132
+ if (lastError && typeof lastError === "object" && "retryable" in lastError && !lastError.retryable)
133
+ break;
134
+ if (attemptNumber === opts.maxAttempts) break;
135
+ }
136
+ }
137
+ throw lastError instanceof Error ? lastError : new Error(String(lastError));
138
+ }
139
+ async function postJson(url, body, headers, opts) {
140
+ const opName = `POST ${url}`;
141
+ await withRetry(
142
+ async () => {
143
+ const resp = await fetch(url, {
144
+ method: "POST",
145
+ headers: {
146
+ "Content-Type": "application/json",
147
+ ...headers
148
+ },
149
+ body: JSON.stringify(body)
150
+ });
151
+ if (!resp.ok) {
152
+ const text = await resp.text().catch(() => "");
153
+ const err = new Error(
154
+ `HTTP ${resp.status} ${resp.statusText}${text ? `: ${text}` : ""}`
155
+ );
156
+ const retryAfterMs = parseRetryAfter(resp.headers);
157
+ if (typeof retryAfterMs === "number") err.retryAfterMs = retryAfterMs;
158
+ err.retryable = resp.status === 429 || resp.status >= 500;
159
+ throw err;
160
+ }
161
+ },
162
+ opName,
163
+ opts
164
+ );
165
+ }
166
+ var SpanStatusCode = {
167
+ UNSET: 0,
168
+ OK: 1,
169
+ ERROR: 2
170
+ };
171
+ function createSpanIds(parent) {
172
+ const traceId = parent ? parent.traceIdB64 : base64Encode(randomBytes(16));
173
+ const spanId = base64Encode(randomBytes(8));
174
+ return {
175
+ traceIdB64: traceId,
176
+ spanIdB64: spanId,
177
+ parentSpanIdB64: parent ? parent.spanIdB64 : void 0
178
+ };
179
+ }
180
+ function nowUnixNanoString() {
181
+ return Date.now().toString() + "000000";
182
+ }
183
+ function attrString(key, value) {
184
+ if (value === void 0) return void 0;
185
+ return { key, value: { stringValue: value } };
186
+ }
187
+ function attrInt(key, value) {
188
+ if (value === void 0) return void 0;
189
+ if (!Number.isFinite(value)) return void 0;
190
+ return { key, value: { intValue: String(Math.trunc(value)) } };
191
+ }
192
+ function buildOtlpSpan(args) {
193
+ const attrs = args.attributes.filter((x) => x !== void 0);
194
+ const span = {
195
+ traceId: args.ids.traceIdB64,
196
+ spanId: args.ids.spanIdB64,
197
+ name: args.name,
198
+ startTimeUnixNano: args.startTimeUnixNano,
199
+ endTimeUnixNano: args.endTimeUnixNano
200
+ };
201
+ if (args.ids.parentSpanIdB64) span.parentSpanId = args.ids.parentSpanIdB64;
202
+ if (attrs.length) span.attributes = attrs;
203
+ if (args.status) span.status = args.status;
204
+ return span;
205
+ }
206
+ function buildExportTraceServiceRequest(spans, serviceName = "raindrop.core", serviceVersion = "0.0.0") {
207
+ return {
208
+ resourceSpans: [
209
+ {
210
+ resource: {
211
+ attributes: [{ key: "service.name", value: { stringValue: serviceName } }]
212
+ },
213
+ scopeSpans: [
214
+ {
215
+ scope: { name: serviceName, version: serviceVersion },
216
+ spans
217
+ }
218
+ ]
219
+ }
220
+ ]
221
+ };
222
+ }
223
+ function mergePatches(target, source) {
224
+ var _a, _b, _c, _d;
225
+ const out = { ...target, ...source };
226
+ if (target.properties || source.properties) {
227
+ out.properties = { ...(_a = target.properties) != null ? _a : {}, ...(_b = source.properties) != null ? _b : {} };
228
+ }
229
+ if (target.attachments || source.attachments) {
230
+ out.attachments = [...(_c = target.attachments) != null ? _c : [], ...(_d = source.attachments) != null ? _d : []];
231
+ }
232
+ return out;
233
+ }
234
+ var EventShipper = class {
235
+ constructor(opts) {
236
+ this.buffers = /* @__PURE__ */ new Map();
237
+ this.sticky = /* @__PURE__ */ new Map();
238
+ this.timers = /* @__PURE__ */ new Map();
239
+ this.inFlight = /* @__PURE__ */ new Set();
240
+ var _a, _b, _c, _d, _e, _f, _g;
241
+ this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
242
+ this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
243
+ this.enabled = opts.enabled !== false;
244
+ this.debug = opts.debug;
245
+ this.partialFlushMs = (_c = opts.partialFlushMs) != null ? _c : 1e3;
246
+ this.sdkName = (_d = opts.sdkName) != null ? _d : "core";
247
+ this.prefix = `[raindrop-ai/${this.sdkName}]`;
248
+ this.defaultEventName = (_e = opts.defaultEventName) != null ? _e : "ai_generation";
249
+ const isNode = typeof process !== "undefined" && typeof process.version === "string";
250
+ this.context = {
251
+ library: {
252
+ name: (_f = opts.libraryName) != null ? _f : "@raindrop-ai/core",
253
+ version: (_g = opts.libraryVersion) != null ? _g : "0.0.0"
254
+ },
255
+ metadata: {
256
+ jsRuntime: isNode ? "node" : "web",
257
+ ...isNode ? { nodeVersion: process.version } : {}
258
+ }
259
+ };
260
+ }
261
+ isDebugEnabled() {
262
+ return this.debug;
263
+ }
264
+ authHeaders() {
265
+ return this.writeKey ? { Authorization: `Bearer ${this.writeKey}` } : {};
266
+ }
267
+ async patch(eventId, patch) {
268
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
269
+ if (!this.enabled) return;
270
+ if (!eventId || !eventId.trim()) return;
271
+ if (this.debug) {
272
+ console.log(`${this.prefix} queue patch`, {
273
+ eventId,
274
+ userId: patch.userId,
275
+ convoId: patch.convoId,
276
+ eventName: patch.eventName,
277
+ hasInput: typeof patch.input === "string" && patch.input.length > 0,
278
+ hasOutput: typeof patch.output === "string" && patch.output.length > 0,
279
+ attachments: (_b = (_a = patch.attachments) == null ? void 0 : _a.length) != null ? _b : 0,
280
+ isPending: patch.isPending
281
+ });
282
+ }
283
+ const sticky = (_c = this.sticky.get(eventId)) != null ? _c : {};
284
+ const existing = (_d = this.buffers.get(eventId)) != null ? _d : {};
285
+ const merged = mergePatches(existing, patch);
286
+ merged.isPending = (_g = (_f = (_e = patch.isPending) != null ? _e : existing.isPending) != null ? _f : sticky.isPending) != null ? _g : true;
287
+ this.buffers.set(eventId, merged);
288
+ this.sticky.set(eventId, {
289
+ userId: (_h = merged.userId) != null ? _h : sticky.userId,
290
+ convoId: (_i = merged.convoId) != null ? _i : sticky.convoId,
291
+ eventName: (_j = merged.eventName) != null ? _j : sticky.eventName,
292
+ isPending: (_k = merged.isPending) != null ? _k : sticky.isPending
293
+ });
294
+ const t = this.timers.get(eventId);
295
+ if (t) clearTimeout(t);
296
+ if (merged.isPending === false) {
297
+ await this.flushOne(eventId);
298
+ return;
299
+ }
300
+ const timeout = setTimeout(() => {
301
+ void this.flushOne(eventId).catch(() => {
302
+ });
303
+ }, this.partialFlushMs);
304
+ this.timers.set(eventId, timeout);
305
+ }
306
+ async finish(eventId, patch) {
307
+ await this.patch(eventId, { ...patch, isPending: false });
308
+ }
309
+ async flush() {
310
+ if (!this.enabled) return;
311
+ const ids = [...this.buffers.keys()];
312
+ await Promise.all(ids.map((id) => this.flushOne(id)));
313
+ await Promise.all([...this.inFlight].map((p) => p.catch(() => {
314
+ })));
315
+ }
316
+ async shutdown() {
317
+ for (const t of this.timers.values()) clearTimeout(t);
318
+ this.timers.clear();
319
+ await this.flush();
320
+ }
321
+ async trackSignal(signal) {
322
+ var _a, _b;
323
+ if (!this.enabled) return;
324
+ const body = [
325
+ {
326
+ event_id: signal.eventId,
327
+ signal_name: signal.name,
328
+ signal_type: (_a = signal.type) != null ? _a : "default",
329
+ timestamp: signal.timestamp,
330
+ sentiment: signal.sentiment,
331
+ attachment_id: signal.attachmentId,
332
+ properties: {
333
+ ...(_b = signal.properties) != null ? _b : {},
334
+ ...signal.comment ? { comment: signal.comment } : {},
335
+ ...signal.after ? { after: signal.after } : {}
336
+ }
337
+ }
338
+ ];
339
+ const url = `${this.baseUrl}signals/track`;
340
+ try {
341
+ await postJson(url, body, this.authHeaders(), {
342
+ maxAttempts: 3,
343
+ debug: this.debug,
344
+ sdkName: this.sdkName
345
+ });
346
+ } catch (err) {
347
+ const msg = err instanceof Error ? err.message : String(err);
348
+ console.warn(`${this.prefix} failed to send signal (dropping): ${msg}`);
349
+ }
350
+ }
351
+ async identify(users) {
352
+ if (!this.enabled) return;
353
+ const list = Array.isArray(users) ? users : [users];
354
+ const body = list.filter((user) => {
355
+ if (!(user == null ? void 0 : user.userId) || !user.userId.trim()) {
356
+ if (this.debug) {
357
+ console.warn(`${this.prefix} skipping identify: missing userId`);
358
+ }
359
+ return false;
360
+ }
361
+ return true;
362
+ }).map((user) => {
363
+ var _a;
364
+ return {
365
+ user_id: user.userId,
366
+ traits: (_a = user.traits) != null ? _a : {}
367
+ };
368
+ });
369
+ if (body.length === 0) return;
370
+ const url = `${this.baseUrl}users/identify`;
371
+ try {
372
+ await postJson(url, body, this.authHeaders(), {
373
+ maxAttempts: 3,
374
+ debug: this.debug,
375
+ sdkName: this.sdkName
376
+ });
377
+ } catch (err) {
378
+ const msg = err instanceof Error ? err.message : String(err);
379
+ console.warn(`${this.prefix} failed to send identify (dropping): ${msg}`);
380
+ }
381
+ }
382
+ async flushOne(eventId) {
383
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
384
+ if (!this.enabled) return;
385
+ const timer = this.timers.get(eventId);
386
+ if (timer) {
387
+ clearTimeout(timer);
388
+ this.timers.delete(eventId);
389
+ }
390
+ const accumulated = this.buffers.get(eventId);
391
+ this.buffers.delete(eventId);
392
+ if (!accumulated) return;
393
+ const sticky = (_a = this.sticky.get(eventId)) != null ? _a : {};
394
+ const eventName = (_c = (_b = accumulated.eventName) != null ? _b : sticky.eventName) != null ? _c : this.defaultEventName;
395
+ const userId = (_d = accumulated.userId) != null ? _d : sticky.userId;
396
+ if (!userId) {
397
+ if (this.debug) {
398
+ console.warn(`${this.prefix} skipping track_partial for ${eventId}: missing userId`);
399
+ }
400
+ this.sticky.delete(eventId);
401
+ return;
402
+ }
403
+ const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
404
+ const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
405
+ const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
406
+ const payload = {
407
+ event_id: eventId,
408
+ user_id: userId,
409
+ event: eventName,
410
+ timestamp: (_i = accumulated.timestamp) != null ? _i : (/* @__PURE__ */ new Date()).toISOString(),
411
+ ai_data: {
412
+ input: accumulated.input,
413
+ output: accumulated.output,
414
+ model: accumulated.model,
415
+ convo_id: convoId
416
+ },
417
+ properties: {
418
+ ...restProperties,
419
+ ...wizardSession ? { "raindrop.wizardSession": wizardSession } : {},
420
+ $context: this.context
421
+ },
422
+ attachments: accumulated.attachments,
423
+ is_pending: isPending
424
+ };
425
+ const url = `${this.baseUrl}events/track_partial`;
426
+ if (this.debug) {
427
+ console.log(`${this.prefix} sending track_partial`, {
428
+ eventId,
429
+ eventName,
430
+ userId,
431
+ convoId,
432
+ isPending,
433
+ inputPreview: typeof accumulated.input === "string" ? accumulated.input.slice(0, 120) : void 0,
434
+ outputPreview: typeof accumulated.output === "string" ? accumulated.output.slice(0, 120) : void 0,
435
+ attachments: (_k = (_j = accumulated.attachments) == null ? void 0 : _j.length) != null ? _k : 0,
436
+ attachmentKinds: (_m = (_l = accumulated.attachments) == null ? void 0 : _l.map((a) => ({
437
+ type: a.type,
438
+ role: a.role,
439
+ name: a.name,
440
+ valuePreview: a.value.slice(0, 60)
441
+ }))) != null ? _m : [],
442
+ endpoint: url
443
+ });
444
+ }
445
+ const p = postJson(url, payload, this.authHeaders(), {
446
+ maxAttempts: 3,
447
+ debug: this.debug,
448
+ sdkName: this.sdkName
449
+ });
450
+ this.inFlight.add(p);
451
+ try {
452
+ try {
453
+ await p;
454
+ if (this.debug) {
455
+ console.log(`${this.prefix} sent track_partial ${eventId} (${eventName})`);
456
+ }
457
+ } catch (err) {
458
+ const msg = err instanceof Error ? err.message : String(err);
459
+ console.warn(`${this.prefix} failed to send track_partial (dropping): ${msg}`);
460
+ }
461
+ } finally {
462
+ this.inFlight.delete(p);
463
+ }
464
+ if (!isPending) {
465
+ this.sticky.delete(eventId);
466
+ }
467
+ }
468
+ };
469
+ var TraceShipper = class {
470
+ constructor(opts) {
471
+ this.queue = [];
472
+ this.inFlight = /* @__PURE__ */ new Set();
473
+ var _a, _b, _c, _d, _e, _f, _g, _h;
474
+ this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
475
+ this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
476
+ this.enabled = opts.enabled !== false;
477
+ this.debug = opts.debug;
478
+ this.debugSpans = opts.debugSpans === true;
479
+ this.flushIntervalMs = (_c = opts.flushIntervalMs) != null ? _c : 1e3;
480
+ this.maxBatchSize = (_d = opts.maxBatchSize) != null ? _d : 50;
481
+ this.maxQueueSize = (_e = opts.maxQueueSize) != null ? _e : 5e3;
482
+ this.sdkName = (_f = opts.sdkName) != null ? _f : "core";
483
+ this.prefix = `[raindrop-ai/${this.sdkName}]`;
484
+ this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
485
+ this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
486
+ }
487
+ isDebugEnabled() {
488
+ return this.debug;
489
+ }
490
+ authHeaders() {
491
+ return this.writeKey ? { Authorization: `Bearer ${this.writeKey}` } : {};
492
+ }
493
+ startSpan(args) {
494
+ var _a, _b;
495
+ const ids = createSpanIds(args.parent);
496
+ const started = (_a = args.startTimeUnixNano) != null ? _a : nowUnixNanoString();
497
+ const attrs = [
498
+ attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
499
+ attrString("ai.operationId", args.operationId)
500
+ ];
501
+ if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
502
+ return { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
503
+ }
504
+ endSpan(span, extra) {
505
+ var _a, _b;
506
+ if (span.endTimeUnixNano) return;
507
+ span.endTimeUnixNano = (_a = extra == null ? void 0 : extra.endTimeUnixNano) != null ? _a : nowUnixNanoString();
508
+ if ((_b = extra == null ? void 0 : extra.attributes) == null ? void 0 : _b.length) {
509
+ span.attributes.push(...extra.attributes);
510
+ }
511
+ let status = extra == null ? void 0 : extra.status;
512
+ if (!status && (extra == null ? void 0 : extra.error) !== void 0) {
513
+ const message = extra.error instanceof Error ? extra.error.message : String(extra.error);
514
+ status = { code: SpanStatusCode.ERROR, message };
515
+ }
516
+ const otlp = buildOtlpSpan({
517
+ ids: span.ids,
518
+ name: span.name,
519
+ startTimeUnixNano: span.startTimeUnixNano,
520
+ endTimeUnixNano: span.endTimeUnixNano,
521
+ attributes: span.attributes,
522
+ status
523
+ });
524
+ this.enqueue(otlp);
525
+ }
526
+ createSpan(args) {
527
+ var _a;
528
+ const ids = createSpanIds(args.parent);
529
+ const attrs = [
530
+ attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId)
531
+ ];
532
+ if ((_a = args.attributes) == null ? void 0 : _a.length) attrs.push(...args.attributes);
533
+ const otlp = buildOtlpSpan({
534
+ ids,
535
+ name: args.name,
536
+ startTimeUnixNano: args.startTimeUnixNano,
537
+ endTimeUnixNano: args.endTimeUnixNano,
538
+ attributes: attrs,
539
+ status: args.status
540
+ });
541
+ this.enqueue(otlp);
542
+ }
543
+ enqueue(span) {
544
+ if (!this.enabled) return;
545
+ if (this.debugSpans) {
546
+ const short = (s) => s ? s.slice(-8) : "none";
547
+ console.log(
548
+ `${this.prefix}[span] name=${span.name} trace=${short(span.traceId)} span=${short(span.spanId)} parent=${short(
549
+ span.parentSpanId
550
+ )}`
551
+ );
552
+ }
553
+ if (this.queue.length >= this.maxQueueSize) {
554
+ this.queue.shift();
555
+ }
556
+ this.queue.push(span);
557
+ if (this.queue.length >= this.maxBatchSize) {
558
+ void this.flush().catch(() => {
559
+ });
560
+ return;
561
+ }
562
+ if (!this.timer) {
563
+ this.timer = setTimeout(() => {
564
+ this.timer = void 0;
565
+ void this.flush().catch(() => {
566
+ });
567
+ }, this.flushIntervalMs);
568
+ }
569
+ }
570
+ async flush() {
571
+ if (!this.enabled) return;
572
+ if (this.timer) {
573
+ clearTimeout(this.timer);
574
+ this.timer = void 0;
575
+ }
576
+ while (this.queue.length > 0) {
577
+ const batch = this.queue.splice(0, this.maxBatchSize);
578
+ const body = buildExportTraceServiceRequest(batch, this.serviceName, this.serviceVersion);
579
+ const url = `${this.baseUrl}traces`;
580
+ if (this.debug) {
581
+ console.log(`${this.prefix} sending traces batch`, {
582
+ spans: batch.length,
583
+ endpoint: url
584
+ });
585
+ }
586
+ const p = postJson(url, body, this.authHeaders(), {
587
+ maxAttempts: 3,
588
+ debug: this.debug,
589
+ sdkName: this.sdkName
590
+ });
591
+ this.inFlight.add(p);
592
+ try {
593
+ try {
594
+ await p;
595
+ if (this.debug) console.log(`${this.prefix} sent ${batch.length} spans`);
596
+ } catch (err) {
597
+ const msg = err instanceof Error ? err.message : String(err);
598
+ console.warn(`${this.prefix} failed to send ${batch.length} spans: ${msg}`);
599
+ }
600
+ } finally {
601
+ this.inFlight.delete(p);
602
+ }
603
+ }
604
+ }
605
+ async shutdown() {
606
+ if (this.timer) {
607
+ clearTimeout(this.timer);
608
+ this.timer = void 0;
609
+ }
610
+ await this.flush();
611
+ await Promise.all([...this.inFlight].map((p) => p.catch(() => {
612
+ })));
613
+ }
614
+ };
615
+
616
+ // ../core/dist/index.node.js
617
+ var import_async_hooks = require("async_hooks");
618
+ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = import_async_hooks.AsyncLocalStorage;
619
+
620
+ // src/package-info.ts
621
+ var PACKAGE_NAME = "@raindrop-ai/claude-code";
622
+ var PACKAGE_VERSION = "0.0.1";
623
+
624
+ // src/shipper.ts
625
+ var EventShipper2 = class extends EventShipper {
626
+ constructor(opts) {
627
+ var _a, _b, _c, _d;
628
+ super({
629
+ ...opts,
630
+ sdkName: (_a = opts.sdkName) != null ? _a : "claude-code",
631
+ libraryName: (_b = opts.libraryName) != null ? _b : PACKAGE_NAME,
632
+ libraryVersion: (_c = opts.libraryVersion) != null ? _c : PACKAGE_VERSION,
633
+ defaultEventName: (_d = opts.defaultEventName) != null ? _d : "claude_code_session"
634
+ });
635
+ }
636
+ };
637
+ var TraceShipper2 = class extends TraceShipper {
638
+ constructor(opts) {
639
+ var _a, _b, _c;
640
+ super({
641
+ ...opts,
642
+ sdkName: (_a = opts.sdkName) != null ? _a : "claude-code",
643
+ serviceName: (_b = opts.serviceName) != null ? _b : "raindrop.claude-code",
644
+ serviceVersion: (_c = opts.serviceVersion) != null ? _c : PACKAGE_VERSION
645
+ });
646
+ }
647
+ enqueue(span) {
648
+ var _a;
649
+ const attrs = (_a = span.attributes) != null ? _a : [];
650
+ attrs.unshift(
651
+ { key: "span.id", value: { stringValue: span.spanId } },
652
+ ...span.parentSpanId ? [{ key: "span.parent.id", value: { stringValue: span.parentSpanId } }] : []
653
+ );
654
+ span.attributes = attrs;
655
+ super.enqueue(span);
656
+ }
657
+ };
658
+
659
+ // src/config.ts
660
+ var import_node_fs = require("fs");
661
+ var import_node_os = require("os");
662
+ var import_node_path = require("path");
663
+ var CONFIG_PATH = (0, import_node_path.join)((0, import_node_os.homedir)(), ".config", "raindrop", "config.json");
664
+ function loadConfig() {
665
+ var _a, _b, _c, _d, _e, _f, _g;
666
+ let file = {};
667
+ try {
668
+ if ((0, import_node_fs.existsSync)(CONFIG_PATH)) {
669
+ file = JSON.parse((0, import_node_fs.readFileSync)(CONFIG_PATH, "utf-8"));
670
+ }
671
+ } catch (e) {
672
+ }
673
+ const systemUser = (() => {
674
+ try {
675
+ return (0, import_node_os.userInfo)().username;
676
+ } catch (e) {
677
+ return "unknown";
678
+ }
679
+ })();
680
+ return {
681
+ writeKey: (_b = (_a = process.env["RAINDROP_WRITE_KEY"]) != null ? _a : file.write_key) != null ? _b : "",
682
+ endpoint: (_d = (_c = process.env["RAINDROP_API_URL"]) != null ? _c : file.api_url) != null ? _d : "https://api.raindrop.ai/v1",
683
+ userId: (_f = (_e = process.env["RAINDROP_USER_ID"]) != null ? _e : file.user_id) != null ? _f : systemUser,
684
+ debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_g = file.debug) != null ? _g : false
685
+ };
686
+ }
687
+ function getConfigPath() {
688
+ return CONFIG_PATH;
689
+ }
690
+
691
+ // src/event-mapper.ts
692
+ var import_node_fs2 = require("fs");
693
+ var import_node_crypto = require("crypto");
694
+ var import_node_os2 = require("os");
695
+ var import_node_path2 = require("path");
696
+ var MAX_ATTR_LENGTH = 32768;
697
+ function truncate(value) {
698
+ if (value === void 0) return void 0;
699
+ if (value.length <= MAX_ATTR_LENGTH) return value;
700
+ const suffix = "\n...[truncated]";
701
+ return value.slice(0, MAX_ATTR_LENGTH - suffix.length) + suffix;
702
+ }
703
+ function safeStringify(value) {
704
+ if (value === void 0 || value === null) return void 0;
705
+ try {
706
+ return truncate(JSON.stringify(value));
707
+ } catch (e) {
708
+ return truncate(String(value));
709
+ }
710
+ }
711
+ var STATE_DIR = (0, import_node_path2.join)((0, import_node_os2.tmpdir)(), "raindrop-claude-code");
712
+ function ensureStateDir() {
713
+ try {
714
+ (0, import_node_fs2.mkdirSync)(STATE_DIR, { recursive: true });
715
+ } catch (e) {
716
+ }
717
+ }
718
+ function safeKey(key) {
719
+ return key.replace(/[^a-zA-Z0-9_\-]/g, "_");
720
+ }
721
+ function statePath(key) {
722
+ const sanitized = safeKey(key);
723
+ const full = (0, import_node_path2.join)(STATE_DIR, sanitized);
724
+ if (!full.startsWith(STATE_DIR)) {
725
+ throw new Error("Path traversal detected");
726
+ }
727
+ return full;
728
+ }
729
+ function writeState(key, value) {
730
+ try {
731
+ ensureStateDir();
732
+ (0, import_node_fs2.writeFileSync)(statePath(key), value, "utf-8");
733
+ } catch (e) {
734
+ }
735
+ }
736
+ function readState(key) {
737
+ try {
738
+ const filePath = statePath(key);
739
+ if (!(0, import_node_fs2.existsSync)(filePath)) return void 0;
740
+ return (0, import_node_fs2.readFileSync)(filePath, "utf-8");
741
+ } catch (e) {
742
+ return void 0;
743
+ }
744
+ }
745
+ function deleteState(key) {
746
+ try {
747
+ (0, import_node_fs2.unlinkSync)(statePath(key));
748
+ } catch (e) {
749
+ }
750
+ }
751
+ function turnEventKey(sessionId) {
752
+ return `event_${sessionId}`;
753
+ }
754
+ function saveCurrentEventId(sessionId, eventId) {
755
+ writeState(turnEventKey(sessionId), eventId);
756
+ }
757
+ function getCurrentEventId(sessionId) {
758
+ const saved = readState(turnEventKey(sessionId));
759
+ if (saved) return saved;
760
+ return `cc_${sessionId}`;
761
+ }
762
+ function saveSpanContext(key, ctx) {
763
+ writeState(key, JSON.stringify(ctx));
764
+ }
765
+ function readSpanContext(key) {
766
+ const raw = readState(key);
767
+ if (!raw) return void 0;
768
+ try {
769
+ return JSON.parse(raw);
770
+ } catch (e) {
771
+ return void 0;
772
+ }
773
+ }
774
+ function rootSpanKey(sessionId) {
775
+ return `rootspan_${sessionId}`;
776
+ }
777
+ function subagentSpanKey(agentId) {
778
+ return `subagentspan_${agentId}`;
779
+ }
780
+ function getParentContext(payload) {
781
+ if (payload.agent_id) {
782
+ const sub = readSpanContext(subagentSpanKey(payload.agent_id));
783
+ if (sub) return sub;
784
+ }
785
+ return readSpanContext(rootSpanKey(payload.session_id));
786
+ }
787
+ function saveTimestamp(key) {
788
+ writeState(key, String(Date.now()));
789
+ }
790
+ function readTimestamp(key) {
791
+ const raw = readState(key);
792
+ deleteState(key);
793
+ if (!raw) return void 0;
794
+ const ts = parseInt(raw, 10);
795
+ return Number.isFinite(ts) ? ts : void 0;
796
+ }
797
+ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
798
+ var _a;
799
+ const convoId = payload.session_id;
800
+ const baseProperties = {
801
+ cwd: payload.cwd,
802
+ permission_mode: payload.permission_mode,
803
+ plugin_version: PACKAGE_VERSION,
804
+ ...payload.agent_id ? { agent_id: payload.agent_id } : {},
805
+ ...payload.agent_type ? { agent_type: payload.agent_type } : {}
806
+ };
807
+ switch (payload.hook_event_name) {
808
+ case "SessionStart":
809
+ writeState(`model_${payload.session_id}`, (_a = payload.model) != null ? _a : "");
810
+ break;
811
+ case "UserPromptSubmit":
812
+ await handleUserPromptSubmit(payload, convoId, config, baseProperties, eventShipper, traceShipper);
813
+ break;
814
+ case "PreToolUse":
815
+ handlePreToolUse(payload);
816
+ break;
817
+ case "PostToolUse":
818
+ handlePostToolUse(payload, getCurrentEventId(payload.session_id), traceShipper);
819
+ break;
820
+ case "PostToolUseFailure":
821
+ handlePostToolUseFailure(payload, getCurrentEventId(payload.session_id), traceShipper);
822
+ break;
823
+ case "Stop":
824
+ await handleStop(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper);
825
+ break;
826
+ case "StopFailure":
827
+ await handleStopFailure(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper);
828
+ break;
829
+ case "SubagentStart":
830
+ handleSubagentStart(payload, getCurrentEventId(payload.session_id), traceShipper);
831
+ break;
832
+ case "SubagentStop":
833
+ handleSubagentStop(payload, getCurrentEventId(payload.session_id), traceShipper);
834
+ break;
835
+ case "PermissionDenied":
836
+ handlePermissionDenied(payload, getCurrentEventId(payload.session_id), traceShipper);
837
+ break;
838
+ case "PostCompact":
839
+ await handlePostCompact(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper);
840
+ break;
841
+ case "SessionEnd":
842
+ await handleSessionEnd(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper);
843
+ deleteState(turnEventKey(payload.session_id));
844
+ deleteState(rootSpanKey(payload.session_id));
845
+ deleteState(`model_${payload.session_id}`);
846
+ break;
847
+ default:
848
+ if (config.debug) {
849
+ console.log(`[raindrop-ai/claude-code] ignoring unhandled event: ${payload.hook_event_name}`);
850
+ }
851
+ }
852
+ }
853
+ async function handleUserPromptSubmit(payload, convoId, config, properties, eventShipper, traceShipper) {
854
+ const eventId = `cc_${(0, import_node_crypto.randomUUID)()}`;
855
+ saveCurrentEventId(payload.session_id, eventId);
856
+ const model = readState(`model_${payload.session_id}`) || void 0;
857
+ const rootSpan = traceShipper.startSpan({
858
+ name: model != null ? model : "claude-code",
859
+ eventId,
860
+ attributes: [
861
+ attrString("ai.operationId", "generateText"),
862
+ attrString("session.model", model),
863
+ attrString("cwd", payload.cwd)
864
+ ]
865
+ });
866
+ traceShipper.endSpan(rootSpan);
867
+ saveSpanContext(rootSpanKey(payload.session_id), {
868
+ traceIdB64: rootSpan.ids.traceIdB64,
869
+ spanIdB64: rootSpan.ids.spanIdB64
870
+ });
871
+ const patch = {
872
+ isPending: true,
873
+ userId: config.userId,
874
+ convoId,
875
+ eventName: "claude_code_session",
876
+ input: payload.prompt,
877
+ model,
878
+ properties
879
+ };
880
+ await eventShipper.patch(eventId, patch);
881
+ }
882
+ function handlePreToolUse(payload) {
883
+ if (payload.tool_use_id) {
884
+ saveTimestamp(`tool_${payload.tool_use_id}`);
885
+ }
886
+ }
887
+ function createToolSpan(payload, eventId, traceShipper, error) {
888
+ const endMs = Date.now();
889
+ const savedStartMs = payload.tool_use_id ? readTimestamp(`tool_${payload.tool_use_id}`) : void 0;
890
+ const startMs = savedStartMs && savedStartMs <= endMs ? savedStartMs : endMs;
891
+ const durationMs = endMs - startMs;
892
+ const startNano = String(startMs) + "000000";
893
+ const endNano = String(endMs) + "000000";
894
+ const parent = getParentContext(payload);
895
+ traceShipper.createSpan({
896
+ name: "ai.toolCall",
897
+ eventId,
898
+ parent,
899
+ startTimeUnixNano: startNano,
900
+ endTimeUnixNano: endNano,
901
+ attributes: [
902
+ attrString("ai.operationId", "ai.toolCall"),
903
+ attrString("ai.toolCall.name", payload.tool_name),
904
+ attrString("ai.toolCall.id", payload.tool_use_id),
905
+ attrString("ai.toolCall.args", safeStringify(payload.tool_input)),
906
+ ...payload.tool_response != null ? [attrString("ai.toolCall.result", safeStringify(payload.tool_response))] : [],
907
+ attrInt("traceloop.entity.duration_ms", durationMs)
908
+ ],
909
+ ...error ? { status: { code: 2, message: error } } : {}
910
+ });
911
+ }
912
+ function handlePostToolUse(payload, eventId, traceShipper) {
913
+ createToolSpan(payload, eventId, traceShipper);
914
+ }
915
+ function handlePostToolUseFailure(payload, eventId, traceShipper) {
916
+ var _a;
917
+ createToolSpan(payload, eventId, traceShipper, (_a = payload.error) != null ? _a : "Tool execution failed");
918
+ }
919
+ function handleSubagentStart(payload, eventId, traceShipper) {
920
+ if (payload.agent_id) {
921
+ saveTimestamp(`subagent_${payload.agent_id}`);
922
+ }
923
+ const parent = getParentContext(payload);
924
+ const span = traceShipper.startSpan({
925
+ name: "ai.subagent.start",
926
+ eventId,
927
+ parent,
928
+ attributes: [
929
+ attrString("ai.operationId", "ai.subagent"),
930
+ attrString("ai.subagent.id", payload.agent_id),
931
+ attrString("ai.subagent.type", payload.agent_type)
932
+ ]
933
+ });
934
+ traceShipper.endSpan(span);
935
+ if (payload.agent_id) {
936
+ saveSpanContext(subagentSpanKey(payload.agent_id), {
937
+ traceIdB64: span.ids.traceIdB64,
938
+ spanIdB64: span.ids.spanIdB64
939
+ });
940
+ }
941
+ }
942
+ function handleSubagentStop(payload, eventId, traceShipper) {
943
+ const endMs = Date.now();
944
+ const savedStartMs = payload.agent_id ? readTimestamp(`subagent_${payload.agent_id}`) : void 0;
945
+ const startMs = savedStartMs && savedStartMs <= endMs ? savedStartMs : endMs;
946
+ const durationMs = endMs - startMs;
947
+ const startNano = String(startMs) + "000000";
948
+ const endNano = String(endMs) + "000000";
949
+ const parent = readSpanContext(rootSpanKey(payload.session_id));
950
+ traceShipper.createSpan({
951
+ name: "ai.subagent",
952
+ eventId,
953
+ parent,
954
+ startTimeUnixNano: startNano,
955
+ endTimeUnixNano: endNano,
956
+ attributes: [
957
+ attrString("ai.operationId", "ai.subagent"),
958
+ attrString("ai.subagent.id", payload.agent_id),
959
+ attrString("ai.subagent.type", payload.agent_type),
960
+ attrString("ai.subagent.result", safeStringify(payload.last_assistant_message)),
961
+ attrInt("traceloop.entity.duration_ms", durationMs)
962
+ ]
963
+ });
964
+ if (payload.agent_id) {
965
+ deleteState(subagentSpanKey(payload.agent_id));
966
+ }
967
+ }
968
+ function handlePermissionDenied(payload, eventId, traceShipper) {
969
+ var _a;
970
+ const parent = getParentContext(payload);
971
+ traceShipper.createSpan({
972
+ name: "ai.permissionDenied",
973
+ eventId,
974
+ parent,
975
+ startTimeUnixNano: nowUnixNanoString(),
976
+ endTimeUnixNano: nowUnixNanoString(),
977
+ attributes: [
978
+ attrString("ai.operationId", "ai.permissionDenied"),
979
+ attrString("ai.toolCall.name", payload.tool_name),
980
+ attrString("ai.toolCall.id", payload.tool_use_id),
981
+ attrString("ai.toolCall.args", safeStringify(payload.tool_input)),
982
+ attrString("ai.permissionDenied.reason", payload.reason)
983
+ ],
984
+ status: {
985
+ code: 2,
986
+ message: (_a = payload.reason) != null ? _a : "Permission denied"
987
+ }
988
+ });
989
+ }
990
+ async function handlePostCompact(payload, eventId, config, properties, eventShipper) {
991
+ await eventShipper.patch(eventId, {
992
+ isPending: true,
993
+ userId: config.userId,
994
+ convoId: payload.session_id,
995
+ eventName: "claude_code_session",
996
+ properties: {
997
+ ...properties,
998
+ compaction_trigger: payload.trigger,
999
+ compact_summary: payload.compact_summary
1000
+ }
1001
+ });
1002
+ }
1003
+ async function handleStop(payload, eventId, config, properties, eventShipper) {
1004
+ await eventShipper.finish(eventId, {
1005
+ userId: config.userId,
1006
+ output: payload.last_assistant_message,
1007
+ properties
1008
+ });
1009
+ }
1010
+ async function handleStopFailure(payload, eventId, config, properties, eventShipper) {
1011
+ await eventShipper.finish(eventId, {
1012
+ userId: config.userId,
1013
+ output: payload.last_assistant_message,
1014
+ properties: {
1015
+ ...properties,
1016
+ error: payload.error,
1017
+ error_details: payload.error_details
1018
+ }
1019
+ });
1020
+ }
1021
+ async function handleSessionEnd(payload, eventId, config, properties, eventShipper) {
1022
+ await eventShipper.finish(eventId, {
1023
+ userId: config.userId,
1024
+ properties: {
1025
+ ...properties,
1026
+ session_end_reason: payload.reason
1027
+ }
1028
+ });
1029
+ }
1030
+ // Annotate the CommonJS export names for ESM import in node:
1031
+ 0 && (module.exports = {
1032
+ EventShipper,
1033
+ PACKAGE_NAME,
1034
+ PACKAGE_VERSION,
1035
+ TraceShipper,
1036
+ getConfigPath,
1037
+ loadConfig,
1038
+ mapHookToRaindrop
1039
+ });