@raindrop-ai/claude-code 0.0.18 → 0.0.20

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/cli.js CHANGED
@@ -7,7 +7,521 @@ import { randomUUID as randomUUID2 } from "crypto";
7
7
  import { tmpdir } from "os";
8
8
  import { join } from "path";
9
9
 
10
- // ../core/dist/chunk-WKRW55KX.js
10
+ // ../core/dist/chunk-BYBMRLZM.js
11
+ var EVAL_CORRELATION_ID_ATTRIBUTE = "raindrop.eval_correlation_id";
12
+ var PROBE_SCOPE = { correlationId: "" };
13
+ var EvalScopeStorage = class {
14
+ constructor() {
15
+ this._als = null;
16
+ this._probed = false;
17
+ }
18
+ maybeAdoptAsyncLocalStorage() {
19
+ if (this._probed) return;
20
+ this._probed = true;
21
+ try {
22
+ const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
23
+ if (!Ctor) return;
24
+ const als = new Ctor();
25
+ als.run(PROBE_SCOPE, () => {
26
+ });
27
+ this._als = als;
28
+ } catch (e) {
29
+ this._als = null;
30
+ }
31
+ }
32
+ run(scope, callback) {
33
+ this.maybeAdoptAsyncLocalStorage();
34
+ if (this._als) return this._als.run(scope, callback);
35
+ const previous = this._syncScope;
36
+ this._syncScope = scope;
37
+ try {
38
+ return callback();
39
+ } finally {
40
+ this._syncScope = previous;
41
+ }
42
+ }
43
+ current() {
44
+ this.maybeAdoptAsyncLocalStorage();
45
+ if (this._als) return this._als.getStore();
46
+ return this._syncScope;
47
+ }
48
+ };
49
+ var EVAL_SCOPE_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.evalScopeStorage");
50
+ function evalScopeStorage() {
51
+ const holder = globalThis;
52
+ let storage = holder[EVAL_SCOPE_STORAGE_KEY];
53
+ if (!storage) {
54
+ storage = new EvalScopeStorage();
55
+ holder[EVAL_SCOPE_STORAGE_KEY] = storage;
56
+ }
57
+ return storage;
58
+ }
59
+ function currentEvalScope() {
60
+ try {
61
+ return evalScopeStorage().current();
62
+ } catch (e) {
63
+ return void 0;
64
+ }
65
+ }
66
+ function evalScopeAttributes() {
67
+ const scope = currentEvalScope();
68
+ if (!scope) return {};
69
+ return { [EVAL_CORRELATION_ID_ATTRIBUTE]: scope.correlationId };
70
+ }
71
+
72
+ // ../core/dist/chunk-WJOR6M7H.js
73
+ var STATE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.replayTraceRoutingState");
74
+ function state() {
75
+ const holder = globalThis;
76
+ let current = holder[STATE_KEY];
77
+ if (!current) {
78
+ let storage = null;
79
+ try {
80
+ const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
81
+ if (Ctor) storage = new Ctor();
82
+ } catch (e) {
83
+ storage = null;
84
+ }
85
+ current = {
86
+ storage,
87
+ syncDestination: void 0,
88
+ spanDestinations: /* @__PURE__ */ new WeakMap()
89
+ };
90
+ holder[STATE_KEY] = current;
91
+ }
92
+ return current;
93
+ }
94
+ function currentReplayTraceDestination() {
95
+ var _a, _b;
96
+ const routing = state();
97
+ return (_b = (_a = routing.storage) == null ? void 0 : _a.getStore()) != null ? _b : routing.syncDestination;
98
+ }
99
+ function rememberReplayTraceDestination(span) {
100
+ const destination = currentReplayTraceDestination();
101
+ if (destination) state().spanDestinations.set(span, destination);
102
+ }
103
+ function copyReplayTraceDestination(source, target) {
104
+ const destination = state().spanDestinations.get(source);
105
+ if (destination) state().spanDestinations.set(target, destination);
106
+ }
107
+ function replayTraceDestinationFor(value) {
108
+ if (typeof value !== "object" && typeof value !== "function" || value === null) {
109
+ return void 0;
110
+ }
111
+ return state().spanDestinations.get(value);
112
+ }
113
+ function recordReplayExportedSpan(destination, spanId, traceId) {
114
+ var _a, _b;
115
+ if (!destination || !spanId || !traceId) return;
116
+ (_a = destination.exportedSpanIds) == null ? void 0 : _a.add(spanId);
117
+ (_b = destination.exportedTraceIds) == null ? void 0 : _b.add(traceId);
118
+ }
119
+ function replayTraceUrl(baseUrl) {
120
+ return `${baseUrl.replace(/\/+$/, "")}/v1/traces`;
121
+ }
122
+ function getAsyncLocalStorageCtor() {
123
+ return globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
124
+ }
125
+ var MAX_BINDING_STACK = 128;
126
+ var EMPTY_STACK = [];
127
+ var ContextStackStorage = class {
128
+ /** Emitted once when this runtime cannot support an ambient push. */
129
+ constructor(noAmbientBindWarning) {
130
+ this.noAmbientBindWarning = noAmbientBindWarning;
131
+ this._als = null;
132
+ this._enterWithUsable = false;
133
+ this._syncStack = EMPTY_STACK;
134
+ this._adoptionChecked = false;
135
+ this._warnedNoAmbientBind = false;
136
+ }
137
+ maybeAdoptAsyncLocalStorage() {
138
+ if (this._adoptionChecked) return;
139
+ this._adoptionChecked = true;
140
+ const Ctor = getAsyncLocalStorageCtor();
141
+ if (!Ctor) return;
142
+ const als = new Ctor();
143
+ try {
144
+ als.run(EMPTY_STACK, () => {
145
+ });
146
+ } catch (e) {
147
+ return;
148
+ }
149
+ this._als = als;
150
+ if (typeof als.enterWith === "function") {
151
+ try {
152
+ als.enterWith(EMPTY_STACK);
153
+ this._enterWithUsable = true;
154
+ } catch (e) {
155
+ this._enterWithUsable = false;
156
+ }
157
+ }
158
+ }
159
+ getStack() {
160
+ var _a;
161
+ this.maybeAdoptAsyncLocalStorage();
162
+ if (this._als) return (_a = this._als.getStore()) != null ? _a : this._syncStack;
163
+ return this._syncStack;
164
+ }
165
+ /**
166
+ * Persist an ambient stack mutation. Returns false when an ALS is adopted but
167
+ * `enterWith` is unusable (workerd): callers must NOT fall back to the
168
+ * process-shared sync stack, since concurrent isolates would cross-stamp.
169
+ */
170
+ setAmbientStack(stack) {
171
+ if (this._als) {
172
+ if (!this._enterWithUsable) return false;
173
+ this._als.enterWith(stack);
174
+ return true;
175
+ }
176
+ this._syncStack = stack;
177
+ return true;
178
+ }
179
+ push(binding) {
180
+ this.maybeAdoptAsyncLocalStorage();
181
+ if (this._als && !this._enterWithUsable) {
182
+ this.warnNoAmbientBindOnce();
183
+ return;
184
+ }
185
+ let stack = this.getStack();
186
+ if (stack.length >= MAX_BINDING_STACK) {
187
+ stack = stack.filter((b) => b.isLive());
188
+ if (stack.length >= MAX_BINDING_STACK) {
189
+ stack = stack.slice(stack.length - (MAX_BINDING_STACK - 1));
190
+ }
191
+ }
192
+ this.setAmbientStack([...stack, binding]);
193
+ }
194
+ remove(binding) {
195
+ binding.markDead();
196
+ const stack = this.getStack();
197
+ const pruned = stack.filter((b) => b !== binding && b.isLive());
198
+ if (pruned.length !== stack.length) {
199
+ this.setAmbientStack(pruned);
200
+ }
201
+ }
202
+ runWith(binding, callback) {
203
+ this.maybeAdoptAsyncLocalStorage();
204
+ if (this._als) {
205
+ return this._als.run([...this.getStack(), binding], callback);
206
+ }
207
+ const previous = this._syncStack;
208
+ this._syncStack = [...previous, binding];
209
+ try {
210
+ return callback();
211
+ } finally {
212
+ this._syncStack = previous;
213
+ }
214
+ }
215
+ current() {
216
+ const stack = this.getStack();
217
+ if (stack.length === 0) return void 0;
218
+ const top = stack[stack.length - 1];
219
+ if (top.isLive()) return top;
220
+ const pruned = stack.filter((b) => b.isLive());
221
+ this.setAmbientStack(pruned);
222
+ return pruned.length > 0 ? pruned[pruned.length - 1] : void 0;
223
+ }
224
+ warnNoAmbientBindOnce() {
225
+ if (this._warnedNoAmbientBind) return;
226
+ this._warnedNoAmbientBind = true;
227
+ console.warn(this.noAmbientBindWarning);
228
+ }
229
+ };
230
+ var NO_AMBIENT_ROUTING_BIND_WARNING = "[raindrop] This runtime's AsyncLocalStorage does not implement enterWith (e.g. Cloudflare Workers), so begin()/finish() cannot scope auto-instrumented spans to a project without cross-contaminating concurrent requests. Manual events and explicit span routing are unaffected; use asCurrent()/withSpan (run-based) to route auto-instrumented spans on this runtime.";
231
+ var ROUTING_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.routingContextStorage");
232
+ function routingStorage() {
233
+ const holder = globalThis;
234
+ let storage = holder[ROUTING_STORAGE_KEY];
235
+ if (!storage) {
236
+ storage = new ContextStackStorage(NO_AMBIENT_ROUTING_BIND_WARNING);
237
+ holder[ROUTING_STORAGE_KEY] = storage;
238
+ }
239
+ return storage;
240
+ }
241
+ function currentRoutingBinding() {
242
+ const bound = routingStorage().current();
243
+ if (!bound) return void 0;
244
+ return {
245
+ projectId: bound.projectId,
246
+ authHint: bound.authHint,
247
+ ...bound.appGit ? { appGit: bound.appGit } : {},
248
+ ...bound.appGitSource ? { appGitSource: bound.appGitSource } : {}
249
+ };
250
+ }
251
+ var APP_COMMIT_SHA = "raindrop.app.commit_sha";
252
+ var APP_COMMIT_DIRTY = "raindrop.app.commit_dirty";
253
+ var APP_BRANCH = "raindrop.app.branch";
254
+ var APP_GIT_KEYS = [APP_COMMIT_SHA, APP_COMMIT_DIRTY, APP_BRANCH];
255
+ var own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
256
+ function appGitExplicitKeys(properties) {
257
+ const keys = /* @__PURE__ */ new Set();
258
+ if (!properties) return keys;
259
+ for (const key of APP_GIT_KEYS) {
260
+ if (own(properties, key)) keys.add(key);
261
+ }
262
+ return keys;
263
+ }
264
+ function mergeAppGitSnapshot(base, properties, explicitKeys = /* @__PURE__ */ new Set()) {
265
+ try {
266
+ const result = { ...base };
267
+ if (properties && own(properties, APP_COMMIT_SHA) && properties[APP_COMMIT_SHA] !== result[APP_COMMIT_SHA]) {
268
+ if (!explicitKeys.has(APP_COMMIT_DIRTY) && !own(properties, APP_COMMIT_DIRTY)) {
269
+ delete result[APP_COMMIT_DIRTY];
270
+ }
271
+ if (!explicitKeys.has(APP_BRANCH) && !own(properties, APP_BRANCH)) {
272
+ delete result[APP_BRANCH];
273
+ }
274
+ }
275
+ for (const key of APP_GIT_KEYS) {
276
+ if (properties && own(properties, key)) result[key] = properties[key];
277
+ }
278
+ return Object.freeze(result);
279
+ } catch (e) {
280
+ return Object.freeze({});
281
+ }
282
+ }
283
+ function validAppCommitSha(value) {
284
+ if (typeof value !== "string" || value.length > 128) return void 0;
285
+ const cleaned = value.trim();
286
+ return /^(?:[a-fA-F0-9]{40}|[a-fA-F0-9]{64})$/.test(cleaned) ? cleaned.toLowerCase() : void 0;
287
+ }
288
+ function shortString(value) {
289
+ if (typeof value !== "string" || value.length > 1024) return void 0;
290
+ const cleaned = value.trim();
291
+ return cleaned.length > 0 ? cleaned : void 0;
292
+ }
293
+ function flag(value) {
294
+ if (value === true || value === "true" || value === "1") return true;
295
+ if (value === false || value === "false" || value === "0") return false;
296
+ return void 0;
297
+ }
298
+ function environment() {
299
+ try {
300
+ return typeof process === "undefined" ? {} : process.env;
301
+ } catch (e) {
302
+ return {};
303
+ }
304
+ }
305
+ var DEPLOYMENTS = [
306
+ ["VERCEL", "VERCEL_GIT_COMMIT_SHA", "VERCEL_GIT_COMMIT_REF"],
307
+ ["NETLIFY", "COMMIT_REF", "BRANCH"],
308
+ ["RAILWAY_ENVIRONMENT_NAME", "RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH"],
309
+ ["RAILWAY_ENVIRONMENT", "RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH"],
310
+ ["RENDER", "RENDER_GIT_COMMIT", "RENDER_GIT_BRANCH"],
311
+ ["DYNO", "HEROKU_BUILD_COMMIT", ""],
312
+ ["DYNO", "HEROKU_SLUG_COMMIT", ""],
313
+ ["AWS_APP_ID", "AWS_COMMIT_ID", "AWS_BRANCH"],
314
+ ["WORKERS_CI", "WORKERS_CI_COMMIT_SHA", "WORKERS_CI_BRANCH"]
315
+ ];
316
+ var CI_SOURCES = [
317
+ ["GITHUB_ACTIONS", "GITHUB_SHA", "GITHUB_REF_NAME"],
318
+ ["GITLAB_CI", "CI_COMMIT_SHA", "CI_COMMIT_REF_NAME"],
319
+ ["CIRCLECI", "CIRCLE_SHA1", "CIRCLE_BRANCH"]
320
+ ];
321
+ function detectedSource(env, table, detectBranch) {
322
+ for (const row of table) {
323
+ const [marker, shaKey, branchKey] = row;
324
+ if (!marker || !shaKey || !shortString(env[marker]) || flag(env[marker]) === false) continue;
325
+ const commitSha = validAppCommitSha(env[shaKey]);
326
+ if (commitSha)
327
+ return {
328
+ commitSha,
329
+ ...detectBranch && branchKey ? { branch: shortString(env[branchKey]) } : {}
330
+ };
331
+ }
332
+ return {};
333
+ }
334
+ var AppGitContextImpl = class {
335
+ constructor(options, runtime = {}) {
336
+ this.defaults = {};
337
+ this.explicit = {};
338
+ this.explicitKeys = /* @__PURE__ */ new Set();
339
+ this.disposed = false;
340
+ this.operations = /* @__PURE__ */ new Map();
341
+ this.operationOverflow = false;
342
+ this.detectBranch = false;
343
+ this.disabled = false;
344
+ var _a, _b, _c, _d, _e, _f;
345
+ try {
346
+ if (options === false) {
347
+ this.disabled = true;
348
+ return;
349
+ }
350
+ const opts = options != null ? options : {};
351
+ const env = (_a = runtime.env) != null ? _a : environment();
352
+ const detectBranch = (_c = (_b = flag(opts.detectBranch)) != null ? _b : flag(env.RAINDROP_GIT_DETECT_BRANCH)) != null ? _c : false;
353
+ this.detectBranch = detectBranch;
354
+ const collectBranch = detectBranch || runtime.captureLegacyReplayBranch === true;
355
+ const autoDetect = runtime.allowDiscovery === false ? false : (_e = (_d = flag(opts.autoDetect)) != null ? _d : flag(env.RAINDROP_GIT_AUTO_DETECT)) != null ? _e : true;
356
+ const configuredSha = opts.commitSha;
357
+ const explicitSha = configuredSha === void 0 ? env.RAINDROP_COMMIT_SHA : configuredSha;
358
+ if (explicitSha === null) this.explicit[APP_COMMIT_SHA] = null;
359
+ else if (typeof explicitSha === "string" && validAppCommitSha(explicitSha))
360
+ this.explicit[APP_COMMIT_SHA] = explicitSha;
361
+ const configuredDirty = opts.commitDirty;
362
+ const explicitDirty = configuredDirty === void 0 ? flag(env.RAINDROP_COMMIT_DIRTY) : configuredDirty;
363
+ if (explicitDirty === null || typeof explicitDirty === "boolean")
364
+ this.explicit[APP_COMMIT_DIRTY] = explicitDirty;
365
+ const configuredBranch = opts.branch;
366
+ const explicitBranch = configuredBranch === void 0 ? env.RAINDROP_BRANCH : configuredBranch;
367
+ if (explicitBranch === null) this.explicit[APP_BRANCH] = null;
368
+ else if (typeof explicitBranch === "string" && explicitBranch.length <= 1024)
369
+ this.explicit[APP_BRANCH] = explicitBranch;
370
+ this.explicitKeys = appGitExplicitKeys(this.explicit);
371
+ this.defaults = { ...this.explicit };
372
+ if (!autoDetect || explicitSha !== void 0) return;
373
+ const sourceDirectory = (_f = shortString(opts.sourceDirectory)) != null ? _f : shortString(env.RAINDROP_GIT_SOURCE_DIRECTORY);
374
+ if (runtime.allowLocalGit === false && !sourceDirectory) return;
375
+ const deploy = sourceDirectory ? {} : detectedSource(env, DEPLOYMENTS, collectBranch);
376
+ if (deploy.commitSha) {
377
+ this.accept(deploy);
378
+ return;
379
+ }
380
+ const fallback = sourceDirectory ? {} : detectedSource(env, CI_SOURCES, collectBranch);
381
+ if (runtime.resolveLocal && (runtime.allowLocalGit !== false || sourceDirectory)) {
382
+ this.cancel = runtime.resolveLocal(sourceDirectory, collectBranch, (result) => {
383
+ try {
384
+ if (!this.disposed) this.accept(result.commitSha ? result : fallback);
385
+ } catch (e) {
386
+ }
387
+ });
388
+ } else this.accept(fallback);
389
+ } catch (e) {
390
+ }
391
+ }
392
+ accept(result) {
393
+ const sha = validAppCommitSha(result.commitSha);
394
+ if (!sha) return;
395
+ this.replayBranch = shortString(result.branch);
396
+ this.defaults = {
397
+ [APP_COMMIT_SHA]: sha,
398
+ ...typeof result.commitDirty === "boolean" ? { [APP_COMMIT_DIRTY]: result.commitDirty } : {},
399
+ ...this.detectBranch && this.replayBranch ? { [APP_BRANCH]: this.replayBranch } : {},
400
+ ...this.explicit
401
+ };
402
+ }
403
+ snapshot(properties) {
404
+ var _a;
405
+ try {
406
+ const binding = currentRoutingBinding();
407
+ const base = this.disabled && (binding == null ? void 0 : binding.appGitSource) !== "replay-override" ? {} : (_a = binding == null ? void 0 : binding.appGit) != null ? _a : this.defaults;
408
+ return this.mergeSnapshot(base, properties);
409
+ } catch (e) {
410
+ return Object.freeze({});
411
+ }
412
+ }
413
+ /** Safe defaults when no operation/span start was observed; never infer identity. */
414
+ snapshotExplicit(properties, eventId) {
415
+ try {
416
+ const base = { ...this.explicit };
417
+ const operation = eventId ? this.operations.get(eventId) : void 0;
418
+ if (operation) {
419
+ for (const key of operation.explicitKeys) base[key] = operation.snapshot[key];
420
+ }
421
+ return this.mergeSnapshot(base, properties, new Set(Object.keys(base)));
422
+ } catch (e) {
423
+ return mergeAppGitSnapshot({}, properties);
424
+ }
425
+ }
426
+ /** Existing replay branch reporting stays separate from opt-in event properties. */
427
+ snapshotForReplay() {
428
+ const snapshot = this.snapshot();
429
+ if (this.replayBranch && !own(snapshot, APP_BRANCH) && snapshot[APP_COMMIT_SHA] === this.defaults[APP_COMMIT_SHA]) {
430
+ return Object.freeze({ ...snapshot, [APP_BRANCH]: this.replayBranch });
431
+ }
432
+ return snapshot;
433
+ }
434
+ /** Merge a frozen span snapshot without losing client-authored provenance. */
435
+ mergeSnapshot(base, properties, explicitKeys = this.explicitKeys) {
436
+ return mergeAppGitSnapshot(base, properties, /* @__PURE__ */ new Set([...this.explicitKeys, ...explicitKeys]));
437
+ }
438
+ /** Shippers belonging to one client share this bounded operation registry. */
439
+ forOperation(eventId, properties, owner) {
440
+ if (!eventId) return this.snapshot(properties);
441
+ let operation = this.operations.get(eventId);
442
+ if (!operation) {
443
+ if (this.operations.size >= 1e4) this.operationOverflow = true;
444
+ if (this.operationOverflow) return this.mergeSnapshot({}, properties);
445
+ operation = {
446
+ snapshot: this.snapshot(properties),
447
+ owners: /* @__PURE__ */ new Set(),
448
+ unowned: owner === void 0,
449
+ explicitKeys: appGitExplicitKeys(properties)
450
+ };
451
+ this.operations.set(eventId, operation);
452
+ } else if (properties && APP_GIT_KEYS.some((key) => own(properties, key))) {
453
+ const explicitKeys = /* @__PURE__ */ new Set([...this.explicitKeys, ...operation.explicitKeys]);
454
+ operation.snapshot = this.mergeSnapshot(operation.snapshot, properties, explicitKeys);
455
+ for (const key of appGitExplicitKeys(properties)) operation.explicitKeys.add(key);
456
+ }
457
+ if (!owner) operation.unowned = true;
458
+ if (owner) operation.owners.add(owner);
459
+ return operation.snapshot;
460
+ }
461
+ releaseOperation(eventId, owner) {
462
+ const operation = this.operations.get(eventId);
463
+ if (!operation) return;
464
+ operation.owners.delete(owner);
465
+ if (operation.owners.size === 0 && !operation.unowned) this.operations.delete(eventId);
466
+ }
467
+ finishOperation(eventId) {
468
+ this.operations.delete(eventId);
469
+ }
470
+ dispose() {
471
+ var _a;
472
+ this.disposed = true;
473
+ try {
474
+ (_a = this.cancel) == null ? void 0 : _a.call(this);
475
+ } catch (e) {
476
+ }
477
+ }
478
+ };
479
+ var AppGitContext = AppGitContextImpl;
480
+ function createAppGitContext(options, runtime = {}) {
481
+ return new AppGitContext(options, runtime);
482
+ }
483
+ function withAppGitProperties(properties, snapshot) {
484
+ try {
485
+ const merged = { ...properties };
486
+ for (const key of APP_GIT_KEYS)
487
+ if (!own(merged, key) && own(snapshot, key)) merged[key] = snapshot[key];
488
+ return merged;
489
+ } catch (e) {
490
+ return properties != null ? properties : {};
491
+ }
492
+ }
493
+ function withAppGitAttributes(attributes, snapshot) {
494
+ try {
495
+ const present = new Set(attributes.flatMap((attr) => attr ? [attr.key] : []));
496
+ const added = [];
497
+ for (const key of APP_GIT_KEYS) {
498
+ if (present.has(key) || present.has(`ai.telemetry.metadata.${key}`) || present.has(`traceloop.association.properties.${key}`))
499
+ continue;
500
+ const value = snapshot[key];
501
+ if (typeof value === "string") added.push({ key, value: { stringValue: value } });
502
+ else if (typeof value === "boolean") added.push({ key, value: { boolValue: value } });
503
+ }
504
+ return added.length ? [...attributes, ...added] : attributes;
505
+ } catch (e) {
506
+ return attributes;
507
+ }
508
+ }
509
+ function appGitPropertiesFromAttributes(attributes) {
510
+ var _a, _b, _c;
511
+ const properties = {};
512
+ try {
513
+ for (const attr of attributes) {
514
+ if (!attr) continue;
515
+ for (const key of APP_GIT_KEYS) {
516
+ if (attr.key === key || attr.key === `ai.telemetry.metadata.${key}` || attr.key === `traceloop.association.properties.${key}`) {
517
+ properties[key] = (_c = (_b = (_a = attr.value.stringValue) != null ? _a : attr.value.boolValue) != null ? _b : attr.value.intValue) != null ? _c : null;
518
+ }
519
+ }
520
+ }
521
+ } catch (e) {
522
+ }
523
+ return properties;
524
+ }
11
525
  function getCrypto() {
12
526
  const c = globalThis.crypto;
13
527
  return c;
@@ -22,6 +536,17 @@ function randomBytes(length) {
22
536
  for (let i = 0; i < out.length; i++) out[i] = Math.floor(Math.random() * 256);
23
537
  return out;
24
538
  }
539
+ function randomUUID() {
540
+ const cryptoObj = getCrypto();
541
+ if (cryptoObj && typeof cryptoObj.randomUUID === "function") {
542
+ return cryptoObj.randomUUID();
543
+ }
544
+ const b = randomBytes(16);
545
+ b[6] = b[6] & 15 | 64;
546
+ b[8] = b[8] & 63 | 128;
547
+ const hex = [...b].map((x) => x.toString(16).padStart(2, "0")).join("");
548
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
549
+ }
25
550
  function base64Encode(bytes) {
26
551
  const maybeBuffer = globalThis.Buffer;
27
552
  if (maybeBuffer) {
@@ -51,6 +576,39 @@ function base64Encode(bytes) {
51
576
  }
52
577
  return out;
53
578
  }
579
+ function base64ToHex(value) {
580
+ if (!value) return "";
581
+ const maybeBuffer = globalThis.Buffer;
582
+ if (maybeBuffer) {
583
+ return maybeBuffer.from(value, "base64").toString("hex");
584
+ }
585
+ const atobFn = globalThis.atob;
586
+ if (typeof atobFn !== "function") return "";
587
+ try {
588
+ const binary = atobFn(value);
589
+ let hex = "";
590
+ for (let i = 0; i < binary.length; i++) {
591
+ hex += (binary.charCodeAt(i) & 255).toString(16).padStart(2, "0");
592
+ }
593
+ return hex;
594
+ } catch (e) {
595
+ return "";
596
+ }
597
+ }
598
+ var HANDOFF_ATTRIBUTE_SUFFIXES = {
599
+ mode: "raindrop.handoff.mode",
600
+ childEventId: "raindrop.handoff.childEventId",
601
+ parentEventId: "raindrop.handoff.parentEventId",
602
+ parentSpanId: "raindrop.handoff.parentSpanId",
603
+ name: "raindrop.handoff.name",
604
+ terminal: "raindrop.handoff.terminal",
605
+ agentRole: "raindrop.agent.role"
606
+ };
607
+ var HANDOFF_TERMINAL_PROPERTY_KEY = HANDOFF_ATTRIBUTE_SUFFIXES.terminal;
608
+ var TRACEPARENT_HEADER = "traceparent";
609
+ var BAGGAGE_HEADER = "baggage";
610
+ var HANDOFF_HEADER = "x-raindrop-handoff";
611
+ 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.`;
54
612
  function runWithTracingSuppressed(fn) {
55
613
  const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
56
614
  if (typeof hook !== "function") return fn();
@@ -68,7 +626,7 @@ function runWithTracingSuppressed(fn) {
68
626
  var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
69
627
  var MAX_RETRY_DELAY_MS = 3e4;
70
628
  function wait(ms) {
71
- return new Promise((resolve2) => setTimeout(resolve2, ms));
629
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
72
630
  }
73
631
  function formatEndpoint(endpoint) {
74
632
  if (!endpoint) return void 0;
@@ -105,9 +663,9 @@ async function raceWithTimeout(promise, timeoutMs) {
105
663
  () => true,
106
664
  () => true
107
665
  ),
108
- new Promise((resolve2) => {
666
+ new Promise((resolve3) => {
109
667
  var _a;
110
- timer = setTimeout(() => resolve2(false), Math.max(0, timeoutMs));
668
+ timer = setTimeout(() => resolve3(false), Math.max(0, timeoutMs));
111
669
  (_a = timer.unref) == null ? void 0 : _a.call(timer);
112
670
  })
113
671
  ]);
@@ -178,6 +736,7 @@ async function postJson(url, body, headers, opts) {
178
736
  const resp = await runWithTracingSuppressed(
179
737
  () => fetch(url, {
180
738
  method: "POST",
739
+ redirect: headers["X-Raindrop-Replay-Id"] !== void 0 ? "error" : "follow",
181
740
  headers: {
182
741
  "Content-Type": "application/json",
183
742
  ...headers
@@ -341,26 +900,29 @@ function resolveLocalDebuggerBaseUrl(baseUrl) {
341
900
  if (shouldAutoEnableLocalWorkshop()) return DEFAULT_LOCAL_WORKSHOP_URL;
342
901
  return null;
343
902
  }
903
+ var LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS = 2e3;
344
904
  function mirrorTraceExportToLocalDebugger(body, options = {}) {
345
905
  var _a;
346
906
  const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
347
- if (!baseUrl) return;
348
- void postJson(`${baseUrl}traces`, body, {}, {
907
+ if (!baseUrl) return Promise.resolve();
908
+ return postJson(`${baseUrl}traces`, body, {}, {
349
909
  maxAttempts: 1,
350
910
  debug: (_a = options.debug) != null ? _a : false,
351
- sdkName: options.sdkName
911
+ sdkName: options.sdkName,
912
+ timeoutMs: LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS
352
913
  }).catch(() => {
353
914
  });
354
915
  }
355
916
  function mirrorPartialEventToLocalDebugger(event, options = {}) {
356
917
  var _a;
357
918
  const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
358
- if (!baseUrl) return;
919
+ if (!baseUrl) return Promise.resolve();
359
920
  const headers = options.writeKey ? { Authorization: `Bearer ${options.writeKey}` } : {};
360
- void postJson(`${baseUrl}events/track_partial`, event, headers, {
921
+ return postJson(`${baseUrl}events/track_partial`, event, headers, {
361
922
  maxAttempts: 1,
362
923
  debug: (_a = options.debug) != null ? _a : false,
363
- sdkName: options.sdkName
924
+ sdkName: options.sdkName,
925
+ timeoutMs: LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS
364
926
  }).catch(() => {
365
927
  });
366
928
  }
@@ -385,35 +947,81 @@ function projectIdHeaders(projectId) {
385
947
  }
386
948
  var SHUTDOWN_DEADLINE_MS = 1e4;
387
949
  var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
950
+ function appGitOwnerId(prefix) {
951
+ try {
952
+ return `${prefix}:${randomUUID()}`;
953
+ } catch (e) {
954
+ return `${prefix}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
955
+ }
956
+ }
388
957
  function mergePatches(target, source) {
389
- var _a, _b, _c, _d;
958
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
390
959
  const out = { ...target, ...source };
391
960
  if (target.properties || source.properties) {
392
961
  out.properties = { ...(_a = target.properties) != null ? _a : {}, ...(_b = source.properties) != null ? _b : {} };
393
962
  }
963
+ if (target.usage || source.usage) {
964
+ out.usage = { ...(_c = target.usage) != null ? _c : {} };
965
+ if (((_d = source.usage) == null ? void 0 : _d.promptTokens) !== void 0) {
966
+ out.usage.promptTokens = source.usage.promptTokens;
967
+ }
968
+ if (((_e = source.usage) == null ? void 0 : _e.completionTokens) !== void 0) {
969
+ out.usage.completionTokens = source.usage.completionTokens;
970
+ }
971
+ }
972
+ if (source.error === void 0) {
973
+ out.error = target.error;
974
+ }
975
+ if (target.featureFlags || source.featureFlags) {
976
+ out.featureFlags = { ...(_f = target.featureFlags) != null ? _f : {}, ...(_g = source.featureFlags) != null ? _g : {} };
977
+ }
394
978
  if (target.attachments || source.attachments) {
395
- out.attachments = [...(_c = target.attachments) != null ? _c : [], ...(_d = source.attachments) != null ? _d : []];
979
+ out.attachments = [...(_h = target.attachments) != null ? _h : [], ...(_i = source.attachments) != null ? _i : []];
396
980
  }
397
981
  return out;
398
982
  }
