@raindrop-ai/opencode-plugin 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -24,7 +24,521 @@ __export(index_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(index_exports);
26
26
 
27
- // ../core/dist/chunk-3V4MIA75.js
27
+ // ../core/dist/chunk-BYBMRLZM.js
28
+ var EVAL_CORRELATION_ID_ATTRIBUTE = "raindrop.eval_correlation_id";
29
+ var PROBE_SCOPE = { correlationId: "" };
30
+ var EvalScopeStorage = class {
31
+ constructor() {
32
+ this._als = null;
33
+ this._probed = false;
34
+ }
35
+ maybeAdoptAsyncLocalStorage() {
36
+ if (this._probed) return;
37
+ this._probed = true;
38
+ try {
39
+ const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
40
+ if (!Ctor) return;
41
+ const als = new Ctor();
42
+ als.run(PROBE_SCOPE, () => {
43
+ });
44
+ this._als = als;
45
+ } catch (e) {
46
+ this._als = null;
47
+ }
48
+ }
49
+ run(scope, callback) {
50
+ this.maybeAdoptAsyncLocalStorage();
51
+ if (this._als) return this._als.run(scope, callback);
52
+ const previous = this._syncScope;
53
+ this._syncScope = scope;
54
+ try {
55
+ return callback();
56
+ } finally {
57
+ this._syncScope = previous;
58
+ }
59
+ }
60
+ current() {
61
+ this.maybeAdoptAsyncLocalStorage();
62
+ if (this._als) return this._als.getStore();
63
+ return this._syncScope;
64
+ }
65
+ };
66
+ var EVAL_SCOPE_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.evalScopeStorage");
67
+ function evalScopeStorage() {
68
+ const holder = globalThis;
69
+ let storage = holder[EVAL_SCOPE_STORAGE_KEY];
70
+ if (!storage) {
71
+ storage = new EvalScopeStorage();
72
+ holder[EVAL_SCOPE_STORAGE_KEY] = storage;
73
+ }
74
+ return storage;
75
+ }
76
+ function currentEvalScope() {
77
+ try {
78
+ return evalScopeStorage().current();
79
+ } catch (e) {
80
+ return void 0;
81
+ }
82
+ }
83
+ function evalScopeAttributes() {
84
+ const scope = currentEvalScope();
85
+ if (!scope) return {};
86
+ return { [EVAL_CORRELATION_ID_ATTRIBUTE]: scope.correlationId };
87
+ }
88
+
89
+ // ../core/dist/chunk-WJOR6M7H.js
90
+ var STATE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.replayTraceRoutingState");
91
+ function state() {
92
+ const holder = globalThis;
93
+ let current = holder[STATE_KEY];
94
+ if (!current) {
95
+ let storage = null;
96
+ try {
97
+ const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
98
+ if (Ctor) storage = new Ctor();
99
+ } catch (e) {
100
+ storage = null;
101
+ }
102
+ current = {
103
+ storage,
104
+ syncDestination: void 0,
105
+ spanDestinations: /* @__PURE__ */ new WeakMap()
106
+ };
107
+ holder[STATE_KEY] = current;
108
+ }
109
+ return current;
110
+ }
111
+ function currentReplayTraceDestination() {
112
+ var _a, _b;
113
+ const routing = state();
114
+ return (_b = (_a = routing.storage) == null ? void 0 : _a.getStore()) != null ? _b : routing.syncDestination;
115
+ }
116
+ function rememberReplayTraceDestination(span) {
117
+ const destination = currentReplayTraceDestination();
118
+ if (destination) state().spanDestinations.set(span, destination);
119
+ }
120
+ function copyReplayTraceDestination(source, target) {
121
+ const destination = state().spanDestinations.get(source);
122
+ if (destination) state().spanDestinations.set(target, destination);
123
+ }
124
+ function replayTraceDestinationFor(value) {
125
+ if (typeof value !== "object" && typeof value !== "function" || value === null) {
126
+ return void 0;
127
+ }
128
+ return state().spanDestinations.get(value);
129
+ }
130
+ function recordReplayExportedSpan(destination, spanId, traceId) {
131
+ var _a, _b;
132
+ if (!destination || !spanId || !traceId) return;
133
+ (_a = destination.exportedSpanIds) == null ? void 0 : _a.add(spanId);
134
+ (_b = destination.exportedTraceIds) == null ? void 0 : _b.add(traceId);
135
+ }
136
+ function replayTraceUrl(baseUrl) {
137
+ return `${baseUrl.replace(/\/+$/, "")}/v1/traces`;
138
+ }
139
+ function getAsyncLocalStorageCtor() {
140
+ return globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
141
+ }
142
+ var MAX_BINDING_STACK = 128;
143
+ var EMPTY_STACK = [];
144
+ var ContextStackStorage = class {
145
+ /** Emitted once when this runtime cannot support an ambient push. */
146
+ constructor(noAmbientBindWarning) {
147
+ this.noAmbientBindWarning = noAmbientBindWarning;
148
+ this._als = null;
149
+ this._enterWithUsable = false;
150
+ this._syncStack = EMPTY_STACK;
151
+ this._adoptionChecked = false;
152
+ this._warnedNoAmbientBind = false;
153
+ }
154
+ maybeAdoptAsyncLocalStorage() {
155
+ if (this._adoptionChecked) return;
156
+ this._adoptionChecked = true;
157
+ const Ctor = getAsyncLocalStorageCtor();
158
+ if (!Ctor) return;
159
+ const als = new Ctor();
160
+ try {
161
+ als.run(EMPTY_STACK, () => {
162
+ });
163
+ } catch (e) {
164
+ return;
165
+ }
166
+ this._als = als;
167
+ if (typeof als.enterWith === "function") {
168
+ try {
169
+ als.enterWith(EMPTY_STACK);
170
+ this._enterWithUsable = true;
171
+ } catch (e) {
172
+ this._enterWithUsable = false;
173
+ }
174
+ }
175
+ }
176
+ getStack() {
177
+ var _a;
178
+ this.maybeAdoptAsyncLocalStorage();
179
+ if (this._als) return (_a = this._als.getStore()) != null ? _a : this._syncStack;
180
+ return this._syncStack;
181
+ }
182
+ /**
183
+ * Persist an ambient stack mutation. Returns false when an ALS is adopted but
184
+ * `enterWith` is unusable (workerd): callers must NOT fall back to the
185
+ * process-shared sync stack, since concurrent isolates would cross-stamp.
186
+ */
187
+ setAmbientStack(stack) {
188
+ if (this._als) {
189
+ if (!this._enterWithUsable) return false;
190
+ this._als.enterWith(stack);
191
+ return true;
192
+ }
193
+ this._syncStack = stack;
194
+ return true;
195
+ }
196
+ push(binding) {
197
+ this.maybeAdoptAsyncLocalStorage();
198
+ if (this._als && !this._enterWithUsable) {
199
+ this.warnNoAmbientBindOnce();
200
+ return;
201
+ }
202
+ let stack = this.getStack();
203
+ if (stack.length >= MAX_BINDING_STACK) {
204
+ stack = stack.filter((b) => b.isLive());
205
+ if (stack.length >= MAX_BINDING_STACK) {
206
+ stack = stack.slice(stack.length - (MAX_BINDING_STACK - 1));
207
+ }
208
+ }
209
+ this.setAmbientStack([...stack, binding]);
210
+ }
211
+ remove(binding) {
212
+ binding.markDead();
213
+ const stack = this.getStack();
214
+ const pruned = stack.filter((b) => b !== binding && b.isLive());
215
+ if (pruned.length !== stack.length) {
216
+ this.setAmbientStack(pruned);
217
+ }
218
+ }
219
+ runWith(binding, callback) {
220
+ this.maybeAdoptAsyncLocalStorage();
221
+ if (this._als) {
222
+ return this._als.run([...this.getStack(), binding], callback);
223
+ }
224
+ const previous = this._syncStack;
225
+ this._syncStack = [...previous, binding];
226
+ try {
227
+ return callback();
228
+ } finally {
229
+ this._syncStack = previous;
230
+ }
231
+ }
232
+ current() {
233
+ const stack = this.getStack();
234
+ if (stack.length === 0) return void 0;
235
+ const top = stack[stack.length - 1];
236
+ if (top.isLive()) return top;
237
+ const pruned = stack.filter((b) => b.isLive());
238
+ this.setAmbientStack(pruned);
239
+ return pruned.length > 0 ? pruned[pruned.length - 1] : void 0;
240
+ }
241
+ warnNoAmbientBindOnce() {
242
+ if (this._warnedNoAmbientBind) return;
243
+ this._warnedNoAmbientBind = true;
244
+ console.warn(this.noAmbientBindWarning);
245
+ }
246
+ };
247
+ 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.";
248
+ var ROUTING_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.routingContextStorage");
249
+ function routingStorage() {
250
+ const holder = globalThis;
251
+ let storage = holder[ROUTING_STORAGE_KEY];
252
+ if (!storage) {
253
+ storage = new ContextStackStorage(NO_AMBIENT_ROUTING_BIND_WARNING);
254
+ holder[ROUTING_STORAGE_KEY] = storage;
255
+ }
256
+ return storage;
257
+ }
258
+ function currentRoutingBinding() {
259
+ const bound = routingStorage().current();
260
+ if (!bound) return void 0;
261
+ return {
262
+ projectId: bound.projectId,
263
+ authHint: bound.authHint,
264
+ ...bound.appGit ? { appGit: bound.appGit } : {},
265
+ ...bound.appGitSource ? { appGitSource: bound.appGitSource } : {}
266
+ };
267
+ }
268
+ var APP_COMMIT_SHA = "raindrop.app.commit_sha";
269
+ var APP_COMMIT_DIRTY = "raindrop.app.commit_dirty";
270
+ var APP_BRANCH = "raindrop.app.branch";
271
+ var APP_GIT_KEYS = [APP_COMMIT_SHA, APP_COMMIT_DIRTY, APP_BRANCH];
272
+ var own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
273
+ function appGitExplicitKeys(properties) {
274
+ const keys = /* @__PURE__ */ new Set();
275
+ if (!properties) return keys;
276
+ for (const key of APP_GIT_KEYS) {
277
+ if (own(properties, key)) keys.add(key);
278
+ }
279
+ return keys;
280
+ }
281
+ function mergeAppGitSnapshot(base, properties, explicitKeys = /* @__PURE__ */ new Set()) {
282
+ try {
283
+ const result = { ...base };
284
+ if (properties && own(properties, APP_COMMIT_SHA) && properties[APP_COMMIT_SHA] !== result[APP_COMMIT_SHA]) {
285
+ if (!explicitKeys.has(APP_COMMIT_DIRTY) && !own(properties, APP_COMMIT_DIRTY)) {
286
+ delete result[APP_COMMIT_DIRTY];
287
+ }
288
+ if (!explicitKeys.has(APP_BRANCH) && !own(properties, APP_BRANCH)) {
289
+ delete result[APP_BRANCH];
290
+ }
291
+ }
292
+ for (const key of APP_GIT_KEYS) {
293
+ if (properties && own(properties, key)) result[key] = properties[key];
294
+ }
295
+ return Object.freeze(result);
296
+ } catch (e) {
297
+ return Object.freeze({});
298
+ }
299
+ }
300
+ function validAppCommitSha(value) {
301
+ if (typeof value !== "string" || value.length > 128) return void 0;
302
+ const cleaned = value.trim();
303
+ return /^(?:[a-fA-F0-9]{40}|[a-fA-F0-9]{64})$/.test(cleaned) ? cleaned.toLowerCase() : void 0;
304
+ }
305
+ function shortString(value) {
306
+ if (typeof value !== "string" || value.length > 1024) return void 0;
307
+ const cleaned = value.trim();
308
+ return cleaned.length > 0 ? cleaned : void 0;
309
+ }
310
+ function flag(value) {
311
+ if (value === true || value === "true" || value === "1") return true;
312
+ if (value === false || value === "false" || value === "0") return false;
313
+ return void 0;
314
+ }
315
+ function environment() {
316
+ try {
317
+ return typeof process === "undefined" ? {} : process.env;
318
+ } catch (e) {
319
+ return {};
320
+ }
321
+ }
322
+ var DEPLOYMENTS = [
323
+ ["VERCEL", "VERCEL_GIT_COMMIT_SHA", "VERCEL_GIT_COMMIT_REF"],
324
+ ["NETLIFY", "COMMIT_REF", "BRANCH"],
325
+ ["RAILWAY_ENVIRONMENT_NAME", "RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH"],
326
+ ["RAILWAY_ENVIRONMENT", "RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH"],
327
+ ["RENDER", "RENDER_GIT_COMMIT", "RENDER_GIT_BRANCH"],
328
+ ["DYNO", "HEROKU_BUILD_COMMIT", ""],
329
+ ["DYNO", "HEROKU_SLUG_COMMIT", ""],
330
+ ["AWS_APP_ID", "AWS_COMMIT_ID", "AWS_BRANCH"],
331
+ ["WORKERS_CI", "WORKERS_CI_COMMIT_SHA", "WORKERS_CI_BRANCH"]
332
+ ];
333
+ var CI_SOURCES = [
334
+ ["GITHUB_ACTIONS", "GITHUB_SHA", "GITHUB_REF_NAME"],
335
+ ["GITLAB_CI", "CI_COMMIT_SHA", "CI_COMMIT_REF_NAME"],
336
+ ["CIRCLECI", "CIRCLE_SHA1", "CIRCLE_BRANCH"]
337
+ ];
338
+ function detectedSource(env, table, detectBranch) {
339
+ for (const row of table) {
340
+ const [marker, shaKey, branchKey] = row;
341
+ if (!marker || !shaKey || !shortString(env[marker]) || flag(env[marker]) === false) continue;
342
+ const commitSha = validAppCommitSha(env[shaKey]);
343
+ if (commitSha)
344
+ return {
345
+ commitSha,
346
+ ...detectBranch && branchKey ? { branch: shortString(env[branchKey]) } : {}
347
+ };
348
+ }
349
+ return {};
350
+ }
351
+ var AppGitContextImpl = class {
352
+ constructor(options, runtime = {}) {
353
+ this.defaults = {};
354
+ this.explicit = {};
355
+ this.explicitKeys = /* @__PURE__ */ new Set();
356
+ this.disposed = false;
357
+ this.operations = /* @__PURE__ */ new Map();
358
+ this.operationOverflow = false;
359
+ this.detectBranch = false;
360
+ this.disabled = false;
361
+ var _a, _b, _c, _d, _e, _f;
362
+ try {
363
+ if (options === false) {
364
+ this.disabled = true;
365
+ return;
366
+ }
367
+ const opts = options != null ? options : {};
368
+ const env = (_a = runtime.env) != null ? _a : environment();
369
+ const detectBranch = (_c = (_b = flag(opts.detectBranch)) != null ? _b : flag(env.RAINDROP_GIT_DETECT_BRANCH)) != null ? _c : false;
370
+ this.detectBranch = detectBranch;
371
+ const collectBranch = detectBranch || runtime.captureLegacyReplayBranch === true;
372
+ const autoDetect = runtime.allowDiscovery === false ? false : (_e = (_d = flag(opts.autoDetect)) != null ? _d : flag(env.RAINDROP_GIT_AUTO_DETECT)) != null ? _e : true;
373
+ const configuredSha = opts.commitSha;
374
+ const explicitSha = configuredSha === void 0 ? env.RAINDROP_COMMIT_SHA : configuredSha;
375
+ if (explicitSha === null) this.explicit[APP_COMMIT_SHA] = null;
376
+ else if (typeof explicitSha === "string" && validAppCommitSha(explicitSha))
377
+ this.explicit[APP_COMMIT_SHA] = explicitSha;
378
+ const configuredDirty = opts.commitDirty;
379
+ const explicitDirty = configuredDirty === void 0 ? flag(env.RAINDROP_COMMIT_DIRTY) : configuredDirty;
380
+ if (explicitDirty === null || typeof explicitDirty === "boolean")
381
+ this.explicit[APP_COMMIT_DIRTY] = explicitDirty;
382
+ const configuredBranch = opts.branch;
383
+ const explicitBranch = configuredBranch === void 0 ? env.RAINDROP_BRANCH : configuredBranch;
384
+ if (explicitBranch === null) this.explicit[APP_BRANCH] = null;
385
+ else if (typeof explicitBranch === "string" && explicitBranch.length <= 1024)
386
+ this.explicit[APP_BRANCH] = explicitBranch;
387
+ this.explicitKeys = appGitExplicitKeys(this.explicit);
388
+ this.defaults = { ...this.explicit };
389
+ if (!autoDetect || explicitSha !== void 0) return;
390
+ const sourceDirectory = (_f = shortString(opts.sourceDirectory)) != null ? _f : shortString(env.RAINDROP_GIT_SOURCE_DIRECTORY);
391
+ if (runtime.allowLocalGit === false && !sourceDirectory) return;
392
+ const deploy = sourceDirectory ? {} : detectedSource(env, DEPLOYMENTS, collectBranch);
393
+ if (deploy.commitSha) {
394
+ this.accept(deploy);
395
+ return;
396
+ }
397
+ const fallback = sourceDirectory ? {} : detectedSource(env, CI_SOURCES, collectBranch);
398
+ if (runtime.resolveLocal && (runtime.allowLocalGit !== false || sourceDirectory)) {
399
+ this.cancel = runtime.resolveLocal(sourceDirectory, collectBranch, (result) => {
400
+ try {
401
+ if (!this.disposed) this.accept(result.commitSha ? result : fallback);
402
+ } catch (e) {
403
+ }
404
+ });
405
+ } else this.accept(fallback);
406
+ } catch (e) {
407
+ }
408
+ }
409
+ accept(result) {
410
+ const sha = validAppCommitSha(result.commitSha);
411
+ if (!sha) return;
412
+ this.replayBranch = shortString(result.branch);
413
+ this.defaults = {
414
+ [APP_COMMIT_SHA]: sha,
415
+ ...typeof result.commitDirty === "boolean" ? { [APP_COMMIT_DIRTY]: result.commitDirty } : {},
416
+ ...this.detectBranch && this.replayBranch ? { [APP_BRANCH]: this.replayBranch } : {},
417
+ ...this.explicit
418
+ };
419
+ }
420
+ snapshot(properties) {
421
+ var _a;
422
+ try {
423
+ const binding = currentRoutingBinding();
424
+ const base = this.disabled && (binding == null ? void 0 : binding.appGitSource) !== "replay-override" ? {} : (_a = binding == null ? void 0 : binding.appGit) != null ? _a : this.defaults;
425
+ return this.mergeSnapshot(base, properties);
426
+ } catch (e) {
427
+ return Object.freeze({});
428
+ }
429
+ }
430
+ /** Safe defaults when no operation/span start was observed; never infer identity. */
431
+ snapshotExplicit(properties, eventId) {
432
+ try {
433
+ const base = { ...this.explicit };
434
+ const operation = eventId ? this.operations.get(eventId) : void 0;
435
+ if (operation) {
436
+ for (const key of operation.explicitKeys) base[key] = operation.snapshot[key];
437
+ }
438
+ return this.mergeSnapshot(base, properties, new Set(Object.keys(base)));
439
+ } catch (e) {
440
+ return mergeAppGitSnapshot({}, properties);
441
+ }
442
+ }
443
+ /** Existing replay branch reporting stays separate from opt-in event properties. */
444
+ snapshotForReplay() {
445
+ const snapshot = this.snapshot();
446
+ if (this.replayBranch && !own(snapshot, APP_BRANCH) && snapshot[APP_COMMIT_SHA] === this.defaults[APP_COMMIT_SHA]) {
447
+ return Object.freeze({ ...snapshot, [APP_BRANCH]: this.replayBranch });
448
+ }
449
+ return snapshot;
450
+ }
451
+ /** Merge a frozen span snapshot without losing client-authored provenance. */
452
+ mergeSnapshot(base, properties, explicitKeys = this.explicitKeys) {
453
+ return mergeAppGitSnapshot(base, properties, /* @__PURE__ */ new Set([...this.explicitKeys, ...explicitKeys]));
454
+ }
455
+ /** Shippers belonging to one client share this bounded operation registry. */
456
+ forOperation(eventId, properties, owner) {
457
+ if (!eventId) return this.snapshot(properties);
458
+ let operation = this.operations.get(eventId);
459
+ if (!operation) {
460
+ if (this.operations.size >= 1e4) this.operationOverflow = true;
461
+ if (this.operationOverflow) return this.mergeSnapshot({}, properties);
462
+ operation = {
463
+ snapshot: this.snapshot(properties),
464
+ owners: /* @__PURE__ */ new Set(),
465
+ unowned: owner === void 0,
466
+ explicitKeys: appGitExplicitKeys(properties)
467
+ };
468
+ this.operations.set(eventId, operation);
469
+ } else if (properties && APP_GIT_KEYS.some((key) => own(properties, key))) {
470
+ const explicitKeys = /* @__PURE__ */ new Set([...this.explicitKeys, ...operation.explicitKeys]);
471
+ operation.snapshot = this.mergeSnapshot(operation.snapshot, properties, explicitKeys);
472
+ for (const key of appGitExplicitKeys(properties)) operation.explicitKeys.add(key);
473
+ }
474
+ if (!owner) operation.unowned = true;
475
+ if (owner) operation.owners.add(owner);
476
+ return operation.snapshot;
477
+ }
478
+ releaseOperation(eventId, owner) {
479
+ const operation = this.operations.get(eventId);
480
+ if (!operation) return;
481
+ operation.owners.delete(owner);
482
+ if (operation.owners.size === 0 && !operation.unowned) this.operations.delete(eventId);
483
+ }
484
+ finishOperation(eventId) {
485
+ this.operations.delete(eventId);
486
+ }
487
+ dispose() {
488
+ var _a;
489
+ this.disposed = true;
490
+ try {
491
+ (_a = this.cancel) == null ? void 0 : _a.call(this);
492
+ } catch (e) {
493
+ }
494
+ }
495
+ };
496
+ var AppGitContext = AppGitContextImpl;
497
+ function createAppGitContext(options, runtime = {}) {
498
+ return new AppGitContext(options, runtime);
499
+ }
500
+ function withAppGitProperties(properties, snapshot) {
501
+ try {
502
+ const merged = { ...properties };
503
+ for (const key of APP_GIT_KEYS)
504
+ if (!own(merged, key) && own(snapshot, key)) merged[key] = snapshot[key];
505
+ return merged;
506
+ } catch (e) {
507
+ return properties != null ? properties : {};
508
+ }
509
+ }
510
+ function withAppGitAttributes(attributes, snapshot) {
511
+ try {
512
+ const present = new Set(attributes.flatMap((attr) => attr ? [attr.key] : []));
513
+ const added = [];
514
+ for (const key of APP_GIT_KEYS) {
515
+ if (present.has(key) || present.has(`ai.telemetry.metadata.${key}`) || present.has(`traceloop.association.properties.${key}`))
516
+ continue;
517
+ const value = snapshot[key];
518
+ if (typeof value === "string") added.push({ key, value: { stringValue: value } });
519
+ else if (typeof value === "boolean") added.push({ key, value: { boolValue: value } });
520
+ }
521
+ return added.length ? [...attributes, ...added] : attributes;
522
+ } catch (e) {
523
+ return attributes;
524
+ }
525
+ }
526
+ function appGitPropertiesFromAttributes(attributes) {
527
+ var _a, _b, _c;
528
+ const properties = {};
529
+ try {
530
+ for (const attr of attributes) {
531
+ if (!attr) continue;
532
+ for (const key of APP_GIT_KEYS) {
533
+ if (attr.key === key || attr.key === `ai.telemetry.metadata.${key}` || attr.key === `traceloop.association.properties.${key}`) {
534
+ properties[key] = (_c = (_b = (_a = attr.value.stringValue) != null ? _a : attr.value.boolValue) != null ? _b : attr.value.intValue) != null ? _c : null;
535
+ }
536
+ }
537
+ }
538
+ } catch (e) {
539
+ }
540
+ return properties;
541
+ }
28
542
  function getCrypto() {
29
543
  const c = globalThis.crypto;
30
544
  return c;
@@ -79,6 +593,25 @@ function base64Encode(bytes) {
79
593
  }
80
594
  return out;
81
595
  }
596
+ function base64ToHex(value) {
597
+ if (!value) return "";
598
+ const maybeBuffer = globalThis.Buffer;
599
+ if (maybeBuffer) {
600
+ return maybeBuffer.from(value, "base64").toString("hex");
601
+ }
602
+ const atobFn = globalThis.atob;
603
+ if (typeof atobFn !== "function") return "";
604
+ try {
605
+ const binary = atobFn(value);
606
+ let hex = "";
607
+ for (let i = 0; i < binary.length; i++) {
608
+ hex += (binary.charCodeAt(i) & 255).toString(16).padStart(2, "0");
609
+ }
610
+ return hex;
611
+ } catch (e) {
612
+ return "";
613
+ }
614
+ }
82
615
  function generateId() {
83
616
  return randomUUID();
84
617
  }
@@ -113,7 +646,7 @@ function runWithTracingSuppressed(fn) {
113
646
  var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
114
647
  var MAX_RETRY_DELAY_MS = 3e4;
115
648
  function wait(ms) {
116
- return new Promise((resolve) => setTimeout(resolve, ms));
649
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
117
650
  }
118
651
  function formatEndpoint(endpoint) {
119
652
  if (!endpoint) return void 0;
@@ -150,9 +683,9 @@ async function raceWithTimeout(promise, timeoutMs) {
150
683
  () => true,
151
684
  () => true
152
685
  ),
153
- new Promise((resolve) => {
686
+ new Promise((resolve2) => {
154
687
  var _a;
155
- timer = setTimeout(() => resolve(false), Math.max(0, timeoutMs));
688
+ timer = setTimeout(() => resolve2(false), Math.max(0, timeoutMs));
156
689
  (_a = timer.unref) == null ? void 0 : _a.call(timer);
157
690
  })
158
691
  ]);
@@ -223,6 +756,7 @@ async function postJson(url, body, headers, opts) {
223
756
  const resp = await runWithTracingSuppressed(
224
757
  () => fetch(url, {
225
758
  method: "POST",
759
+ redirect: headers["X-Raindrop-Replay-Id"] !== void 0 ? "error" : "follow",
226
760
  headers: {
227
761
  "Content-Type": "application/json",
228
762
  ...headers
@@ -391,26 +925,29 @@ function resolveLocalDebuggerBaseUrl(baseUrl) {
391
925
  if (shouldAutoEnableLocalWorkshop()) return DEFAULT_LOCAL_WORKSHOP_URL;
392
926
  return null;
393
927
  }
928
+ var LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS = 2e3;
394
929
  function mirrorTraceExportToLocalDebugger(body, options = {}) {
395
930
  var _a;
396
931
  const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
397
- if (!baseUrl) return;
398
- void postJson(`${baseUrl}traces`, body, {}, {
932
+ if (!baseUrl) return Promise.resolve();
933
+ return postJson(`${baseUrl}traces`, body, {}, {
399
934
  maxAttempts: 1,
400
935
  debug: (_a = options.debug) != null ? _a : false,
401
- sdkName: options.sdkName
936
+ sdkName: options.sdkName,
937
+ timeoutMs: LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS
402
938
  }).catch(() => {
403
939
  });
404
940
  }
405
941
  function mirrorPartialEventToLocalDebugger(event, options = {}) {
406
942
  var _a;
407
943
  const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
408
- if (!baseUrl) return;
944
+ if (!baseUrl) return Promise.resolve();
409
945
  const headers = options.writeKey ? { Authorization: `Bearer ${options.writeKey}` } : {};
410
- void postJson(`${baseUrl}events/track_partial`, event, headers, {
946
+ return postJson(`${baseUrl}events/track_partial`, event, headers, {
411
947
  maxAttempts: 1,
412
948
  debug: (_a = options.debug) != null ? _a : false,
413
- sdkName: options.sdkName
949
+ sdkName: options.sdkName,
950
+ timeoutMs: LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS
414
951
  }).catch(() => {
415
952
  });
416
953
  }
@@ -435,6 +972,13 @@ function projectIdHeaders(projectId) {
435
972
  }
436
973
  var SHUTDOWN_DEADLINE_MS = 1e4;
437
974
  var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
975
+ function appGitOwnerId(prefix) {
976
+ try {
977
+ return `${prefix}:${randomUUID()}`;
978
+ } catch (e) {
979
+ return `${prefix}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
980
+ }
981
+ }
438
982
  function mergePatches(target, source) {
439
983
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
440
984
  const out = { ...target, ...source };
@@ -484,22 +1028,25 @@ function eventTelemetryProperties(patch) {
484
1028
  }
485
1029
  var EventShipper = class {
486
1030
  constructor(opts) {
1031
+ this.appGitOwner = appGitOwnerId("event");
487
1032
  this.buffers = /* @__PURE__ */ new Map();
488
1033
  this.sticky = /* @__PURE__ */ new Map();
489
1034
  this.timers = /* @__PURE__ */ new Map();
490
1035
  this.inFlight = /* @__PURE__ */ new Set();
491
1036
  this.hasShutdown = false;
492
- var _a, _b, _c, _d, _e, _f, _g, _h;
493
- this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
494
- this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
1037
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1038
+ this.appGitContext = (_a = opts.appGitContext) != null ? _a : createAppGitContext(opts.appGit);
1039
+ this.ownsAppGitContext = opts.appGitContext === void 0;
1040
+ this.writeKey = (_b = opts.writeKey) == null ? void 0 : _b.trim();
1041
+ this.baseUrl = (_c = formatEndpoint(opts.endpoint)) != null ? _c : "https://api.raindrop.ai/v1/";
495
1042
  this.enabled = opts.enabled !== false;
496
1043
  this.debug = opts.debug;
497
- this.partialFlushMs = (_c = opts.partialFlushMs) != null ? _c : 1e3;
498
- this.sdkName = (_d = opts.sdkName) != null ? _d : "core";
1044
+ this.partialFlushMs = (_d = opts.partialFlushMs) != null ? _d : 1e3;
1045
+ this.sdkName = (_e = opts.sdkName) != null ? _e : "core";
499
1046
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
500
- this.defaultEventName = (_e = opts.defaultEventName) != null ? _e : "ai_generation";
1047
+ this.defaultEventName = (_f = opts.defaultEventName) != null ? _f : "ai_generation";
501
1048
  this.maxTextFieldCharsOpt = opts.maxTextFieldChars;
502
- this.localDebuggerUrl = (_f = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _f : void 0;
1049
+ this.localDebuggerUrl = (_g = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _g : void 0;
503
1050
  if (this.debug && this.localDebuggerUrl) {
504
1051
  console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
505
1052
  }
@@ -510,8 +1057,8 @@ var EventShipper = class {
510
1057
  const isNode = typeof process !== "undefined" && typeof process.version === "string";
511
1058
  this.context = {
512
1059
  library: {
513
- name: (_g = opts.libraryName) != null ? _g : "@raindrop-ai/core",
514
- version: (_h = opts.libraryVersion) != null ? _h : "0.0.0"
1060
+ name: (_h = opts.libraryName) != null ? _h : "@raindrop-ai/core",
1061
+ version: (_i = opts.libraryVersion) != null ? _i : "0.0.0"
515
1062
  },
516
1063
  metadata: {
517
1064
  jsRuntime: isNode ? "node" : "web",
@@ -519,6 +1066,9 @@ var EventShipper = class {
519
1066
  }
520
1067
  };
521
1068
  }
1069
+ ownAppGitContextForShutdown() {
1070
+ this.ownsAppGitContext = true;
1071
+ }
522
1072
  isDebugEnabled() {
523
1073
  return this.debug;
524
1074
  }
@@ -567,6 +1117,15 @@ var EventShipper = class {
567
1117
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
568
1118
  if (!this.enabled) return;
569
1119
  if (!eventId || !eventId.trim()) return;
1120
+ const capturedSticky = this.sticky.get(eventId);
1121
+ const eventAlreadyKnown = capturedSticky !== void 0 || this.buffers.has(eventId);
1122
+ const destination = currentReplayTraceDestination();
1123
+ const cloudReplay = destination !== void 0 && destination.kind !== "workshop";
1124
+ if ((capturedSticky == null ? void 0 : capturedSticky.replayOnly) === true || !eventAlreadyKnown && cloudReplay) {
1125
+ if (patch.isPending === false) this.sticky.delete(eventId);
1126
+ else this.sticky.set(eventId, { ...capturedSticky, replayOnly: true });
1127
+ return;
1128
+ }
570
1129
  const maxChars = resolveMaxTextFieldChars(this.maxTextFieldCharsOpt);
571
1130
  if (typeof patch.input === "string" && patch.input.length > maxChars) {
572
1131
  patch = { ...patch, input: capText(patch.input, maxChars) };
@@ -588,6 +1147,13 @@ var EventShipper = class {
588
1147
  }
589
1148
  const sticky = (_c = this.sticky.get(eventId)) != null ? _c : {};
590
1149
  const existing = (_d = this.buffers.get(eventId)) != null ? _d : {};
1150
+ patch = {
1151
+ ...patch,
1152
+ properties: withAppGitProperties(
1153
+ patch.properties,
1154
+ this.appGitContext.forOperation(eventId, patch.properties, this.appGitOwner)
1155
+ )
1156
+ };
591
1157
  const merged = mergePatches(existing, patch);
592
1158
  merged.isPending = (_g = (_f = (_e = patch.isPending) != null ? _e : existing.isPending) != null ? _f : sticky.isPending) != null ? _g : true;
593
1159
  this.buffers.set(eventId, merged);
@@ -601,6 +1167,8 @@ var EventShipper = class {
601
1167
  if (t) clearTimeout(t);
602
1168
  if (merged.isPending === false) {
603
1169
  await this.flushOne(eventId);
1170
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(eventId, this.appGitOwner);
1171
+ else this.appGitContext.finishOperation(eventId);
604
1172
  return;
605
1173
  }
606
1174
  const timeout = setTimeout(() => {
@@ -625,15 +1193,21 @@ var EventShipper = class {
625
1193
  try {
626
1194
  for (const t of this.timers.values()) clearTimeout(t);
627
1195
  this.timers.clear();
1196
+ for (const [eventId, sticky] of this.sticky) {
1197
+ if (sticky.replayOnly) this.sticky.delete(eventId);
1198
+ }
628
1199
  const settled = await raceWithTimeout(this.flush(), SHUTDOWN_DEADLINE_MS);
629
1200
  if (!settled) this.warnShutdownDrop("in-flight request(s) at shutdown");
630
1201
  } finally {
631
1202
  this.shutdownDeadlineAt = void 0;
1203
+ if (this.ownsAppGitContext) this.appGitContext.dispose();
632
1204
  }
633
1205
  }
634
1206
  async trackSignal(signal) {
635
1207
  var _a, _b;
636
1208
  if (!this.enabled) return;
1209
+ const destination = currentReplayTraceDestination();
1210
+ if (destination && destination.kind !== "workshop") return;
637
1211
  const body = [
638
1212
  {
639
1213
  event_id: signal.eventId,
@@ -668,6 +1242,8 @@ var EventShipper = class {
668
1242
  }
669
1243
  async identify(users) {
670
1244
  if (!this.enabled) return;
1245
+ const destination = currentReplayTraceDestination();
1246
+ if (destination && destination.kind !== "workshop") return;
671
1247
  const list = Array.isArray(users) ? users : [users];
672
1248
  const body = list.filter((user) => {
673
1249
  if (!(user == null ? void 0 : user.userId) || !user.userId.trim()) {
@@ -720,8 +1296,9 @@ var EventShipper = class {
720
1296
  this.buffers.delete(eventId);
721
1297
  if (!accumulated) return;
722
1298
  const sticky = (_a = this.sticky.get(eventId)) != null ? _a : {};
723
- const eventName = (_c = (_b = accumulated.eventName) != null ? _b : sticky.eventName) != null ? _c : this.defaultEventName;
724
- const userId = (_d = accumulated.userId) != null ? _d : sticky.userId;
1299
+ const isPending = (_c = (_b = accumulated.isPending) != null ? _b : sticky.isPending) != null ? _c : true;
1300
+ const eventName = (_e = (_d = accumulated.eventName) != null ? _d : sticky.eventName) != null ? _e : this.defaultEventName;
1301
+ const userId = (_f = accumulated.userId) != null ? _f : sticky.userId;
725
1302
  if (!userId) {
726
1303
  if (this.debug) {
727
1304
  console.warn(`${this.prefix} skipping track_partial for ${eventId}: missing userId`);
@@ -729,14 +1306,13 @@ var EventShipper = class {
729
1306
  this.sticky.delete(eventId);
730
1307
  return;
731
1308
  }
732
- const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
1309
+ const { wizardSession, ...restProperties } = (_g = accumulated.properties) != null ? _g : {};
733
1310
  let telemetryProperties = {};
734
1311
  try {
735
1312
  telemetryProperties = eventTelemetryProperties(accumulated);
736
1313
  } catch (e) {
737
1314
  }
738
- const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
739
- const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
1315
+ const convoId = (_h = accumulated.convoId) != null ? _h : sticky.convoId;
740
1316
  const payload = {
741
1317
  event_id: eventId,
742
1318
  user_id: userId,
@@ -778,29 +1354,30 @@ var EventShipper = class {
778
1354
  endpoint: url
779
1355
  });
780
1356
  }
781
- if (this.localDebuggerUrl) {
782
- mirrorPartialEventToLocalDebugger(payload, {
783
- baseUrl: this.localDebuggerUrl,
784
- writeKey: this.writeKey,
785
- debug: this.debug,
786
- sdkName: this.sdkName
787
- });
788
- }
1357
+ const mirror = this.localDebuggerUrl ? mirrorPartialEventToLocalDebugger(payload, {
1358
+ baseUrl: this.localDebuggerUrl,
1359
+ writeKey: this.writeKey,
1360
+ debug: this.debug,
1361
+ sdkName: this.sdkName
1362
+ }) : void 0;
789
1363
  if (!this.writeKey) {
790
1364
  if (!isPending) this.sticky.delete(eventId);
1365
+ if (mirror) await mirror;
791
1366
  return;
792
1367
  }
793
1368
  const opts = this.requestOpts();
794
1369
  if (!opts) {
795
1370
  this.warnShutdownDrop(`track_partial ${eventId}`);
796
1371
  if (!isPending) this.sticky.delete(eventId);
1372
+ if (mirror) await mirror;
797
1373
  return;
798
1374
  }
799
1375
  const p = postJson(url, payload, this.requestHeaders(), opts);
800
- this.inFlight.add(p);
1376
+ const combined = mirror ? Promise.all([mirror, p]).then(() => void 0) : p;
1377
+ this.inFlight.add(combined);
801
1378
  try {
802
1379
  try {
803
- await p;
1380
+ await combined;
804
1381
  if (this.debug) {
805
1382
  console.log(`${this.prefix} sent track_partial ${eventId} (${eventName})`);
806
1383
  }
@@ -812,7 +1389,7 @@ var EventShipper = class {
812
1389
  );
813
1390
  }
814
1391
  } finally {
815
- this.inFlight.delete(p);
1392
+ this.inFlight.delete(combined);
816
1393
  }
817
1394
  if (!isPending) {
818
1395
  this.sticky.delete(eventId);
@@ -1065,6 +1642,13 @@ function redactJsonAttributeValue(key, value) {
1065
1642
  if (scrubbedJson === json) return void 0;
1066
1643
  return { stringValue: scrubbedJson };
1067
1644
  }
1645
+ function appGitOwnerId2(prefix) {
1646
+ try {
1647
+ return `${prefix}:${randomUUID()}`;
1648
+ } catch (e) {
1649
+ return `${prefix}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
1650
+ }
1651
+ }
1068
1652
  function identityAttrs(args) {
1069
1653
  return [
1070
1654
  attrString("ai.telemetry.metadata.raindrop.ai.userId", args.userId),
@@ -1087,23 +1671,30 @@ function applyOtelSpanAttributeLimit(limit) {
1087
1671
  }
1088
1672
  var TraceShipper = class {
1089
1673
  constructor(opts) {
1674
+ this.appGitOwner = appGitOwnerId2("trace");
1675
+ this.appGitEventIds = /* @__PURE__ */ new WeakMap();
1676
+ this.appGitActiveSpans = /* @__PURE__ */ new Map();
1677
+ this.appGitCaptured = /* @__PURE__ */ new WeakSet();
1678
+ this.appGitAdded = /* @__PURE__ */ new WeakMap();
1090
1679
  this.queue = [];
1091
1680
  this.inFlight = /* @__PURE__ */ new Set();
1092
1681
  this.hasShutdown = false;
1093
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1094
- this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
1095
- this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
1682
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1683
+ this.appGitContext = (_a = opts.appGitContext) != null ? _a : createAppGitContext(opts.appGit);
1684
+ this.ownsAppGitContext = opts.appGitContext === void 0;
1685
+ this.writeKey = (_b = opts.writeKey) == null ? void 0 : _b.trim();
1686
+ this.baseUrl = (_c = formatEndpoint(opts.endpoint)) != null ? _c : "https://api.raindrop.ai/v1/";
1096
1687
  this.enabled = opts.enabled !== false;
1097
1688
  this.debug = opts.debug;
1098
1689
  this.debugSpans = opts.debugSpans === true;
1099
- this.flushIntervalMs = (_c = opts.flushIntervalMs) != null ? _c : 1e3;
1100
- this.maxBatchSize = (_d = opts.maxBatchSize) != null ? _d : 50;
1101
- this.maxQueueSize = (_e = opts.maxQueueSize) != null ? _e : 5e3;
1102
- this.sdkName = (_f = opts.sdkName) != null ? _f : "core";
1690
+ this.flushIntervalMs = (_d = opts.flushIntervalMs) != null ? _d : 1e3;
1691
+ this.maxBatchSize = (_e = opts.maxBatchSize) != null ? _e : 50;
1692
+ this.maxQueueSize = (_f = opts.maxQueueSize) != null ? _f : 5e3;
1693
+ this.sdkName = (_g = opts.sdkName) != null ? _g : "core";
1103
1694
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
1104
- this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
1105
- this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
1106
- this.localDebuggerUrl = (_i = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _i : void 0;
1695
+ this.serviceName = (_h = opts.serviceName) != null ? _h : "raindrop.core";
1696
+ this.serviceVersion = (_i = opts.serviceVersion) != null ? _i : "0.0.0";
1697
+ this.localDebuggerUrl = (_j = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _j : void 0;
1107
1698
  if (this.debug && this.localDebuggerUrl) {
1108
1699
  console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
1109
1700
  }
@@ -1167,7 +1758,10 @@ var TraceShipper = class {
1167
1758
  try {
1168
1759
  const result = this.transformSpanHook(current);
1169
1760
  if (result === null) return null;
1170
- if (result !== void 0) current = result;
1761
+ if (result !== void 0) {
1762
+ copyReplayTraceDestination(current, result);
1763
+ current = result;
1764
+ }
1171
1765
  } catch (err) {
1172
1766
  if (this.debug) {
1173
1767
  const msg = err instanceof Error ? err.message : String(err);
@@ -1177,13 +1771,19 @@ var TraceShipper = class {
1177
1771
  }
1178
1772
  }
1179
1773
  try {
1180
- current = normalizeModelUsageSpan(current);
1774
+ const normalized = normalizeModelUsageSpan(current);
1775
+ copyReplayTraceDestination(current, normalized);
1776
+ current = normalized;
1181
1777
  } catch (e) {
1182
1778
  }
1183
1779
  if (!this.disableDefaultRedaction) {
1184
- current = defaultTransformSpan(current);
1780
+ const redacted = defaultTransformSpan(current);
1781
+ copyReplayTraceDestination(current, redacted);
1782
+ current = redacted;
1185
1783
  }
1186
- return this.capSpanAttributes(current);
1784
+ const capped = this.capSpanAttributes(current);
1785
+ copyReplayTraceDestination(current, capped);
1786
+ return capped;
1187
1787
  }
1188
1788
  isDebugEnabled() {
1189
1789
  return this.debug;
@@ -1195,46 +1795,84 @@ var TraceShipper = class {
1195
1795
  return { ...this.authHeaders(), ...projectIdHeaders(this.projectId) };
1196
1796
  }
1197
1797
  startSpan(args) {
1198
- var _a, _b;
1798
+ var _a, _b, _c;
1199
1799
  const ids = createSpanIds(args.parent);
1200
1800
  const started = (_a = args.startTimeUnixNano) != null ? _a : nowUnixNanoString();
1201
1801
  const attrs = [
1202
1802
  attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
1203
1803
  ...identityAttrs(args),
1204
- attrString("ai.operationId", args.operationId)
1804
+ attrString("ai.operationId", args.operationId),
1805
+ ...Object.entries(evalScopeAttributes()).map(([key, value]) => attrString(key, value))
1205
1806
  ];
1206
1807
  if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
1207
- const span = { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
1208
- this.mirrorToLocalDebugger(
1209
- buildOtlpSpan({
1210
- ids: span.ids,
1211
- name: span.name,
1212
- startTimeUnixNano: span.startTimeUnixNano,
1213
- endTimeUnixNano: span.startTimeUnixNano,
1214
- // placeholder — will be updated on endSpan
1215
- attributes: span.attributes,
1216
- status: { code: SpanStatusCode.UNSET }
1217
- })
1218
- );
1808
+ const tracksAppGit = this.appGitActiveSpans.has(args.eventId) || this.appGitActiveSpans.size < 1e4;
1809
+ const appGitOverrides = appGitPropertiesFromAttributes(attrs);
1810
+ const span = {
1811
+ ids,
1812
+ name: args.name,
1813
+ startTimeUnixNano: started,
1814
+ attributes: withAppGitAttributes(
1815
+ attrs,
1816
+ this.appGitContext.forOperation(args.eventId, appGitOverrides, this.appGitOwner)
1817
+ )
1818
+ };
1819
+ rememberReplayTraceDestination(span);
1820
+ this.appGitCaptured.add(span);
1821
+ this.appGitEventIds.set(span, args.eventId);
1822
+ if (tracksAppGit) {
1823
+ this.appGitActiveSpans.set(args.eventId, ((_c = this.appGitActiveSpans.get(args.eventId)) != null ? _c : 0) + 1);
1824
+ }
1825
+ this.appGitAdded.set(span, new Set(span.attributes.filter((attr) => !attrs.includes(attr))));
1826
+ const openSpan = buildOtlpSpan({
1827
+ ids: span.ids,
1828
+ name: span.name,
1829
+ startTimeUnixNano: span.startTimeUnixNano,
1830
+ endTimeUnixNano: span.startTimeUnixNano,
1831
+ // placeholder — will be updated on endSpan
1832
+ attributes: span.attributes,
1833
+ status: { code: SpanStatusCode.UNSET }
1834
+ });
1835
+ copyReplayTraceDestination(span, openSpan);
1836
+ this.mirrorToLocalDebugger(openSpan);
1219
1837
  return span;
1220
1838
  }
1221
- mirrorToLocalDebugger(span) {
1222
- if (!this.localDebuggerUrl) return;
1839
+ mirrorToLocalDebugger(span, completed = false) {
1840
+ const destination = replayTraceDestinationFor(span);
1841
+ if (destination && destination.kind !== "workshop") return;
1842
+ const localDebuggerUrl = (destination == null ? void 0 : destination.kind) === "workshop" ? destination.url : this.localDebuggerUrl;
1843
+ if (!localDebuggerUrl) return;
1223
1844
  const redacted = this.redactSpan(span);
1224
1845
  if (redacted === null) return;
1846
+ if (completed && (destination == null ? void 0 : destination.kind) === "workshop") {
1847
+ recordReplayExportedSpan(
1848
+ destination,
1849
+ base64ToHex(redacted.spanId),
1850
+ base64ToHex(redacted.traceId)
1851
+ );
1852
+ }
1225
1853
  const body = buildExportTraceServiceRequest([redacted], this.serviceName, this.serviceVersion);
1226
- mirrorTraceExportToLocalDebugger(body, {
1227
- baseUrl: this.localDebuggerUrl,
1854
+ const p = mirrorTraceExportToLocalDebugger(body, {
1855
+ baseUrl: localDebuggerUrl,
1228
1856
  debug: false,
1229
1857
  sdkName: this.sdkName
1230
1858
  });
1859
+ this.inFlight.add(p);
1860
+ void p.finally(() => {
1861
+ this.inFlight.delete(p);
1862
+ });
1231
1863
  }
1232
1864
  endSpan(span, extra) {
1233
- var _a, _b;
1865
+ var _a, _b, _c;
1234
1866
  if (span.endTimeUnixNano) return;
1235
1867
  span.endTimeUnixNano = (_a = extra == null ? void 0 : extra.endTimeUnixNano) != null ? _a : nowUnixNanoString();
1236
1868
  if ((_b = extra == null ? void 0 : extra.attributes) == null ? void 0 : _b.length) {
1869
+ const overrides = appGitPropertiesFromAttributes(extra.attributes);
1870
+ const eventId2 = this.appGitEventIds.get(span);
1871
+ const snapshot = eventId2 ? this.appGitContext.forOperation(eventId2, overrides, this.appGitOwner) : overrides;
1872
+ const added = this.appGitAdded.get(span);
1873
+ 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));
1237
1874
  span.attributes.push(...extra.attributes);
1875
+ span.attributes = withAppGitAttributes(span.attributes, snapshot);
1238
1876
  }
1239
1877
  let status = extra == null ? void 0 : extra.status;
1240
1878
  if (!status && (extra == null ? void 0 : extra.error) !== void 0) {
@@ -1249,30 +1887,65 @@ var TraceShipper = class {
1249
1887
  attributes: span.attributes,
1250
1888
  status
1251
1889
  });
1890
+ copyReplayTraceDestination(span, otlp);
1891
+ this.appGitCaptured.add(otlp);
1252
1892
  this.enqueue(otlp);
1253
- this.mirrorToLocalDebugger(otlp);
1893
+ this.mirrorToLocalDebugger(otlp, true);
1894
+ const eventId = this.appGitEventIds.get(span);
1895
+ if (eventId && this.appGitActiveSpans.has(eventId)) {
1896
+ const remaining = ((_c = this.appGitActiveSpans.get(eventId)) != null ? _c : 1) - 1;
1897
+ if (remaining > 0) this.appGitActiveSpans.set(eventId, remaining);
1898
+ else {
1899
+ this.appGitActiveSpans.delete(eventId);
1900
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(eventId, this.appGitOwner);
1901
+ else if (this.ownsAppGitContext) this.appGitContext.finishOperation(eventId);
1902
+ }
1903
+ }
1254
1904
  }
1255
1905
  createSpan(args) {
1256
1906
  var _a;
1257
1907
  const ids = createSpanIds(args.parent);
1258
1908
  const attrs = [
1259
1909
  attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
1260
- ...identityAttrs(args)
1910
+ ...identityAttrs(args),
1911
+ ...Object.entries(evalScopeAttributes()).map(([key, value]) => attrString(key, value))
1261
1912
  ];
1262
1913
  if ((_a = args.attributes) == null ? void 0 : _a.length) attrs.push(...args.attributes);
1914
+ const tracksAppGit = !this.appGitActiveSpans.has(args.eventId);
1263
1915
  const otlp = buildOtlpSpan({
1264
1916
  ids,
1265
1917
  name: args.name,
1266
1918
  startTimeUnixNano: args.startTimeUnixNano,
1267
1919
  endTimeUnixNano: args.endTimeUnixNano,
1268
- attributes: attrs,
1920
+ attributes: withAppGitAttributes(
1921
+ attrs,
1922
+ this.appGitContext.forOperation(
1923
+ args.eventId,
1924
+ appGitPropertiesFromAttributes(attrs),
1925
+ this.appGitOwner
1926
+ )
1927
+ ),
1269
1928
  status: args.status
1270
1929
  });
1930
+ rememberReplayTraceDestination(otlp);
1931
+ this.appGitCaptured.add(otlp);
1932
+ if (tracksAppGit) {
1933
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(args.eventId, this.appGitOwner);
1934
+ else if (this.ownsAppGitContext) this.appGitContext.finishOperation(args.eventId);
1935
+ }
1271
1936
  this.enqueue(otlp);
1272
- this.mirrorToLocalDebugger(otlp);
1937
+ this.mirrorToLocalDebugger(otlp, true);
1273
1938
  }
1274
1939
  enqueue(span) {
1940
+ var _a;
1275
1941
  if (!this.enabled) return;
1942
+ const attributes = (_a = span.attributes) != null ? _a : [];
1943
+ const enriched = this.appGitCaptured.has(span) ? attributes : withAppGitAttributes(attributes, this.appGitContext.snapshot(appGitPropertiesFromAttributes(attributes)));
1944
+ if (enriched !== attributes) {
1945
+ const original = span;
1946
+ span = { ...span, attributes: enriched.filter((attr) => attr !== void 0) };
1947
+ copyReplayTraceDestination(original, span);
1948
+ }
1276
1949
  if (this.debugSpans) {
1277
1950
  const short = (s) => s ? s.slice(-8) : "none";
1278
1951
  console.log(
@@ -1283,6 +1956,13 @@ var TraceShipper = class {
1283
1956
  }
1284
1957
  const redacted = this.redactSpan(span);
1285
1958
  if (redacted === null) return;
1959
+ const destination = replayTraceDestinationFor(redacted);
1960
+ recordReplayExportedSpan(
1961
+ destination,
1962
+ base64ToHex(redacted.spanId),
1963
+ base64ToHex(redacted.traceId)
1964
+ );
1965
+ if ((destination == null ? void 0 : destination.kind) === "workshop") return;
1286
1966
  if (this.queue.length >= this.maxQueueSize) {
1287
1967
  this.queue.shift();
1288
1968
  }
@@ -1301,47 +1981,67 @@ var TraceShipper = class {
1301
1981
  }
1302
1982
  }
1303
1983
  async flush() {
1304
- if (!this.enabled) return;
1984
+ var _a;
1985
+ if (!this.enabled) {
1986
+ await Promise.all([...this.inFlight].map((p) => p.catch(() => {
1987
+ })));
1988
+ return;
1989
+ }
1305
1990
  if (this.timer) {
1306
1991
  clearTimeout(this.timer);
1307
1992
  this.timer = void 0;
1308
1993
  }
1309
1994
  while (this.queue.length > 0) {
1310
1995
  const batch = this.queue.splice(0, this.maxBatchSize);
1311
- if (!this.writeKey) continue;
1312
- const opts = this.requestOpts();
1313
- if (!opts) {
1314
- rateLimitedLog(
1315
- `${this.prefix}.shutdown_deadline`,
1316
- () => console.warn(
1317
- `${this.prefix} shutdown flush deadline exceeded; dropping ${batch.length} spans`
1318
- )
1319
- );
1320
- continue;
1996
+ const groups = /* @__PURE__ */ new Map();
1997
+ for (const span of batch) {
1998
+ const destination = replayTraceDestinationFor(span);
1999
+ const spans = groups.get(destination);
2000
+ if (spans) spans.push(span);
2001
+ else groups.set(destination, [span]);
1321
2002
  }
1322
- const body = buildExportTraceServiceRequest(batch, this.serviceName, this.serviceVersion);
1323
- const url = `${this.baseUrl}traces`;
1324
- if (this.debug) {
1325
- console.log(`${this.prefix} sending traces batch`, {
1326
- spans: batch.length,
1327
- endpoint: url
1328
- });
1329
- }
1330
- const p = postJson(url, body, this.requestHeaders(), opts);
1331
- this.inFlight.add(p);
1332
- try {
1333
- try {
1334
- await p;
1335
- if (this.debug) console.log(`${this.prefix} sent ${batch.length} spans`);
1336
- } catch (err) {
1337
- const msg = err instanceof Error ? err.message : String(err);
2003
+ for (const [destination, spans] of groups) {
2004
+ if (!destination && !this.writeKey) continue;
2005
+ if ((destination == null ? void 0 : destination.kind) === "workshop") continue;
2006
+ const opts = this.requestOpts();
2007
+ if (!opts) {
1338
2008
  rateLimitedLog(
1339
- `${this.prefix}.send_spans_failed`,
1340
- () => console.warn(`${this.prefix} failed to send ${batch.length} spans: ${msg}`)
2009
+ `${this.prefix}.shutdown_deadline`,
2010
+ () => console.warn(
2011
+ `${this.prefix} shutdown flush deadline exceeded; dropping ${spans.length} spans`
2012
+ )
1341
2013
  );
2014
+ continue;
2015
+ }
2016
+ const body = buildExportTraceServiceRequest(spans, this.serviceName, this.serviceVersion);
2017
+ const url = destination ? replayTraceUrl(destination.url) : `${this.baseUrl}traces`;
2018
+ const headers = destination ? {
2019
+ Authorization: `Bearer ${destination.apiKey}`,
2020
+ "X-Raindrop-Replay-Id": destination.replayId,
2021
+ "X-Raindrop-Project-Id": (_a = destination.projectId) != null ? _a : "default"
2022
+ } : this.requestHeaders();
2023
+ if (this.debug) {
2024
+ console.log(`${this.prefix} sending traces batch`, {
2025
+ spans: spans.length,
2026
+ endpoint: url
2027
+ });
2028
+ }
2029
+ const p = postJson(url, body, headers, opts);
2030
+ this.inFlight.add(p);
2031
+ try {
2032
+ try {
2033
+ await p;
2034
+ if (this.debug) console.log(`${this.prefix} sent ${spans.length} spans`);
2035
+ } catch (err) {
2036
+ const msg = err instanceof Error ? err.message : String(err);
2037
+ rateLimitedLog(
2038
+ `${this.prefix}.send_spans_failed`,
2039
+ () => console.warn(`${this.prefix} failed to send ${spans.length} spans: ${msg}`)
2040
+ );
2041
+ }
2042
+ } finally {
2043
+ this.inFlight.delete(p);
1342
2044
  }
1343
- } finally {
1344
- this.inFlight.delete(p);
1345
2045
  }
1346
2046
  }
1347
2047
  }
@@ -1384,17 +2084,165 @@ var TraceShipper = class {
1384
2084
  if (!settled) {
1385
2085
  rateLimitedLog(
1386
2086
  `${this.prefix}.shutdown_deadline`,
1387
- () => console.warn(`${this.prefix} shutdown flush deadline exceeded; abandoning in-flight spans`)
2087
+ () => console.warn(
2088
+ `${this.prefix} shutdown flush deadline exceeded; abandoning in-flight spans`
2089
+ )
1388
2090
  );
1389
2091
  }
1390
2092
  } finally {
1391
2093
  this.shutdownDeadlineAt = void 0;
2094
+ if (this.ownsAppGitContext) this.appGitContext.dispose();
1392
2095
  }
1393
2096
  }
1394
2097
  };
1395
2098
 
1396
2099
  // ../core/dist/index.node.js
1397
2100
  var import_async_hooks = require("async_hooks");
2101
+ var import_child_process = require("child_process");
2102
+ var import_path = require("path");
2103
+ var resolveLocal = (sourceDirectory, detectBranch, completed) => {
2104
+ const cwd = sourceDirectory ? (0, import_path.resolve)(sourceDirectory) : process.cwd();
2105
+ let cancelled = false;
2106
+ let active;
2107
+ let deadlineTimer;
2108
+ const deadline = Date.now() + 1e3;
2109
+ const run = (args, done) => {
2110
+ if (cancelled) return;
2111
+ const remaining = deadline - Date.now();
2112
+ if (remaining <= 0) {
2113
+ done(void 0);
2114
+ return;
2115
+ }
2116
+ try {
2117
+ active = (0, import_child_process.execFile)(
2118
+ "git",
2119
+ args,
2120
+ {
2121
+ cwd,
2122
+ encoding: "utf8",
2123
+ maxBuffer: 4096,
2124
+ windowsHide: true,
2125
+ env: {
2126
+ ...process.env,
2127
+ // The selected application cwd, not the invoking shell's Git plumbing, owns identity.
2128
+ GIT_DIR: void 0,
2129
+ GIT_WORK_TREE: void 0,
2130
+ GIT_COMMON_DIR: void 0,
2131
+ GIT_NAMESPACE: void 0,
2132
+ GIT_INDEX_FILE: void 0,
2133
+ GIT_OBJECT_DIRECTORY: void 0,
2134
+ GIT_ALTERNATE_OBJECT_DIRECTORIES: void 0,
2135
+ GIT_CONFIG_PARAMETERS: void 0,
2136
+ GIT_CONFIG_COUNT: "0",
2137
+ GIT_TERMINAL_PROMPT: "0",
2138
+ GIT_OPTIONAL_LOCKS: "0"
2139
+ }
2140
+ },
2141
+ (error, stdout) => {
2142
+ clearTimeout(deadlineTimer);
2143
+ deadlineTimer = void 0;
2144
+ active = void 0;
2145
+ if (!cancelled) {
2146
+ try {
2147
+ done(error ? void 0 : stdout.trim());
2148
+ } catch (e) {
2149
+ }
2150
+ }
2151
+ }
2152
+ );
2153
+ active.unref();
2154
+ if (active.stdout && "unref" in active.stdout && typeof active.stdout.unref === "function")
2155
+ active.stdout.unref();
2156
+ if (active.stderr && "unref" in active.stderr && typeof active.stderr.unref === "function")
2157
+ active.stderr.unref();
2158
+ deadlineTimer = setTimeout(() => {
2159
+ try {
2160
+ active == null ? void 0 : active.kill("SIGKILL");
2161
+ } catch (e) {
2162
+ }
2163
+ }, remaining);
2164
+ deadlineTimer.unref();
2165
+ } catch (e) {
2166
+ try {
2167
+ done(void 0);
2168
+ } catch (e2) {
2169
+ }
2170
+ }
2171
+ };
2172
+ const scheduled = setTimeout(() => {
2173
+ try {
2174
+ run(["rev-parse", "HEAD"], (rawSha) => {
2175
+ const commitSha = validAppCommitSha(rawSha);
2176
+ if (!commitSha) {
2177
+ completed({});
2178
+ return;
2179
+ }
2180
+ run(["-c", "core.fsmonitor=false", "status", "--porcelain"], (status) => {
2181
+ const finish = (branch) => {
2182
+ run(["rev-parse", "HEAD"], (finalSha) => {
2183
+ const coherent = validAppCommitSha(finalSha) === commitSha;
2184
+ completed({
2185
+ commitSha,
2186
+ ...coherent && status !== void 0 ? { commitDirty: status !== "" } : {},
2187
+ ...coherent && branch && branch !== "HEAD" ? { branch } : {}
2188
+ });
2189
+ });
2190
+ };
2191
+ if (detectBranch) run(["symbolic-ref", "--quiet", "--short", "HEAD"], finish);
2192
+ else finish();
2193
+ });
2194
+ });
2195
+ } catch (e) {
2196
+ completed({});
2197
+ }
2198
+ }, 0);
2199
+ scheduled.unref();
2200
+ return () => {
2201
+ cancelled = true;
2202
+ clearTimeout(scheduled);
2203
+ clearTimeout(deadlineTimer);
2204
+ try {
2205
+ active == null ? void 0 : active.kill("SIGKILL");
2206
+ } catch (e) {
2207
+ }
2208
+ };
2209
+ };
2210
+ function createAppGitContext2(options, runtime = {}) {
2211
+ return new AppGitContext(options, { ...runtime, resolveLocal });
2212
+ }
2213
+ function hasDestination(options) {
2214
+ var _a;
2215
+ if (options.enabled === false) return false;
2216
+ return Boolean(((_a = options.writeKey) == null ? void 0 : _a.trim()) || resolveLocalDebuggerBaseUrl(options.localDebuggerUrl));
2217
+ }
2218
+ var EventShipper2 = class extends EventShipper {
2219
+ constructor(options) {
2220
+ var _a;
2221
+ const ownsAppGitContext = options.appGitContext === void 0;
2222
+ const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
2223
+ try {
2224
+ super({ ...options, appGitContext });
2225
+ } catch (error) {
2226
+ if (ownsAppGitContext) appGitContext.dispose();
2227
+ throw error;
2228
+ }
2229
+ if (ownsAppGitContext) this.ownAppGitContextForShutdown();
2230
+ }
2231
+ };
2232
+ var TraceShipper2 = class extends TraceShipper {
2233
+ constructor(options) {
2234
+ var _a;
2235
+ const ownsAppGitContext = options.appGitContext === void 0;
2236
+ const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
2237
+ try {
2238
+ super({ ...options, appGitContext });
2239
+ } catch (error) {
2240
+ if (ownsAppGitContext) appGitContext.dispose();
2241
+ throw error;
2242
+ }
2243
+ this.ownsAppGitContext = ownsAppGitContext;
2244
+ }
2245
+ };
1398
2246
  globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = import_async_hooks.AsyncLocalStorage;
1399
2247
  var SUPPRESS_TRACING_KEY = /* @__PURE__ */ Symbol.for(
1400
2248
  "OpenTelemetry SDK Context Key SUPPRESS_TRACING"
@@ -1459,7 +2307,20 @@ function loadConfig(projectDirectory) {
1459
2307
  debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_g = merged.debug) != null ? _g : false,
1460
2308
  captureSystemPrompt: process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] !== void 0 ? process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] === "true" : (_h = merged.capture_system_prompt) != null ? _h : false,
1461
2309
  eventMetadata,
1462
- localWorkshopUrl: resolveLocalWorkshopUrl(merged.local_workshop_url)
2310
+ localWorkshopUrl: resolveLocalWorkshopUrl(merged.local_workshop_url),
2311
+ appGit: mapAppGit(merged.app_git)
2312
+ };
2313
+ }
2314
+ function mapAppGit(value) {
2315
+ if (value === false) return false;
2316
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
2317
+ return {
2318
+ commitSha: "commit_sha" in value && (typeof value.commit_sha === "string" || value.commit_sha === null) ? value.commit_sha : void 0,
2319
+ commitDirty: "commit_dirty" in value && (typeof value.commit_dirty === "boolean" || value.commit_dirty === null) ? value.commit_dirty : void 0,
2320
+ branch: "branch" in value && (typeof value.branch === "string" || value.branch === null) ? value.branch : void 0,
2321
+ detectBranch: "detect_branch" in value && typeof value.detect_branch === "boolean" ? value.detect_branch : void 0,
2322
+ sourceDirectory: "source_directory" in value && typeof value.source_directory === "string" ? value.source_directory : void 0,
2323
+ autoDetect: "auto_detect" in value && typeof value.auto_detect === "boolean" ? value.auto_detect : void 0
1463
2324
  };
1464
2325
  }
1465
2326
  function resolveLocalWorkshopUrl(fileValue) {
@@ -1476,7 +2337,7 @@ function resolveLocalWorkshopUrl(fileValue) {
1476
2337
  // package.json
1477
2338
  var package_default = {
1478
2339
  name: "@raindrop-ai/opencode-plugin",
1479
- version: "0.1.3",
2340
+ version: "0.1.4",
1480
2341
  description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
1481
2342
  type: "module",
1482
2343
  main: "dist/index.js",
@@ -1547,7 +2408,7 @@ var PLUGIN_NAME = package_default.name;
1547
2408
  var PLUGIN_VERSION = package_default.version;
1548
2409
 
1549
2410
  // src/shipper.ts
1550
- var EventShipper2 = class extends EventShipper {
2411
+ var EventShipper3 = class extends EventShipper2 {
1551
2412
  constructor(opts) {
1552
2413
  var _a, _b, _c, _d;
1553
2414
  super({
@@ -1559,7 +2420,7 @@ var EventShipper2 = class extends EventShipper {
1559
2420
  });
1560
2421
  }
1561
2422
  };
1562
- var TraceShipper2 = class extends TraceShipper {
2423
+ var TraceShipper3 = class extends TraceShipper2 {
1563
2424
  constructor(opts) {
1564
2425
  var _a, _b, _c;
1565
2426
  super({
@@ -1717,11 +2578,11 @@ function createSessionParentMapHelpers({
1717
2578
  }) {
1718
2579
  function applyChildSessionParentToState(childSessionId) {
1719
2580
  const parentInfo = mapChildSessionToParent2.get(childSessionId);
1720
- const state = sessions2.get(childSessionId);
1721
- if (!parentInfo || !state) return;
1722
- state.parentId = parentInfo.parentId;
1723
- state.parentTaskSpanIds = parentInfo.parentTaskSpanIds;
1724
- state.parentEventContext = parentInfo.eventContext;
2581
+ const state2 = sessions2.get(childSessionId);
2582
+ if (!parentInfo || !state2) return;
2583
+ state2.parentId = parentInfo.parentId;
2584
+ state2.parentTaskSpanIds = parentInfo.parentTaskSpanIds;
2585
+ state2.parentEventContext = parentInfo.eventContext;
1725
2586
  }
1726
2587
  function queuePendingChildByCallKey(key, childSessionId) {
1727
2588
  var _a;
@@ -1817,10 +2678,10 @@ function markTaskCallFinished(sessionID, callID) {
1817
2678
  running.delete(callID);
1818
2679
  if (running.size === 0) runningTaskCallsBySession.delete(sessionID);
1819
2680
  }
1820
- function endPendingToolSpanWithError(state, callID, tool, toolCallArgs, errorMessage, traceShipper) {
1821
- const startInfo = state.toolSpanStarts.get(callID);
2681
+ function endPendingToolSpanWithError(state2, callID, tool, toolCallArgs, errorMessage, traceShipper) {
2682
+ const startInfo = state2.toolSpanStarts.get(callID);
1822
2683
  if (!startInfo) return false;
1823
- state.toolSpanStarts.delete(callID);
2684
+ state2.toolSpanStarts.delete(callID);
1824
2685
  const error = new Error(errorMessage);
1825
2686
  const endAttrs = [
1826
2687
  attrString("ai.toolCall.args", toolCallArgs),
@@ -1920,17 +2781,17 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
1920
2781
  if (info == null || typeof info !== "object")
1921
2782
  throw new Error("session.created: props.info is required");
1922
2783
  const parentID = info["parentID"];
1923
- let state = sessions.get(sessionID);
1924
- if (!state) {
1925
- state = createSessionState(sessionID);
1926
- sessions.set(sessionID, state);
2784
+ let state2 = sessions.get(sessionID);
2785
+ if (!state2) {
2786
+ state2 = createSessionState(sessionID);
2787
+ sessions.set(sessionID, state2);
1927
2788
  }
1928
- state.parentId = parentID;
1929
- if (state.parentId) mapChildSessionToParent.set(sessionID, { parentId: state.parentId });
2789
+ state2.parentId = parentID;
2790
+ if (state2.parentId) mapChildSessionToParent.set(sessionID, { parentId: state2.parentId });
1930
2791
  } else if (event.type === "session.compacted") {
1931
- const state = sessions.get(String(sessionID));
1932
- if (!state) return;
1933
- state.isCompacting = true;
2792
+ const state2 = sessions.get(String(sessionID));
2793
+ if (!state2) return;
2794
+ state2.isCompacting = true;
1934
2795
  } else if (event.type === "message.part.updated") {
1935
2796
  const part = props["part"];
1936
2797
  if (part == null || typeof part !== "object")
@@ -1942,10 +2803,10 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
1942
2803
  throw new Error("message.part.updated: part.sessionID is required");
1943
2804
  if (messageId == null || messageId === "")
1944
2805
  throw new Error("message.part.updated: part.messageID is required");
1945
- const state = sessions.get(partSessionID);
1946
- if (!state) return;
2806
+ const state2 = sessions.get(partSessionID);
2807
+ if (!state2) return;
1947
2808
  if (partObj["type"] === "text" && typeof partObj["text"] === "string") {
1948
- state.outputParts.set(messageId, capText2(partObj["text"]));
2809
+ state2.outputParts.set(messageId, capText2(partObj["text"]));
1949
2810
  } else if (partObj["type"] === "tool" && messageId) {
1950
2811
  const tool = partObj["tool"];
1951
2812
  const callID = partObj["callID"];
@@ -1977,7 +2838,7 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
1977
2838
  const input = toolState["input"];
1978
2839
  const toolCallArgs = input === void 0 ? void 0 : typeof input === "string" ? capText2(input) : boundedStringify(input);
1979
2840
  if (endPendingToolSpanWithError(
1980
- state,
2841
+ state2,
1981
2842
  callID,
1982
2843
  tool,
1983
2844
  toolCallArgs,
@@ -1988,7 +2849,7 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
1988
2849
  }
1989
2850
  }
1990
2851
  } else if (partObj["type"] === "reasoning" && typeof partObj["text"] === "string") {
1991
- state.reasoningParts.set(messageId, capText2(partObj["text"]));
2852
+ state2.reasoningParts.set(messageId, capText2(partObj["text"]));
1992
2853
  }
1993
2854
  } else if (event.type === "message.updated") {
1994
2855
  const msgInfo = props["info"];
@@ -2008,10 +2869,10 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
2008
2869
  throw new Error("message.updated: info.time is required");
2009
2870
  const timeObj = time;
2010
2871
  if (timeObj["completed"] == null) return;
2011
- const state = sessions.get(msgSessionID);
2012
- if (!state || !state.currentEventId || !state.currentRootSpan) return;
2013
- if (state.processedMessages.has(messageId)) return;
2014
- state.processedMessages.add(messageId);
2872
+ const state2 = sessions.get(msgSessionID);
2873
+ if (!state2 || !state2.currentEventId || !state2.currentRootSpan) return;
2874
+ if (state2.processedMessages.has(messageId)) return;
2875
+ state2.processedMessages.add(messageId);
2015
2876
  const tokens = info2["tokens"];
2016
2877
  if (tokens == null || typeof tokens !== "object")
2017
2878
  throw new Error("message.updated: info.tokens is required");
@@ -2028,13 +2889,13 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
2028
2889
  );
2029
2890
  const modelName = `${providerID}/${modelID}`;
2030
2891
  const finishReason = info2["finish"];
2031
- const outputText = state.outputParts.get(messageId);
2032
- const reasoningText = state.reasoningParts.get(messageId);
2892
+ const outputText = state2.outputParts.get(messageId);
2893
+ const reasoningText = state2.reasoningParts.get(messageId);
2033
2894
  const isToolCallsCompletion = finishReason === "tool-calls";
2034
2895
  if (outputText !== void 0 && outputText.trim().length > 0) {
2035
- state.turnOutputParts.push(outputText);
2896
+ state2.turnOutputParts.push(outputText);
2036
2897
  }
2037
- state.turnOutputTokens += outputTokens;
2898
+ state2.turnOutputTokens += outputTokens;
2038
2899
  if (outputText === void 0 && !isToolCallsCompletion) return;
2039
2900
  const msgError = info2["error"];
2040
2901
  const errorForSpan = msgError ? (() => {
@@ -2054,17 +2915,17 @@ type: ${name != null ? name : "UnknownError"}`;
2054
2915
  attrString("ai.response.text", responseText),
2055
2916
  ...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
2056
2917
  ];
2057
- if (state.currentSystemPrompt) {
2918
+ if (state2.currentSystemPrompt) {
2058
2919
  llmAttrs.push(
2059
2920
  attrString("gen_ai.prompt.0.role", "system"),
2060
- attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
2921
+ attrString("gen_ai.prompt.0.content", state2.currentSystemPrompt)
2061
2922
  );
2062
2923
  }
2063
- const llmParent = state.parentId && state.parentTaskSpanIds ? state.parentTaskSpanIds : state.currentRootSpan.ids;
2924
+ const llmParent = state2.parentId && state2.parentTaskSpanIds ? state2.parentTaskSpanIds : state2.currentRootSpan.ids;
2064
2925
  const llmSpan = traceShipper.startSpan({
2065
2926
  name: modelName,
2066
2927
  parent: llmParent,
2067
- eventId: state.currentEventId,
2928
+ eventId: state2.currentEventId,
2068
2929
  attributes: llmAttrs
2069
2930
  });
2070
2931
  if (typeof timeObj["created"] === "number") {
@@ -2075,40 +2936,40 @@ type: ${name != null ? name : "UnknownError"}`;
2075
2936
  return;
2076
2937
  }
2077
2938
  if (outputText === void 0) return;
2078
- const turnOutputText = capText2(state.turnOutputParts.join("\n\n"));
2079
- const rootSpan = state.currentRootSpan;
2080
- const isCompaction = state.isCompacting === true;
2081
- if (state.parentId) {
2082
- const userInput = unwrapQuotes(state.currentInput);
2939
+ const turnOutputText = capText2(state2.turnOutputParts.join("\n\n"));
2940
+ const rootSpan = state2.currentRootSpan;
2941
+ const isCompaction = state2.isCompacting === true;
2942
+ if (state2.parentId) {
2943
+ const userInput = unwrapQuotes(state2.currentInput);
2083
2944
  const llmAttrs = [
2084
2945
  attrString("ai.operationId", "generateText"),
2085
2946
  attrString("ai.prompt", userInput),
2086
2947
  attrString(
2087
2948
  "ai.prompt.messages",
2088
- buildPromptMessages(state.currentSystemPrompt, state.currentInput)
2949
+ buildPromptMessages(state2.currentSystemPrompt, state2.currentInput)
2089
2950
  ),
2090
2951
  attrString("ai.response.text", turnOutputText),
2091
2952
  ...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
2092
2953
  ];
2093
- if (state.currentSystemPrompt) {
2954
+ if (state2.currentSystemPrompt) {
2094
2955
  llmAttrs.push(
2095
2956
  attrString("gen_ai.prompt.0.role", "system"),
2096
- attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
2957
+ attrString("gen_ai.prompt.0.content", state2.currentSystemPrompt)
2097
2958
  );
2098
2959
  }
2099
- if (!state.parentTaskSpanIds) {
2960
+ if (!state2.parentTaskSpanIds) {
2100
2961
  traceShipper.endSpan(rootSpan, {
2101
2962
  error: "Missing strict parent task for child session"
2102
2963
  });
2103
- state.currentRootSpan = void 0;
2104
- state.currentEventId = void 0;
2964
+ state2.currentRootSpan = void 0;
2965
+ state2.currentEventId = void 0;
2105
2966
  await traceShipper.flush();
2106
2967
  return;
2107
2968
  }
2108
2969
  const finalLlmSpan = traceShipper.startSpan({
2109
2970
  name: modelName,
2110
- parent: state.parentTaskSpanIds,
2111
- eventId: state.currentEventId,
2971
+ parent: state2.parentTaskSpanIds,
2972
+ eventId: state2.currentEventId,
2112
2973
  attributes: llmAttrs
2113
2974
  });
2114
2975
  if (typeof timeObj["created"] === "number") {
@@ -2118,19 +2979,19 @@ type: ${name != null ? name : "UnknownError"}`;
2118
2979
  traceShipper.endSpan(rootSpan, {
2119
2980
  attributes: [
2120
2981
  attrString("is_subagent", "true"),
2121
- attrString("parent_session_id", state.parentId)
2982
+ attrString("parent_session_id", state2.parentId)
2122
2983
  ],
2123
2984
  error: errorForSpan
2124
2985
  });
2125
2986
  } else {
2126
2987
  rootSpan.name = isCompaction ? "ai.compaction" : modelName;
2127
- const userInput = unwrapQuotes(state.currentInput);
2988
+ const userInput = unwrapQuotes(state2.currentInput);
2128
2989
  const rootAttrs = [
2129
2990
  attrString("ai.operationId", "generateText"),
2130
2991
  attrString("ai.prompt", userInput),
2131
2992
  attrString(
2132
2993
  "ai.prompt.messages",
2133
- buildPromptMessages(state.currentSystemPrompt, state.currentInput)
2994
+ buildPromptMessages(state2.currentSystemPrompt, state2.currentInput)
2134
2995
  ),
2135
2996
  attrString("ai.response.text", turnOutputText),
2136
2997
  ...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
@@ -2139,10 +3000,10 @@ type: ${name != null ? name : "UnknownError"}`;
2139
3000
  rootAttrs.push(attrString("is_compaction", "true"));
2140
3001
  }
2141
3002
  rootAttrs.push(attrString("message_id", messageId));
2142
- if (state.currentSystemPrompt) {
3003
+ if (state2.currentSystemPrompt) {
2143
3004
  rootAttrs.push(
2144
3005
  attrString("gen_ai.prompt.0.role", "system"),
2145
- attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
3006
+ attrString("gen_ai.prompt.0.content", state2.currentSystemPrompt)
2146
3007
  );
2147
3008
  }
2148
3009
  traceShipper.endSpan(rootSpan, {
@@ -2150,24 +3011,24 @@ type: ${name != null ? name : "UnknownError"}`;
2150
3011
  error: errorForSpan
2151
3012
  });
2152
3013
  if (isCompaction) {
2153
- state.isCompacting = false;
3014
+ state2.isCompacting = false;
2154
3015
  }
2155
3016
  }
2156
- state.currentRootSpan = void 0;
3017
+ state2.currentRootSpan = void 0;
2157
3018
  const hasAssistantResponse = turnOutputText.trim().length > 0;
2158
3019
  if (!hasAssistantResponse && !msgError) {
2159
3020
  await traceShipper.flush();
2160
- state.currentEventId = void 0;
3021
+ state2.currentEventId = void 0;
2161
3022
  return;
2162
3023
  }
2163
- if (!state.parentId) {
2164
- await eventShipper.finish(state.currentEventId, {
2165
- userId: (_d = (_c = state.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state.sessionId,
3024
+ if (!state2.parentId) {
3025
+ await eventShipper.finish(state2.currentEventId, {
3026
+ userId: (_d = (_c = state2.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state2.sessionId,
2166
3027
  model: modelID,
2167
3028
  output: msgError ? void 0 : turnOutputText,
2168
3029
  usage: {
2169
3030
  promptTokens: inputTokens,
2170
- completionTokens: state.turnOutputTokens
3031
+ completionTokens: state2.turnOutputTokens
2171
3032
  },
2172
3033
  error: msgError ? {
2173
3034
  name: msgError.name,
@@ -2182,35 +3043,35 @@ type: ${name != null ? name : "UnknownError"}`;
2182
3043
  });
2183
3044
  }
2184
3045
  await traceShipper.flush();
2185
- state.currentEventId = void 0;
3046
+ state2.currentEventId = void 0;
2186
3047
  } else if (event.type === "session.idle") {
2187
3048
  if (!sessionID) return;
2188
- const state = sessions.get(String(sessionID));
2189
- if (!state) return;
2190
- if (state.currentRootSpan) {
2191
- traceShipper.endSpan(state.currentRootSpan);
2192
- state.currentRootSpan = void 0;
3049
+ const state2 = sessions.get(String(sessionID));
3050
+ if (!state2) return;
3051
+ if (state2.currentRootSpan) {
3052
+ traceShipper.endSpan(state2.currentRootSpan);
3053
+ state2.currentRootSpan = void 0;
2193
3054
  }
2194
- if (state.currentEventId) {
2195
- state.currentEventId = void 0;
3055
+ if (state2.currentEventId) {
3056
+ state2.currentEventId = void 0;
2196
3057
  }
2197
- state.isCompacting = false;
3058
+ state2.isCompacting = false;
2198
3059
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
2199
- if (state.parentId) {
3060
+ if (state2.parentId) {
2200
3061
  cleanupSessionParentMap(String(sessionID));
2201
3062
  sessions.delete(String(sessionID));
2202
3063
  } else {
2203
3064
  }
2204
3065
  } else if (event.type === "session.deleted") {
2205
3066
  if (!sessionID) return;
2206
- const state = sessions.get(String(sessionID));
2207
- if (!state) return;
2208
- if (state.currentRootSpan) {
2209
- traceShipper.endSpan(state.currentRootSpan);
2210
- state.currentRootSpan = void 0;
3067
+ const state2 = sessions.get(String(sessionID));
3068
+ if (!state2) return;
3069
+ if (state2.currentRootSpan) {
3070
+ traceShipper.endSpan(state2.currentRootSpan);
3071
+ state2.currentRootSpan = void 0;
2211
3072
  }
2212
- if (state.currentEventId) {
2213
- state.currentEventId = void 0;
3073
+ if (state2.currentEventId) {
3074
+ state2.currentEventId = void 0;
2214
3075
  }
2215
3076
  cleanupSessionParentMap(String(sessionID));
2216
3077
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
@@ -2219,8 +3080,8 @@ type: ${name != null ? name : "UnknownError"}`;
2219
3080
  const errorSessionID = (_h = props["sessionID"]) != null ? _h : sessionID;
2220
3081
  if (errorSessionID === void 0 || errorSessionID === "")
2221
3082
  throw new Error("session.error: missing sessionID");
2222
- const state = sessions.get(String(errorSessionID));
2223
- if (!state) return;
3083
+ const state2 = sessions.get(String(errorSessionID));
3084
+ if (!state2) return;
2224
3085
  const errorObj = props["error"];
2225
3086
  if (errorObj == null) throw new Error("session.error: missing error object");
2226
3087
  const errorName = errorObj.name;
@@ -2230,12 +3091,12 @@ type: ${name != null ? name : "UnknownError"}`;
2230
3091
  const errorStr = `${errorMessage != null ? errorMessage : errorName}
2231
3092
 
2232
3093
  type: ${errorName != null ? errorName : "UnknownError"}`;
2233
- if (state.currentRootSpan) {
2234
- traceShipper.endSpan(state.currentRootSpan, { error: errorStr });
2235
- state.currentRootSpan = void 0;
3094
+ if (state2.currentRootSpan) {
3095
+ traceShipper.endSpan(state2.currentRootSpan, { error: errorStr });
3096
+ state2.currentRootSpan = void 0;
2236
3097
  }
2237
- if (state.currentEventId) {
2238
- state.currentEventId = void 0;
3098
+ if (state2.currentEventId) {
3099
+ state2.currentEventId = void 0;
2239
3100
  }
2240
3101
  cleanupSessionParentMap(String(errorSessionID));
2241
3102
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
@@ -2255,15 +3116,15 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2255
3116
  var _a, _b, _c, _d, _e, _f, _g;
2256
3117
  try {
2257
3118
  const { sessionID } = messageInput;
2258
- let state = sessions.get(sessionID);
2259
- if (!state) {
2260
- state = createSessionState(sessionID);
2261
- sessions.set(sessionID, state);
3119
+ let state2 = sessions.get(sessionID);
3120
+ if (!state2) {
3121
+ state2 = createSessionState(sessionID);
3122
+ sessions.set(sessionID, state2);
2262
3123
  }
2263
3124
  applyChildSessionParentToState(sessionID);
2264
- if (state.currentRootSpan) {
2265
- traceShipper.endSpan(state.currentRootSpan);
2266
- state.currentRootSpan = void 0;
3125
+ if (state2.currentRootSpan) {
3126
+ traceShipper.endSpan(state2.currentRootSpan);
3127
+ state2.currentRootSpan = void 0;
2267
3128
  }
2268
3129
  if (output == null) throw new Error("chat.message: output is required");
2269
3130
  const parts = output.parts;
@@ -2294,39 +3155,39 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2294
3155
  }
2295
3156
  }
2296
3157
  }
2297
- state.eventMetadata = {
3158
+ state2.eventMetadata = {
2298
3159
  ...baseMeta,
2299
3160
  ...promptMeta,
2300
3161
  properties: baseMeta.properties || promptMeta.properties ? { ...(_a = baseMeta.properties) != null ? _a : {}, ...(_b = promptMeta.properties) != null ? _b : {} } : void 0
2301
3162
  };
2302
3163
  const userText = capText2(textParts.join("\n"));
2303
- state.currentInput = userText;
2304
- state.turnOutputParts = [];
2305
- state.turnOutputTokens = 0;
2306
- if (state.parentId) {
2307
- if (!state.parentTaskSpanIds || !state.parentEventContext) {
3164
+ state2.currentInput = userText;
3165
+ state2.turnOutputParts = [];
3166
+ state2.turnOutputTokens = 0;
3167
+ if (state2.parentId) {
3168
+ if (!state2.parentTaskSpanIds || !state2.parentEventContext) {
2308
3169
  return;
2309
3170
  }
2310
- state.currentEventId = state.parentEventContext.eventId;
2311
- state.currentRootSpan = traceShipper.startSpan({
3171
+ state2.currentEventId = state2.parentEventContext.eventId;
3172
+ state2.currentRootSpan = traceShipper.startSpan({
2312
3173
  name: "Subagent",
2313
- parent: state.parentTaskSpanIds,
2314
- eventId: state.currentEventId,
3174
+ parent: state2.parentTaskSpanIds,
3175
+ eventId: state2.currentEventId,
2315
3176
  attributes: [
2316
3177
  attrString("workspace", worktree),
2317
3178
  attrString("directory", directory),
2318
3179
  attrString("hostname", hostname),
2319
3180
  attrString("os", os),
2320
3181
  attrString("is_subagent", "true"),
2321
- attrString("parent_session_id", state.parentId)
3182
+ attrString("parent_session_id", state2.parentId)
2322
3183
  ]
2323
3184
  });
2324
3185
  return;
2325
3186
  }
2326
- state.currentEventId = generateId();
2327
- state.currentRootSpan = traceShipper.startSpan({
2328
- name: state.isCompacting ? "ai.compaction" : "ai.event",
2329
- eventId: state.currentEventId,
3187
+ state2.currentEventId = generateId();
3188
+ state2.currentRootSpan = traceShipper.startSpan({
3189
+ name: state2.isCompacting ? "ai.compaction" : "ai.event",
3190
+ eventId: state2.currentEventId,
2330
3191
  attributes: [
2331
3192
  attrString("workspace", worktree),
2332
3193
  attrString("directory", directory),
@@ -2334,11 +3195,11 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2334
3195
  attrString("os", os)
2335
3196
  ]
2336
3197
  });
2337
- await eventShipper.patch(state.currentEventId, {
3198
+ await eventShipper.patch(state2.currentEventId, {
2338
3199
  isPending: true,
2339
- userId: (_d = (_c = state.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state.sessionId,
2340
- convoId: state.sessionId,
2341
- eventName: (_f = (_e = state.eventMetadata) == null ? void 0 : _e.eventName) != null ? _f : config.eventName,
3200
+ userId: (_d = (_c = state2.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state2.sessionId,
3201
+ convoId: state2.sessionId,
3202
+ eventName: (_f = (_e = state2.eventMetadata) == null ? void 0 : _e.eventName) != null ? _f : config.eventName,
2342
3203
  input: userText,
2343
3204
  ...newAttachments.length > 0 ? { attachments: newAttachments } : {},
2344
3205
  properties: {
@@ -2347,7 +3208,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2347
3208
  hostname,
2348
3209
  os,
2349
3210
  plugin_version: PLUGIN_VERSION,
2350
- ...(_g = state.eventMetadata) == null ? void 0 : _g.properties
3211
+ ...(_g = state2.eventMetadata) == null ? void 0 : _g.properties
2351
3212
  }
2352
3213
  });
2353
3214
  } catch (err) {
@@ -2361,16 +3222,16 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2361
3222
  var _a, _b, _c;
2362
3223
  try {
2363
3224
  const { tool, sessionID, callID } = toolInput;
2364
- const state = sessions.get(sessionID);
2365
- if (!state || !state.currentEventId) return;
2366
- const spanParent = state.parentId && state.parentTaskSpanIds ? state.parentTaskSpanIds : (_a = state.currentRootSpan) == null ? void 0 : _a.ids;
3225
+ const state2 = sessions.get(sessionID);
3226
+ if (!state2 || !state2.currentEventId) return;
3227
+ const spanParent = state2.parentId && state2.parentTaskSpanIds ? state2.parentTaskSpanIds : (_a = state2.currentRootSpan) == null ? void 0 : _a.ids;
2367
3228
  if (!spanParent) return;
2368
3229
  const startTimeUnixNano = nowUnixNanoString();
2369
3230
  if (tool === "task") {
2370
3231
  const liveTaskSpan = traceShipper.startSpan({
2371
3232
  name: "ai.toolCall",
2372
3233
  parent: spanParent,
2373
- eventId: state.currentEventId,
3234
+ eventId: state2.currentEventId,
2374
3235
  attributes: [
2375
3236
  attrString("ai.operationId", "ai.toolCall"),
2376
3237
  attrString("ai.toolCall.name", tool),
@@ -2381,9 +3242,9 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2381
3242
  const ctx = {
2382
3243
  ids: liveTaskSpan.ids,
2383
3244
  eventContext: {
2384
- eventId: state.currentEventId,
2385
- userId: (_c = (_b = state.eventMetadata) == null ? void 0 : _b.userId) != null ? _c : state.sessionId,
2386
- convoId: state.sessionId
3245
+ eventId: state2.currentEventId,
3246
+ userId: (_c = (_b = state2.eventMetadata) == null ? void 0 : _b.userId) != null ? _c : state2.sessionId,
3247
+ convoId: state2.sessionId
2387
3248
  }
2388
3249
  };
2389
3250
  taskContexts.set(callKey(sessionID, callID), ctx);
@@ -2394,18 +3255,18 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2394
3255
  }
2395
3256
  running.add(callID);
2396
3257
  resolvePendingChildrenForCall(sessionID, callID, "tool.execute.before");
2397
- state.toolSpanStarts.set(callID, {
3258
+ state2.toolSpanStarts.set(callID, {
2398
3259
  startTimeUnixNano,
2399
3260
  parent: spanParent,
2400
- eventId: state.currentEventId,
3261
+ eventId: state2.currentEventId,
2401
3262
  name: tool,
2402
3263
  liveSpan: liveTaskSpan
2403
3264
  });
2404
3265
  } else {
2405
- state.toolSpanStarts.set(callID, {
3266
+ state2.toolSpanStarts.set(callID, {
2406
3267
  startTimeUnixNano,
2407
3268
  parent: spanParent,
2408
- eventId: state.currentEventId,
3269
+ eventId: state2.currentEventId,
2409
3270
  name: tool
2410
3271
  });
2411
3272
  }
@@ -2422,13 +3283,13 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2422
3283
  "tool.execute.after": async (toolInput, result) => {
2423
3284
  try {
2424
3285
  const { tool, sessionID, callID, args } = toolInput;
2425
- const state = sessions.get(sessionID);
2426
- if (!state || !state.currentEventId) return;
3286
+ const state2 = sessions.get(sessionID);
3287
+ if (!state2 || !state2.currentEventId) return;
2427
3288
  if (args === void 0 || args === null)
2428
3289
  throw new Error("tool.execute.after: args is required");
2429
3290
  const toolCallArgs = typeof args === "string" ? capText2(args) : boundedStringify(args);
2430
- const startInfo = state.toolSpanStarts.get(callID);
2431
- state.toolSpanStarts.delete(callID);
3291
+ const startInfo = state2.toolSpanStarts.get(callID);
3292
+ state2.toolSpanStarts.delete(callID);
2432
3293
  const resultMetadata = result.metadata;
2433
3294
  const childSessionId = resultMetadata == null ? void 0 : resultMetadata["sessionId"];
2434
3295
  if (tool === "task" && childSessionId) {
@@ -2481,9 +3342,9 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2481
3342
  try {
2482
3343
  const sessionID = input.sessionID;
2483
3344
  if (!sessionID) return;
2484
- const state = sessions.get(sessionID);
2485
- if (state) {
2486
- state.isCompacting = true;
3345
+ const state2 = sessions.get(sessionID);
3346
+ if (state2) {
3347
+ state2.isCompacting = true;
2487
3348
  }
2488
3349
  } catch (err) {
2489
3350
  rateLimitedErrorLog(
@@ -2500,15 +3361,15 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2500
3361
  if (!config.captureSystemPrompt) return;
2501
3362
  const sessionID = input.sessionID;
2502
3363
  if (!sessionID) return;
2503
- let state = sessions.get(sessionID);
2504
- if (!state) {
2505
- state = createSessionState(sessionID);
2506
- sessions.set(sessionID, state);
3364
+ let state2 = sessions.get(sessionID);
3365
+ if (!state2) {
3366
+ state2 = createSessionState(sessionID);
3367
+ sessions.set(sessionID, state2);
2507
3368
  }
2508
3369
  const MAX_SYSTEM_PROMPT_LENGTH = 32768;
2509
3370
  const TRUNCATION_MARKER3 = "\n...[truncated]";
2510
3371
  const joined = output.system.join("\n\n");
2511
- state.currentSystemPrompt = joined.length > MAX_SYSTEM_PROMPT_LENGTH ? joined.slice(0, MAX_SYSTEM_PROMPT_LENGTH - TRUNCATION_MARKER3.length) + TRUNCATION_MARKER3 : joined;
3372
+ state2.currentSystemPrompt = joined.length > MAX_SYSTEM_PROMPT_LENGTH ? joined.slice(0, MAX_SYSTEM_PROMPT_LENGTH - TRUNCATION_MARKER3.length) + TRUNCATION_MARKER3 : joined;
2512
3373
  } catch (err) {
2513
3374
  rateLimitedErrorLog(
2514
3375
  "experimental.chat.system.transform",
@@ -2520,7 +3381,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2520
3381
  }
2521
3382
 
2522
3383
  // src/index.ts
2523
- function createRaindropHandle(eventShipper, traceShipper) {
3384
+ function createRaindropHandle(eventShipper, traceShipper, appGitContext) {
2524
3385
  return {
2525
3386
  users: {
2526
3387
  async identify(users) {
@@ -2531,12 +3392,19 @@ function createRaindropHandle(eventShipper, traceShipper) {
2531
3392
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
2532
3393
  },
2533
3394
  async shutdown() {
2534
- await Promise.all([eventShipper.shutdown(), traceShipper.shutdown()]);
3395
+ try {
3396
+ await Promise.all([eventShipper.shutdown(), traceShipper.shutdown()]);
3397
+ } finally {
3398
+ try {
3399
+ appGitContext.dispose();
3400
+ } catch (e) {
3401
+ }
3402
+ }
2535
3403
  }
2536
3404
  };
2537
3405
  }
2538
- async function plugin(input) {
2539
- var _a;
3406
+ async function plugin(input, opts = {}) {
3407
+ var _a, _b, _c;
2540
3408
  const config = loadConfig(input.directory);
2541
3409
  function appLog(level, message) {
2542
3410
  console.log(`[raindrop-ai/opencode-plugin] [${level}] ${message}`);
@@ -2558,21 +3426,28 @@ async function plugin(input) {
2558
3426
  ].filter(Boolean);
2559
3427
  appLog("info", `Raindrop tracing enabled \u2014 destinations: ${destinations.join(", ")}`);
2560
3428
  }
2561
- const eventShipper = new EventShipper2({
3429
+ const configuredAppGit = (_a = opts.appGit) != null ? _a : config.appGit;
3430
+ const appGitContext = createAppGitContext2(
3431
+ ((_b = config.writeKey) == null ? void 0 : _b.trim()) || hasLocalDestination ? configuredAppGit : false,
3432
+ { allowLocalGit: false }
3433
+ );
3434
+ const eventShipper = new EventShipper3({
2562
3435
  writeKey: config.writeKey,
2563
3436
  endpoint: config.endpoint,
2564
3437
  debug: config.debug,
2565
3438
  projectId: config.projectId,
2566
- localDebuggerUrl: config.localWorkshopUrl
3439
+ localDebuggerUrl: config.localWorkshopUrl,
3440
+ appGitContext
2567
3441
  });
2568
- const traceShipper = new TraceShipper2({
3442
+ const traceShipper = new TraceShipper3({
2569
3443
  writeKey: config.writeKey,
2570
3444
  endpoint: config.endpoint,
2571
3445
  debug: config.debug,
2572
3446
  projectId: config.projectId,
2573
- localDebuggerUrl: config.localWorkshopUrl
3447
+ localDebuggerUrl: config.localWorkshopUrl,
3448
+ appGitContext
2574
3449
  });
2575
- const worktree = (_a = input.worktree) != null ? _a : input.directory;
3450
+ const worktree = (_c = input.worktree) != null ? _c : input.directory;
2576
3451
  const hooks = createHooks(
2577
3452
  config,
2578
3453
  worktree,
@@ -2580,5 +3455,5 @@ async function plugin(input) {
2580
3455
  eventShipper,
2581
3456
  traceShipper
2582
3457
  );
2583
- return { ...hooks, raindrop: createRaindropHandle(eventShipper, traceShipper) };
3458
+ return { ...hooks, raindrop: createRaindropHandle(eventShipper, traceShipper, appGitContext) };
2584
3459
  }