@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/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-5PSWD267.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,25 @@ 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
+ }
54
598
  var HANDOFF_ATTRIBUTE_SUFFIXES = {
55
599
  mode: "raindrop.handoff.mode",
56
600
  childEventId: "raindrop.handoff.childEventId",
@@ -82,7 +626,7 @@ function runWithTracingSuppressed(fn) {
82
626
  var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
83
627
  var MAX_RETRY_DELAY_MS = 3e4;
84
628
  function wait(ms) {
85
- return new Promise((resolve2) => setTimeout(resolve2, ms));
629
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
86
630
  }
87
631
  function formatEndpoint(endpoint) {
88
632
  if (!endpoint) return void 0;
@@ -119,9 +663,9 @@ async function raceWithTimeout(promise, timeoutMs) {
119
663
  () => true,
120
664
  () => true
121
665
  ),
122
- new Promise((resolve2) => {
666
+ new Promise((resolve3) => {
123
667
  var _a;
124
- timer = setTimeout(() => resolve2(false), Math.max(0, timeoutMs));
668
+ timer = setTimeout(() => resolve3(false), Math.max(0, timeoutMs));
125
669
  (_a = timer.unref) == null ? void 0 : _a.call(timer);
126
670
  })
127
671
  ]);
@@ -192,6 +736,7 @@ async function postJson(url, body, headers, opts) {
192
736
  const resp = await runWithTracingSuppressed(
193
737
  () => fetch(url, {
194
738
  method: "POST",
739
+ redirect: headers["X-Raindrop-Replay-Id"] !== void 0 ? "error" : "follow",
195
740
  headers: {
196
741
  "Content-Type": "application/json",
197
742
  ...headers
@@ -402,6 +947,13 @@ function projectIdHeaders(projectId) {
402
947
  }
403
948
  var SHUTDOWN_DEADLINE_MS = 1e4;
404
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
+ }
405
957
  function mergePatches(target, source) {
406
958
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
407
959
  const out = { ...target, ...source };
@@ -451,22 +1003,25 @@ function eventTelemetryProperties(patch) {
451
1003
  }
452
1004
  var EventShipper = class {
453
1005
  constructor(opts) {
1006
+ this.appGitOwner = appGitOwnerId("event");
454
1007
  this.buffers = /* @__PURE__ */ new Map();
455
1008
  this.sticky = /* @__PURE__ */ new Map();
456
1009
  this.timers = /* @__PURE__ */ new Map();
457
1010
  this.inFlight = /* @__PURE__ */ new Set();
458
1011
  this.hasShutdown = false;
459
- var _a, _b, _c, _d, _e, _f, _g, _h;
460
- this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
461
- 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/";
462
1017
  this.enabled = opts.enabled !== false;
463
1018
  this.debug = opts.debug;
464
- this.partialFlushMs = (_c = opts.partialFlushMs) != null ? _c : 1e3;
465
- 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";
466
1021
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
467
- this.defaultEventName = (_e = opts.defaultEventName) != null ? _e : "ai_generation";
1022
+ this.defaultEventName = (_f = opts.defaultEventName) != null ? _f : "ai_generation";
468
1023
  this.maxTextFieldCharsOpt = opts.maxTextFieldChars;
469
- this.localDebuggerUrl = (_f = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _f : void 0;
1024
+ this.localDebuggerUrl = (_g = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _g : void 0;
470
1025
  if (this.debug && this.localDebuggerUrl) {
471
1026
  console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
472
1027
  }
@@ -477,8 +1032,8 @@ var EventShipper = class {
477
1032
  const isNode = typeof process !== "undefined" && typeof process.version === "string";
478
1033
  this.context = {
479
1034
  library: {
480
- name: (_g = opts.libraryName) != null ? _g : "@raindrop-ai/core",
481
- 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"
482
1037
  },
483
1038
  metadata: {
484
1039
  jsRuntime: isNode ? "node" : "web",
@@ -486,6 +1041,9 @@ var EventShipper = class {
486
1041
  }
487
1042
  };
488
1043
  }
1044
+ ownAppGitContextForShutdown() {
1045
+ this.ownsAppGitContext = true;
1046
+ }
489
1047
  isDebugEnabled() {
490
1048
  return this.debug;
491
1049
  }
@@ -534,6 +1092,15 @@ var EventShipper = class {
534
1092
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
535
1093
  if (!this.enabled) return;
536
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
+ }
537
1104
  const maxChars = resolveMaxTextFieldChars(this.maxTextFieldCharsOpt);
538
1105
  if (typeof patch.input === "string" && patch.input.length > maxChars) {
539
1106
  patch = { ...patch, input: capText(patch.input, maxChars) };
@@ -555,6 +1122,13 @@ var EventShipper = class {
555
1122
  }
556
1123
  const sticky = (_c = this.sticky.get(eventId)) != null ? _c : {};
557
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
+ };
558
1132
  const merged = mergePatches(existing, patch);
559
1133
  merged.isPending = (_g = (_f = (_e = patch.isPending) != null ? _e : existing.isPending) != null ? _f : sticky.isPending) != null ? _g : true;
560
1134
  this.buffers.set(eventId, merged);
@@ -568,6 +1142,8 @@ var EventShipper = class {
568
1142
  if (t) clearTimeout(t);
569
1143
  if (merged.isPending === false) {
570
1144
  await this.flushOne(eventId);
1145
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(eventId, this.appGitOwner);
1146
+ else this.appGitContext.finishOperation(eventId);
571
1147
  return;
572
1148
  }
573
1149
  const timeout = setTimeout(() => {
@@ -592,15 +1168,21 @@ var EventShipper = class {
592
1168
  try {
593
1169
  for (const t of this.timers.values()) clearTimeout(t);
594
1170
  this.timers.clear();
1171
+ for (const [eventId, sticky] of this.sticky) {
1172
+ if (sticky.replayOnly) this.sticky.delete(eventId);
1173
+ }
595
1174
  const settled = await raceWithTimeout(this.flush(), SHUTDOWN_DEADLINE_MS);
596
1175
  if (!settled) this.warnShutdownDrop("in-flight request(s) at shutdown");
597
1176
  } finally {
598
1177
  this.shutdownDeadlineAt = void 0;
1178
+ if (this.ownsAppGitContext) this.appGitContext.dispose();
599
1179
  }
600
1180
  }
601
1181
  async trackSignal(signal) {
602
1182
  var _a, _b;
603
1183
  if (!this.enabled) return;
1184
+ const destination = currentReplayTraceDestination();
1185
+ if (destination && destination.kind !== "workshop") return;
604
1186
  const body = [
605
1187
  {
606
1188
  event_id: signal.eventId,
@@ -635,6 +1217,8 @@ var EventShipper = class {
635
1217
  }
636
1218
  async identify(users) {
637
1219
  if (!this.enabled) return;
1220
+ const destination = currentReplayTraceDestination();
1221
+ if (destination && destination.kind !== "workshop") return;
638
1222
  const list = Array.isArray(users) ? users : [users];
639
1223
  const body = list.filter((user) => {
640
1224
  if (!(user == null ? void 0 : user.userId) || !user.userId.trim()) {
@@ -687,8 +1271,9 @@ var EventShipper = class {
687
1271
  this.buffers.delete(eventId);
688
1272
  if (!accumulated) return;
689
1273
  const sticky = (_a = this.sticky.get(eventId)) != null ? _a : {};
690
- const eventName = (_c = (_b = accumulated.eventName) != null ? _b : sticky.eventName) != null ? _c : this.defaultEventName;
691
- 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;
692
1277
  if (!userId) {
693
1278
  if (this.debug) {
694
1279
  console.warn(`${this.prefix} skipping track_partial for ${eventId}: missing userId`);
@@ -696,14 +1281,13 @@ var EventShipper = class {
696
1281
  this.sticky.delete(eventId);
697
1282
  return;
698
1283
  }
699
- const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
1284
+ const { wizardSession, ...restProperties } = (_g = accumulated.properties) != null ? _g : {};
700
1285
  let telemetryProperties = {};
701
1286
  try {
702
1287
  telemetryProperties = eventTelemetryProperties(accumulated);
703
1288
  } catch (e) {
704
1289
  }
705
- const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
706
- const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
1290
+ const convoId = (_h = accumulated.convoId) != null ? _h : sticky.convoId;
707
1291
  const payload = {
708
1292
  event_id: eventId,
709
1293
  user_id: userId,
@@ -1019,6 +1603,13 @@ function redactJsonAttributeValue(key, value) {
1019
1603
  if (scrubbedJson === json) return void 0;
1020
1604
  return { stringValue: scrubbedJson };
1021
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
+ }
1022
1613
  function identityAttrs(args2) {
1023
1614
  return [
1024
1615
  attrString("ai.telemetry.metadata.raindrop.ai.userId", args2.userId),
@@ -1041,23 +1632,30 @@ function applyOtelSpanAttributeLimit(limit) {
1041
1632
  }
1042
1633
  var TraceShipper = class {
1043
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();
1044
1640
  this.queue = [];
1045
1641
  this.inFlight = /* @__PURE__ */ new Set();
1046
1642
  this.hasShutdown = false;
1047
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1048
- this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
1049
- 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/";
1050
1648
  this.enabled = opts.enabled !== false;
1051
1649
  this.debug = opts.debug;
1052
1650
  this.debugSpans = opts.debugSpans === true;
1053
- this.flushIntervalMs = (_c = opts.flushIntervalMs) != null ? _c : 1e3;
1054
- this.maxBatchSize = (_d = opts.maxBatchSize) != null ? _d : 50;
1055
- this.maxQueueSize = (_e = opts.maxQueueSize) != null ? _e : 5e3;
1056
- 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";
1057
1655
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
1058
- this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
1059
- this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
1060
- 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;
1061
1659
  if (this.debug && this.localDebuggerUrl) {
1062
1660
  console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
1063
1661
  }
@@ -1121,7 +1719,10 @@ var TraceShipper = class {
1121
1719
  try {
1122
1720
  const result = this.transformSpanHook(current);
1123
1721
  if (result === null) return null;
1124
- if (result !== void 0) current = result;
1722
+ if (result !== void 0) {
1723
+ copyReplayTraceDestination(current, result);
1724
+ current = result;
1725
+ }
1125
1726
  } catch (err) {
1126
1727
  if (this.debug) {
1127
1728
  const msg = err instanceof Error ? err.message : String(err);
@@ -1131,13 +1732,19 @@ var TraceShipper = class {
1131
1732
  }
1132
1733
  }
1133
1734
  try {
1134
- current = normalizeModelUsageSpan(current);
1735
+ const normalized = normalizeModelUsageSpan(current);
1736
+ copyReplayTraceDestination(current, normalized);
1737
+ current = normalized;
1135
1738
  } catch (e) {
1136
1739
  }
1137
1740
  if (!this.disableDefaultRedaction) {
1138
- current = defaultTransformSpan(current);
1741
+ const redacted = defaultTransformSpan(current);
1742
+ copyReplayTraceDestination(current, redacted);
1743
+ current = redacted;
1139
1744
  }
1140
- return this.capSpanAttributes(current);
1745
+ const capped = this.capSpanAttributes(current);
1746
+ copyReplayTraceDestination(current, capped);
1747
+ return capped;
1141
1748
  }
1142
1749
  isDebugEnabled() {
1143
1750
  return this.debug;
@@ -1149,36 +1756,64 @@ var TraceShipper = class {
1149
1756
  return { ...this.authHeaders(), ...projectIdHeaders(this.projectId) };
1150
1757
  }
1151
1758
  startSpan(args2) {
1152
- var _a, _b;
1759
+ var _a, _b, _c;
1153
1760
  const ids = createSpanIds(args2.parent);
1154
1761
  const started = (_a = args2.startTimeUnixNano) != null ? _a : nowUnixNanoString();
1155
1762
  const attrs = [
1156
1763
  attrString("ai.telemetry.metadata.raindrop.eventId", args2.eventId),
1157
1764
  ...identityAttrs(args2),
1158
- attrString("ai.operationId", args2.operationId)
1765
+ attrString("ai.operationId", args2.operationId),
1766
+ ...Object.entries(evalScopeAttributes()).map(([key, value]) => attrString(key, value))
1159
1767
  ];
1160
1768
  if ((_b = args2.attributes) == null ? void 0 : _b.length) attrs.push(...args2.attributes);
1161
- const span = { ids, name: args2.name, startTimeUnixNano: started, attributes: attrs };
1162
- this.mirrorToLocalDebugger(
1163
- buildOtlpSpan({
1164
- ids: span.ids,
1165
- name: span.name,
1166
- startTimeUnixNano: span.startTimeUnixNano,
1167
- endTimeUnixNano: span.startTimeUnixNano,
1168
- // placeholder — will be updated on endSpan
1169
- attributes: span.attributes,
1170
- status: { code: SpanStatusCode.UNSET }
1171
- })
1172
- );
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);
1173
1798
  return span;
1174
1799
  }
1175
- mirrorToLocalDebugger(span) {
1176
- 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;
1177
1805
  const redacted = this.redactSpan(span);
1178
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
+ }
1179
1814
  const body = buildExportTraceServiceRequest([redacted], this.serviceName, this.serviceVersion);
1180
1815
  const p = mirrorTraceExportToLocalDebugger(body, {
1181
- baseUrl: this.localDebuggerUrl,
1816
+ baseUrl: localDebuggerUrl,
1182
1817
  debug: false,
1183
1818
  sdkName: this.sdkName
1184
1819
  });
@@ -1188,11 +1823,17 @@ var TraceShipper = class {
1188
1823
  });
1189
1824
  }
1190
1825
  endSpan(span, extra) {
1191
- var _a, _b;
1826
+ var _a, _b, _c;
1192
1827
  if (span.endTimeUnixNano) return;
1193
1828
  span.endTimeUnixNano = (_a = extra == null ? void 0 : extra.endTimeUnixNano) != null ? _a : nowUnixNanoString();
1194
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));
1195
1835
  span.attributes.push(...extra.attributes);
1836
+ span.attributes = withAppGitAttributes(span.attributes, snapshot);
1196
1837
  }
1197
1838
  let status = extra == null ? void 0 : extra.status;
1198
1839
  if (!status && (extra == null ? void 0 : extra.error) !== void 0) {
@@ -1207,30 +1848,65 @@ var TraceShipper = class {
1207
1848
  attributes: span.attributes,
1208
1849
  status
1209
1850
  });
1851
+ copyReplayTraceDestination(span, otlp);
1852
+ this.appGitCaptured.add(otlp);
1210
1853
  this.enqueue(otlp);
1211
- 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
+ }
1212
1865
  }
1213
1866
  createSpan(args2) {
1214
1867
  var _a;
1215
1868
  const ids = createSpanIds(args2.parent);
1216
1869
  const attrs = [
1217
1870
  attrString("ai.telemetry.metadata.raindrop.eventId", args2.eventId),
1218
- ...identityAttrs(args2)
1871
+ ...identityAttrs(args2),
1872
+ ...Object.entries(evalScopeAttributes()).map(([key, value]) => attrString(key, value))
1219
1873
  ];
1220
1874
  if ((_a = args2.attributes) == null ? void 0 : _a.length) attrs.push(...args2.attributes);
1875
+ const tracksAppGit = !this.appGitActiveSpans.has(args2.eventId);
1221
1876
  const otlp = buildOtlpSpan({
1222
1877
  ids,
1223
1878
  name: args2.name,
1224
1879
  startTimeUnixNano: args2.startTimeUnixNano,
1225
1880
  endTimeUnixNano: args2.endTimeUnixNano,
1226
- attributes: attrs,
1881
+ attributes: withAppGitAttributes(
1882
+ attrs,
1883
+ this.appGitContext.forOperation(
1884
+ args2.eventId,
1885
+ appGitPropertiesFromAttributes(attrs),
1886
+ this.appGitOwner
1887
+ )
1888
+ ),
1227
1889
  status: args2.status
1228
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
+ }
1229
1897
  this.enqueue(otlp);
1230
- this.mirrorToLocalDebugger(otlp);
1898
+ this.mirrorToLocalDebugger(otlp, true);
1231
1899
  }
1232
1900
  enqueue(span) {
1901
+ var _a;
1233
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
+ }
1234
1910
  if (this.debugSpans) {
1235
1911
  const short = (s) => s ? s.slice(-8) : "none";
1236
1912
  console.log(
@@ -1241,6 +1917,13 @@ var TraceShipper = class {
1241
1917
  }
1242
1918
  const redacted = this.redactSpan(span);
1243
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;
1244
1927
  if (this.queue.length >= this.maxQueueSize) {
1245
1928
  this.queue.shift();
1246
1929
  }
@@ -1259,6 +1942,7 @@ var TraceShipper = class {
1259
1942
  }
1260
1943
  }
1261
1944
  async flush() {
1945
+ var _a;
1262
1946
  if (!this.enabled) {
1263
1947
  await Promise.all([...this.inFlight].map((p) => p.catch(() => {
1264
1948
  })));
@@ -1270,40 +1954,55 @@ var TraceShipper = class {
1270
1954
  }
1271
1955
  while (this.queue.length > 0) {
1272
1956
  const batch = this.queue.splice(0, this.maxBatchSize);
1273
- if (!this.writeKey) continue;
1274
- const opts = this.requestOpts();
1275
- if (!opts) {
1276
- rateLimitedLog(
1277
- `${this.prefix}.shutdown_deadline`,
1278
- () => console.warn(
1279
- `${this.prefix} shutdown flush deadline exceeded; dropping ${batch.length} spans`
1280
- )
1281
- );
1282
- continue;
1283
- }
1284
- const body = buildExportTraceServiceRequest(batch, this.serviceName, this.serviceVersion);
1285
- const url = `${this.baseUrl}traces`;
1286
- if (this.debug) {
1287
- console.log(`${this.prefix} sending traces batch`, {
1288
- spans: batch.length,
1289
- endpoint: url
1290
- });
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]);
1291
1963
  }
1292
- const p = postJson(url, body, this.requestHeaders(), opts);
1293
- this.inFlight.add(p);
1294
- try {
1295
- try {
1296
- await p;
1297
- if (this.debug) console.log(`${this.prefix} sent ${batch.length} spans`);
1298
- } catch (err) {
1299
- 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) {
1300
1969
  rateLimitedLog(
1301
- `${this.prefix}.send_spans_failed`,
1302
- () => 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
+ )
1303
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);
1304
2005
  }
1305
- } finally {
1306
- this.inFlight.delete(p);
1307
2006
  }
1308
2007
  }
1309
2008
  }
@@ -1346,17 +2045,165 @@ var TraceShipper = class {
1346
2045
  if (!settled) {
1347
2046
  rateLimitedLog(
1348
2047
  `${this.prefix}.shutdown_deadline`,
1349
- () => 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
+ )
1350
2051
  );
1351
2052
  }
1352
2053
  } finally {
1353
2054
  this.shutdownDeadlineAt = void 0;
2055
+ if (this.ownsAppGitContext) this.appGitContext.dispose();
1354
2056
  }
1355
2057
  }
1356
2058
  };
1357
2059
 
1358
2060
  // ../core/dist/index.node.js
1359
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
+ };
1360
2207
  globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = AsyncLocalStorage;
1361
2208
  var SUPPRESS_TRACING_KEY = /* @__PURE__ */ Symbol.for(
1362
2209
  "OpenTelemetry SDK Context Key SUPPRESS_TRACING"
@@ -1387,7 +2234,7 @@ installTracingSuppressionHook();
1387
2234
  // package.json
1388
2235
  var package_default = {
1389
2236
  name: "@raindrop-ai/claude-code",
1390
- version: "0.0.19",
2237
+ version: "0.0.20",
1391
2238
  description: "Raindrop observability for Claude Code CLI \u2014 automatic session, tool call, and prompt tracing via hooks",
1392
2239
  license: "MIT",
1393
2240
  homepage: "https://www.raindrop.ai/docs/integrations/claude-code/",
@@ -1461,7 +2308,7 @@ var PACKAGE_NAME = "@raindrop-ai/claude-code";
1461
2308
  var PACKAGE_VERSION = package_default.version;
1462
2309
 
1463
2310
  // src/shipper.ts
1464
- var EventShipper2 = class extends EventShipper {
2311
+ var EventShipper3 = class extends EventShipper2 {
1465
2312
  constructor(opts) {
1466
2313
  var _a, _b, _c, _d;
1467
2314
  super({
@@ -1473,7 +2320,7 @@ var EventShipper2 = class extends EventShipper {
1473
2320
  });
1474
2321
  }
1475
2322
  };
1476
- var TraceShipper2 = class extends TraceShipper {
2323
+ var TraceShipper3 = class extends TraceShipper2 {
1477
2324
  constructor(opts) {
1478
2325
  var _a, _b, _c;
1479
2326
  super({
@@ -2475,7 +3322,20 @@ function loadConfig() {
2475
3322
  })(),
2476
3323
  eventName: (_l = (_k = process.env["RAINDROP_EVENT_NAME"]) != null ? _k : file.event_name) != null ? _l : "claude_code_session",
2477
3324
  customProperties,
2478
- 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
2479
3339
  };
2480
3340
  }
2481
3341
  function getConfigPath() {
@@ -2597,16 +3457,16 @@ function hookFlushDeadlineMs() {
2597
3457
  return DEFAULT_HOOK_FLUSH_DEADLINE_MS;
2598
3458
  }
2599
3459
  function withDeadline(promise, ms) {
2600
- return new Promise((resolve2, reject) => {
3460
+ return new Promise((resolve3, reject) => {
2601
3461
  const timer = setTimeout(() => {
2602
3462
  promise.catch(() => {
2603
3463
  });
2604
- resolve2("deadline");
3464
+ resolve3("deadline");
2605
3465
  }, ms);
2606
3466
  promise.then(
2607
3467
  (value) => {
2608
3468
  clearTimeout(timer);
2609
- resolve2(value);
3469
+ resolve3(value);
2610
3470
  },
2611
3471
  (err) => {
2612
3472
  clearTimeout(timer);
@@ -2628,9 +3488,9 @@ function getOtlpTraceId(sessionId) {
2628
3488
  }
2629
3489
  }
2630
3490
  function readStdin() {
2631
- return new Promise((resolve2) => {
3491
+ return new Promise((resolve3) => {
2632
3492
  if (process.stdin.isTTY) {
2633
- resolve2("");
3493
+ resolve3("");
2634
3494
  return;
2635
3495
  }
2636
3496
  const chunks = [];
@@ -2641,7 +3501,7 @@ function readStdin() {
2641
3501
  clearTimeout(timeout);
2642
3502
  process.stdin.removeAllListeners();
2643
3503
  process.stdin.destroy();
2644
- resolve2(value);
3504
+ resolve3(value);
2645
3505
  }
2646
3506
  const timeout = setTimeout(() => {
2647
3507
  done(chunks.length > 0 ? Buffer.concat(chunks).toString("utf-8") : "");
@@ -2652,6 +3512,7 @@ function readStdin() {
2652
3512
  });
2653
3513
  }
2654
3514
  async function handleHook() {
3515
+ var _a;
2655
3516
  const startedAtMs = Date.now();
2656
3517
  const raw = await readStdin();
2657
3518
  if (!raw.trim()) {
@@ -2686,7 +3547,11 @@ async function handleHook() {
2686
3547
  eventName: config.eventName,
2687
3548
  customProperties: config.customProperties
2688
3549
  };
2689
- 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({
2690
3555
  writeKey: config.writeKey,
2691
3556
  endpoint: config.endpoint,
2692
3557
  debug: config.debug,
@@ -2694,21 +3559,23 @@ async function handleHook() {
2694
3559
  // Only ship to the cloud when we have an API key. When only the local
2695
3560
  // debugger is present the shipper still needs to be instantiated so the
2696
3561
  // event mapper can call patch/finish, but cloud POSTs are skipped.
2697
- enabled: hasCloudKey
3562
+ enabled: hasCloudKey,
3563
+ appGitContext
2698
3564
  });
2699
- const traceShipper = new TraceShipper2({
3565
+ const traceShipper = new TraceShipper3({
2700
3566
  writeKey: config.writeKey,
2701
3567
  endpoint: config.endpoint,
2702
3568
  debug: config.debug,
2703
3569
  projectId: config.projectId,
2704
- enabled: hasCloudKey
3570
+ enabled: hasCloudKey,
3571
+ appGitContext
2705
3572
  });
2706
3573
  if (debugger_.url) {
2707
3574
  const debuggerUrl = debugger_.url;
2708
3575
  const origPatch = eventShipper.patch.bind(eventShipper);
2709
3576
  eventShipper.patch = async (eventId, patch) => {
2710
- var _a, _b, _c, _d;
2711
- const traceId = (_a = getOtlpTraceId(payload.session_id)) != null ? _a : payload.session_id;
3577
+ var _a2, _b, _c, _d;
3578
+ const traceId = (_a2 = getOtlpTraceId(payload.session_id)) != null ? _a2 : payload.session_id;
2712
3579
  await Promise.all([
2713
3580
  mirrorEventToLocalDebugger(debuggerUrl, {
2714
3581
  event_id: eventId,
@@ -2722,7 +3589,10 @@ async function handleHook() {
2722
3589
  convo_id: patch.convoId
2723
3590
  },
2724
3591
  properties: {
2725
- ...patch.properties,
3592
+ ...withAppGitProperties(
3593
+ patch.properties,
3594
+ appGitContext.forOperation(eventId, patch.properties)
3595
+ ),
2726
3596
  ...payload.session_id ? { trace_id: traceId } : {}
2727
3597
  },
2728
3598
  is_pending: (_d = patch.isPending) != null ? _d : true
@@ -2736,14 +3606,23 @@ async function handleHook() {
2736
3606
  MIN_FLUSH_WINDOW_MS,
2737
3607
  hookFlushDeadlineMs() - (Date.now() - startedAtMs)
2738
3608
  );
2739
- const outcome = await withDeadline(
2740
- (async () => {
3609
+ const hookWork = (async () => {
3610
+ try {
2741
3611
  await mapHookToRaindrop(payload, mapperConfig, eventShipper, traceShipper);
2742
3612
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
2743
3613
  await Promise.all([eventShipper.shutdown(), traceShipper.shutdown()]);
2744
- })(),
2745
- remainingMs
2746
- );
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
+ }
2747
3626
  if (outcome === "deadline" && config.debug) {
2748
3627
  console.error(
2749
3628
  `[raindrop-ai/claude-code] hook work exceeded the ${hookFlushDeadlineMs()}ms deadline; exiting without waiting on the network (pending telemetry dropped)`
@@ -2761,12 +3640,12 @@ async function handleHook() {
2761
3640
  // src/setup.ts
2762
3641
  import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
2763
3642
  import { homedir as homedir2, userInfo as userInfo2 } from "os";
2764
- import { dirname as dirname2, join as join5, resolve } from "path";
3643
+ import { dirname as dirname2, join as join5, resolve as resolve2 } from "path";
2765
3644
  import { createInterface } from "readline";
2766
3645
  import { execSync as execSync2 } from "child_process";
2767
3646
  function getClaudeSettingsPath(scope, cwd) {
2768
3647
  if (scope === "project") {
2769
- return resolve(cwd, ".claude", "settings.json");
3648
+ return resolve2(cwd, ".claude", "settings.json");
2770
3649
  }
2771
3650
  return join5(homedir2(), ".claude", "settings.json");
2772
3651
  }
@@ -2849,10 +3728,10 @@ function makeHookConfig(hookEvents, useAsync) {
2849
3728
  }
2850
3729
  function prompt(question) {
2851
3730
  const rl = createInterface({ input: process.stdin, output: process.stdout });
2852
- return new Promise((resolve2) => {
3731
+ return new Promise((resolve3) => {
2853
3732
  rl.question(question, (answer) => {
2854
3733
  rl.close();
2855
- resolve2(answer.trim());
3734
+ resolve3(answer.trim());
2856
3735
  });
2857
3736
  });
2858
3737
  }
@@ -3192,6 +4071,7 @@ function resolveCurrentEventId() {
3192
4071
  }
3193
4072
  }
3194
4073
  async function executeTool(args2) {
4074
+ var _a;
3195
4075
  const category = typeof args2["category"] === "string" ? args2["category"] : "";
3196
4076
  const detail = typeof args2["detail"] === "string" ? args2["detail"] : "";
3197
4077
  if (!category || !activeSignals[category]) {
@@ -3217,12 +4097,17 @@ async function executeTool(args2) {
3217
4097
  if (!eventId) {
3218
4098
  return { content: [{ type: "text", text: "Signal noted (no active event found)." }] };
3219
4099
  }
3220
- 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({
3221
4105
  writeKey: config.writeKey,
3222
4106
  endpoint: config.endpoint,
3223
4107
  debug: false,
3224
4108
  projectId: config.projectId,
3225
- enabled: true
4109
+ enabled: true,
4110
+ appGitContext
3226
4111
  });
3227
4112
  try {
3228
4113
  const signalDef = activeSignals[category];
@@ -3249,6 +4134,11 @@ async function executeTool(args2) {
3249
4134
  });
3250
4135
  await shipper.shutdown();
3251
4136
  } catch (e) {
4137
+ } finally {
4138
+ try {
4139
+ appGitContext.dispose();
4140
+ } catch (e) {
4141
+ }
3252
4142
  }
3253
4143
  return { content: [{ type: "text", text: "Signal recorded." }] };
3254
4144
  }
@@ -3374,8 +4264,8 @@ var args = process.argv.slice(2);
3374
4264
  var command = args[0];
3375
4265
  function parseFlag(name) {
3376
4266
  const prefix = `--${name}=`;
3377
- const flag = args.find((a) => a.startsWith(prefix));
3378
- 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;
3379
4269
  }
3380
4270
  async function main() {
3381
4271
  switch (command) {