983
+ function isErrorLike(value) {
984
+ return value !== null && typeof value === "object";
985
+ }
986
+ function eventTelemetryProperties(patch) {
987
+ var _a, _b;
988
+ const properties = {};
989
+ if (((_a = patch.usage) == null ? void 0 : _a.promptTokens) !== void 0 && Number.isFinite(patch.usage.promptTokens)) {
990
+ properties["ai.usage.prompt_tokens"] = patch.usage.promptTokens;
991
+ }
992
+ if (((_b = patch.usage) == null ? void 0 : _b.completionTokens) !== void 0 && Number.isFinite(patch.usage.completionTokens)) {
993
+ properties["ai.usage.completion_tokens"] = patch.usage.completionTokens;
994
+ }
995
+ if (patch.error !== void 0 && patch.error !== null) {
996
+ const constructorName = patch.error instanceof Error && patch.error.constructor !== Error ? patch.error.constructor.name : void 0;
997
+ 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";
998
+ const errorMessage = patch.error instanceof Error ? patch.error.message : isErrorLike(patch.error) && typeof patch.error.message === "string" ? patch.error.message : String(patch.error);
999
+ properties["error.type"] = errorType;
1000
+ properties["error.message"] = errorMessage;
1001
+ }
1002
+ return properties;
1003
+ }
399
1004
  var EventShipper = class {
400
1005
  constructor(opts) {
1006
+ this.appGitOwner = appGitOwnerId("event");
401
1007
  this.buffers = /* @__PURE__ */ new Map();
402
1008
  this.sticky = /* @__PURE__ */ new Map();
403
1009
  this.timers = /* @__PURE__ */ new Map();
404
1010
  this.inFlight = /* @__PURE__ */ new Set();
405
1011
  this.hasShutdown = false;
406
- var _a, _b, _c, _d, _e, _f, _g, _h;
407
- this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
408
- this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
1012
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1013
+ this.appGitContext = (_a = opts.appGitContext) != null ? _a : createAppGitContext(opts.appGit);
1014
+ this.ownsAppGitContext = opts.appGitContext === void 0;
1015
+ this.writeKey = (_b = opts.writeKey) == null ? void 0 : _b.trim();
1016
+ this.baseUrl = (_c = formatEndpoint(opts.endpoint)) != null ? _c : "https://api.raindrop.ai/v1/";
409
1017
  this.enabled = opts.enabled !== false;
410
1018
  this.debug = opts.debug;
411
- this.partialFlushMs = (_c = opts.partialFlushMs) != null ? _c : 1e3;
412
- this.sdkName = (_d = opts.sdkName) != null ? _d : "core";
1019
+ this.partialFlushMs = (_d = opts.partialFlushMs) != null ? _d : 1e3;
1020
+ this.sdkName = (_e = opts.sdkName) != null ? _e : "core";
413
1021
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
414
- this.defaultEventName = (_e = opts.defaultEventName) != null ? _e : "ai_generation";
1022
+ this.defaultEventName = (_f = opts.defaultEventName) != null ? _f : "ai_generation";
415
1023
  this.maxTextFieldCharsOpt = opts.maxTextFieldChars;
416
- this.localDebuggerUrl = (_f = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _f : void 0;
1024
+ this.localDebuggerUrl = (_g = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _g : void 0;
417
1025
  if (this.debug && this.localDebuggerUrl) {
418
1026
  console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
419
1027
  }
@@ -424,8 +1032,8 @@ var EventShipper = class {
424
1032
  const isNode = typeof process !== "undefined" && typeof process.version === "string";
425
1033
  this.context = {
426
1034
  library: {
427
- name: (_g = opts.libraryName) != null ? _g : "@raindrop-ai/core",
428
- version: (_h = opts.libraryVersion) != null ? _h : "0.0.0"
1035
+ name: (_h = opts.libraryName) != null ? _h : "@raindrop-ai/core",
1036
+ version: (_i = opts.libraryVersion) != null ? _i : "0.0.0"
429
1037
  },
430
1038
  metadata: {
431
1039
  jsRuntime: isNode ? "node" : "web",
@@ -433,6 +1041,9 @@ var EventShipper = class {
433
1041
  }
434
1042
  };
435
1043
  }
1044
+ ownAppGitContextForShutdown() {
1045
+ this.ownsAppGitContext = true;
1046
+ }
436
1047
  isDebugEnabled() {
437
1048
  return this.debug;
438
1049
  }
@@ -481,6 +1092,15 @@ var EventShipper = class {
481
1092
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
482
1093
  if (!this.enabled) return;
483
1094
  if (!eventId || !eventId.trim()) return;
1095
+ const capturedSticky = this.sticky.get(eventId);
1096
+ const eventAlreadyKnown = capturedSticky !== void 0 || this.buffers.has(eventId);
1097
+ const destination = currentReplayTraceDestination();
1098
+ const cloudReplay = destination !== void 0 && destination.kind !== "workshop";
1099
+ if ((capturedSticky == null ? void 0 : capturedSticky.replayOnly) === true || !eventAlreadyKnown && cloudReplay) {
1100
+ if (patch.isPending === false) this.sticky.delete(eventId);
1101
+ else this.sticky.set(eventId, { ...capturedSticky, replayOnly: true });
1102
+ return;
1103
+ }
484
1104
  const maxChars = resolveMaxTextFieldChars(this.maxTextFieldCharsOpt);
485
1105
  if (typeof patch.input === "string" && patch.input.length > maxChars) {
486
1106
  patch = { ...patch, input: capText(patch.input, maxChars) };
@@ -502,6 +1122,13 @@ var EventShipper = class {
502
1122
  }
503
1123
  const sticky = (_c = this.sticky.get(eventId)) != null ? _c : {};
504
1124
  const existing = (_d = this.buffers.get(eventId)) != null ? _d : {};
1125
+ patch = {
1126
+ ...patch,
1127
+ properties: withAppGitProperties(
1128
+ patch.properties,
1129
+ this.appGitContext.forOperation(eventId, patch.properties, this.appGitOwner)
1130
+ )
1131
+ };
505
1132
  const merged = mergePatches(existing, patch);
506
1133
  merged.isPending = (_g = (_f = (_e = patch.isPending) != null ? _e : existing.isPending) != null ? _f : sticky.isPending) != null ? _g : true;
507
1134
  this.buffers.set(eventId, merged);
@@ -515,6 +1142,8 @@ var EventShipper = class {
515
1142
  if (t) clearTimeout(t);
516
1143
  if (merged.isPending === false) {
517
1144
  await this.flushOne(eventId);
1145
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(eventId, this.appGitOwner);
1146
+ else this.appGitContext.finishOperation(eventId);
518
1147
  return;
519
1148
  }
520
1149
  const timeout = setTimeout(() => {
@@ -539,15 +1168,21 @@ var EventShipper = class {
539
1168
  try {
540
1169
  for (const t of this.timers.values()) clearTimeout(t);
541
1170
  this.timers.clear();
1171
+ for (const [eventId, sticky] of this.sticky) {
1172
+ if (sticky.replayOnly) this.sticky.delete(eventId);
1173
+ }
542
1174
  const settled = await raceWithTimeout(this.flush(), SHUTDOWN_DEADLINE_MS);
543
1175
  if (!settled) this.warnShutdownDrop("in-flight request(s) at shutdown");
544
1176
  } finally {
545
1177
  this.shutdownDeadlineAt = void 0;
1178
+ if (this.ownsAppGitContext) this.appGitContext.dispose();
546
1179
  }
547
1180
  }
548
1181
  async trackSignal(signal) {
549
1182
  var _a, _b;
550
1183
  if (!this.enabled) return;
1184
+ const destination = currentReplayTraceDestination();
1185
+ if (destination && destination.kind !== "workshop") return;
551
1186
  const body = [
552
1187
  {
553
1188
  event_id: signal.eventId,
@@ -582,6 +1217,8 @@ var EventShipper = class {
582
1217
  }
583
1218
  async identify(users) {
584
1219
  if (!this.enabled) return;
1220
+ const destination = currentReplayTraceDestination();
1221
+ if (destination && destination.kind !== "workshop") return;
585
1222
  const list = Array.isArray(users) ? users : [users];
586
1223
  const body = list.filter((user) => {
587
1224
  if (!(user == null ? void 0 : user.userId) || !user.userId.trim()) {
@@ -634,8 +1271,9 @@ var EventShipper = class {
634
1271
  this.buffers.delete(eventId);
635
1272
  if (!accumulated) return;
636
1273
  const sticky = (_a = this.sticky.get(eventId)) != null ? _a : {};
637
- const eventName = (_c = (_b = accumulated.eventName) != null ? _b : sticky.eventName) != null ? _c : this.defaultEventName;
638
- const userId = (_d = accumulated.userId) != null ? _d : sticky.userId;
1274
+ const isPending = (_c = (_b = accumulated.isPending) != null ? _b : sticky.isPending) != null ? _c : true;
1275
+ const eventName = (_e = (_d = accumulated.eventName) != null ? _d : sticky.eventName) != null ? _e : this.defaultEventName;
1276
+ const userId = (_f = accumulated.userId) != null ? _f : sticky.userId;
639
1277
  if (!userId) {
640
1278
  if (this.debug) {
641
1279
  console.warn(`${this.prefix} skipping track_partial for ${eventId}: missing userId`);
@@ -643,9 +1281,13 @@ var EventShipper = class {
643
1281
  this.sticky.delete(eventId);
644
1282
  return;
645
1283
  }
646
- const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
647
- const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
648
- const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
1284
+ const { wizardSession, ...restProperties } = (_g = accumulated.properties) != null ? _g : {};
1285
+ let telemetryProperties = {};
1286
+ try {
1287
+ telemetryProperties = eventTelemetryProperties(accumulated);
1288
+ } catch (e) {
1289
+ }
1290
+ const convoId = (_h = accumulated.convoId) != null ? _h : sticky.convoId;
649
1291
  const payload = {
650
1292
  event_id: eventId,
651
1293
  user_id: userId,
@@ -653,15 +1295,17 @@ var EventShipper = class {
653
1295
  timestamp: (_i = accumulated.timestamp) != null ? _i : (/* @__PURE__ */ new Date()).toISOString(),
654
1296
  ai_data: {
655
1297
  input: accumulated.input,
656
- output: accumulated.output,
1298
+ output: accumulated.error !== void 0 && accumulated.error !== null ? void 0 : accumulated.output,
657
1299
  model: accumulated.model,
658
1300
  convo_id: convoId
659
1301
  },
660
1302
  properties: {
661
1303
  ...restProperties,
1304
+ ...telemetryProperties,
662
1305
  ...wizardSession ? { "raindrop.wizardSession": wizardSession } : {},
663
1306
  $context: this.context
664
1307
  },
1308
+ ...accumulated.featureFlags && Object.keys(accumulated.featureFlags).length > 0 ? { feature_flags: accumulated.featureFlags } : {},
665
1309
  attachments: accumulated.attachments,
666
1310
  is_pending: isPending
667
1311
  };
@@ -685,29 +1329,30 @@ var EventShipper = class {
685
1329
  endpoint: url
686
1330
  });
687
1331
  }
688
- if (this.localDebuggerUrl) {
689
- mirrorPartialEventToLocalDebugger(payload, {
690
- baseUrl: this.localDebuggerUrl,
691
- writeKey: this.writeKey,
692
- debug: this.debug,
693
- sdkName: this.sdkName
694
- });
695
- }
1332
+ const mirror = this.localDebuggerUrl ? mirrorPartialEventToLocalDebugger(payload, {
1333
+ baseUrl: this.localDebuggerUrl,
1334
+ writeKey: this.writeKey,
1335
+ debug: this.debug,
1336
+ sdkName: this.sdkName
1337
+ }) : void 0;
696
1338
  if (!this.writeKey) {
697
1339
  if (!isPending) this.sticky.delete(eventId);
1340
+ if (mirror) await mirror;
698
1341
  return;
699
1342
  }
700
1343
  const opts = this.requestOpts();
701
1344
  if (!opts) {
702
1345
  this.warnShutdownDrop(`track_partial ${eventId}`);
703
1346
  if (!isPending) this.sticky.delete(eventId);
1347
+ if (mirror) await mirror;
704
1348
  return;
705
1349
  }
706
1350
  const p = postJson(url, payload, this.requestHeaders(), opts);
707
- this.inFlight.add(p);
1351
+ const combined = mirror ? Promise.all([mirror, p]).then(() => void 0) : p;
1352
+ this.inFlight.add(combined);
708
1353
  try {
709
1354
  try {
710
- await p;
1355
+ await combined;
711
1356
  if (this.debug) {
712
1357
  console.log(`${this.prefix} sent track_partial ${eventId} (${eventName})`);
713
1358
  }
@@ -719,13 +1364,156 @@ var EventShipper = class {
719
1364
  );
720
1365
  }
721
1366
  } finally {
722
- this.inFlight.delete(p);
1367
+ this.inFlight.delete(combined);
723
1368
  }
724
1369
  if (!isPending) {
725
1370
  this.sticky.delete(eventId);
726
1371
  }
727
1372
  }
728
1373
  };
1374
+ var MODEL_USAGE_ATTRIBUTES = {
1375
+ usageSource: "raindrop.usage.source",
1376
+ providerName: "gen_ai.provider.name",
1377
+ requestModel: "gen_ai.request.model",
1378
+ responseModel: "gen_ai.response.model",
1379
+ inputTokens: "gen_ai.usage.input_tokens",
1380
+ outputTokens: "gen_ai.usage.output_tokens",
1381
+ reasoningTokens: "gen_ai.usage.reasoning_tokens",
1382
+ cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
1383
+ cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
1384
+ providerReportedCost: "gen_ai.usage.provider_reported_cost",
1385
+ nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
1386
+ nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
1387
+ totalOutputTokens: "raindrop.usage.output_tokens.total",
1388
+ reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
1389
+ cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
1390
+ cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
1391
+ };
1392
+ var MODEL_PROVIDER_NAMES = [
1393
+ ["google.vertex.anthropic", "google-vertex"],
1394
+ ["google.vertex_ai", "google-vertex"],
1395
+ ["google.vertex", "google-vertex"],
1396
+ ["gcp.vertex_ai", "google-vertex"],
1397
+ ["gcp.gemini", "google"],
1398
+ ["google_vertexai", "google-vertex"],
1399
+ ["vertex.anthropic", "google-vertex"],
1400
+ ["amazon-bedrock", "amazon-bedrock"],
1401
+ ["aws.bedrock", "amazon-bedrock"],
1402
+ ["bedrock", "amazon-bedrock"],
1403
+ ["anthropic", "anthropic"],
1404
+ ["openai", "openai"],
1405
+ ["google", "google"],
1406
+ ["az.ai.openai", "azure"],
1407
+ ["azure", "azure"],
1408
+ ["openrouter", "openrouter"]
1409
+ ];
1410
+ function canonicalModelProvider(provider) {
1411
+ var _a;
1412
+ const normalizedProvider = provider.trim().toLowerCase();
1413
+ if (normalizedProvider === "gateway") return "vercel";
1414
+ const match = MODEL_PROVIDER_NAMES.find(
1415
+ ([family]) => normalizedProvider === family || normalizedProvider.startsWith(`${family}.`)
1416
+ );
1417
+ return (_a = match == null ? void 0 : match[1]) != null ? _a : normalizedProvider;
1418
+ }
1419
+ var STRING_ALIASES = {
1420
+ [MODEL_USAGE_ATTRIBUTES.requestModel]: ["ai.model.id", "ai.model"]
1421
+ };
1422
+ var NUMBER_ALIASES = {
1423
+ [MODEL_USAGE_ATTRIBUTES.inputTokens]: [
1424
+ "gen_ai.usage.prompt_tokens",
1425
+ "ai.usage.prompt_tokens",
1426
+ "ai.usage.promptTokens",
1427
+ "ai.usage.input_tokens",
1428
+ "ai.usage.inputTokens"
1429
+ ],
1430
+ [MODEL_USAGE_ATTRIBUTES.outputTokens]: [
1431
+ "gen_ai.usage.completion_tokens",
1432
+ "ai.usage.completion_tokens",
1433
+ "ai.usage.completionTokens",
1434
+ "ai.usage.output_tokens",
1435
+ "ai.usage.outputTokens"
1436
+ ],
1437
+ [MODEL_USAGE_ATTRIBUTES.reasoningTokens]: [
1438
+ "gen_ai.usage.reasoning.output_tokens",
1439
+ "ai.usage.reasoningTokens",
1440
+ "ai.usage.thoughts_tokens"
1441
+ ],
1442
+ [MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens]: [
1443
+ "gen_ai.usage.cache_read_tokens",
1444
+ "gen_ai.usage.cache_read.input_tokens",
1445
+ "ai.usage.cachedInputTokens",
1446
+ "ai.usage.cached_tokens",
1447
+ "ai.usage.cache_read_tokens",
1448
+ "ai.usage.cache_read_input_tokens",
1449
+ "ai.usage.cacheReadInputTokens"
1450
+ ],
1451
+ [MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens]: [
1452
+ "gen_ai.usage.cache_creation_input_tokens",
1453
+ "gen_ai.usage.cache_creation.input_tokens",
1454
+ "ai.usage.cacheWriteInputTokens",
1455
+ "ai.usage.cache_creation_input_tokens",
1456
+ "ai.usage.cacheCreationInputTokens"
1457
+ ]
1458
+ };
1459
+ function hasAttribute(attributes, key) {
1460
+ return attributes.some((attribute) => attribute.key === key);
1461
+ }
1462
+ function findStringAttribute(attributes, keys) {
1463
+ return attributes.find(
1464
+ (attribute) => keys.includes(attribute.key) && typeof attribute.value.stringValue === "string" && attribute.value.stringValue.length > 0
1465
+ );
1466
+ }
1467
+ function findNumberAttribute(attributes, keys) {
1468
+ return attributes.find((attribute) => {
1469
+ if (!keys.includes(attribute.key)) return false;
1470
+ if (typeof attribute.value.doubleValue === "number" && Number.isSafeInteger(attribute.value.doubleValue) && attribute.value.doubleValue >= 0) {
1471
+ return true;
1472
+ }
1473
+ const intValue = attribute.value.intValue;
1474
+ return integerValue(intValue) !== void 0;
1475
+ });
1476
+ }
1477
+ function integerValue(value) {
1478
+ if (typeof value === "number") {
1479
+ return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
1480
+ }
1481
+ if (typeof value !== "string") return void 0;
1482
+ const parsed = Number(value);
1483
+ return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
1484
+ }
1485
+ function appendAlias(attributes, target, source) {
1486
+ if (!source || hasAttribute(attributes, target)) return attributes;
1487
+ return [...attributes, { key: target, value: { ...source.value } }];
1488
+ }
1489
+ function appendProviderAlias(attributes) {
1490
+ if (hasAttribute(attributes, MODEL_USAGE_ATTRIBUTES.providerName)) return attributes;
1491
+ const source = findStringAttribute(attributes, ["gen_ai.system", "ai.model.provider"]);
1492
+ if (!(source == null ? void 0 : source.value.stringValue)) return attributes;
1493
+ const attribute = attrString(
1494
+ MODEL_USAGE_ATTRIBUTES.providerName,
1495
+ canonicalModelProvider(source.value.stringValue)
1496
+ );
1497
+ return attribute ? [...attributes, attribute] : attributes;
1498
+ }
1499
+ function normalizeModelUsageSpan(span) {
1500
+ const original = span.attributes;
1501
+ if (!original || original.length === 0) return span;
1502
+ const responseModel = findStringAttribute(original, [
1503
+ MODEL_USAGE_ATTRIBUTES.responseModel,
1504
+ "ai.response.model"
1505
+ ]);
1506
+ if (!responseModel) return span;
1507
+ let attributes = appendAlias(original, MODEL_USAGE_ATTRIBUTES.responseModel, responseModel);
1508
+ attributes = appendProviderAlias(attributes);
1509
+ for (const [target, aliases] of Object.entries(STRING_ALIASES)) {
1510
+ attributes = appendAlias(attributes, target, findStringAttribute(attributes, aliases));
1511
+ }
1512
+ for (const [target, aliases] of Object.entries(NUMBER_ALIASES)) {
1513
+ attributes = appendAlias(attributes, target, findNumberAttribute(attributes, aliases));
1514
+ }
1515
+ return attributes === original ? span : { ...span, attributes };
1516
+ }
729
1517
  var DEFAULT_SECRET_KEY_NAMES = [
730
1518
  "apikey",
731
1519
  "apisecret",
@@ -815,6 +1603,20 @@ function redactJsonAttributeValue(key, value) {
815
1603
  if (scrubbedJson === json) return void 0;
816
1604
  return { stringValue: scrubbedJson };
817
1605
  }
1606
+ function appGitOwnerId2(prefix) {
1607
+ try {
1608
+ return `${prefix}:${randomUUID()}`;
1609
+ } catch (e) {
1610
+ return `${prefix}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
1611
+ }
1612
+ }
1613
+ function identityAttrs(args2) {
1614
+ return [
1615
+ attrString("ai.telemetry.metadata.raindrop.ai.userId", args2.userId),
1616
+ attrString("ai.telemetry.metadata.raindrop.convoId", args2.convoId),
1617
+ attrString("ai.telemetry.metadata.raindrop.eventName", args2.eventName)
1618
+ ];
1619
+ }
818
1620
  function applyOtelSpanAttributeLimit(limit) {
819
1621
  var _a, _b;
820
1622
  try {
@@ -830,23 +1632,30 @@ function applyOtelSpanAttributeLimit(limit) {
830
1632
  }
831
1633
  var TraceShipper = class {
832
1634
  constructor(opts) {
1635
+ this.appGitOwner = appGitOwnerId2("trace");
1636
+ this.appGitEventIds = /* @__PURE__ */ new WeakMap();
1637
+ this.appGitActiveSpans = /* @__PURE__ */ new Map();
1638
+ this.appGitCaptured = /* @__PURE__ */ new WeakSet();
1639
+ this.appGitAdded = /* @__PURE__ */ new WeakMap();
833
1640
  this.queue = [];
834
1641
  this.inFlight = /* @__PURE__ */ new Set();
835
1642
  this.hasShutdown = false;
836
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
837
- this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
838
- this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
1643
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1644
+ this.appGitContext = (_a = opts.appGitContext) != null ? _a : createAppGitContext(opts.appGit);
1645
+ this.ownsAppGitContext = opts.appGitContext === void 0;
1646
+ this.writeKey = (_b = opts.writeKey) == null ? void 0 : _b.trim();
1647
+ this.baseUrl = (_c = formatEndpoint(opts.endpoint)) != null ? _c : "https://api.raindrop.ai/v1/";
839
1648
  this.enabled = opts.enabled !== false;
840
1649
  this.debug = opts.debug;
841
1650
  this.debugSpans = opts.debugSpans === true;
842
- this.flushIntervalMs = (_c = opts.flushIntervalMs) != null ? _c : 1e3;
843
- this.maxBatchSize = (_d = opts.maxBatchSize) != null ? _d : 50;
844
- this.maxQueueSize = (_e = opts.maxQueueSize) != null ? _e : 5e3;
845
- this.sdkName = (_f = opts.sdkName) != null ? _f : "core";
1651
+ this.flushIntervalMs = (_d = opts.flushIntervalMs) != null ? _d : 1e3;
1652
+ this.maxBatchSize = (_e = opts.maxBatchSize) != null ? _e : 50;
1653
+ this.maxQueueSize = (_f = opts.maxQueueSize) != null ? _f : 5e3;
1654
+ this.sdkName = (_g = opts.sdkName) != null ? _g : "core";
846
1655
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
847
- this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
848
- this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
849
- this.localDebuggerUrl = (_i = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _i : void 0;
1656
+ this.serviceName = (_h = opts.serviceName) != null ? _h : "raindrop.core";
1657
+ this.serviceVersion = (_i = opts.serviceVersion) != null ? _i : "0.0.0";
1658
+ this.localDebuggerUrl = (_j = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _j : void 0;
850
1659
  if (this.debug && this.localDebuggerUrl) {
851
1660
  console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
852
1661
  }
@@ -910,7 +1719,10 @@ var TraceShipper = class {
910
1719
  try {
911
1720
  const result = this.transformSpanHook(current);
912
1721
  if (result === null) return null;
913
- if (result !== void 0) current = result;
1722
+ if (result !== void 0) {
1723
+ copyReplayTraceDestination(current, result);
1724
+ current = result;
1725
+ }
914
1726
  } catch (err) {
915
1727
  if (this.debug) {
916
1728
  const msg = err instanceof Error ? err.message : String(err);
@@ -919,10 +1731,20 @@ var TraceShipper = class {
919
1731
  return null;
920
1732
  }
921
1733
  }
1734
+ try {
1735
+ const normalized = normalizeModelUsageSpan(current);
1736
+ copyReplayTraceDestination(current, normalized);
1737
+ current = normalized;
1738
+ } catch (e) {
1739
+ }
922
1740
  if (!this.disableDefaultRedaction) {
923
- current = defaultTransformSpan(current);
1741
+ const redacted = defaultTransformSpan(current);
1742
+ copyReplayTraceDestination(current, redacted);
1743
+ current = redacted;
924
1744
  }
925
- return this.capSpanAttributes(current);
1745
+ const capped = this.capSpanAttributes(current);
1746
+ copyReplayTraceDestination(current, capped);
1747
+ return capped;
926
1748
  }
927
1749
  isDebugEnabled() {
928
1750
  return this.debug;
@@ -934,45 +1756,84 @@ var TraceShipper = class {
934
1756
  return { ...this.authHeaders(), ...projectIdHeaders(this.projectId) };
935
1757
  }
936
1758
  startSpan(args2) {
937
- var _a, _b;
1759
+ var _a, _b, _c;
938
1760
  const ids = createSpanIds(args2.parent);
939
1761
  const started = (_a = args2.startTimeUnixNano) != null ? _a : nowUnixNanoString();
940
1762
  const attrs = [
941
1763
  attrString("ai.telemetry.metadata.raindrop.eventId", args2.eventId),
942
- attrString("ai.operationId", args2.operationId)
1764
+ ...identityAttrs(args2),
1765
+ attrString("ai.operationId", args2.operationId),
1766
+ ...Object.entries(evalScopeAttributes()).map(([key, value]) => attrString(key, value))
943
1767
  ];
944
1768
  if ((_b = args2.attributes) == null ? void 0 : _b.length) attrs.push(...args2.attributes);
945
- const span = { ids, name: args2.name, startTimeUnixNano: started, attributes: attrs };
946
- this.mirrorToLocalDebugger(
947
- buildOtlpSpan({
948
- ids: span.ids,
949
- name: span.name,
950
- startTimeUnixNano: span.startTimeUnixNano,
951
- endTimeUnixNano: span.startTimeUnixNano,
952
- // placeholder — will be updated on endSpan
953
- attributes: span.attributes,
954
- status: { code: SpanStatusCode.UNSET }
955
- })
956
- );
1769
+ const tracksAppGit = this.appGitActiveSpans.has(args2.eventId) || this.appGitActiveSpans.size < 1e4;
1770
+ const appGitOverrides = appGitPropertiesFromAttributes(attrs);
1771
+ const span = {
1772
+ ids,
1773
+ name: args2.name,
1774
+ startTimeUnixNano: started,
1775
+ attributes: withAppGitAttributes(
1776
+ attrs,
1777
+ this.appGitContext.forOperation(args2.eventId, appGitOverrides, this.appGitOwner)
1778
+ )
1779
+ };
1780
+ rememberReplayTraceDestination(span);
1781
+ this.appGitCaptured.add(span);
1782
+ this.appGitEventIds.set(span, args2.eventId);
1783
+ if (tracksAppGit) {
1784
+ this.appGitActiveSpans.set(args2.eventId, ((_c = this.appGitActiveSpans.get(args2.eventId)) != null ? _c : 0) + 1);
1785
+ }
1786
+ this.appGitAdded.set(span, new Set(span.attributes.filter((attr) => !attrs.includes(attr))));
1787
+ const openSpan = buildOtlpSpan({
1788
+ ids: span.ids,
1789
+ name: span.name,
1790
+ startTimeUnixNano: span.startTimeUnixNano,
1791
+ endTimeUnixNano: span.startTimeUnixNano,
1792
+ // placeholder — will be updated on endSpan
1793
+ attributes: span.attributes,
1794
+ status: { code: SpanStatusCode.UNSET }
1795
+ });
1796
+ copyReplayTraceDestination(span, openSpan);
1797
+ this.mirrorToLocalDebugger(openSpan);
957
1798
  return span;
958
1799
  }
959
- mirrorToLocalDebugger(span) {
960
- if (!this.localDebuggerUrl) return;
1800
+ mirrorToLocalDebugger(span, completed = false) {
1801
+ const destination = replayTraceDestinationFor(span);
1802
+ if (destination && destination.kind !== "workshop") return;
1803
+ const localDebuggerUrl = (destination == null ? void 0 : destination.kind) === "workshop" ? destination.url : this.localDebuggerUrl;
1804
+ if (!localDebuggerUrl) return;
961
1805
  const redacted = this.redactSpan(span);
962
1806
  if (redacted === null) return;
1807
+ if (completed && (destination == null ? void 0 : destination.kind) === "workshop") {
1808
+ recordReplayExportedSpan(
1809
+ destination,
1810
+ base64ToHex(redacted.spanId),
1811
+ base64ToHex(redacted.traceId)
1812
+ );
1813
+ }
963
1814
  const body = buildExportTraceServiceRequest([redacted], this.serviceName, this.serviceVersion);
964
- mirrorTraceExportToLocalDebugger(body, {
965
- baseUrl: this.localDebuggerUrl,
1815
+ const p = mirrorTraceExportToLocalDebugger(body, {
1816
+ baseUrl: localDebuggerUrl,
966
1817
  debug: false,
967
1818
  sdkName: this.sdkName
968
1819
  });
1820
+ this.inFlight.add(p);
1821
+ void p.finally(() => {
1822
+ this.inFlight.delete(p);
1823
+ });
969
1824
  }
970
1825
  endSpan(span, extra) {
971
- var _a, _b;
1826
+ var _a, _b, _c;
972
1827
  if (span.endTimeUnixNano) return;
973
1828
  span.endTimeUnixNano = (_a = extra == null ? void 0 : extra.endTimeUnixNano) != null ? _a : nowUnixNanoString();
974
1829
  if ((_b = extra == null ? void 0 : extra.attributes) == null ? void 0 : _b.length) {
1830
+ const overrides = appGitPropertiesFromAttributes(extra.attributes);
1831
+ const eventId2 = this.appGitEventIds.get(span);
1832
+ const snapshot = eventId2 ? this.appGitContext.forOperation(eventId2, overrides, this.appGitOwner) : overrides;
1833
+ const added = this.appGitAdded.get(span);
1834
+ span.attributes = span.attributes.filter((attr) => !(added == null ? void 0 : added.has(attr)) || !attr || !Object.prototype.hasOwnProperty.call(overrides, APP_COMMIT_SHA) && !Object.prototype.hasOwnProperty.call(overrides, attr.key));
975
1835
  span.attributes.push(...extra.attributes);
1836
+ span.attributes = withAppGitAttributes(span.attributes, snapshot);
976
1837
  }
977
1838
  let status = extra == null ? void 0 : extra.status;
978
1839
  if (!status && (extra == null ? void 0 : extra.error) !== void 0) {
@@ -987,29 +1848,65 @@ var TraceShipper = class {
987
1848
  attributes: span.attributes,
988
1849
  status
989
1850
  });
1851
+ copyReplayTraceDestination(span, otlp);
1852
+ this.appGitCaptured.add(otlp);
990
1853
  this.enqueue(otlp);
991
- this.mirrorToLocalDebugger(otlp);
1854
+ this.mirrorToLocalDebugger(otlp, true);
1855
+ const eventId = this.appGitEventIds.get(span);
1856
+ if (eventId && this.appGitActiveSpans.has(eventId)) {
1857
+ const remaining = ((_c = this.appGitActiveSpans.get(eventId)) != null ? _c : 1) - 1;
1858
+ if (remaining > 0) this.appGitActiveSpans.set(eventId, remaining);
1859
+ else {
1860
+ this.appGitActiveSpans.delete(eventId);
1861
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(eventId, this.appGitOwner);
1862
+ else if (this.ownsAppGitContext) this.appGitContext.finishOperation(eventId);
1863
+ }
1864
+ }
992
1865
  }
993
1866
  createSpan(args2) {
994
1867
  var _a;
995
1868
  const ids = createSpanIds(args2.parent);
996
1869
  const attrs = [
997
- attrString("ai.telemetry.metadata.raindrop.eventId", args2.eventId)
1870
+ attrString("ai.telemetry.metadata.raindrop.eventId", args2.eventId),
1871
+ ...identityAttrs(args2),
1872
+ ...Object.entries(evalScopeAttributes()).map(([key, value]) => attrString(key, value))
998
1873
  ];
999
1874
  if ((_a = args2.attributes) == null ? void 0 : _a.length) attrs.push(...args2.attributes);
1875
+ const tracksAppGit = !this.appGitActiveSpans.has(args2.eventId);
1000
1876
  const otlp = buildOtlpSpan({
1001
1877
  ids,
1002
1878
  name: args2.name,
1003
1879
  startTimeUnixNano: args2.startTimeUnixNano,
1004
1880
  endTimeUnixNano: args2.endTimeUnixNano,
1005
- attributes: attrs,
1881
+ attributes: withAppGitAttributes(
1882
+ attrs,
1883
+ this.appGitContext.forOperation(
1884
+ args2.eventId,
1885
+ appGitPropertiesFromAttributes(attrs),
1886
+ this.appGitOwner
1887
+ )
1888
+ ),
1006
1889
  status: args2.status
1007
1890
  });
1891
+ rememberReplayTraceDestination(otlp);
1892
+ this.appGitCaptured.add(otlp);
1893
+ if (tracksAppGit) {
1894
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(args2.eventId, this.appGitOwner);
1895
+ else if (this.ownsAppGitContext) this.appGitContext.finishOperation(args2.eventId);
1896
+ }
1008
1897
  this.enqueue(otlp);
1009
- this.mirrorToLocalDebugger(otlp);
1898
+ this.mirrorToLocalDebugger(otlp, true);
1010
1899
  }
1011
1900
  enqueue(span) {
1901
+ var _a;
1012
1902
  if (!this.enabled) return;
1903
+ const attributes = (_a = span.attributes) != null ? _a : [];
1904
+ const enriched = this.appGitCaptured.has(span) ? attributes : withAppGitAttributes(attributes, this.appGitContext.snapshot(appGitPropertiesFromAttributes(attributes)));
1905
+ if (enriched !== attributes) {
1906
+ const original = span;
1907
+ span = { ...span, attributes: enriched.filter((attr) => attr !== void 0) };
1908
+ copyReplayTraceDestination(original, span);
1909
+ }
1013
1910
  if (this.debugSpans) {
1014
1911
  const short = (s) => s ? s.slice(-8) : "none";
1015
1912
  console.log(
@@ -1020,6 +1917,13 @@ var TraceShipper = class {
1020
1917
  }
1021
1918
  const redacted = this.redactSpan(span);
1022
1919
  if (redacted === null) return;
1920
+ const destination = replayTraceDestinationFor(redacted);
1921
+ recordReplayExportedSpan(
1922
+ destination,
1923
+ base64ToHex(redacted.spanId),
1924
+ base64ToHex(redacted.traceId)
1925
+ );
1926
+ if ((destination == null ? void 0 : destination.kind) === "workshop") return;
1023
1927
  if (this.queue.length >= this.maxQueueSize) {
1024
1928
  this.queue.shift();
1025
1929
  }
@@ -1038,47 +1942,67 @@ var TraceShipper = class {
1038
1942
  }
1039
1943
  }
1040
1944
  async flush() {
1041
- if (!this.enabled) return;
1945
+ var _a;
1946
+ if (!this.enabled) {
1947
+ await Promise.all([...this.inFlight].map((p) => p.catch(() => {
1948
+ })));
1949
+ return;
1950
+ }
1042
1951
  if (this.timer) {
1043
1952
  clearTimeout(this.timer);
1044
1953
  this.timer = void 0;
1045
1954
  }
1046
1955
  while (this.queue.length > 0) {
1047
1956
  const batch = this.queue.splice(0, this.maxBatchSize);
1048
- if (!this.writeKey) continue;
1049
- const opts = this.requestOpts();
1050
- if (!opts) {
1051
- rateLimitedLog(
1052
- `${this.prefix}.shutdown_deadline`,
1053
- () => console.warn(
1054
- `${this.prefix} shutdown flush deadline exceeded; dropping ${batch.length} spans`
1055
- )
1056
- );
1057
- continue;
1058
- }
1059
- const body = buildExportTraceServiceRequest(batch, this.serviceName, this.serviceVersion);
1060
- const url = `${this.baseUrl}traces`;
1061
- if (this.debug) {
1062
- console.log(`${this.prefix} sending traces batch`, {
1063
- spans: batch.length,
1064
- endpoint: url
1065
- });
1957
+ const groups = /* @__PURE__ */ new Map();
1958
+ for (const span of batch) {
1959
+ const destination = replayTraceDestinationFor(span);
1960
+ const spans = groups.get(destination);
1961
+ if (spans) spans.push(span);
1962
+ else groups.set(destination, [span]);
1066
1963
  }
1067
- const p = postJson(url, body, this.requestHeaders(), opts);
1068
- this.inFlight.add(p);
1069
- try {
1070
- try {
1071
- await p;
1072
- if (this.debug) console.log(`${this.prefix} sent ${batch.length} spans`);
1073
- } catch (err) {
1074
- const msg = err instanceof Error ? err.message : String(err);
1964
+ for (const [destination, spans] of groups) {
1965
+ if (!destination && !this.writeKey) continue;
1966
+ if ((destination == null ? void 0 : destination.kind) === "workshop") continue;
1967
+ const opts = this.requestOpts();
1968
+ if (!opts) {
1075
1969
  rateLimitedLog(
1076
- `${this.prefix}.send_spans_failed`,
1077
- () => console.warn(`${this.prefix} failed to send ${batch.length} spans: ${msg}`)
1970
+ `${this.prefix}.shutdown_deadline`,
1971
+ () => console.warn(
1972
+ `${this.prefix} shutdown flush deadline exceeded; dropping ${spans.length} spans`
1973
+ )
1078
1974
  );
1975
+ continue;
1976
+ }
1977
+ const body = buildExportTraceServiceRequest(spans, this.serviceName, this.serviceVersion);
1978
+ const url = destination ? replayTraceUrl(destination.url) : `${this.baseUrl}traces`;
1979
+ const headers = destination ? {
1980
+ Authorization: `Bearer ${destination.apiKey}`,
1981
+ "X-Raindrop-Replay-Id": destination.replayId,
1982
+ "X-Raindrop-Project-Id": (_a = destination.projectId) != null ? _a : "default"
1983
+ } : this.requestHeaders();
1984
+ if (this.debug) {
1985
+ console.log(`${this.prefix} sending traces batch`, {
1986
+ spans: spans.length,
1987
+ endpoint: url
1988
+ });
1989
+ }
1990
+ const p = postJson(url, body, headers, opts);
1991
+ this.inFlight.add(p);
1992
+ try {
1993
+ try {
1994
+ await p;
1995
+ if (this.debug) console.log(`${this.prefix} sent ${spans.length} spans`);
1996
+ } catch (err) {
1997
+ const msg = err instanceof Error ? err.message : String(err);
1998
+ rateLimitedLog(
1999
+ `${this.prefix}.send_spans_failed`,
2000
+ () => console.warn(`${this.prefix} failed to send ${spans.length} spans: ${msg}`)
2001
+ );
2002
+ }
2003
+ } finally {
2004
+ this.inFlight.delete(p);
1079
2005
  }
1080
- } finally {
1081
- this.inFlight.delete(p);
1082
2006
  }
1083
2007
  }
1084
2008
  }
@@ -1121,17 +2045,165 @@ var TraceShipper = class {
1121
2045
  if (!settled) {
1122
2046
  rateLimitedLog(
1123
2047
  `${this.prefix}.shutdown_deadline`,
1124
- () => console.warn(`${this.prefix} shutdown flush deadline exceeded; abandoning in-flight spans`)
2048
+ () => console.warn(
2049
+ `${this.prefix} shutdown flush deadline exceeded; abandoning in-flight spans`
2050
+ )
1125
2051
  );
1126
2052
  }
1127
2053
  } finally {
1128
2054
  this.shutdownDeadlineAt = void 0;
2055
+ if (this.ownsAppGitContext) this.appGitContext.dispose();
1129
2056
  }
1130
2057
  }
1131
2058
  };
1132
2059
 
1133
2060
  // ../core/dist/index.node.js
1134
2061
  import { AsyncLocalStorage } from "async_hooks";
2062
+ import { execFile } from "child_process";
2063
+ import { resolve } from "path";
2064
+ var resolveLocal = (sourceDirectory, detectBranch, completed) => {
2065
+ const cwd = sourceDirectory ? resolve(sourceDirectory) : process.cwd();
2066
+ let cancelled = false;
2067
+ let active;
2068
+ let deadlineTimer;
2069
+ const deadline = Date.now() + 1e3;
2070
+ const run = (args2, done) => {
2071
+ if (cancelled) return;
2072
+ const remaining = deadline - Date.now();
2073
+ if (remaining <= 0) {
2074
+ done(void 0);
2075
+ return;
2076
+ }
2077
+ try {
2078
+ active = execFile(
2079
+ "git",
2080
+ args2,
2081
+ {
2082
+ cwd,
2083
+ encoding: "utf8",
2084
+ maxBuffer: 4096,
2085
+ windowsHide: true,
2086
+ env: {
2087
+ ...process.env,
2088
+ // The selected application cwd, not the invoking shell's Git plumbing, owns identity.
2089
+ GIT_DIR: void 0,
2090
+ GIT_WORK_TREE: void 0,
2091
+ GIT_COMMON_DIR: void 0,
2092
+ GIT_NAMESPACE: void 0,
2093
+ GIT_INDEX_FILE: void 0,
2094
+ GIT_OBJECT_DIRECTORY: void 0,
2095
+ GIT_ALTERNATE_OBJECT_DIRECTORIES: void 0,
2096
+ GIT_CONFIG_PARAMETERS: void 0,
2097
+ GIT_CONFIG_COUNT: "0",
2098
+ GIT_TERMINAL_PROMPT: "0",
2099
+ GIT_OPTIONAL_LOCKS: "0"
2100
+ }
2101
+ },
2102
+ (error, stdout) => {
2103
+ clearTimeout(deadlineTimer);
2104
+ deadlineTimer = void 0;
2105
+ active = void 0;
2106
+ if (!cancelled) {
2107
+ try {
2108
+ done(error ? void 0 : stdout.trim());
2109
+ } catch (e) {
2110
+ }
2111
+ }
2112
+ }
2113
+ );
2114
+ active.unref();
2115
+ if (active.stdout && "unref" in active.stdout && typeof active.stdout.unref === "function")
2116
+ active.stdout.unref();
2117
+ if (active.stderr && "unref" in active.stderr && typeof active.stderr.unref === "function")
2118
+ active.stderr.unref();
2119
+ deadlineTimer = setTimeout(() => {
2120
+ try {
2121
+ active == null ? void 0 : active.kill("SIGKILL");
2122
+ } catch (e) {
2123
+ }
2124
+ }, remaining);
2125
+ deadlineTimer.unref();
2126
+ } catch (e) {
2127
+ try {
2128
+ done(void 0);
2129
+ } catch (e2) {
2130
+ }
2131
+ }
2132
+ };
2133
+ const scheduled = setTimeout(() => {
2134
+ try {
2135
+ run(["rev-parse", "HEAD"], (rawSha) => {
2136
+ const commitSha = validAppCommitSha(rawSha);
2137
+ if (!commitSha) {
2138
+ completed({});
2139
+ return;
2140
+ }
2141
+ run(["-c", "core.fsmonitor=false", "status", "--porcelain"], (status) => {
2142
+ const finish = (branch) => {
2143
+ run(["rev-parse", "HEAD"], (finalSha) => {
2144
+ const coherent = validAppCommitSha(finalSha) === commitSha;
2145
+ completed({
2146
+ commitSha,
2147
+ ...coherent && status !== void 0 ? { commitDirty: status !== "" } : {},
2148
+ ...coherent && branch && branch !== "HEAD" ? { branch } : {}
2149
+ });
2150
+ });
2151
+ };
2152
+ if (detectBranch) run(["symbolic-ref", "--quiet", "--short", "HEAD"], finish);
2153
+ else finish();
2154
+ });
2155
+ });
2156
+ } catch (e) {
2157
+ completed({});
2158
+ }
2159
+ }, 0);
2160
+ scheduled.unref();
2161
+ return () => {
2162
+ cancelled = true;
2163
+ clearTimeout(scheduled);
2164
+ clearTimeout(deadlineTimer);
2165
+ try {
2166
+ active == null ? void 0 : active.kill("SIGKILL");
2167
+ } catch (e) {
2168
+ }
2169
+ };
2170
+ };
2171
+ function createAppGitContext2(options, runtime = {}) {
2172
+ return new AppGitContext(options, { ...runtime, resolveLocal });
2173
+ }
2174
+ function hasDestination(options) {
2175
+ var _a;
2176
+ if (options.enabled === false) return false;
2177
+ return Boolean(((_a = options.writeKey) == null ? void 0 : _a.trim()) || resolveLocalDebuggerBaseUrl(options.localDebuggerUrl));
2178
+ }
2179
+ var EventShipper2 = class extends EventShipper {
2180
+ constructor(options) {
2181
+ var _a;
2182
+ const ownsAppGitContext = options.appGitContext === void 0;
2183
+ const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
2184
+ try {
2185
+ super({ ...options, appGitContext });
2186
+ } catch (error) {
2187
+ if (ownsAppGitContext) appGitContext.dispose();
2188
+ throw error;
2189
+ }
2190
+ if (ownsAppGitContext) this.ownAppGitContextForShutdown();
2191
+ }
2192
+ };
2193
+ var TraceShipper2 = class extends TraceShipper {
2194
+ constructor(options) {
2195
+ var _a;
2196
+ const ownsAppGitContext = options.appGitContext === void 0;
2197
+ const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
2198
+ try {
2199
+ super({ ...options, appGitContext });
2200
+ } catch (error) {
2201
+ if (ownsAppGitContext) appGitContext.dispose();
2202
+ throw error;
2203
+ }
2204
+ this.ownsAppGitContext = ownsAppGitContext;
2205
+ }
2206
+ };
1135
2207
  globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = AsyncLocalStorage;
1136
2208
  var SUPPRESS_TRACING_KEY = /* @__PURE__ */ Symbol.for(
1137
2209
  "OpenTelemetry SDK Context Key SUPPRESS_TRACING"
@@ -1159,12 +2231,84 @@ function installTracingSuppressionHook() {
1159
2231
  }
1160
2232
  installTracingSuppressionHook();
1161
2233
 
2234
+ // package.json
2235
+ var package_default = {
2236
+ name: "@raindrop-ai/claude-code",
2237
+ version: "0.0.20",
2238
+ description: "Raindrop observability for Claude Code CLI \u2014 automatic session, tool call, and prompt tracing via hooks",
2239
+ license: "MIT",
2240
+ homepage: "https://www.raindrop.ai/docs/integrations/claude-code/",
2241
+ bugs: {
2242
+ url: "https://www.raindrop.ai/docs/support/"
2243
+ },
2244
+ type: "module",
2245
+ main: "dist/index.cjs",
2246
+ module: "dist/index.js",
2247
+ types: "dist/index.d.ts",
2248
+ bin: {
2249
+ "raindrop-claude-code": "dist/cli.js"
2250
+ },
2251
+ exports: {
2252
+ ".": {
2253
+ import: {
2254
+ types: "./dist/index.d.ts",
2255
+ default: "./dist/index.js"
2256
+ },
2257
+ require: {
2258
+ types: "./dist/index.d.cts",
2259
+ default: "./dist/index.cjs"
2260
+ }
2261
+ }
2262
+ },
2263
+ sideEffects: false,
2264
+ files: [
2265
+ "dist/**",
2266
+ "README.md",
2267
+ ".claude-plugin/**",
2268
+ "hooks/**",
2269
+ ".mcp.json"
2270
+ ],
2271
+ keywords: [
2272
+ "raindrop",
2273
+ "claude-code",
2274
+ "claude",
2275
+ "anthropic",
2276
+ "observability",
2277
+ "tracing",
2278
+ "hooks",
2279
+ "cli"
2280
+ ],
2281
+ engines: {
2282
+ node: ">=18"
2283
+ },
2284
+ scripts: {
2285
+ build: "tsup",
2286
+ postbuild: "chmod +x ./dist/cli.js && node ./scripts/sync-plugin-version.mjs",
2287
+ prepack: "node ./scripts/sync-plugin-version.mjs",
2288
+ dev: "tsup --watch",
2289
+ clean: "rm -rf dist",
2290
+ test: "pnpm build && cd tests && pnpm test",
2291
+ "test:watch": "cd tests && pnpm test:watch"
2292
+ },
2293
+ devDependencies: {
2294
+ "@raindrop-ai/core": "workspace:*",
2295
+ "@types/node": "^20.11.17",
2296
+ msw: "^2.12.7",
2297
+ tsup: "^8.4.0",
2298
+ typescript: "^5.3.3",
2299
+ vitest: "^2.1.0"
2300
+ },
2301
+ publishConfig: {
2302
+ access: "public"
2303
+ }
2304
+ };
2305
+
1162
2306
  // src/package-info.ts
1163
2307
  var PACKAGE_NAME = "@raindrop-ai/claude-code";
1164
- var PACKAGE_VERSION = "0.0.13";
2308
+ var PACKAGE_VERSION = package_default.version;
1165
2309
 
1166
2310
  // src/shipper.ts
1167
- var EventShipper2 = class extends EventShipper {
2311
+ var EventShipper3 = class extends EventShipper2 {
1168
2312
  constructor(opts) {
1169
2313
  var _a, _b, _c, _d;
1170
2314
  super({
@@ -1176,7 +2320,7 @@ var EventShipper2 = class extends EventShipper {
1176
2320
  });
1177
2321
  }
1178
2322
  };
1179
- var TraceShipper2 = class extends TraceShipper {
2323
+ var TraceShipper3 = class extends TraceShipper2 {
1180
2324
  constructor(opts) {
1181
2325
  var _a, _b, _c;
1182
2326
  super({
@@ -2178,7 +3322,20 @@ function loadConfig() {
2178
3322
  })(),
2179
3323
  eventName: (_l = (_k = process.env["RAINDROP_EVENT_NAME"]) != null ? _k : file.event_name) != null ? _l : "claude_code_session",
2180
3324
  customProperties,
2181
- selfDiagnostics
3325
+ selfDiagnostics,
3326
+ appGit: mapAppGit(file.app_git)
3327
+ };
3328
+ }
3329
+ function mapAppGit(value) {
3330
+ if (value === false) return false;
3331
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
3332
+ return {
3333
+ commitSha: "commit_sha" in value && (typeof value.commit_sha === "string" || value.commit_sha === null) ? value.commit_sha : void 0,
3334
+ commitDirty: "commit_dirty" in value && (typeof value.commit_dirty === "boolean" || value.commit_dirty === null) ? value.commit_dirty : void 0,
3335
+ branch: "branch" in value && (typeof value.branch === "string" || value.branch === null) ? value.branch : void 0,
3336
+ detectBranch: "detect_branch" in value && typeof value.detect_branch === "boolean" ? value.detect_branch : void 0,
3337
+ sourceDirectory: "source_directory" in value && typeof value.source_directory === "string" ? value.source_directory : void 0,
3338
+ autoDetect: "auto_detect" in value && typeof value.auto_detect === "boolean" ? value.auto_detect : void 0
2182
3339
  };
2183
3340
  }
2184
3341
  function getConfigPath() {
@@ -2204,7 +3361,6 @@ import { join as join3 } from "path";
2204
3361
  var DEFAULT_PORT = 5899;
2205
3362
  var DEFAULT_URL = `http://localhost:${DEFAULT_PORT}/v1/`;
2206
3363
  var HEALTH_TIMEOUT_MS = 300;
2207
- var MIRROR_TIMEOUT_MS = 2e3;
2208
3364
  var CACHE_DIR = join3(tmpdir2(), "raindrop-claude-code");
2209
3365
  var CACHE_FILE = join3(CACHE_DIR, "debugger_cache");
2210
3366
  var CACHE_TTL_MS = 5e3;
@@ -2266,20 +3422,22 @@ async function detectLocalDebugger(debug) {
2266
3422
  }
2267
3423
  return { url: detected, autoDetected: detected !== null };
2268
3424
  }
2269
- function mirrorEventToLocalDebugger(baseUrl, payload, debug) {
3425
+ async function mirrorEventToLocalDebugger(baseUrl, payload, debug) {
2270
3426
  const url = `${baseUrl}events/track_partial`;
2271
3427
  if (debug) {
2272
3428
  console.log(`[raindrop-ai/claude-code] Mirroring event to local debugger: ${url}`);
2273
3429
  }
2274
- void runWithTracingSuppressed(
2275
- () => fetch(url, {
2276
- method: "POST",
2277
- headers: { "Content-Type": "application/json" },
2278
- body: JSON.stringify(payload),
2279
- signal: AbortSignal.timeout(MIRROR_TIMEOUT_MS)
2280
- })
2281
- ).catch(() => {
2282
- });
3430
+ try {
3431
+ await runWithTracingSuppressed(
3432
+ () => fetch(url, {
3433
+ method: "POST",
3434
+ headers: { "Content-Type": "application/json" },
3435
+ body: JSON.stringify(payload),
3436
+ signal: AbortSignal.timeout(LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS)
3437
+ })
3438
+ );
3439
+ } catch (e) {
3440
+ }
2283
3441
  }
2284
3442
 
2285
3443
  // src/hook-handler.ts
@@ -2299,16 +3457,16 @@ function hookFlushDeadlineMs() {
2299
3457
  return DEFAULT_HOOK_FLUSH_DEADLINE_MS;
2300
3458
  }
2301
3459
  function withDeadline(promise, ms) {
2302
- return new Promise((resolve2, reject) => {
3460
+ return new Promise((resolve3, reject) => {
2303
3461
  const timer = setTimeout(() => {
2304
3462
  promise.catch(() => {
2305
3463
  });
2306
- resolve2("deadline");
3464
+ resolve3("deadline");
2307
3465
  }, ms);
2308
3466
  promise.then(
2309
3467
  (value) => {
2310
3468
  clearTimeout(timer);
2311
- resolve2(value);
3469
+ resolve3(value);
2312
3470
  },
2313
3471
  (err) => {
2314
3472
  clearTimeout(timer);
@@ -2330,9 +3488,9 @@ function getOtlpTraceId(sessionId) {
2330
3488
  }
2331
3489
  }
2332
3490
  function readStdin() {
2333
- return new Promise((resolve2) => {
3491
+ return new Promise((resolve3) => {
2334
3492
  if (process.stdin.isTTY) {
2335
- resolve2("");
3493
+ resolve3("");
2336
3494
  return;
2337
3495
  }
2338
3496
  const chunks = [];
@@ -2343,7 +3501,7 @@ function readStdin() {
2343
3501
  clearTimeout(timeout);
2344
3502
  process.stdin.removeAllListeners();
2345
3503
  process.stdin.destroy();
2346
- resolve2(value);
3504
+ resolve3(value);
2347
3505
  }
2348
3506
  const timeout = setTimeout(() => {
2349
3507
  done(chunks.length > 0 ? Buffer.concat(chunks).toString("utf-8") : "");
@@ -2354,6 +3512,7 @@ function readStdin() {
2354
3512
  });
2355
3513
  }
2356
3514
  async function handleHook() {
3515
+ var _a;
2357
3516
  const startedAtMs = Date.now();
2358
3517
  const raw = await readStdin();
2359
3518
  if (!raw.trim()) {
@@ -2388,7 +3547,11 @@ async function handleHook() {
2388
3547
  eventName: config.eventName,
2389
3548
  customProperties: config.customProperties
2390
3549
  };
2391
- const eventShipper = new EventShipper2({
3550
+ const appGitContext = createAppGitContext2(
3551
+ ((_a = config.writeKey) == null ? void 0 : _a.trim()) || hasDebugger ? config.appGit : false,
3552
+ { allowLocalGit: false }
3553
+ );
3554
+ const eventShipper = new EventShipper3({
2392
3555
  writeKey: config.writeKey,
2393
3556
  endpoint: config.endpoint,
2394
3557
  debug: config.debug,
@@ -2396,39 +3559,46 @@ async function handleHook() {
2396
3559
  // Only ship to the cloud when we have an API key. When only the local
2397
3560
  // debugger is present the shipper still needs to be instantiated so the
2398
3561
  // event mapper can call patch/finish, but cloud POSTs are skipped.
2399
- enabled: hasCloudKey
3562
+ enabled: hasCloudKey,
3563
+ appGitContext
2400
3564
  });
2401
- const traceShipper = new TraceShipper2({
3565
+ const traceShipper = new TraceShipper3({
2402
3566
  writeKey: config.writeKey,
2403
3567
  endpoint: config.endpoint,
2404
3568
  debug: config.debug,
2405
3569
  projectId: config.projectId,
2406
- enabled: hasCloudKey
3570
+ enabled: hasCloudKey,
3571
+ appGitContext
2407
3572
  });
2408
3573
  if (debugger_.url) {
2409
3574
  const debuggerUrl = debugger_.url;
2410
3575
  const origPatch = eventShipper.patch.bind(eventShipper);
2411
3576
  eventShipper.patch = async (eventId, patch) => {
2412
- var _a, _b, _c, _d;
2413
- const traceId = (_a = getOtlpTraceId(payload.session_id)) != null ? _a : payload.session_id;
2414
- mirrorEventToLocalDebugger(debuggerUrl, {
2415
- event_id: eventId,
2416
- user_id: (_b = patch.userId) != null ? _b : config.userId,
2417
- event: (_c = patch.eventName) != null ? _c : "claude_code_session",
2418
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2419
- ai_data: {
2420
- input: patch.input,
2421
- output: patch.output,
2422
- model: patch.model,
2423
- convo_id: patch.convoId
2424
- },
2425
- properties: {
2426
- ...patch.properties,
2427
- ...payload.session_id ? { trace_id: traceId } : {}
2428
- },
2429
- is_pending: (_d = patch.isPending) != null ? _d : true
2430
- }, config.debug);
2431
- await origPatch(eventId, patch);
3577
+ var _a2, _b, _c, _d;
3578
+ const traceId = (_a2 = getOtlpTraceId(payload.session_id)) != null ? _a2 : payload.session_id;
3579
+ await Promise.all([
3580
+ mirrorEventToLocalDebugger(debuggerUrl, {
3581
+ event_id: eventId,
3582
+ user_id: (_b = patch.userId) != null ? _b : config.userId,
3583
+ event: (_c = patch.eventName) != null ? _c : "claude_code_session",
3584
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3585
+ ai_data: {
3586
+ input: patch.input,
3587
+ output: patch.output,
3588
+ model: patch.model,
3589
+ convo_id: patch.convoId
3590
+ },
3591
+ properties: {
3592
+ ...withAppGitProperties(
3593
+ patch.properties,
3594
+ appGitContext.forOperation(eventId, patch.properties)
3595
+ ),
3596
+ ...payload.session_id ? { trace_id: traceId } : {}
3597
+ },
3598
+ is_pending: (_d = patch.isPending) != null ? _d : true
3599
+ }, config.debug),
3600
+ origPatch(eventId, patch)
3601
+ ]);
2432
3602
  };
2433
3603
  }
2434
3604
  try {
@@ -2436,14 +3606,23 @@ async function handleHook() {
2436
3606
  MIN_FLUSH_WINDOW_MS,
2437
3607
  hookFlushDeadlineMs() - (Date.now() - startedAtMs)
2438
3608
  );
2439
- const outcome = await withDeadline(
2440
- (async () => {
3609
+ const hookWork = (async () => {
3610
+ try {
2441
3611
  await mapHookToRaindrop(payload, mapperConfig, eventShipper, traceShipper);
2442
3612
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
2443
3613
  await Promise.all([eventShipper.shutdown(), traceShipper.shutdown()]);
2444
- })(),
2445
- remainingMs
2446
- );
3614
+ } finally {
3615
+ try {
3616
+ appGitContext.dispose();
3617
+ } catch (e) {
3618
+ }
3619
+ }
3620
+ })();
3621
+ const outcome = await withDeadline(hookWork, remainingMs);
3622
+ try {
3623
+ appGitContext.dispose();
3624
+ } catch (e) {
3625
+ }
2447
3626
  if (outcome === "deadline" && config.debug) {
2448
3627
  console.error(
2449
3628
  `[raindrop-ai/claude-code] hook work exceeded the ${hookFlushDeadlineMs()}ms deadline; exiting without waiting on the network (pending telemetry dropped)`
@@ -2461,12 +3640,12 @@ async function handleHook() {
2461
3640
  // src/setup.ts
2462
3641
  import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
2463
3642
  import { homedir as homedir2, userInfo as userInfo2 } from "os";
2464
- import { dirname as dirname2, join as join5, resolve } from "path";
3643
+ import { dirname as dirname2, join as join5, resolve as resolve2 } from "path";
2465
3644
  import { createInterface } from "readline";
2466
3645
  import { execSync as execSync2 } from "child_process";
2467
3646
  function getClaudeSettingsPath(scope, cwd) {
2468
3647
  if (scope === "project") {
2469
- return resolve(cwd, ".claude", "settings.json");
3648
+ return resolve2(cwd, ".claude", "settings.json");
2470
3649
  }
2471
3650
  return join5(homedir2(), ".claude", "settings.json");
2472
3651
  }
@@ -2549,10 +3728,10 @@ function makeHookConfig(hookEvents, useAsync) {
2549
3728
  }
2550
3729
  function prompt(question) {
2551
3730
  const rl = createInterface({ input: process.stdin, output: process.stdout });
2552
- return new Promise((resolve2) => {
3731
+ return new Promise((resolve3) => {
2553
3732
  rl.question(question, (answer) => {
2554
3733
  rl.close();
2555
- resolve2(answer.trim());
3734
+ resolve3(answer.trim());
2556
3735
  });
2557
3736
  });
2558
3737
  }
@@ -2892,6 +4071,7 @@ function resolveCurrentEventId() {
2892
4071
  }
2893
4072
  }
2894
4073
  async function executeTool(args2) {
4074
+ var _a;
2895
4075
  const category = typeof args2["category"] === "string" ? args2["category"] : "";
2896
4076
  const detail = typeof args2["detail"] === "string" ? args2["detail"] : "";
2897
4077
  if (!category || !activeSignals[category]) {
@@ -2917,12 +4097,17 @@ async function executeTool(args2) {
2917
4097
  if (!eventId) {
2918
4098
  return { content: [{ type: "text", text: "Signal noted (no active event found)." }] };
2919
4099
  }
2920
- const shipper = new EventShipper2({
4100
+ const appGitContext = createAppGitContext2(
4101
+ ((_a = config.writeKey) == null ? void 0 : _a.trim()) ? config.appGit : false,
4102
+ { allowLocalGit: false }
4103
+ );
4104
+ const shipper = new EventShipper3({
2921
4105
  writeKey: config.writeKey,
2922
4106
  endpoint: config.endpoint,
2923
4107
  debug: false,
2924
4108
  projectId: config.projectId,
2925
- enabled: true
4109
+ enabled: true,
4110
+ appGitContext
2926
4111
  });
2927
4112
  try {
2928
4113
  const signalDef = activeSignals[category];
@@ -2949,6 +4134,11 @@ async function executeTool(args2) {
2949
4134
  });
2950
4135
  await shipper.shutdown();
2951
4136
  } catch (e) {
4137
+ } finally {
4138
+ try {
4139
+ appGitContext.dispose();
4140
+ } catch (e) {
4141
+ }
2952
4142
  }
2953
4143
  return { content: [{ type: "text", text: "Signal recorded." }] };
2954
4144
  }
@@ -3074,8 +4264,8 @@ var args = process.argv.slice(2);
3074
4264
  var command = args[0];
3075
4265
  function parseFlag(name) {
3076
4266
  const prefix = `--${name}=`;
3077
- const flag = args.find((a) => a.startsWith(prefix));
3078
- return flag ? flag.slice(prefix.length) : void 0;
4267
+ const flag2 = args.find((a) => a.startsWith(prefix));
4268
+ return flag2 ? flag2.slice(prefix.length) : void 0;
3079
4269
  }
3080
4270
  async function main() {
3081
4271
  switch (command) {