@raindrop-ai/claude-code 0.0.19 → 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/index.js CHANGED
@@ -1,4 +1,518 @@
1
- // ../core/dist/chunk-5PSWD267.js
1
+ // ../core/dist/chunk-BYBMRLZM.js
2
+ var EVAL_CORRELATION_ID_ATTRIBUTE = "raindrop.eval_correlation_id";
3
+ var PROBE_SCOPE = { correlationId: "" };
4
+ var EvalScopeStorage = class {
5
+ constructor() {
6
+ this._als = null;
7
+ this._probed = false;
8
+ }
9
+ maybeAdoptAsyncLocalStorage() {
10
+ if (this._probed) return;
11
+ this._probed = true;
12
+ try {
13
+ const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
14
+ if (!Ctor) return;
15
+ const als = new Ctor();
16
+ als.run(PROBE_SCOPE, () => {
17
+ });
18
+ this._als = als;
19
+ } catch (e) {
20
+ this._als = null;
21
+ }
22
+ }
23
+ run(scope, callback) {
24
+ this.maybeAdoptAsyncLocalStorage();
25
+ if (this._als) return this._als.run(scope, callback);
26
+ const previous = this._syncScope;
27
+ this._syncScope = scope;
28
+ try {
29
+ return callback();
30
+ } finally {
31
+ this._syncScope = previous;
32
+ }
33
+ }
34
+ current() {
35
+ this.maybeAdoptAsyncLocalStorage();
36
+ if (this._als) return this._als.getStore();
37
+ return this._syncScope;
38
+ }
39
+ };
40
+ var EVAL_SCOPE_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.evalScopeStorage");
41
+ function evalScopeStorage() {
42
+ const holder = globalThis;
43
+ let storage = holder[EVAL_SCOPE_STORAGE_KEY];
44
+ if (!storage) {
45
+ storage = new EvalScopeStorage();
46
+ holder[EVAL_SCOPE_STORAGE_KEY] = storage;
47
+ }
48
+ return storage;
49
+ }
50
+ function currentEvalScope() {
51
+ try {
52
+ return evalScopeStorage().current();
53
+ } catch (e) {
54
+ return void 0;
55
+ }
56
+ }
57
+ function evalScopeAttributes() {
58
+ const scope = currentEvalScope();
59
+ if (!scope) return {};
60
+ return { [EVAL_CORRELATION_ID_ATTRIBUTE]: scope.correlationId };
61
+ }
62
+
63
+ // ../core/dist/chunk-WJOR6M7H.js
64
+ var STATE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.replayTraceRoutingState");
65
+ function state() {
66
+ const holder = globalThis;
67
+ let current = holder[STATE_KEY];
68
+ if (!current) {
69
+ let storage = null;
70
+ try {
71
+ const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
72
+ if (Ctor) storage = new Ctor();
73
+ } catch (e) {
74
+ storage = null;
75
+ }
76
+ current = {
77
+ storage,
78
+ syncDestination: void 0,
79
+ spanDestinations: /* @__PURE__ */ new WeakMap()
80
+ };
81
+ holder[STATE_KEY] = current;
82
+ }
83
+ return current;
84
+ }
85
+ function currentReplayTraceDestination() {
86
+ var _a, _b;
87
+ const routing = state();
88
+ return (_b = (_a = routing.storage) == null ? void 0 : _a.getStore()) != null ? _b : routing.syncDestination;
89
+ }
90
+ function rememberReplayTraceDestination(span) {
91
+ const destination = currentReplayTraceDestination();
92
+ if (destination) state().spanDestinations.set(span, destination);
93
+ }
94
+ function copyReplayTraceDestination(source, target) {
95
+ const destination = state().spanDestinations.get(source);
96
+ if (destination) state().spanDestinations.set(target, destination);
97
+ }
98
+ function replayTraceDestinationFor(value) {
99
+ if (typeof value !== "object" && typeof value !== "function" || value === null) {
100
+ return void 0;
101
+ }
102
+ return state().spanDestinations.get(value);
103
+ }
104
+ function recordReplayExportedSpan(destination, spanId, traceId) {
105
+ var _a, _b;
106
+ if (!destination || !spanId || !traceId) return;
107
+ (_a = destination.exportedSpanIds) == null ? void 0 : _a.add(spanId);
108
+ (_b = destination.exportedTraceIds) == null ? void 0 : _b.add(traceId);
109
+ }
110
+ function replayTraceUrl(baseUrl) {
111
+ return `${baseUrl.replace(/\/+$/, "")}/v1/traces`;
112
+ }
113
+ function getAsyncLocalStorageCtor() {
114
+ return globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
115
+ }
116
+ var MAX_BINDING_STACK = 128;
117
+ var EMPTY_STACK = [];
118
+ var ContextStackStorage = class {
119
+ /** Emitted once when this runtime cannot support an ambient push. */
120
+ constructor(noAmbientBindWarning) {
121
+ this.noAmbientBindWarning = noAmbientBindWarning;
122
+ this._als = null;
123
+ this._enterWithUsable = false;
124
+ this._syncStack = EMPTY_STACK;
125
+ this._adoptionChecked = false;
126
+ this._warnedNoAmbientBind = false;
127
+ }
128
+ maybeAdoptAsyncLocalStorage() {
129
+ if (this._adoptionChecked) return;
130
+ this._adoptionChecked = true;
131
+ const Ctor = getAsyncLocalStorageCtor();
132
+ if (!Ctor) return;
133
+ const als = new Ctor();
134
+ try {
135
+ als.run(EMPTY_STACK, () => {
136
+ });
137
+ } catch (e) {
138
+ return;
139
+ }
140
+ this._als = als;
141
+ if (typeof als.enterWith === "function") {
142
+ try {
143
+ als.enterWith(EMPTY_STACK);
144
+ this._enterWithUsable = true;
145
+ } catch (e) {
146
+ this._enterWithUsable = false;
147
+ }
148
+ }
149
+ }
150
+ getStack() {
151
+ var _a;
152
+ this.maybeAdoptAsyncLocalStorage();
153
+ if (this._als) return (_a = this._als.getStore()) != null ? _a : this._syncStack;
154
+ return this._syncStack;
155
+ }
156
+ /**
157
+ * Persist an ambient stack mutation. Returns false when an ALS is adopted but
158
+ * `enterWith` is unusable (workerd): callers must NOT fall back to the
159
+ * process-shared sync stack, since concurrent isolates would cross-stamp.
160
+ */
161
+ setAmbientStack(stack) {
162
+ if (this._als) {
163
+ if (!this._enterWithUsable) return false;
164
+ this._als.enterWith(stack);
165
+ return true;
166
+ }
167
+ this._syncStack = stack;
168
+ return true;
169
+ }
170
+ push(binding) {
171
+ this.maybeAdoptAsyncLocalStorage();
172
+ if (this._als && !this._enterWithUsable) {
173
+ this.warnNoAmbientBindOnce();
174
+ return;
175
+ }
176
+ let stack = this.getStack();
177
+ if (stack.length >= MAX_BINDING_STACK) {
178
+ stack = stack.filter((b) => b.isLive());
179
+ if (stack.length >= MAX_BINDING_STACK) {
180
+ stack = stack.slice(stack.length - (MAX_BINDING_STACK - 1));
181
+ }
182
+ }
183
+ this.setAmbientStack([...stack, binding]);
184
+ }
185
+ remove(binding) {
186
+ binding.markDead();
187
+ const stack = this.getStack();
188
+ const pruned = stack.filter((b) => b !== binding && b.isLive());
189
+ if (pruned.length !== stack.length) {
190
+ this.setAmbientStack(pruned);
191
+ }
192
+ }
193
+ runWith(binding, callback) {
194
+ this.maybeAdoptAsyncLocalStorage();
195
+ if (this._als) {
196
+ return this._als.run([...this.getStack(), binding], callback);
197
+ }
198
+ const previous = this._syncStack;
199
+ this._syncStack = [...previous, binding];
200
+ try {
201
+ return callback();
202
+ } finally {
203
+ this._syncStack = previous;
204
+ }
205
+ }
206
+ current() {
207
+ const stack = this.getStack();
208
+ if (stack.length === 0) return void 0;
209
+ const top = stack[stack.length - 1];
210
+ if (top.isLive()) return top;
211
+ const pruned = stack.filter((b) => b.isLive());
212
+ this.setAmbientStack(pruned);
213
+ return pruned.length > 0 ? pruned[pruned.length - 1] : void 0;
214
+ }
215
+ warnNoAmbientBindOnce() {
216
+ if (this._warnedNoAmbientBind) return;
217
+ this._warnedNoAmbientBind = true;
218
+ console.warn(this.noAmbientBindWarning);
219
+ }
220
+ };
221
+ 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.";
222
+ var ROUTING_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.routingContextStorage");
223
+ function routingStorage() {
224
+ const holder = globalThis;
225
+ let storage = holder[ROUTING_STORAGE_KEY];
226
+ if (!storage) {
227
+ storage = new ContextStackStorage(NO_AMBIENT_ROUTING_BIND_WARNING);
228
+ holder[ROUTING_STORAGE_KEY] = storage;
229
+ }
230
+ return storage;
231
+ }
232
+ function currentRoutingBinding() {
233
+ const bound = routingStorage().current();
234
+ if (!bound) return void 0;
235
+ return {
236
+ projectId: bound.projectId,
237
+ authHint: bound.authHint,
238
+ ...bound.appGit ? { appGit: bound.appGit } : {},
239
+ ...bound.appGitSource ? { appGitSource: bound.appGitSource } : {}
240
+ };
241
+ }
242
+ var APP_COMMIT_SHA = "raindrop.app.commit_sha";
243
+ var APP_COMMIT_DIRTY = "raindrop.app.commit_dirty";
244
+ var APP_BRANCH = "raindrop.app.branch";
245
+ var APP_GIT_KEYS = [APP_COMMIT_SHA, APP_COMMIT_DIRTY, APP_BRANCH];
246
+ var own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
247
+ function appGitExplicitKeys(properties) {
248
+ const keys = /* @__PURE__ */ new Set();
249
+ if (!properties) return keys;
250
+ for (const key of APP_GIT_KEYS) {
251
+ if (own(properties, key)) keys.add(key);
252
+ }
253
+ return keys;
254
+ }
255
+ function mergeAppGitSnapshot(base, properties, explicitKeys = /* @__PURE__ */ new Set()) {
256
+ try {
257
+ const result = { ...base };
258
+ if (properties && own(properties, APP_COMMIT_SHA) && properties[APP_COMMIT_SHA] !== result[APP_COMMIT_SHA]) {
259
+ if (!explicitKeys.has(APP_COMMIT_DIRTY) && !own(properties, APP_COMMIT_DIRTY)) {
260
+ delete result[APP_COMMIT_DIRTY];
261
+ }
262
+ if (!explicitKeys.has(APP_BRANCH) && !own(properties, APP_BRANCH)) {
263
+ delete result[APP_BRANCH];
264
+ }
265
+ }
266
+ for (const key of APP_GIT_KEYS) {
267
+ if (properties && own(properties, key)) result[key] = properties[key];
268
+ }
269
+ return Object.freeze(result);
270
+ } catch (e) {
271
+ return Object.freeze({});
272
+ }
273
+ }
274
+ function validAppCommitSha(value) {
275
+ if (typeof value !== "string" || value.length > 128) return void 0;
276
+ const cleaned = value.trim();
277
+ return /^(?:[a-fA-F0-9]{40}|[a-fA-F0-9]{64})$/.test(cleaned) ? cleaned.toLowerCase() : void 0;
278
+ }
279
+ function shortString(value) {
280
+ if (typeof value !== "string" || value.length > 1024) return void 0;
281
+ const cleaned = value.trim();
282
+ return cleaned.length > 0 ? cleaned : void 0;
283
+ }
284
+ function flag(value) {
285
+ if (value === true || value === "true" || value === "1") return true;
286
+ if (value === false || value === "false" || value === "0") return false;
287
+ return void 0;
288
+ }
289
+ function environment() {
290
+ try {
291
+ return typeof process === "undefined" ? {} : process.env;
292
+ } catch (e) {
293
+ return {};
294
+ }
295
+ }
296
+ var DEPLOYMENTS = [
297
+ ["VERCEL", "VERCEL_GIT_COMMIT_SHA", "VERCEL_GIT_COMMIT_REF"],
298
+ ["NETLIFY", "COMMIT_REF", "BRANCH"],
299
+ ["RAILWAY_ENVIRONMENT_NAME", "RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH"],
300
+ ["RAILWAY_ENVIRONMENT", "RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH"],
301
+ ["RENDER", "RENDER_GIT_COMMIT", "RENDER_GIT_BRANCH"],
302
+ ["DYNO", "HEROKU_BUILD_COMMIT", ""],
303
+ ["DYNO", "HEROKU_SLUG_COMMIT", ""],
304
+ ["AWS_APP_ID", "AWS_COMMIT_ID", "AWS_BRANCH"],
305
+ ["WORKERS_CI", "WORKERS_CI_COMMIT_SHA", "WORKERS_CI_BRANCH"]
306
+ ];
307
+ var CI_SOURCES = [
308
+ ["GITHUB_ACTIONS", "GITHUB_SHA", "GITHUB_REF_NAME"],
309
+ ["GITLAB_CI", "CI_COMMIT_SHA", "CI_COMMIT_REF_NAME"],
310
+ ["CIRCLECI", "CIRCLE_SHA1", "CIRCLE_BRANCH"]
311
+ ];
312
+ function detectedSource(env, table, detectBranch) {
313
+ for (const row of table) {
314
+ const [marker, shaKey, branchKey] = row;
315
+ if (!marker || !shaKey || !shortString(env[marker]) || flag(env[marker]) === false) continue;
316
+ const commitSha = validAppCommitSha(env[shaKey]);
317
+ if (commitSha)
318
+ return {
319
+ commitSha,
320
+ ...detectBranch && branchKey ? { branch: shortString(env[branchKey]) } : {}
321
+ };
322
+ }
323
+ return {};
324
+ }
325
+ var AppGitContextImpl = class {
326
+ constructor(options, runtime = {}) {
327
+ this.defaults = {};
328
+ this.explicit = {};
329
+ this.explicitKeys = /* @__PURE__ */ new Set();
330
+ this.disposed = false;
331
+ this.operations = /* @__PURE__ */ new Map();
332
+ this.operationOverflow = false;
333
+ this.detectBranch = false;
334
+ this.disabled = false;
335
+ var _a, _b, _c, _d, _e, _f;
336
+ try {
337
+ if (options === false) {
338
+ this.disabled = true;
339
+ return;
340
+ }
341
+ const opts = options != null ? options : {};
342
+ const env = (_a = runtime.env) != null ? _a : environment();
343
+ const detectBranch = (_c = (_b = flag(opts.detectBranch)) != null ? _b : flag(env.RAINDROP_GIT_DETECT_BRANCH)) != null ? _c : false;
344
+ this.detectBranch = detectBranch;
345
+ const collectBranch = detectBranch || runtime.captureLegacyReplayBranch === true;
346
+ const autoDetect = runtime.allowDiscovery === false ? false : (_e = (_d = flag(opts.autoDetect)) != null ? _d : flag(env.RAINDROP_GIT_AUTO_DETECT)) != null ? _e : true;
347
+ const configuredSha = opts.commitSha;
348
+ const explicitSha = configuredSha === void 0 ? env.RAINDROP_COMMIT_SHA : configuredSha;
349
+ if (explicitSha === null) this.explicit[APP_COMMIT_SHA] = null;
350
+ else if (typeof explicitSha === "string" && validAppCommitSha(explicitSha))
351
+ this.explicit[APP_COMMIT_SHA] = explicitSha;
352
+ const configuredDirty = opts.commitDirty;
353
+ const explicitDirty = configuredDirty === void 0 ? flag(env.RAINDROP_COMMIT_DIRTY) : configuredDirty;
354
+ if (explicitDirty === null || typeof explicitDirty === "boolean")
355
+ this.explicit[APP_COMMIT_DIRTY] = explicitDirty;
356
+ const configuredBranch = opts.branch;
357
+ const explicitBranch = configuredBranch === void 0 ? env.RAINDROP_BRANCH : configuredBranch;
358
+ if (explicitBranch === null) this.explicit[APP_BRANCH] = null;
359
+ else if (typeof explicitBranch === "string" && explicitBranch.length <= 1024)
360
+ this.explicit[APP_BRANCH] = explicitBranch;
361
+ this.explicitKeys = appGitExplicitKeys(this.explicit);
362
+ this.defaults = { ...this.explicit };
363
+ if (!autoDetect || explicitSha !== void 0) return;
364
+ const sourceDirectory = (_f = shortString(opts.sourceDirectory)) != null ? _f : shortString(env.RAINDROP_GIT_SOURCE_DIRECTORY);
365
+ if (runtime.allowLocalGit === false && !sourceDirectory) return;
366
+ const deploy = sourceDirectory ? {} : detectedSource(env, DEPLOYMENTS, collectBranch);
367
+ if (deploy.commitSha) {
368
+ this.accept(deploy);
369
+ return;
370
+ }
371
+ const fallback = sourceDirectory ? {} : detectedSource(env, CI_SOURCES, collectBranch);
372
+ if (runtime.resolveLocal && (runtime.allowLocalGit !== false || sourceDirectory)) {
373
+ this.cancel = runtime.resolveLocal(sourceDirectory, collectBranch, (result) => {
374
+ try {
375
+ if (!this.disposed) this.accept(result.commitSha ? result : fallback);
376
+ } catch (e) {
377
+ }
378
+ });
379
+ } else this.accept(fallback);
380
+ } catch (e) {
381
+ }
382
+ }
383
+ accept(result) {
384
+ const sha = validAppCommitSha(result.commitSha);
385
+ if (!sha) return;
386
+ this.replayBranch = shortString(result.branch);
387
+ this.defaults = {
388
+ [APP_COMMIT_SHA]: sha,
389
+ ...typeof result.commitDirty === "boolean" ? { [APP_COMMIT_DIRTY]: result.commitDirty } : {},
390
+ ...this.detectBranch && this.replayBranch ? { [APP_BRANCH]: this.replayBranch } : {},
391
+ ...this.explicit
392
+ };
393
+ }
394
+ snapshot(properties) {
395
+ var _a;
396
+ try {
397
+ const binding = currentRoutingBinding();
398
+ const base = this.disabled && (binding == null ? void 0 : binding.appGitSource) !== "replay-override" ? {} : (_a = binding == null ? void 0 : binding.appGit) != null ? _a : this.defaults;
399
+ return this.mergeSnapshot(base, properties);
400
+ } catch (e) {
401
+ return Object.freeze({});
402
+ }
403
+ }
404
+ /** Safe defaults when no operation/span start was observed; never infer identity. */
405
+ snapshotExplicit(properties, eventId) {
406
+ try {
407
+ const base = { ...this.explicit };
408
+ const operation = eventId ? this.operations.get(eventId) : void 0;
409
+ if (operation) {
410
+ for (const key of operation.explicitKeys) base[key] = operation.snapshot[key];
411
+ }
412
+ return this.mergeSnapshot(base, properties, new Set(Object.keys(base)));
413
+ } catch (e) {
414
+ return mergeAppGitSnapshot({}, properties);
415
+ }
416
+ }
417
+ /** Existing replay branch reporting stays separate from opt-in event properties. */
418
+ snapshotForReplay() {
419
+ const snapshot = this.snapshot();
420
+ if (this.replayBranch && !own(snapshot, APP_BRANCH) && snapshot[APP_COMMIT_SHA] === this.defaults[APP_COMMIT_SHA]) {
421
+ return Object.freeze({ ...snapshot, [APP_BRANCH]: this.replayBranch });
422
+ }
423
+ return snapshot;
424
+ }
425
+ /** Merge a frozen span snapshot without losing client-authored provenance. */
426
+ mergeSnapshot(base, properties, explicitKeys = this.explicitKeys) {
427
+ return mergeAppGitSnapshot(base, properties, /* @__PURE__ */ new Set([...this.explicitKeys, ...explicitKeys]));
428
+ }
429
+ /** Shippers belonging to one client share this bounded operation registry. */
430
+ forOperation(eventId, properties, owner) {
431
+ if (!eventId) return this.snapshot(properties);
432
+ let operation = this.operations.get(eventId);
433
+ if (!operation) {
434
+ if (this.operations.size >= 1e4) this.operationOverflow = true;
435
+ if (this.operationOverflow) return this.mergeSnapshot({}, properties);
436
+ operation = {
437
+ snapshot: this.snapshot(properties),
438
+ owners: /* @__PURE__ */ new Set(),
439
+ unowned: owner === void 0,
440
+ explicitKeys: appGitExplicitKeys(properties)
441
+ };
442
+ this.operations.set(eventId, operation);
443
+ } else if (properties && APP_GIT_KEYS.some((key) => own(properties, key))) {
444
+ const explicitKeys = /* @__PURE__ */ new Set([...this.explicitKeys, ...operation.explicitKeys]);
445
+ operation.snapshot = this.mergeSnapshot(operation.snapshot, properties, explicitKeys);
446
+ for (const key of appGitExplicitKeys(properties)) operation.explicitKeys.add(key);
447
+ }
448
+ if (!owner) operation.unowned = true;
449
+ if (owner) operation.owners.add(owner);
450
+ return operation.snapshot;
451
+ }
452
+ releaseOperation(eventId, owner) {
453
+ const operation = this.operations.get(eventId);
454
+ if (!operation) return;
455
+ operation.owners.delete(owner);
456
+ if (operation.owners.size === 0 && !operation.unowned) this.operations.delete(eventId);
457
+ }
458
+ finishOperation(eventId) {
459
+ this.operations.delete(eventId);
460
+ }
461
+ dispose() {
462
+ var _a;
463
+ this.disposed = true;
464
+ try {
465
+ (_a = this.cancel) == null ? void 0 : _a.call(this);
466
+ } catch (e) {
467
+ }
468
+ }
469
+ };
470
+ var AppGitContext = AppGitContextImpl;
471
+ function createAppGitContext(options, runtime = {}) {
472
+ return new AppGitContext(options, runtime);
473
+ }
474
+ function withAppGitProperties(properties, snapshot) {
475
+ try {
476
+ const merged = { ...properties };
477
+ for (const key of APP_GIT_KEYS)
478
+ if (!own(merged, key) && own(snapshot, key)) merged[key] = snapshot[key];
479
+ return merged;
480
+ } catch (e) {
481
+ return properties != null ? properties : {};
482
+ }
483
+ }
484
+ function withAppGitAttributes(attributes, snapshot) {
485
+ try {
486
+ const present = new Set(attributes.flatMap((attr) => attr ? [attr.key] : []));
487
+ const added = [];
488
+ for (const key of APP_GIT_KEYS) {
489
+ if (present.has(key) || present.has(`ai.telemetry.metadata.${key}`) || present.has(`traceloop.association.properties.${key}`))
490
+ continue;
491
+ const value = snapshot[key];
492
+ if (typeof value === "string") added.push({ key, value: { stringValue: value } });
493
+ else if (typeof value === "boolean") added.push({ key, value: { boolValue: value } });
494
+ }
495
+ return added.length ? [...attributes, ...added] : attributes;
496
+ } catch (e) {
497
+ return attributes;
498
+ }
499
+ }
500
+ function appGitPropertiesFromAttributes(attributes) {
501
+ var _a, _b, _c;
502
+ const properties = {};
503
+ try {
504
+ for (const attr of attributes) {
505
+ if (!attr) continue;
506
+ for (const key of APP_GIT_KEYS) {
507
+ if (attr.key === key || attr.key === `ai.telemetry.metadata.${key}` || attr.key === `traceloop.association.properties.${key}`) {
508
+ properties[key] = (_c = (_b = (_a = attr.value.stringValue) != null ? _a : attr.value.boolValue) != null ? _b : attr.value.intValue) != null ? _c : null;
509
+ }
510
+ }
511
+ }
512
+ } catch (e) {
513
+ }
514
+ return properties;
515
+ }
2
516
  function getCrypto() {
3
517
  const c = globalThis.crypto;
4
518
  return c;
@@ -13,6 +527,17 @@ function randomBytes(length) {
13
527
  for (let i = 0; i < out.length; i++) out[i] = Math.floor(Math.random() * 256);
14
528
  return out;
15
529
  }
530
+ function randomUUID() {
531
+ const cryptoObj = getCrypto();
532
+ if (cryptoObj && typeof cryptoObj.randomUUID === "function") {
533
+ return cryptoObj.randomUUID();
534
+ }
535
+ const b = randomBytes(16);
536
+ b[6] = b[6] & 15 | 64;
537
+ b[8] = b[8] & 63 | 128;
538
+ const hex = [...b].map((x) => x.toString(16).padStart(2, "0")).join("");
539
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
540
+ }
16
541
  function base64Encode(bytes) {
17
542
  const maybeBuffer = globalThis.Buffer;
18
543
  if (maybeBuffer) {
@@ -42,6 +567,25 @@ function base64Encode(bytes) {
42
567
  }
43
568
  return out;
44
569
  }
570
+ function base64ToHex(value) {
571
+ if (!value) return "";
572
+ const maybeBuffer = globalThis.Buffer;
573
+ if (maybeBuffer) {
574
+ return maybeBuffer.from(value, "base64").toString("hex");
575
+ }
576
+ const atobFn = globalThis.atob;
577
+ if (typeof atobFn !== "function") return "";
578
+ try {
579
+ const binary = atobFn(value);
580
+ let hex = "";
581
+ for (let i = 0; i < binary.length; i++) {
582
+ hex += (binary.charCodeAt(i) & 255).toString(16).padStart(2, "0");
583
+ }
584
+ return hex;
585
+ } catch (e) {
586
+ return "";
587
+ }
588
+ }
45
589
  var HANDOFF_ATTRIBUTE_SUFFIXES = {
46
590
  mode: "raindrop.handoff.mode",
47
591
  childEventId: "raindrop.handoff.childEventId",
@@ -73,7 +617,7 @@ function runWithTracingSuppressed(fn) {
73
617
  var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
74
618
  var MAX_RETRY_DELAY_MS = 3e4;
75
619
  function wait(ms) {
76
- return new Promise((resolve) => setTimeout(resolve, ms));
620
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
77
621
  }
78
622
  function formatEndpoint(endpoint) {
79
623
  if (!endpoint) return void 0;
@@ -110,9 +654,9 @@ async function raceWithTimeout(promise, timeoutMs) {
110
654
  () => true,
111
655
  () => true
112
656
  ),
113
- new Promise((resolve) => {
657
+ new Promise((resolve2) => {
114
658
  var _a;
115
- timer = setTimeout(() => resolve(false), Math.max(0, timeoutMs));
659
+ timer = setTimeout(() => resolve2(false), Math.max(0, timeoutMs));
116
660
  (_a = timer.unref) == null ? void 0 : _a.call(timer);
117
661
  })
118
662
  ]);
@@ -183,6 +727,7 @@ async function postJson(url, body, headers, opts) {
183
727
  const resp = await runWithTracingSuppressed(
184
728
  () => fetch(url, {
185
729
  method: "POST",
730
+ redirect: headers["X-Raindrop-Replay-Id"] !== void 0 ? "error" : "follow",
186
731
  headers: {
187
732
  "Content-Type": "application/json",
188
733
  ...headers
@@ -393,6 +938,13 @@ function projectIdHeaders(projectId) {
393
938
  }
394
939
  var SHUTDOWN_DEADLINE_MS = 1e4;
395
940
  var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
941
+ function appGitOwnerId(prefix) {
942
+ try {
943
+ return `${prefix}:${randomUUID()}`;
944
+ } catch (e) {
945
+ return `${prefix}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
946
+ }
947
+ }
396
948
  function mergePatches(target, source) {
397
949
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
398
950
  const out = { ...target, ...source };
@@ -442,22 +994,25 @@ function eventTelemetryProperties(patch) {
442
994
  }
443
995
  var EventShipper = class {
444
996
  constructor(opts) {
997
+ this.appGitOwner = appGitOwnerId("event");
445
998
  this.buffers = /* @__PURE__ */ new Map();
446
999
  this.sticky = /* @__PURE__ */ new Map();
447
1000
  this.timers = /* @__PURE__ */ new Map();
448
1001
  this.inFlight = /* @__PURE__ */ new Set();
449
1002
  this.hasShutdown = false;
450
- var _a, _b, _c, _d, _e, _f, _g, _h;
451
- this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
452
- this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
1003
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1004
+ this.appGitContext = (_a = opts.appGitContext) != null ? _a : createAppGitContext(opts.appGit);
1005
+ this.ownsAppGitContext = opts.appGitContext === void 0;
1006
+ this.writeKey = (_b = opts.writeKey) == null ? void 0 : _b.trim();
1007
+ this.baseUrl = (_c = formatEndpoint(opts.endpoint)) != null ? _c : "https://api.raindrop.ai/v1/";
453
1008
  this.enabled = opts.enabled !== false;
454
1009
  this.debug = opts.debug;
455
- this.partialFlushMs = (_c = opts.partialFlushMs) != null ? _c : 1e3;
456
- this.sdkName = (_d = opts.sdkName) != null ? _d : "core";
1010
+ this.partialFlushMs = (_d = opts.partialFlushMs) != null ? _d : 1e3;
1011
+ this.sdkName = (_e = opts.sdkName) != null ? _e : "core";
457
1012
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
458
- this.defaultEventName = (_e = opts.defaultEventName) != null ? _e : "ai_generation";
1013
+ this.defaultEventName = (_f = opts.defaultEventName) != null ? _f : "ai_generation";
459
1014
  this.maxTextFieldCharsOpt = opts.maxTextFieldChars;
460
- this.localDebuggerUrl = (_f = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _f : void 0;
1015
+ this.localDebuggerUrl = (_g = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _g : void 0;
461
1016
  if (this.debug && this.localDebuggerUrl) {
462
1017
  console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
463
1018
  }
@@ -468,8 +1023,8 @@ var EventShipper = class {
468
1023
  const isNode = typeof process !== "undefined" && typeof process.version === "string";
469
1024
  this.context = {
470
1025
  library: {
471
- name: (_g = opts.libraryName) != null ? _g : "@raindrop-ai/core",
472
- version: (_h = opts.libraryVersion) != null ? _h : "0.0.0"
1026
+ name: (_h = opts.libraryName) != null ? _h : "@raindrop-ai/core",
1027
+ version: (_i = opts.libraryVersion) != null ? _i : "0.0.0"
473
1028
  },
474
1029
  metadata: {
475
1030
  jsRuntime: isNode ? "node" : "web",
@@ -477,6 +1032,9 @@ var EventShipper = class {
477
1032
  }
478
1033
  };
479
1034
  }
1035
+ ownAppGitContextForShutdown() {
1036
+ this.ownsAppGitContext = true;
1037
+ }
480
1038
  isDebugEnabled() {
481
1039
  return this.debug;
482
1040
  }
@@ -525,6 +1083,15 @@ var EventShipper = class {
525
1083
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
526
1084
  if (!this.enabled) return;
527
1085
  if (!eventId || !eventId.trim()) return;
1086
+ const capturedSticky = this.sticky.get(eventId);
1087
+ const eventAlreadyKnown = capturedSticky !== void 0 || this.buffers.has(eventId);
1088
+ const destination = currentReplayTraceDestination();
1089
+ const cloudReplay = destination !== void 0 && destination.kind !== "workshop";
1090
+ if ((capturedSticky == null ? void 0 : capturedSticky.replayOnly) === true || !eventAlreadyKnown && cloudReplay) {
1091
+ if (patch.isPending === false) this.sticky.delete(eventId);
1092
+ else this.sticky.set(eventId, { ...capturedSticky, replayOnly: true });
1093
+ return;
1094
+ }
528
1095
  const maxChars = resolveMaxTextFieldChars(this.maxTextFieldCharsOpt);
529
1096
  if (typeof patch.input === "string" && patch.input.length > maxChars) {
530
1097
  patch = { ...patch, input: capText(patch.input, maxChars) };
@@ -546,6 +1113,13 @@ var EventShipper = class {
546
1113
  }
547
1114
  const sticky = (_c = this.sticky.get(eventId)) != null ? _c : {};
548
1115
  const existing = (_d = this.buffers.get(eventId)) != null ? _d : {};
1116
+ patch = {
1117
+ ...patch,
1118
+ properties: withAppGitProperties(
1119
+ patch.properties,
1120
+ this.appGitContext.forOperation(eventId, patch.properties, this.appGitOwner)
1121
+ )
1122
+ };
549
1123
  const merged = mergePatches(existing, patch);
550
1124
  merged.isPending = (_g = (_f = (_e = patch.isPending) != null ? _e : existing.isPending) != null ? _f : sticky.isPending) != null ? _g : true;
551
1125
  this.buffers.set(eventId, merged);
@@ -559,6 +1133,8 @@ var EventShipper = class {
559
1133
  if (t) clearTimeout(t);
560
1134
  if (merged.isPending === false) {
561
1135
  await this.flushOne(eventId);
1136
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(eventId, this.appGitOwner);
1137
+ else this.appGitContext.finishOperation(eventId);
562
1138
  return;
563
1139
  }
564
1140
  const timeout = setTimeout(() => {
@@ -583,15 +1159,21 @@ var EventShipper = class {
583
1159
  try {
584
1160
  for (const t of this.timers.values()) clearTimeout(t);
585
1161
  this.timers.clear();
1162
+ for (const [eventId, sticky] of this.sticky) {
1163
+ if (sticky.replayOnly) this.sticky.delete(eventId);
1164
+ }
586
1165
  const settled = await raceWithTimeout(this.flush(), SHUTDOWN_DEADLINE_MS);
587
1166
  if (!settled) this.warnShutdownDrop("in-flight request(s) at shutdown");
588
1167
  } finally {
589
1168
  this.shutdownDeadlineAt = void 0;
1169
+ if (this.ownsAppGitContext) this.appGitContext.dispose();
590
1170
  }
591
1171
  }
592
1172
  async trackSignal(signal) {
593
1173
  var _a, _b;
594
1174
  if (!this.enabled) return;
1175
+ const destination = currentReplayTraceDestination();
1176
+ if (destination && destination.kind !== "workshop") return;
595
1177
  const body = [
596
1178
  {
597
1179
  event_id: signal.eventId,
@@ -626,6 +1208,8 @@ var EventShipper = class {
626
1208
  }
627
1209
  async identify(users) {
628
1210
  if (!this.enabled) return;
1211
+ const destination = currentReplayTraceDestination();
1212
+ if (destination && destination.kind !== "workshop") return;
629
1213
  const list = Array.isArray(users) ? users : [users];
630
1214
  const body = list.filter((user) => {
631
1215
  if (!(user == null ? void 0 : user.userId) || !user.userId.trim()) {
@@ -678,8 +1262,9 @@ var EventShipper = class {
678
1262
  this.buffers.delete(eventId);
679
1263
  if (!accumulated) return;
680
1264
  const sticky = (_a = this.sticky.get(eventId)) != null ? _a : {};
681
- const eventName = (_c = (_b = accumulated.eventName) != null ? _b : sticky.eventName) != null ? _c : this.defaultEventName;
682
- const userId = (_d = accumulated.userId) != null ? _d : sticky.userId;
1265
+ const isPending = (_c = (_b = accumulated.isPending) != null ? _b : sticky.isPending) != null ? _c : true;
1266
+ const eventName = (_e = (_d = accumulated.eventName) != null ? _d : sticky.eventName) != null ? _e : this.defaultEventName;
1267
+ const userId = (_f = accumulated.userId) != null ? _f : sticky.userId;
683
1268
  if (!userId) {
684
1269
  if (this.debug) {
685
1270
  console.warn(`${this.prefix} skipping track_partial for ${eventId}: missing userId`);
@@ -687,14 +1272,13 @@ var EventShipper = class {
687
1272
  this.sticky.delete(eventId);
688
1273
  return;
689
1274
  }
690
- const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
1275
+ const { wizardSession, ...restProperties } = (_g = accumulated.properties) != null ? _g : {};
691
1276
  let telemetryProperties = {};
692
1277
  try {
693
1278
  telemetryProperties = eventTelemetryProperties(accumulated);
694
1279
  } catch (e) {
695
1280
  }
696
- const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
697
- const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
1281
+ const convoId = (_h = accumulated.convoId) != null ? _h : sticky.convoId;
698
1282
  const payload = {
699
1283
  event_id: eventId,
700
1284
  user_id: userId,
@@ -1010,6 +1594,13 @@ function redactJsonAttributeValue(key, value) {
1010
1594
  if (scrubbedJson === json) return void 0;
1011
1595
  return { stringValue: scrubbedJson };
1012
1596
  }
1597
+ function appGitOwnerId2(prefix) {
1598
+ try {
1599
+ return `${prefix}:${randomUUID()}`;
1600
+ } catch (e) {
1601
+ return `${prefix}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
1602
+ }
1603
+ }
1013
1604
  function identityAttrs(args) {
1014
1605
  return [
1015
1606
  attrString("ai.telemetry.metadata.raindrop.ai.userId", args.userId),
@@ -1032,23 +1623,30 @@ function applyOtelSpanAttributeLimit(limit) {
1032
1623
  }
1033
1624
  var TraceShipper = class {
1034
1625
  constructor(opts) {
1626
+ this.appGitOwner = appGitOwnerId2("trace");
1627
+ this.appGitEventIds = /* @__PURE__ */ new WeakMap();
1628
+ this.appGitActiveSpans = /* @__PURE__ */ new Map();
1629
+ this.appGitCaptured = /* @__PURE__ */ new WeakSet();
1630
+ this.appGitAdded = /* @__PURE__ */ new WeakMap();
1035
1631
  this.queue = [];
1036
1632
  this.inFlight = /* @__PURE__ */ new Set();
1037
1633
  this.hasShutdown = false;
1038
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1039
- this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
1040
- this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
1634
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1635
+ this.appGitContext = (_a = opts.appGitContext) != null ? _a : createAppGitContext(opts.appGit);
1636
+ this.ownsAppGitContext = opts.appGitContext === void 0;
1637
+ this.writeKey = (_b = opts.writeKey) == null ? void 0 : _b.trim();
1638
+ this.baseUrl = (_c = formatEndpoint(opts.endpoint)) != null ? _c : "https://api.raindrop.ai/v1/";
1041
1639
  this.enabled = opts.enabled !== false;
1042
1640
  this.debug = opts.debug;
1043
1641
  this.debugSpans = opts.debugSpans === true;
1044
- this.flushIntervalMs = (_c = opts.flushIntervalMs) != null ? _c : 1e3;
1045
- this.maxBatchSize = (_d = opts.maxBatchSize) != null ? _d : 50;
1046
- this.maxQueueSize = (_e = opts.maxQueueSize) != null ? _e : 5e3;
1047
- this.sdkName = (_f = opts.sdkName) != null ? _f : "core";
1642
+ this.flushIntervalMs = (_d = opts.flushIntervalMs) != null ? _d : 1e3;
1643
+ this.maxBatchSize = (_e = opts.maxBatchSize) != null ? _e : 50;
1644
+ this.maxQueueSize = (_f = opts.maxQueueSize) != null ? _f : 5e3;
1645
+ this.sdkName = (_g = opts.sdkName) != null ? _g : "core";
1048
1646
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
1049
- this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
1050
- this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
1051
- this.localDebuggerUrl = (_i = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _i : void 0;
1647
+ this.serviceName = (_h = opts.serviceName) != null ? _h : "raindrop.core";
1648
+ this.serviceVersion = (_i = opts.serviceVersion) != null ? _i : "0.0.0";
1649
+ this.localDebuggerUrl = (_j = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _j : void 0;
1052
1650
  if (this.debug && this.localDebuggerUrl) {
1053
1651
  console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
1054
1652
  }
@@ -1112,7 +1710,10 @@ var TraceShipper = class {
1112
1710
  try {
1113
1711
  const result = this.transformSpanHook(current);
1114
1712
  if (result === null) return null;
1115
- if (result !== void 0) current = result;
1713
+ if (result !== void 0) {
1714
+ copyReplayTraceDestination(current, result);
1715
+ current = result;
1716
+ }
1116
1717
  } catch (err) {
1117
1718
  if (this.debug) {
1118
1719
  const msg = err instanceof Error ? err.message : String(err);
@@ -1122,13 +1723,19 @@ var TraceShipper = class {
1122
1723
  }
1123
1724
  }
1124
1725
  try {
1125
- current = normalizeModelUsageSpan(current);
1726
+ const normalized = normalizeModelUsageSpan(current);
1727
+ copyReplayTraceDestination(current, normalized);
1728
+ current = normalized;
1126
1729
  } catch (e) {
1127
1730
  }
1128
1731
  if (!this.disableDefaultRedaction) {
1129
- current = defaultTransformSpan(current);
1732
+ const redacted = defaultTransformSpan(current);
1733
+ copyReplayTraceDestination(current, redacted);
1734
+ current = redacted;
1130
1735
  }
1131
- return this.capSpanAttributes(current);
1736
+ const capped = this.capSpanAttributes(current);
1737
+ copyReplayTraceDestination(current, capped);
1738
+ return capped;
1132
1739
  }
1133
1740
  isDebugEnabled() {
1134
1741
  return this.debug;
@@ -1140,36 +1747,64 @@ var TraceShipper = class {
1140
1747
  return { ...this.authHeaders(), ...projectIdHeaders(this.projectId) };
1141
1748
  }
1142
1749
  startSpan(args) {
1143
- var _a, _b;
1750
+ var _a, _b, _c;
1144
1751
  const ids = createSpanIds(args.parent);
1145
1752
  const started = (_a = args.startTimeUnixNano) != null ? _a : nowUnixNanoString();
1146
1753
  const attrs = [
1147
1754
  attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
1148
1755
  ...identityAttrs(args),
1149
- attrString("ai.operationId", args.operationId)
1756
+ attrString("ai.operationId", args.operationId),
1757
+ ...Object.entries(evalScopeAttributes()).map(([key, value]) => attrString(key, value))
1150
1758
  ];
1151
1759
  if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
1152
- const span = { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
1153
- this.mirrorToLocalDebugger(
1154
- buildOtlpSpan({
1155
- ids: span.ids,
1156
- name: span.name,
1157
- startTimeUnixNano: span.startTimeUnixNano,
1158
- endTimeUnixNano: span.startTimeUnixNano,
1159
- // placeholder — will be updated on endSpan
1160
- attributes: span.attributes,
1161
- status: { code: SpanStatusCode.UNSET }
1162
- })
1163
- );
1760
+ const tracksAppGit = this.appGitActiveSpans.has(args.eventId) || this.appGitActiveSpans.size < 1e4;
1761
+ const appGitOverrides = appGitPropertiesFromAttributes(attrs);
1762
+ const span = {
1763
+ ids,
1764
+ name: args.name,
1765
+ startTimeUnixNano: started,
1766
+ attributes: withAppGitAttributes(
1767
+ attrs,
1768
+ this.appGitContext.forOperation(args.eventId, appGitOverrides, this.appGitOwner)
1769
+ )
1770
+ };
1771
+ rememberReplayTraceDestination(span);
1772
+ this.appGitCaptured.add(span);
1773
+ this.appGitEventIds.set(span, args.eventId);
1774
+ if (tracksAppGit) {
1775
+ this.appGitActiveSpans.set(args.eventId, ((_c = this.appGitActiveSpans.get(args.eventId)) != null ? _c : 0) + 1);
1776
+ }
1777
+ this.appGitAdded.set(span, new Set(span.attributes.filter((attr) => !attrs.includes(attr))));
1778
+ const openSpan = buildOtlpSpan({
1779
+ ids: span.ids,
1780
+ name: span.name,
1781
+ startTimeUnixNano: span.startTimeUnixNano,
1782
+ endTimeUnixNano: span.startTimeUnixNano,
1783
+ // placeholder — will be updated on endSpan
1784
+ attributes: span.attributes,
1785
+ status: { code: SpanStatusCode.UNSET }
1786
+ });
1787
+ copyReplayTraceDestination(span, openSpan);
1788
+ this.mirrorToLocalDebugger(openSpan);
1164
1789
  return span;
1165
1790
  }
1166
- mirrorToLocalDebugger(span) {
1167
- if (!this.localDebuggerUrl) return;
1791
+ mirrorToLocalDebugger(span, completed = false) {
1792
+ const destination = replayTraceDestinationFor(span);
1793
+ if (destination && destination.kind !== "workshop") return;
1794
+ const localDebuggerUrl = (destination == null ? void 0 : destination.kind) === "workshop" ? destination.url : this.localDebuggerUrl;
1795
+ if (!localDebuggerUrl) return;
1168
1796
  const redacted = this.redactSpan(span);
1169
1797
  if (redacted === null) return;
1798
+ if (completed && (destination == null ? void 0 : destination.kind) === "workshop") {
1799
+ recordReplayExportedSpan(
1800
+ destination,
1801
+ base64ToHex(redacted.spanId),
1802
+ base64ToHex(redacted.traceId)
1803
+ );
1804
+ }
1170
1805
  const body = buildExportTraceServiceRequest([redacted], this.serviceName, this.serviceVersion);
1171
1806
  const p = mirrorTraceExportToLocalDebugger(body, {
1172
- baseUrl: this.localDebuggerUrl,
1807
+ baseUrl: localDebuggerUrl,
1173
1808
  debug: false,
1174
1809
  sdkName: this.sdkName
1175
1810
  });
@@ -1179,11 +1814,17 @@ var TraceShipper = class {
1179
1814
  });
1180
1815
  }
1181
1816
  endSpan(span, extra) {
1182
- var _a, _b;
1817
+ var _a, _b, _c;
1183
1818
  if (span.endTimeUnixNano) return;
1184
1819
  span.endTimeUnixNano = (_a = extra == null ? void 0 : extra.endTimeUnixNano) != null ? _a : nowUnixNanoString();
1185
1820
  if ((_b = extra == null ? void 0 : extra.attributes) == null ? void 0 : _b.length) {
1821
+ const overrides = appGitPropertiesFromAttributes(extra.attributes);
1822
+ const eventId2 = this.appGitEventIds.get(span);
1823
+ const snapshot = eventId2 ? this.appGitContext.forOperation(eventId2, overrides, this.appGitOwner) : overrides;
1824
+ const added = this.appGitAdded.get(span);
1825
+ 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));
1186
1826
  span.attributes.push(...extra.attributes);
1827
+ span.attributes = withAppGitAttributes(span.attributes, snapshot);
1187
1828
  }
1188
1829
  let status = extra == null ? void 0 : extra.status;
1189
1830
  if (!status && (extra == null ? void 0 : extra.error) !== void 0) {
@@ -1198,30 +1839,65 @@ var TraceShipper = class {
1198
1839
  attributes: span.attributes,
1199
1840
  status
1200
1841
  });
1842
+ copyReplayTraceDestination(span, otlp);
1843
+ this.appGitCaptured.add(otlp);
1201
1844
  this.enqueue(otlp);
1202
- this.mirrorToLocalDebugger(otlp);
1845
+ this.mirrorToLocalDebugger(otlp, true);
1846
+ const eventId = this.appGitEventIds.get(span);
1847
+ if (eventId && this.appGitActiveSpans.has(eventId)) {
1848
+ const remaining = ((_c = this.appGitActiveSpans.get(eventId)) != null ? _c : 1) - 1;
1849
+ if (remaining > 0) this.appGitActiveSpans.set(eventId, remaining);
1850
+ else {
1851
+ this.appGitActiveSpans.delete(eventId);
1852
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(eventId, this.appGitOwner);
1853
+ else if (this.ownsAppGitContext) this.appGitContext.finishOperation(eventId);
1854
+ }
1855
+ }
1203
1856
  }
1204
1857
  createSpan(args) {
1205
1858
  var _a;
1206
1859
  const ids = createSpanIds(args.parent);
1207
1860
  const attrs = [
1208
1861
  attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
1209
- ...identityAttrs(args)
1862
+ ...identityAttrs(args),
1863
+ ...Object.entries(evalScopeAttributes()).map(([key, value]) => attrString(key, value))
1210
1864
  ];
1211
1865
  if ((_a = args.attributes) == null ? void 0 : _a.length) attrs.push(...args.attributes);
1866
+ const tracksAppGit = !this.appGitActiveSpans.has(args.eventId);
1212
1867
  const otlp = buildOtlpSpan({
1213
1868
  ids,
1214
1869
  name: args.name,
1215
1870
  startTimeUnixNano: args.startTimeUnixNano,
1216
1871
  endTimeUnixNano: args.endTimeUnixNano,
1217
- attributes: attrs,
1872
+ attributes: withAppGitAttributes(
1873
+ attrs,
1874
+ this.appGitContext.forOperation(
1875
+ args.eventId,
1876
+ appGitPropertiesFromAttributes(attrs),
1877
+ this.appGitOwner
1878
+ )
1879
+ ),
1218
1880
  status: args.status
1219
1881
  });
1882
+ rememberReplayTraceDestination(otlp);
1883
+ this.appGitCaptured.add(otlp);
1884
+ if (tracksAppGit) {
1885
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(args.eventId, this.appGitOwner);
1886
+ else if (this.ownsAppGitContext) this.appGitContext.finishOperation(args.eventId);
1887
+ }
1220
1888
  this.enqueue(otlp);
1221
- this.mirrorToLocalDebugger(otlp);
1889
+ this.mirrorToLocalDebugger(otlp, true);
1222
1890
  }
1223
1891
  enqueue(span) {
1892
+ var _a;
1224
1893
  if (!this.enabled) return;
1894
+ const attributes = (_a = span.attributes) != null ? _a : [];
1895
+ const enriched = this.appGitCaptured.has(span) ? attributes : withAppGitAttributes(attributes, this.appGitContext.snapshot(appGitPropertiesFromAttributes(attributes)));
1896
+ if (enriched !== attributes) {
1897
+ const original = span;
1898
+ span = { ...span, attributes: enriched.filter((attr) => attr !== void 0) };
1899
+ copyReplayTraceDestination(original, span);
1900
+ }
1225
1901
  if (this.debugSpans) {
1226
1902
  const short = (s) => s ? s.slice(-8) : "none";
1227
1903
  console.log(
@@ -1232,6 +1908,13 @@ var TraceShipper = class {
1232
1908
  }
1233
1909
  const redacted = this.redactSpan(span);
1234
1910
  if (redacted === null) return;
1911
+ const destination = replayTraceDestinationFor(redacted);
1912
+ recordReplayExportedSpan(
1913
+ destination,
1914
+ base64ToHex(redacted.spanId),
1915
+ base64ToHex(redacted.traceId)
1916
+ );
1917
+ if ((destination == null ? void 0 : destination.kind) === "workshop") return;
1235
1918
  if (this.queue.length >= this.maxQueueSize) {
1236
1919
  this.queue.shift();
1237
1920
  }
@@ -1250,6 +1933,7 @@ var TraceShipper = class {
1250
1933
  }
1251
1934
  }
1252
1935
  async flush() {
1936
+ var _a;
1253
1937
  if (!this.enabled) {
1254
1938
  await Promise.all([...this.inFlight].map((p) => p.catch(() => {
1255
1939
  })));
@@ -1261,40 +1945,55 @@ var TraceShipper = class {
1261
1945
  }
1262
1946
  while (this.queue.length > 0) {
1263
1947
  const batch = this.queue.splice(0, this.maxBatchSize);
1264
- if (!this.writeKey) continue;
1265
- const opts = this.requestOpts();
1266
- if (!opts) {
1267
- rateLimitedLog(
1268
- `${this.prefix}.shutdown_deadline`,
1269
- () => console.warn(
1270
- `${this.prefix} shutdown flush deadline exceeded; dropping ${batch.length} spans`
1271
- )
1272
- );
1273
- continue;
1274
- }
1275
- const body = buildExportTraceServiceRequest(batch, this.serviceName, this.serviceVersion);
1276
- const url = `${this.baseUrl}traces`;
1277
- if (this.debug) {
1278
- console.log(`${this.prefix} sending traces batch`, {
1279
- spans: batch.length,
1280
- endpoint: url
1281
- });
1948
+ const groups = /* @__PURE__ */ new Map();
1949
+ for (const span of batch) {
1950
+ const destination = replayTraceDestinationFor(span);
1951
+ const spans = groups.get(destination);
1952
+ if (spans) spans.push(span);
1953
+ else groups.set(destination, [span]);
1282
1954
  }
1283
- const p = postJson(url, body, this.requestHeaders(), opts);
1284
- this.inFlight.add(p);
1285
- try {
1286
- try {
1287
- await p;
1288
- if (this.debug) console.log(`${this.prefix} sent ${batch.length} spans`);
1289
- } catch (err) {
1290
- const msg = err instanceof Error ? err.message : String(err);
1955
+ for (const [destination, spans] of groups) {
1956
+ if (!destination && !this.writeKey) continue;
1957
+ if ((destination == null ? void 0 : destination.kind) === "workshop") continue;
1958
+ const opts = this.requestOpts();
1959
+ if (!opts) {
1291
1960
  rateLimitedLog(
1292
- `${this.prefix}.send_spans_failed`,
1293
- () => console.warn(`${this.prefix} failed to send ${batch.length} spans: ${msg}`)
1961
+ `${this.prefix}.shutdown_deadline`,
1962
+ () => console.warn(
1963
+ `${this.prefix} shutdown flush deadline exceeded; dropping ${spans.length} spans`
1964
+ )
1294
1965
  );
1966
+ continue;
1967
+ }
1968
+ const body = buildExportTraceServiceRequest(spans, this.serviceName, this.serviceVersion);
1969
+ const url = destination ? replayTraceUrl(destination.url) : `${this.baseUrl}traces`;
1970
+ const headers = destination ? {
1971
+ Authorization: `Bearer ${destination.apiKey}`,
1972
+ "X-Raindrop-Replay-Id": destination.replayId,
1973
+ "X-Raindrop-Project-Id": (_a = destination.projectId) != null ? _a : "default"
1974
+ } : this.requestHeaders();
1975
+ if (this.debug) {
1976
+ console.log(`${this.prefix} sending traces batch`, {
1977
+ spans: spans.length,
1978
+ endpoint: url
1979
+ });
1980
+ }
1981
+ const p = postJson(url, body, headers, opts);
1982
+ this.inFlight.add(p);
1983
+ try {
1984
+ try {
1985
+ await p;
1986
+ if (this.debug) console.log(`${this.prefix} sent ${spans.length} spans`);
1987
+ } catch (err) {
1988
+ const msg = err instanceof Error ? err.message : String(err);
1989
+ rateLimitedLog(
1990
+ `${this.prefix}.send_spans_failed`,
1991
+ () => console.warn(`${this.prefix} failed to send ${spans.length} spans: ${msg}`)
1992
+ );
1993
+ }
1994
+ } finally {
1995
+ this.inFlight.delete(p);
1295
1996
  }
1296
- } finally {
1297
- this.inFlight.delete(p);
1298
1997
  }
1299
1998
  }
1300
1999
  }
@@ -1337,17 +2036,165 @@ var TraceShipper = class {
1337
2036
  if (!settled) {
1338
2037
  rateLimitedLog(
1339
2038
  `${this.prefix}.shutdown_deadline`,
1340
- () => console.warn(`${this.prefix} shutdown flush deadline exceeded; abandoning in-flight spans`)
2039
+ () => console.warn(
2040
+ `${this.prefix} shutdown flush deadline exceeded; abandoning in-flight spans`
2041
+ )
1341
2042
  );
1342
2043
  }
1343
2044
  } finally {
1344
2045
  this.shutdownDeadlineAt = void 0;
2046
+ if (this.ownsAppGitContext) this.appGitContext.dispose();
1345
2047
  }
1346
2048
  }
1347
2049
  };
1348
2050
 
1349
2051
  // ../core/dist/index.node.js
1350
2052
  import { AsyncLocalStorage } from "async_hooks";
2053
+ import { execFile } from "child_process";
2054
+ import { resolve } from "path";
2055
+ var resolveLocal = (sourceDirectory, detectBranch, completed) => {
2056
+ const cwd = sourceDirectory ? resolve(sourceDirectory) : process.cwd();
2057
+ let cancelled = false;
2058
+ let active;
2059
+ let deadlineTimer;
2060
+ const deadline = Date.now() + 1e3;
2061
+ const run = (args, done) => {
2062
+ if (cancelled) return;
2063
+ const remaining = deadline - Date.now();
2064
+ if (remaining <= 0) {
2065
+ done(void 0);
2066
+ return;
2067
+ }
2068
+ try {
2069
+ active = execFile(
2070
+ "git",
2071
+ args,
2072
+ {
2073
+ cwd,
2074
+ encoding: "utf8",
2075
+ maxBuffer: 4096,
2076
+ windowsHide: true,
2077
+ env: {
2078
+ ...process.env,
2079
+ // The selected application cwd, not the invoking shell's Git plumbing, owns identity.
2080
+ GIT_DIR: void 0,
2081
+ GIT_WORK_TREE: void 0,
2082
+ GIT_COMMON_DIR: void 0,
2083
+ GIT_NAMESPACE: void 0,
2084
+ GIT_INDEX_FILE: void 0,
2085
+ GIT_OBJECT_DIRECTORY: void 0,
2086
+ GIT_ALTERNATE_OBJECT_DIRECTORIES: void 0,
2087
+ GIT_CONFIG_PARAMETERS: void 0,
2088
+ GIT_CONFIG_COUNT: "0",
2089
+ GIT_TERMINAL_PROMPT: "0",
2090
+ GIT_OPTIONAL_LOCKS: "0"
2091
+ }
2092
+ },
2093
+ (error, stdout) => {
2094
+ clearTimeout(deadlineTimer);
2095
+ deadlineTimer = void 0;
2096
+ active = void 0;
2097
+ if (!cancelled) {
2098
+ try {
2099
+ done(error ? void 0 : stdout.trim());
2100
+ } catch (e) {
2101
+ }
2102
+ }
2103
+ }
2104
+ );
2105
+ active.unref();
2106
+ if (active.stdout && "unref" in active.stdout && typeof active.stdout.unref === "function")
2107
+ active.stdout.unref();
2108
+ if (active.stderr && "unref" in active.stderr && typeof active.stderr.unref === "function")
2109
+ active.stderr.unref();
2110
+ deadlineTimer = setTimeout(() => {
2111
+ try {
2112
+ active == null ? void 0 : active.kill("SIGKILL");
2113
+ } catch (e) {
2114
+ }
2115
+ }, remaining);
2116
+ deadlineTimer.unref();
2117
+ } catch (e) {
2118
+ try {
2119
+ done(void 0);
2120
+ } catch (e2) {
2121
+ }
2122
+ }
2123
+ };
2124
+ const scheduled = setTimeout(() => {
2125
+ try {
2126
+ run(["rev-parse", "HEAD"], (rawSha) => {
2127
+ const commitSha = validAppCommitSha(rawSha);
2128
+ if (!commitSha) {
2129
+ completed({});
2130
+ return;
2131
+ }
2132
+ run(["-c", "core.fsmonitor=false", "status", "--porcelain"], (status) => {
2133
+ const finish = (branch) => {
2134
+ run(["rev-parse", "HEAD"], (finalSha) => {
2135
+ const coherent = validAppCommitSha(finalSha) === commitSha;
2136
+ completed({
2137
+ commitSha,
2138
+ ...coherent && status !== void 0 ? { commitDirty: status !== "" } : {},
2139
+ ...coherent && branch && branch !== "HEAD" ? { branch } : {}
2140
+ });
2141
+ });
2142
+ };
2143
+ if (detectBranch) run(["symbolic-ref", "--quiet", "--short", "HEAD"], finish);
2144
+ else finish();
2145
+ });
2146
+ });
2147
+ } catch (e) {
2148
+ completed({});
2149
+ }
2150
+ }, 0);
2151
+ scheduled.unref();
2152
+ return () => {
2153
+ cancelled = true;
2154
+ clearTimeout(scheduled);
2155
+ clearTimeout(deadlineTimer);
2156
+ try {
2157
+ active == null ? void 0 : active.kill("SIGKILL");
2158
+ } catch (e) {
2159
+ }
2160
+ };
2161
+ };
2162
+ function createAppGitContext2(options, runtime = {}) {
2163
+ return new AppGitContext(options, { ...runtime, resolveLocal });
2164
+ }
2165
+ function hasDestination(options) {
2166
+ var _a;
2167
+ if (options.enabled === false) return false;
2168
+ return Boolean(((_a = options.writeKey) == null ? void 0 : _a.trim()) || resolveLocalDebuggerBaseUrl(options.localDebuggerUrl));
2169
+ }
2170
+ var EventShipper2 = class extends EventShipper {
2171
+ constructor(options) {
2172
+ var _a;
2173
+ const ownsAppGitContext = options.appGitContext === void 0;
2174
+ const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
2175
+ try {
2176
+ super({ ...options, appGitContext });
2177
+ } catch (error) {
2178
+ if (ownsAppGitContext) appGitContext.dispose();
2179
+ throw error;
2180
+ }
2181
+ if (ownsAppGitContext) this.ownAppGitContextForShutdown();
2182
+ }
2183
+ };
2184
+ var TraceShipper2 = class extends TraceShipper {
2185
+ constructor(options) {
2186
+ var _a;
2187
+ const ownsAppGitContext = options.appGitContext === void 0;
2188
+ const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
2189
+ try {
2190
+ super({ ...options, appGitContext });
2191
+ } catch (error) {
2192
+ if (ownsAppGitContext) appGitContext.dispose();
2193
+ throw error;
2194
+ }
2195
+ this.ownsAppGitContext = ownsAppGitContext;
2196
+ }
2197
+ };
1351
2198
  globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = AsyncLocalStorage;
1352
2199
  var SUPPRESS_TRACING_KEY = /* @__PURE__ */ Symbol.for(
1353
2200
  "OpenTelemetry SDK Context Key SUPPRESS_TRACING"
@@ -1378,7 +2225,7 @@ installTracingSuppressionHook();
1378
2225
  // package.json
1379
2226
  var package_default = {
1380
2227
  name: "@raindrop-ai/claude-code",
1381
- version: "0.0.19",
2228
+ version: "0.0.20",
1382
2229
  description: "Raindrop observability for Claude Code CLI \u2014 automatic session, tool call, and prompt tracing via hooks",
1383
2230
  license: "MIT",
1384
2231
  homepage: "https://www.raindrop.ai/docs/integrations/claude-code/",
@@ -1452,7 +2299,7 @@ var PACKAGE_NAME = "@raindrop-ai/claude-code";
1452
2299
  var PACKAGE_VERSION = package_default.version;
1453
2300
 
1454
2301
  // src/shipper.ts
1455
- var EventShipper2 = class extends EventShipper {
2302
+ var EventShipper3 = class extends EventShipper2 {
1456
2303
  constructor(opts) {
1457
2304
  var _a, _b, _c, _d;
1458
2305
  super({
@@ -1464,7 +2311,7 @@ var EventShipper2 = class extends EventShipper {
1464
2311
  });
1465
2312
  }
1466
2313
  };
1467
- var TraceShipper2 = class extends TraceShipper {
2314
+ var TraceShipper3 = class extends TraceShipper2 {
1468
2315
  constructor(opts) {
1469
2316
  var _a, _b, _c;
1470
2317
  super({
@@ -1545,7 +2392,20 @@ function loadConfig() {
1545
2392
  })(),
1546
2393
  eventName: (_l = (_k = process.env["RAINDROP_EVENT_NAME"]) != null ? _k : file.event_name) != null ? _l : "claude_code_session",
1547
2394
  customProperties,
1548
- selfDiagnostics
2395
+ selfDiagnostics,
2396
+ appGit: mapAppGit(file.app_git)
2397
+ };
2398
+ }
2399
+ function mapAppGit(value) {
2400
+ if (value === false) return false;
2401
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
2402
+ return {
2403
+ commitSha: "commit_sha" in value && (typeof value.commit_sha === "string" || value.commit_sha === null) ? value.commit_sha : void 0,
2404
+ commitDirty: "commit_dirty" in value && (typeof value.commit_dirty === "boolean" || value.commit_dirty === null) ? value.commit_dirty : void 0,
2405
+ branch: "branch" in value && (typeof value.branch === "string" || value.branch === null) ? value.branch : void 0,
2406
+ detectBranch: "detect_branch" in value && typeof value.detect_branch === "boolean" ? value.detect_branch : void 0,
2407
+ sourceDirectory: "source_directory" in value && typeof value.source_directory === "string" ? value.source_directory : void 0,
2408
+ autoDetect: "auto_detect" in value && typeof value.auto_detect === "boolean" ? value.auto_detect : void 0
1549
2409
  };
1550
2410
  }
1551
2411
  function getConfigPath() {
@@ -2685,6 +3545,7 @@ function resolveCurrentEventId() {
2685
3545
  }
2686
3546
  }
2687
3547
  async function executeTool(args) {
3548
+ var _a;
2688
3549
  const category = typeof args["category"] === "string" ? args["category"] : "";
2689
3550
  const detail = typeof args["detail"] === "string" ? args["detail"] : "";
2690
3551
  if (!category || !activeSignals[category]) {
@@ -2710,12 +3571,17 @@ async function executeTool(args) {
2710
3571
  if (!eventId) {
2711
3572
  return { content: [{ type: "text", text: "Signal noted (no active event found)." }] };
2712
3573
  }
2713
- const shipper = new EventShipper2({
3574
+ const appGitContext = createAppGitContext2(
3575
+ ((_a = config.writeKey) == null ? void 0 : _a.trim()) ? config.appGit : false,
3576
+ { allowLocalGit: false }
3577
+ );
3578
+ const shipper = new EventShipper3({
2714
3579
  writeKey: config.writeKey,
2715
3580
  endpoint: config.endpoint,
2716
3581
  debug: false,
2717
3582
  projectId: config.projectId,
2718
- enabled: true
3583
+ enabled: true,
3584
+ appGitContext
2719
3585
  });
2720
3586
  try {
2721
3587
  const signalDef = activeSignals[category];
@@ -2742,6 +3608,11 @@ async function executeTool(args) {
2742
3608
  });
2743
3609
  await shipper.shutdown();
2744
3610
  } catch (e) {
3611
+ } finally {
3612
+ try {
3613
+ appGitContext.dispose();
3614
+ } catch (e) {
3615
+ }
2745
3616
  }
2746
3617
  return { content: [{ type: "text", text: "Signal recorded." }] };
2747
3618
  }
@@ -2863,11 +3734,12 @@ async function handleLine(line, toolSchema) {
2863
3734
  }
2864
3735
  export {
2865
3736
  DEFAULT_CATEGORY_KEYS,
2866
- EventShipper2 as EventShipper,
3737
+ EventShipper3 as EventShipper,
2867
3738
  PACKAGE_NAME,
2868
3739
  PACKAGE_VERSION,
2869
3740
  TOOL_SCHEMA,
2870
- TraceShipper2 as TraceShipper,
3741
+ TraceShipper3 as TraceShipper,
3742
+ createAppGitContext2 as createAppGitContext,
2871
3743
  detectLocalDebugger,
2872
3744
  executeTool,
2873
3745
  extractAppendSystemPrompt,