@raindrop-ai/claude-code 0.0.19 → 0.0.21

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-I6TVJQEC.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;
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]);
1283
1963
  }
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
- });
1291
- }
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,317 @@ 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
  };
2059
+ var PROMPT_TOOLS_ATTRIBUTE = "ai.prompt.tools";
2060
+ function isRecord(value) {
2061
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2062
+ }
2063
+ var JSON_SCHEMA_KEYS = [
2064
+ "type",
2065
+ "properties",
2066
+ "$schema",
2067
+ "$ref",
2068
+ "anyOf",
2069
+ "oneOf",
2070
+ "allOf",
2071
+ "enum",
2072
+ "const",
2073
+ "items",
2074
+ "additionalProperties",
2075
+ "required"
2076
+ ];
2077
+ function isJsonSchema(value) {
2078
+ if (!isRecord(value)) return false;
2079
+ if (typeof value["~standard"] === "object") return false;
2080
+ if (isRecord(value._def) || isRecord(value._zod)) return false;
2081
+ if (Object.keys(value).length === 0) return true;
2082
+ return JSON_SCHEMA_KEYS.some((key) => key in value);
2083
+ }
2084
+ function toJsonSchema(value, options) {
2085
+ if (value === void 0 || value === null) return void 0;
2086
+ if (isJsonSchema(value)) return value;
2087
+ if (isRecord(value) && isJsonSchema(value.jsonSchema)) return value.jsonSchema;
2088
+ if (isRecord(value) && isJsonSchema(value.json)) return value.json;
2089
+ if (options == null ? void 0 : options.schema) {
2090
+ try {
2091
+ return options.schema(value);
2092
+ } catch (e) {
2093
+ return void 0;
2094
+ }
2095
+ }
2096
+ return void 0;
2097
+ }
2098
+ function pickString(value) {
2099
+ return typeof value === "string" && value.length > 0 ? value : void 0;
2100
+ }
2101
+ function functionTool(name, description, schema, options) {
2102
+ const tool = { type: "function", name };
2103
+ const desc = pickString(description);
2104
+ if (desc !== void 0) tool.description = desc;
2105
+ const inputSchema = toJsonSchema(schema, options);
2106
+ if (inputSchema !== void 0) tool.inputSchema = inputSchema;
2107
+ return tool;
2108
+ }
2109
+ function normalizeToolDeclaration(tool, options, fallbackName) {
2110
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2111
+ if (!isRecord(tool)) return void 0;
2112
+ if (tool.type === "provider-defined" || tool.type === "provider") {
2113
+ const name2 = (_b = (_a = pickString(tool.name)) != null ? _a : pickString(tool.id)) != null ? _b : fallbackName;
2114
+ if (name2 === void 0) return void 0;
2115
+ const declaration = { type: "provider-defined", name: name2 };
2116
+ const id = pickString(tool.id);
2117
+ if (id !== void 0) declaration.id = id;
2118
+ if (isRecord(tool.args)) declaration.args = tool.args;
2119
+ return declaration;
2120
+ }
2121
+ if (isRecord(tool.toolSpec)) {
2122
+ const spec = tool.toolSpec;
2123
+ const name2 = (_c = pickString(spec.name)) != null ? _c : fallbackName;
2124
+ if (name2 === void 0) return void 0;
2125
+ return functionTool(name2, spec.description, spec.inputSchema, options);
2126
+ }
2127
+ if (isRecord(tool.function)) {
2128
+ const fn = tool.function;
2129
+ const name2 = (_d = pickString(fn.name)) != null ? _d : fallbackName;
2130
+ if (name2 === void 0) return void 0;
2131
+ return functionTool(name2, fn.description, (_e = fn.parameters) != null ? _e : fn.input_schema, options);
2132
+ }
2133
+ const name = (_g = (_f = pickString(tool.name)) != null ? _f : pickString(tool.id)) != null ? _g : fallbackName;
2134
+ if (name === void 0) return void 0;
2135
+ const type = pickString(tool.type);
2136
+ if (type !== void 0 && type !== "function" && type !== "dynamic" && type !== "custom") {
2137
+ if (!("input_schema" in tool) && !("inputSchema" in tool) && !("parameters" in tool)) {
2138
+ return { type: "provider-defined", id: type, name };
2139
+ }
2140
+ }
2141
+ return functionTool(
2142
+ name,
2143
+ tool.description,
2144
+ (_j = (_i = (_h = tool.inputSchema) != null ? _h : tool.input_schema) != null ? _i : tool.parameters) != null ? _j : tool.schema,
2145
+ options
2146
+ );
2147
+ }
2148
+ var NOT_A_GEMINI_GROUP_KEYS = ["name", "id", "type", "function", "toolSpec", "cachePoint"];
2149
+ function isGeminiToolGroup(tool) {
2150
+ if (Array.isArray(tool.functionDeclarations)) return true;
2151
+ const keys = Object.keys(tool);
2152
+ if (keys.length === 0 || NOT_A_GEMINI_GROUP_KEYS.some((key) => key in tool)) return false;
2153
+ return keys.every((key) => isRecord(tool[key]));
2154
+ }
2155
+ function expandGeminiTool(tool, options) {
2156
+ const declarations = [];
2157
+ for (const [key, value] of Object.entries(tool)) {
2158
+ if (key === "functionDeclarations" && Array.isArray(value)) {
2159
+ for (const declaration of value) {
2160
+ const normalized = normalizeToolDeclaration(declaration, options);
2161
+ if (normalized) declarations.push(normalized);
2162
+ }
2163
+ } else if (isRecord(value)) {
2164
+ declarations.push({ type: "provider-defined", id: key, name: key, args: value });
2165
+ }
2166
+ }
2167
+ return declarations;
2168
+ }
2169
+ function normalizeToolDeclarations(tools, options) {
2170
+ if (tools === void 0 || tools === null) return void 0;
2171
+ if (Array.isArray(tools)) {
2172
+ return tools.flatMap((tool) => {
2173
+ if (isRecord(tool) && isGeminiToolGroup(tool)) {
2174
+ return expandGeminiTool(tool, options);
2175
+ }
2176
+ const declaration = normalizeToolDeclaration(tool, options);
2177
+ return declaration ? [declaration] : [];
2178
+ });
2179
+ }
2180
+ if (!isRecord(tools)) return void 0;
2181
+ return Object.entries(tools).flatMap(([key, tool]) => {
2182
+ const declaration = normalizeToolDeclaration(tool, options, key);
2183
+ return declaration ? [declaration] : [];
2184
+ });
2185
+ }
2186
+ function resolvePromptTools(args2) {
2187
+ var _a;
2188
+ if (args2.override !== void 0) {
2189
+ return (_a = normalizeToolDeclarations(args2.override, args2.options)) != null ? _a : [];
2190
+ }
2191
+ return normalizeToolDeclarations(args2.inferred, args2.options);
2192
+ }
2193
+ function promptToolsAttribute(tools) {
2194
+ const values = promptToolsAttributeValue(tools);
2195
+ if (values === void 0) return void 0;
2196
+ return {
2197
+ key: PROMPT_TOOLS_ATTRIBUTE,
2198
+ value: { arrayValue: { values: values.map((stringValue) => ({ stringValue })) } }
2199
+ };
2200
+ }
2201
+ function promptToolsAttributeValue(tools) {
2202
+ if (tools === void 0) return void 0;
2203
+ return tools.map((tool) => {
2204
+ try {
2205
+ return JSON.stringify(tool);
2206
+ } catch (e) {
2207
+ return JSON.stringify({ type: tool.type, name: tool.name });
2208
+ }
2209
+ });
2210
+ }
1357
2211
 
1358
2212
  // ../core/dist/index.node.js
1359
2213
  import { AsyncLocalStorage } from "async_hooks";
2214
+ import { execFile } from "child_process";
2215
+ import { resolve } from "path";
2216
+ var resolveLocal = (sourceDirectory, detectBranch, completed) => {
2217
+ const cwd = sourceDirectory ? resolve(sourceDirectory) : process.cwd();
2218
+ let cancelled = false;
2219
+ let active;
2220
+ let deadlineTimer;
2221
+ const deadline = Date.now() + 1e3;
2222
+ const run = (args2, done) => {
2223
+ if (cancelled) return;
2224
+ const remaining = deadline - Date.now();
2225
+ if (remaining <= 0) {
2226
+ done(void 0);
2227
+ return;
2228
+ }
2229
+ try {
2230
+ active = execFile(
2231
+ "git",
2232
+ args2,
2233
+ {
2234
+ cwd,
2235
+ encoding: "utf8",
2236
+ maxBuffer: 4096,
2237
+ windowsHide: true,
2238
+ env: {
2239
+ ...process.env,
2240
+ // The selected application cwd, not the invoking shell's Git plumbing, owns identity.
2241
+ GIT_DIR: void 0,
2242
+ GIT_WORK_TREE: void 0,
2243
+ GIT_COMMON_DIR: void 0,
2244
+ GIT_NAMESPACE: void 0,
2245
+ GIT_INDEX_FILE: void 0,
2246
+ GIT_OBJECT_DIRECTORY: void 0,
2247
+ GIT_ALTERNATE_OBJECT_DIRECTORIES: void 0,
2248
+ GIT_CONFIG_PARAMETERS: void 0,
2249
+ GIT_CONFIG_COUNT: "0",
2250
+ GIT_TERMINAL_PROMPT: "0",
2251
+ GIT_OPTIONAL_LOCKS: "0"
2252
+ }
2253
+ },
2254
+ (error, stdout) => {
2255
+ clearTimeout(deadlineTimer);
2256
+ deadlineTimer = void 0;
2257
+ active = void 0;
2258
+ if (!cancelled) {
2259
+ try {
2260
+ done(error ? void 0 : stdout.trim());
2261
+ } catch (e) {
2262
+ }
2263
+ }
2264
+ }
2265
+ );
2266
+ active.unref();
2267
+ if (active.stdout && "unref" in active.stdout && typeof active.stdout.unref === "function")
2268
+ active.stdout.unref();
2269
+ if (active.stderr && "unref" in active.stderr && typeof active.stderr.unref === "function")
2270
+ active.stderr.unref();
2271
+ deadlineTimer = setTimeout(() => {
2272
+ try {
2273
+ active == null ? void 0 : active.kill("SIGKILL");
2274
+ } catch (e) {
2275
+ }
2276
+ }, remaining);
2277
+ deadlineTimer.unref();
2278
+ } catch (e) {
2279
+ try {
2280
+ done(void 0);
2281
+ } catch (e2) {
2282
+ }
2283
+ }
2284
+ };
2285
+ const scheduled = setTimeout(() => {
2286
+ try {
2287
+ run(["rev-parse", "HEAD"], (rawSha) => {
2288
+ const commitSha = validAppCommitSha(rawSha);
2289
+ if (!commitSha) {
2290
+ completed({});
2291
+ return;
2292
+ }
2293
+ run(["-c", "core.fsmonitor=false", "status", "--porcelain"], (status) => {
2294
+ const finish = (branch) => {
2295
+ run(["rev-parse", "HEAD"], (finalSha) => {
2296
+ const coherent = validAppCommitSha(finalSha) === commitSha;
2297
+ completed({
2298
+ commitSha,
2299
+ ...coherent && status !== void 0 ? { commitDirty: status !== "" } : {},
2300
+ ...coherent && branch && branch !== "HEAD" ? { branch } : {}
2301
+ });
2302
+ });
2303
+ };
2304
+ if (detectBranch) run(["symbolic-ref", "--quiet", "--short", "HEAD"], finish);
2305
+ else finish();
2306
+ });
2307
+ });
2308
+ } catch (e) {
2309
+ completed({});
2310
+ }
2311
+ }, 0);
2312
+ scheduled.unref();
2313
+ return () => {
2314
+ cancelled = true;
2315
+ clearTimeout(scheduled);
2316
+ clearTimeout(deadlineTimer);
2317
+ try {
2318
+ active == null ? void 0 : active.kill("SIGKILL");
2319
+ } catch (e) {
2320
+ }
2321
+ };
2322
+ };
2323
+ function createAppGitContext2(options, runtime = {}) {
2324
+ return new AppGitContext(options, { ...runtime, resolveLocal });
2325
+ }
2326
+ function hasDestination(options) {
2327
+ var _a;
2328
+ if (options.enabled === false) return false;
2329
+ return Boolean(((_a = options.writeKey) == null ? void 0 : _a.trim()) || resolveLocalDebuggerBaseUrl(options.localDebuggerUrl));
2330
+ }
2331
+ var EventShipper2 = class extends EventShipper {
2332
+ constructor(options) {
2333
+ var _a;
2334
+ const ownsAppGitContext = options.appGitContext === void 0;
2335
+ const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
2336
+ try {
2337
+ super({ ...options, appGitContext });
2338
+ } catch (error) {
2339
+ if (ownsAppGitContext) appGitContext.dispose();
2340
+ throw error;
2341
+ }
2342
+ if (ownsAppGitContext) this.ownAppGitContextForShutdown();
2343
+ }
2344
+ };
2345
+ var TraceShipper2 = class extends TraceShipper {
2346
+ constructor(options) {
2347
+ var _a;
2348
+ const ownsAppGitContext = options.appGitContext === void 0;
2349
+ const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
2350
+ try {
2351
+ super({ ...options, appGitContext });
2352
+ } catch (error) {
2353
+ if (ownsAppGitContext) appGitContext.dispose();
2354
+ throw error;
2355
+ }
2356
+ this.ownsAppGitContext = ownsAppGitContext;
2357
+ }
2358
+ };
1360
2359
  globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = AsyncLocalStorage;
1361
2360
  var SUPPRESS_TRACING_KEY = /* @__PURE__ */ Symbol.for(
1362
2361
  "OpenTelemetry SDK Context Key SUPPRESS_TRACING"
@@ -1387,7 +2386,7 @@ installTracingSuppressionHook();
1387
2386
  // package.json
1388
2387
  var package_default = {
1389
2388
  name: "@raindrop-ai/claude-code",
1390
- version: "0.0.19",
2389
+ version: "0.0.21",
1391
2390
  description: "Raindrop observability for Claude Code CLI \u2014 automatic session, tool call, and prompt tracing via hooks",
1392
2391
  license: "MIT",
1393
2392
  homepage: "https://www.raindrop.ai/docs/integrations/claude-code/",
@@ -1461,7 +2460,7 @@ var PACKAGE_NAME = "@raindrop-ai/claude-code";
1461
2460
  var PACKAGE_VERSION = package_default.version;
1462
2461
 
1463
2462
  // src/shipper.ts
1464
- var EventShipper2 = class extends EventShipper {
2463
+ var EventShipper3 = class extends EventShipper2 {
1465
2464
  constructor(opts) {
1466
2465
  var _a, _b, _c, _d;
1467
2466
  super({
@@ -1473,7 +2472,7 @@ var EventShipper2 = class extends EventShipper {
1473
2472
  });
1474
2473
  }
1475
2474
  };
1476
- var TraceShipper2 = class extends TraceShipper {
2475
+ var TraceShipper3 = class extends TraceShipper2 {
1477
2476
  constructor(opts) {
1478
2477
  var _a, _b, _c;
1479
2478
  super({
@@ -2296,7 +3295,7 @@ function isoToNanoString(iso, fallback) {
2296
3295
  return fallback;
2297
3296
  }
2298
3297
  }
2299
- function enrichFromTranscript(payload, eventId, traceShipper) {
3298
+ function enrichFromTranscript(payload, eventId, traceShipper, promptTools) {
2300
3299
  var _a, _b, _c, _d;
2301
3300
  if (!payload.transcript_path) {
2302
3301
  return { summary: void 0, props: {} };
@@ -2335,7 +3334,8 @@ function enrichFromTranscript(payload, eventId, traceShipper) {
2335
3334
  attrString("ai.response.text", truncate(outputText)),
2336
3335
  ...toolCallNames ? [attrString("ai.toolCall.names", toolCallNames)] : [],
2337
3336
  ...phase.hasThinking ? [attrString("ai.has_thinking", "true")] : [],
2338
- attrInt("ai.llm_call.index", emittedPhaseIndex)
3337
+ attrInt("ai.llm_call.index", emittedPhaseIndex),
3338
+ promptTools
2339
3339
  ]
2340
3340
  });
2341
3341
  emittedPhaseIndex++;
@@ -2357,7 +3357,8 @@ function enrichFromTranscript(payload, eventId, traceShipper) {
2357
3357
  attrString("gen_ai.system", "anthropic"),
2358
3358
  attrInt("gen_ai.usage.prompt_tokens", spanInputTokens),
2359
3359
  attrInt("gen_ai.usage.completion_tokens", spanOutputTokens),
2360
- ...summary.lastTurnCacheReadTokens != null && summary.lastTurnCacheReadTokens > 0 ? [attrInt("gen_ai.usage.cache_read_tokens", summary.lastTurnCacheReadTokens)] : []
3360
+ ...summary.lastTurnCacheReadTokens != null && summary.lastTurnCacheReadTokens > 0 ? [attrInt("gen_ai.usage.cache_read_tokens", summary.lastTurnCacheReadTokens)] : [],
3361
+ promptTools
2361
3362
  ]
2362
3363
  });
2363
3364
  }
@@ -2383,7 +3384,12 @@ function buildStopOutput(summary, lastAssistantMessage) {
2383
3384
  return finalMessage;
2384
3385
  }
2385
3386
  async function handleStopOrFailure(payload, eventId, convoId, config, properties, eventShipper, traceShipper, extraProperties) {
2386
- const { summary, props: transcriptProps } = enrichFromTranscript(payload, eventId, traceShipper);
3387
+ const { summary, props: transcriptProps } = enrichFromTranscript(
3388
+ payload,
3389
+ eventId,
3390
+ traceShipper,
3391
+ promptToolsAttribute(resolvePromptTools({ override: config.tools }))
3392
+ );
2387
3393
  const instructions = gatherInstructions(payload.session_id);
2388
3394
  const appendSysPrompt = readAppendSystemPrompt(payload.session_id);
2389
3395
  const output = buildStopOutput(summary, payload.last_assistant_message);
@@ -2448,6 +3454,15 @@ function loadConfig() {
2448
3454
  } catch (e) {
2449
3455
  }
2450
3456
  }
3457
+ let tools = Array.isArray(file.tools) ? file.tools : void 0;
3458
+ const envTools = process.env["RAINDROP_TOOLS"];
3459
+ if (envTools) {
3460
+ try {
3461
+ const parsed = JSON.parse(envTools);
3462
+ if (Array.isArray(parsed)) tools = parsed;
3463
+ } catch (e) {
3464
+ }
3465
+ }
2451
3466
  let selfDiagnostics = file.self_diagnostics;
2452
3467
  const envDiag = process.env["RAINDROP_SELF_DIAGNOSTICS"];
2453
3468
  if (envDiag) {
@@ -2475,7 +3490,21 @@ function loadConfig() {
2475
3490
  })(),
2476
3491
  eventName: (_l = (_k = process.env["RAINDROP_EVENT_NAME"]) != null ? _k : file.event_name) != null ? _l : "claude_code_session",
2477
3492
  customProperties,
2478
- selfDiagnostics
3493
+ selfDiagnostics,
3494
+ appGit: mapAppGit(file.app_git),
3495
+ tools
3496
+ };
3497
+ }
3498
+ function mapAppGit(value) {
3499
+ if (value === false) return false;
3500
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
3501
+ return {
3502
+ commitSha: "commit_sha" in value && (typeof value.commit_sha === "string" || value.commit_sha === null) ? value.commit_sha : void 0,
3503
+ commitDirty: "commit_dirty" in value && (typeof value.commit_dirty === "boolean" || value.commit_dirty === null) ? value.commit_dirty : void 0,
3504
+ branch: "branch" in value && (typeof value.branch === "string" || value.branch === null) ? value.branch : void 0,
3505
+ detectBranch: "detect_branch" in value && typeof value.detect_branch === "boolean" ? value.detect_branch : void 0,
3506
+ sourceDirectory: "source_directory" in value && typeof value.source_directory === "string" ? value.source_directory : void 0,
3507
+ autoDetect: "auto_detect" in value && typeof value.auto_detect === "boolean" ? value.auto_detect : void 0
2479
3508
  };
2480
3509
  }
2481
3510
  function getConfigPath() {
@@ -2597,16 +3626,16 @@ function hookFlushDeadlineMs() {
2597
3626
  return DEFAULT_HOOK_FLUSH_DEADLINE_MS;
2598
3627
  }
2599
3628
  function withDeadline(promise, ms) {
2600
- return new Promise((resolve2, reject) => {
3629
+ return new Promise((resolve3, reject) => {
2601
3630
  const timer = setTimeout(() => {
2602
3631
  promise.catch(() => {
2603
3632
  });
2604
- resolve2("deadline");
3633
+ resolve3("deadline");
2605
3634
  }, ms);
2606
3635
  promise.then(
2607
3636
  (value) => {
2608
3637
  clearTimeout(timer);
2609
- resolve2(value);
3638
+ resolve3(value);
2610
3639
  },
2611
3640
  (err) => {
2612
3641
  clearTimeout(timer);
@@ -2628,9 +3657,9 @@ function getOtlpTraceId(sessionId) {
2628
3657
  }
2629
3658
  }
2630
3659
  function readStdin() {
2631
- return new Promise((resolve2) => {
3660
+ return new Promise((resolve3) => {
2632
3661
  if (process.stdin.isTTY) {
2633
- resolve2("");
3662
+ resolve3("");
2634
3663
  return;
2635
3664
  }
2636
3665
  const chunks = [];
@@ -2641,7 +3670,7 @@ function readStdin() {
2641
3670
  clearTimeout(timeout);
2642
3671
  process.stdin.removeAllListeners();
2643
3672
  process.stdin.destroy();
2644
- resolve2(value);
3673
+ resolve3(value);
2645
3674
  }
2646
3675
  const timeout = setTimeout(() => {
2647
3676
  done(chunks.length > 0 ? Buffer.concat(chunks).toString("utf-8") : "");
@@ -2652,6 +3681,7 @@ function readStdin() {
2652
3681
  });
2653
3682
  }
2654
3683
  async function handleHook() {
3684
+ var _a;
2655
3685
  const startedAtMs = Date.now();
2656
3686
  const raw = await readStdin();
2657
3687
  if (!raw.trim()) {
@@ -2684,9 +3714,14 @@ async function handleHook() {
2684
3714
  convoId: config.convoId,
2685
3715
  debug: config.debug,
2686
3716
  eventName: config.eventName,
2687
- customProperties: config.customProperties
3717
+ customProperties: config.customProperties,
3718
+ tools: config.tools
2688
3719
  };
2689
- const eventShipper = new EventShipper2({
3720
+ const appGitContext = createAppGitContext2(
3721
+ ((_a = config.writeKey) == null ? void 0 : _a.trim()) || hasDebugger ? config.appGit : false,
3722
+ { allowLocalGit: false }
3723
+ );
3724
+ const eventShipper = new EventShipper3({
2690
3725
  writeKey: config.writeKey,
2691
3726
  endpoint: config.endpoint,
2692
3727
  debug: config.debug,
@@ -2694,21 +3729,23 @@ async function handleHook() {
2694
3729
  // Only ship to the cloud when we have an API key. When only the local
2695
3730
  // debugger is present the shipper still needs to be instantiated so the
2696
3731
  // event mapper can call patch/finish, but cloud POSTs are skipped.
2697
- enabled: hasCloudKey
3732
+ enabled: hasCloudKey,
3733
+ appGitContext
2698
3734
  });
2699
- const traceShipper = new TraceShipper2({
3735
+ const traceShipper = new TraceShipper3({
2700
3736
  writeKey: config.writeKey,
2701
3737
  endpoint: config.endpoint,
2702
3738
  debug: config.debug,
2703
3739
  projectId: config.projectId,
2704
- enabled: hasCloudKey
3740
+ enabled: hasCloudKey,
3741
+ appGitContext
2705
3742
  });
2706
3743
  if (debugger_.url) {
2707
3744
  const debuggerUrl = debugger_.url;
2708
3745
  const origPatch = eventShipper.patch.bind(eventShipper);
2709
3746
  eventShipper.patch = async (eventId, patch) => {
2710
- var _a, _b, _c, _d;
2711
- const traceId = (_a = getOtlpTraceId(payload.session_id)) != null ? _a : payload.session_id;
3747
+ var _a2, _b, _c, _d;
3748
+ const traceId = (_a2 = getOtlpTraceId(payload.session_id)) != null ? _a2 : payload.session_id;
2712
3749
  await Promise.all([
2713
3750
  mirrorEventToLocalDebugger(debuggerUrl, {
2714
3751
  event_id: eventId,
@@ -2722,7 +3759,10 @@ async function handleHook() {
2722
3759
  convo_id: patch.convoId
2723
3760
  },
2724
3761
  properties: {
2725
- ...patch.properties,
3762
+ ...withAppGitProperties(
3763
+ patch.properties,
3764
+ appGitContext.forOperation(eventId, patch.properties)
3765
+ ),
2726
3766
  ...payload.session_id ? { trace_id: traceId } : {}
2727
3767
  },
2728
3768
  is_pending: (_d = patch.isPending) != null ? _d : true
@@ -2736,14 +3776,23 @@ async function handleHook() {
2736
3776
  MIN_FLUSH_WINDOW_MS,
2737
3777
  hookFlushDeadlineMs() - (Date.now() - startedAtMs)
2738
3778
  );
2739
- const outcome = await withDeadline(
2740
- (async () => {
3779
+ const hookWork = (async () => {
3780
+ try {
2741
3781
  await mapHookToRaindrop(payload, mapperConfig, eventShipper, traceShipper);
2742
3782
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
2743
3783
  await Promise.all([eventShipper.shutdown(), traceShipper.shutdown()]);
2744
- })(),
2745
- remainingMs
2746
- );
3784
+ } finally {
3785
+ try {
3786
+ appGitContext.dispose();
3787
+ } catch (e) {
3788
+ }
3789
+ }
3790
+ })();
3791
+ const outcome = await withDeadline(hookWork, remainingMs);
3792
+ try {
3793
+ appGitContext.dispose();
3794
+ } catch (e) {
3795
+ }
2747
3796
  if (outcome === "deadline" && config.debug) {
2748
3797
  console.error(
2749
3798
  `[raindrop-ai/claude-code] hook work exceeded the ${hookFlushDeadlineMs()}ms deadline; exiting without waiting on the network (pending telemetry dropped)`
@@ -2761,12 +3810,12 @@ async function handleHook() {
2761
3810
  // src/setup.ts
2762
3811
  import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
2763
3812
  import { homedir as homedir2, userInfo as userInfo2 } from "os";
2764
- import { dirname as dirname2, join as join5, resolve } from "path";
3813
+ import { dirname as dirname2, join as join5, resolve as resolve2 } from "path";
2765
3814
  import { createInterface } from "readline";
2766
3815
  import { execSync as execSync2 } from "child_process";
2767
3816
  function getClaudeSettingsPath(scope, cwd) {
2768
3817
  if (scope === "project") {
2769
- return resolve(cwd, ".claude", "settings.json");
3818
+ return resolve2(cwd, ".claude", "settings.json");
2770
3819
  }
2771
3820
  return join5(homedir2(), ".claude", "settings.json");
2772
3821
  }
@@ -2849,10 +3898,10 @@ function makeHookConfig(hookEvents, useAsync) {
2849
3898
  }
2850
3899
  function prompt(question) {
2851
3900
  const rl = createInterface({ input: process.stdin, output: process.stdout });
2852
- return new Promise((resolve2) => {
3901
+ return new Promise((resolve3) => {
2853
3902
  rl.question(question, (answer) => {
2854
3903
  rl.close();
2855
- resolve2(answer.trim());
3904
+ resolve3(answer.trim());
2856
3905
  });
2857
3906
  });
2858
3907
  }
@@ -3192,6 +4241,7 @@ function resolveCurrentEventId() {
3192
4241
  }
3193
4242
  }
3194
4243
  async function executeTool(args2) {
4244
+ var _a;
3195
4245
  const category = typeof args2["category"] === "string" ? args2["category"] : "";
3196
4246
  const detail = typeof args2["detail"] === "string" ? args2["detail"] : "";
3197
4247
  if (!category || !activeSignals[category]) {
@@ -3217,12 +4267,17 @@ async function executeTool(args2) {
3217
4267
  if (!eventId) {
3218
4268
  return { content: [{ type: "text", text: "Signal noted (no active event found)." }] };
3219
4269
  }
3220
- const shipper = new EventShipper2({
4270
+ const appGitContext = createAppGitContext2(
4271
+ ((_a = config.writeKey) == null ? void 0 : _a.trim()) ? config.appGit : false,
4272
+ { allowLocalGit: false }
4273
+ );
4274
+ const shipper = new EventShipper3({
3221
4275
  writeKey: config.writeKey,
3222
4276
  endpoint: config.endpoint,
3223
4277
  debug: false,
3224
4278
  projectId: config.projectId,
3225
- enabled: true
4279
+ enabled: true,
4280
+ appGitContext
3226
4281
  });
3227
4282
  try {
3228
4283
  const signalDef = activeSignals[category];
@@ -3249,6 +4304,11 @@ async function executeTool(args2) {
3249
4304
  });
3250
4305
  await shipper.shutdown();
3251
4306
  } catch (e) {
4307
+ } finally {
4308
+ try {
4309
+ appGitContext.dispose();
4310
+ } catch (e) {
4311
+ }
3252
4312
  }
3253
4313
  return { content: [{ type: "text", text: "Signal recorded." }] };
3254
4314
  }
@@ -3374,8 +4434,8 @@ var args = process.argv.slice(2);
3374
4434
  var command = args[0];
3375
4435
  function parseFlag(name) {
3376
4436
  const prefix = `--${name}=`;
3377
- const flag = args.find((a) => a.startsWith(prefix));
3378
- return flag ? flag.slice(prefix.length) : void 0;
4437
+ const flag2 = args.find((a) => a.startsWith(prefix));
4438
+ return flag2 ? flag2.slice(prefix.length) : void 0;
3379
4439
  }
3380
4440
  async function main() {
3381
4441
  switch (command) {