@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.js CHANGED
@@ -1,4 +1,518 @@
1
- // ../core/dist/chunk-3V4MIA75.js
1
+ // ../core/dist/chunk-BYBMRLZM.js
2
+ var EVAL_CORRELATION_ID_ATTRIBUTE = "raindrop.eval_correlation_id";
3
+ var PROBE_SCOPE = { correlationId: "" };
4
+ var EvalScopeStorage = class {
5
+ constructor() {
6
+ this._als = null;
7
+ this._probed = false;
8
+ }
9
+ maybeAdoptAsyncLocalStorage() {
10
+ if (this._probed) return;
11
+ this._probed = true;
12
+ try {
13
+ const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
14
+ if (!Ctor) return;
15
+ const als = new Ctor();
16
+ als.run(PROBE_SCOPE, () => {
17
+ });
18
+ this._als = als;
19
+ } catch (e) {
20
+ this._als = null;
21
+ }
22
+ }
23
+ run(scope, callback) {
24
+ this.maybeAdoptAsyncLocalStorage();
25
+ if (this._als) return this._als.run(scope, callback);
26
+ const previous = this._syncScope;
27
+ this._syncScope = scope;
28
+ try {
29
+ return callback();
30
+ } finally {
31
+ this._syncScope = previous;
32
+ }
33
+ }
34
+ current() {
35
+ this.maybeAdoptAsyncLocalStorage();
36
+ if (this._als) return this._als.getStore();
37
+ return this._syncScope;
38
+ }
39
+ };
40
+ var EVAL_SCOPE_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.evalScopeStorage");
41
+ function evalScopeStorage() {
42
+ const holder = globalThis;
43
+ let storage = holder[EVAL_SCOPE_STORAGE_KEY];
44
+ if (!storage) {
45
+ storage = new EvalScopeStorage();
46
+ holder[EVAL_SCOPE_STORAGE_KEY] = storage;
47
+ }
48
+ return storage;
49
+ }
50
+ function currentEvalScope() {
51
+ try {
52
+ return evalScopeStorage().current();
53
+ } catch (e) {
54
+ return void 0;
55
+ }
56
+ }
57
+ function evalScopeAttributes() {
58
+ const scope = currentEvalScope();
59
+ if (!scope) return {};
60
+ return { [EVAL_CORRELATION_ID_ATTRIBUTE]: scope.correlationId };
61
+ }
62
+
63
+ // ../core/dist/chunk-WJOR6M7H.js
64
+ var STATE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.replayTraceRoutingState");
65
+ function state() {
66
+ const holder = globalThis;
67
+ let current = holder[STATE_KEY];
68
+ if (!current) {
69
+ let storage = null;
70
+ try {
71
+ const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
72
+ if (Ctor) storage = new Ctor();
73
+ } catch (e) {
74
+ storage = null;
75
+ }
76
+ current = {
77
+ storage,
78
+ syncDestination: void 0,
79
+ spanDestinations: /* @__PURE__ */ new WeakMap()
80
+ };
81
+ holder[STATE_KEY] = current;
82
+ }
83
+ return current;
84
+ }
85
+ function currentReplayTraceDestination() {
86
+ var _a, _b;
87
+ const routing = state();
88
+ return (_b = (_a = routing.storage) == null ? void 0 : _a.getStore()) != null ? _b : routing.syncDestination;
89
+ }
90
+ function rememberReplayTraceDestination(span) {
91
+ const destination = currentReplayTraceDestination();
92
+ if (destination) state().spanDestinations.set(span, destination);
93
+ }
94
+ function copyReplayTraceDestination(source, target) {
95
+ const destination = state().spanDestinations.get(source);
96
+ if (destination) state().spanDestinations.set(target, destination);
97
+ }
98
+ function replayTraceDestinationFor(value) {
99
+ if (typeof value !== "object" && typeof value !== "function" || value === null) {
100
+ return void 0;
101
+ }
102
+ return state().spanDestinations.get(value);
103
+ }
104
+ function recordReplayExportedSpan(destination, spanId, traceId) {
105
+ var _a, _b;
106
+ if (!destination || !spanId || !traceId) return;
107
+ (_a = destination.exportedSpanIds) == null ? void 0 : _a.add(spanId);
108
+ (_b = destination.exportedTraceIds) == null ? void 0 : _b.add(traceId);
109
+ }
110
+ function replayTraceUrl(baseUrl) {
111
+ return `${baseUrl.replace(/\/+$/, "")}/v1/traces`;
112
+ }
113
+ function getAsyncLocalStorageCtor() {
114
+ return globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
115
+ }
116
+ var MAX_BINDING_STACK = 128;
117
+ var EMPTY_STACK = [];
118
+ var ContextStackStorage = class {
119
+ /** Emitted once when this runtime cannot support an ambient push. */
120
+ constructor(noAmbientBindWarning) {
121
+ this.noAmbientBindWarning = noAmbientBindWarning;
122
+ this._als = null;
123
+ this._enterWithUsable = false;
124
+ this._syncStack = EMPTY_STACK;
125
+ this._adoptionChecked = false;
126
+ this._warnedNoAmbientBind = false;
127
+ }
128
+ maybeAdoptAsyncLocalStorage() {
129
+ if (this._adoptionChecked) return;
130
+ this._adoptionChecked = true;
131
+ const Ctor = getAsyncLocalStorageCtor();
132
+ if (!Ctor) return;
133
+ const als = new Ctor();
134
+ try {
135
+ als.run(EMPTY_STACK, () => {
136
+ });
137
+ } catch (e) {
138
+ return;
139
+ }
140
+ this._als = als;
141
+ if (typeof als.enterWith === "function") {
142
+ try {
143
+ als.enterWith(EMPTY_STACK);
144
+ this._enterWithUsable = true;
145
+ } catch (e) {
146
+ this._enterWithUsable = false;
147
+ }
148
+ }
149
+ }
150
+ getStack() {
151
+ var _a;
152
+ this.maybeAdoptAsyncLocalStorage();
153
+ if (this._als) return (_a = this._als.getStore()) != null ? _a : this._syncStack;
154
+ return this._syncStack;
155
+ }
156
+ /**
157
+ * Persist an ambient stack mutation. Returns false when an ALS is adopted but
158
+ * `enterWith` is unusable (workerd): callers must NOT fall back to the
159
+ * process-shared sync stack, since concurrent isolates would cross-stamp.
160
+ */
161
+ setAmbientStack(stack) {
162
+ if (this._als) {
163
+ if (!this._enterWithUsable) return false;
164
+ this._als.enterWith(stack);
165
+ return true;
166
+ }
167
+ this._syncStack = stack;
168
+ return true;
169
+ }
170
+ push(binding) {
171
+ this.maybeAdoptAsyncLocalStorage();
172
+ if (this._als && !this._enterWithUsable) {
173
+ this.warnNoAmbientBindOnce();
174
+ return;
175
+ }
176
+ let stack = this.getStack();
177
+ if (stack.length >= MAX_BINDING_STACK) {
178
+ stack = stack.filter((b) => b.isLive());
179
+ if (stack.length >= MAX_BINDING_STACK) {
180
+ stack = stack.slice(stack.length - (MAX_BINDING_STACK - 1));
181
+ }
182
+ }
183
+ this.setAmbientStack([...stack, binding]);
184
+ }
185
+ remove(binding) {
186
+ binding.markDead();
187
+ const stack = this.getStack();
188
+ const pruned = stack.filter((b) => b !== binding && b.isLive());
189
+ if (pruned.length !== stack.length) {
190
+ this.setAmbientStack(pruned);
191
+ }
192
+ }
193
+ runWith(binding, callback) {
194
+ this.maybeAdoptAsyncLocalStorage();
195
+ if (this._als) {
196
+ return this._als.run([...this.getStack(), binding], callback);
197
+ }
198
+ const previous = this._syncStack;
199
+ this._syncStack = [...previous, binding];
200
+ try {
201
+ return callback();
202
+ } finally {
203
+ this._syncStack = previous;
204
+ }
205
+ }
206
+ current() {
207
+ const stack = this.getStack();
208
+ if (stack.length === 0) return void 0;
209
+ const top = stack[stack.length - 1];
210
+ if (top.isLive()) return top;
211
+ const pruned = stack.filter((b) => b.isLive());
212
+ this.setAmbientStack(pruned);
213
+ return pruned.length > 0 ? pruned[pruned.length - 1] : void 0;
214
+ }
215
+ warnNoAmbientBindOnce() {
216
+ if (this._warnedNoAmbientBind) return;
217
+ this._warnedNoAmbientBind = true;
218
+ console.warn(this.noAmbientBindWarning);
219
+ }
220
+ };
221
+ var NO_AMBIENT_ROUTING_BIND_WARNING = "[raindrop] This runtime's AsyncLocalStorage does not implement enterWith (e.g. Cloudflare Workers), so begin()/finish() cannot scope auto-instrumented spans to a project without cross-contaminating concurrent requests. Manual events and explicit span routing are unaffected; use asCurrent()/withSpan (run-based) to route auto-instrumented spans on this runtime.";
222
+ var ROUTING_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.routingContextStorage");
223
+ function routingStorage() {
224
+ const holder = globalThis;
225
+ let storage = holder[ROUTING_STORAGE_KEY];
226
+ if (!storage) {
227
+ storage = new ContextStackStorage(NO_AMBIENT_ROUTING_BIND_WARNING);
228
+ holder[ROUTING_STORAGE_KEY] = storage;
229
+ }
230
+ return storage;
231
+ }
232
+ function currentRoutingBinding() {
233
+ const bound = routingStorage().current();
234
+ if (!bound) return void 0;
235
+ return {
236
+ projectId: bound.projectId,
237
+ authHint: bound.authHint,
238
+ ...bound.appGit ? { appGit: bound.appGit } : {},
239
+ ...bound.appGitSource ? { appGitSource: bound.appGitSource } : {}
240
+ };
241
+ }
242
+ var APP_COMMIT_SHA = "raindrop.app.commit_sha";
243
+ var APP_COMMIT_DIRTY = "raindrop.app.commit_dirty";
244
+ var APP_BRANCH = "raindrop.app.branch";
245
+ var APP_GIT_KEYS = [APP_COMMIT_SHA, APP_COMMIT_DIRTY, APP_BRANCH];
246
+ var own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
247
+ function appGitExplicitKeys(properties) {
248
+ const keys = /* @__PURE__ */ new Set();
249
+ if (!properties) return keys;
250
+ for (const key of APP_GIT_KEYS) {
251
+ if (own(properties, key)) keys.add(key);
252
+ }
253
+ return keys;
254
+ }
255
+ function mergeAppGitSnapshot(base, properties, explicitKeys = /* @__PURE__ */ new Set()) {
256
+ try {
257
+ const result = { ...base };
258
+ if (properties && own(properties, APP_COMMIT_SHA) && properties[APP_COMMIT_SHA] !== result[APP_COMMIT_SHA]) {
259
+ if (!explicitKeys.has(APP_COMMIT_DIRTY) && !own(properties, APP_COMMIT_DIRTY)) {
260
+ delete result[APP_COMMIT_DIRTY];
261
+ }
262
+ if (!explicitKeys.has(APP_BRANCH) && !own(properties, APP_BRANCH)) {
263
+ delete result[APP_BRANCH];
264
+ }
265
+ }
266
+ for (const key of APP_GIT_KEYS) {
267
+ if (properties && own(properties, key)) result[key] = properties[key];
268
+ }
269
+ return Object.freeze(result);
270
+ } catch (e) {
271
+ return Object.freeze({});
272
+ }
273
+ }
274
+ function validAppCommitSha(value) {
275
+ if (typeof value !== "string" || value.length > 128) return void 0;
276
+ const cleaned = value.trim();
277
+ return /^(?:[a-fA-F0-9]{40}|[a-fA-F0-9]{64})$/.test(cleaned) ? cleaned.toLowerCase() : void 0;
278
+ }
279
+ function shortString(value) {
280
+ if (typeof value !== "string" || value.length > 1024) return void 0;
281
+ const cleaned = value.trim();
282
+ return cleaned.length > 0 ? cleaned : void 0;
283
+ }
284
+ function flag(value) {
285
+ if (value === true || value === "true" || value === "1") return true;
286
+ if (value === false || value === "false" || value === "0") return false;
287
+ return void 0;
288
+ }
289
+ function environment() {
290
+ try {
291
+ return typeof process === "undefined" ? {} : process.env;
292
+ } catch (e) {
293
+ return {};
294
+ }
295
+ }
296
+ var DEPLOYMENTS = [
297
+ ["VERCEL", "VERCEL_GIT_COMMIT_SHA", "VERCEL_GIT_COMMIT_REF"],
298
+ ["NETLIFY", "COMMIT_REF", "BRANCH"],
299
+ ["RAILWAY_ENVIRONMENT_NAME", "RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH"],
300
+ ["RAILWAY_ENVIRONMENT", "RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH"],
301
+ ["RENDER", "RENDER_GIT_COMMIT", "RENDER_GIT_BRANCH"],
302
+ ["DYNO", "HEROKU_BUILD_COMMIT", ""],
303
+ ["DYNO", "HEROKU_SLUG_COMMIT", ""],
304
+ ["AWS_APP_ID", "AWS_COMMIT_ID", "AWS_BRANCH"],
305
+ ["WORKERS_CI", "WORKERS_CI_COMMIT_SHA", "WORKERS_CI_BRANCH"]
306
+ ];
307
+ var CI_SOURCES = [
308
+ ["GITHUB_ACTIONS", "GITHUB_SHA", "GITHUB_REF_NAME"],
309
+ ["GITLAB_CI", "CI_COMMIT_SHA", "CI_COMMIT_REF_NAME"],
310
+ ["CIRCLECI", "CIRCLE_SHA1", "CIRCLE_BRANCH"]
311
+ ];
312
+ function detectedSource(env, table, detectBranch) {
313
+ for (const row of table) {
314
+ const [marker, shaKey, branchKey] = row;
315
+ if (!marker || !shaKey || !shortString(env[marker]) || flag(env[marker]) === false) continue;
316
+ const commitSha = validAppCommitSha(env[shaKey]);
317
+ if (commitSha)
318
+ return {
319
+ commitSha,
320
+ ...detectBranch && branchKey ? { branch: shortString(env[branchKey]) } : {}
321
+ };
322
+ }
323
+ return {};
324
+ }
325
+ var AppGitContextImpl = class {
326
+ constructor(options, runtime = {}) {
327
+ this.defaults = {};
328
+ this.explicit = {};
329
+ this.explicitKeys = /* @__PURE__ */ new Set();
330
+ this.disposed = false;
331
+ this.operations = /* @__PURE__ */ new Map();
332
+ this.operationOverflow = false;
333
+ this.detectBranch = false;
334
+ this.disabled = false;
335
+ var _a, _b, _c, _d, _e, _f;
336
+ try {
337
+ if (options === false) {
338
+ this.disabled = true;
339
+ return;
340
+ }
341
+ const opts = options != null ? options : {};
342
+ const env = (_a = runtime.env) != null ? _a : environment();
343
+ const detectBranch = (_c = (_b = flag(opts.detectBranch)) != null ? _b : flag(env.RAINDROP_GIT_DETECT_BRANCH)) != null ? _c : false;
344
+ this.detectBranch = detectBranch;
345
+ const collectBranch = detectBranch || runtime.captureLegacyReplayBranch === true;
346
+ const autoDetect = runtime.allowDiscovery === false ? false : (_e = (_d = flag(opts.autoDetect)) != null ? _d : flag(env.RAINDROP_GIT_AUTO_DETECT)) != null ? _e : true;
347
+ const configuredSha = opts.commitSha;
348
+ const explicitSha = configuredSha === void 0 ? env.RAINDROP_COMMIT_SHA : configuredSha;
349
+ if (explicitSha === null) this.explicit[APP_COMMIT_SHA] = null;
350
+ else if (typeof explicitSha === "string" && validAppCommitSha(explicitSha))
351
+ this.explicit[APP_COMMIT_SHA] = explicitSha;
352
+ const configuredDirty = opts.commitDirty;
353
+ const explicitDirty = configuredDirty === void 0 ? flag(env.RAINDROP_COMMIT_DIRTY) : configuredDirty;
354
+ if (explicitDirty === null || typeof explicitDirty === "boolean")
355
+ this.explicit[APP_COMMIT_DIRTY] = explicitDirty;
356
+ const configuredBranch = opts.branch;
357
+ const explicitBranch = configuredBranch === void 0 ? env.RAINDROP_BRANCH : configuredBranch;
358
+ if (explicitBranch === null) this.explicit[APP_BRANCH] = null;
359
+ else if (typeof explicitBranch === "string" && explicitBranch.length <= 1024)
360
+ this.explicit[APP_BRANCH] = explicitBranch;
361
+ this.explicitKeys = appGitExplicitKeys(this.explicit);
362
+ this.defaults = { ...this.explicit };
363
+ if (!autoDetect || explicitSha !== void 0) return;
364
+ const sourceDirectory = (_f = shortString(opts.sourceDirectory)) != null ? _f : shortString(env.RAINDROP_GIT_SOURCE_DIRECTORY);
365
+ if (runtime.allowLocalGit === false && !sourceDirectory) return;
366
+ const deploy = sourceDirectory ? {} : detectedSource(env, DEPLOYMENTS, collectBranch);
367
+ if (deploy.commitSha) {
368
+ this.accept(deploy);
369
+ return;
370
+ }
371
+ const fallback = sourceDirectory ? {} : detectedSource(env, CI_SOURCES, collectBranch);
372
+ if (runtime.resolveLocal && (runtime.allowLocalGit !== false || sourceDirectory)) {
373
+ this.cancel = runtime.resolveLocal(sourceDirectory, collectBranch, (result) => {
374
+ try {
375
+ if (!this.disposed) this.accept(result.commitSha ? result : fallback);
376
+ } catch (e) {
377
+ }
378
+ });
379
+ } else this.accept(fallback);
380
+ } catch (e) {
381
+ }
382
+ }
383
+ accept(result) {
384
+ const sha = validAppCommitSha(result.commitSha);
385
+ if (!sha) return;
386
+ this.replayBranch = shortString(result.branch);
387
+ this.defaults = {
388
+ [APP_COMMIT_SHA]: sha,
389
+ ...typeof result.commitDirty === "boolean" ? { [APP_COMMIT_DIRTY]: result.commitDirty } : {},
390
+ ...this.detectBranch && this.replayBranch ? { [APP_BRANCH]: this.replayBranch } : {},
391
+ ...this.explicit
392
+ };
393
+ }
394
+ snapshot(properties) {
395
+ var _a;
396
+ try {
397
+ const binding = currentRoutingBinding();
398
+ const base = this.disabled && (binding == null ? void 0 : binding.appGitSource) !== "replay-override" ? {} : (_a = binding == null ? void 0 : binding.appGit) != null ? _a : this.defaults;
399
+ return this.mergeSnapshot(base, properties);
400
+ } catch (e) {
401
+ return Object.freeze({});
402
+ }
403
+ }
404
+ /** Safe defaults when no operation/span start was observed; never infer identity. */
405
+ snapshotExplicit(properties, eventId) {
406
+ try {
407
+ const base = { ...this.explicit };
408
+ const operation = eventId ? this.operations.get(eventId) : void 0;
409
+ if (operation) {
410
+ for (const key of operation.explicitKeys) base[key] = operation.snapshot[key];
411
+ }
412
+ return this.mergeSnapshot(base, properties, new Set(Object.keys(base)));
413
+ } catch (e) {
414
+ return mergeAppGitSnapshot({}, properties);
415
+ }
416
+ }
417
+ /** Existing replay branch reporting stays separate from opt-in event properties. */
418
+ snapshotForReplay() {
419
+ const snapshot = this.snapshot();
420
+ if (this.replayBranch && !own(snapshot, APP_BRANCH) && snapshot[APP_COMMIT_SHA] === this.defaults[APP_COMMIT_SHA]) {
421
+ return Object.freeze({ ...snapshot, [APP_BRANCH]: this.replayBranch });
422
+ }
423
+ return snapshot;
424
+ }
425
+ /** Merge a frozen span snapshot without losing client-authored provenance. */
426
+ mergeSnapshot(base, properties, explicitKeys = this.explicitKeys) {
427
+ return mergeAppGitSnapshot(base, properties, /* @__PURE__ */ new Set([...this.explicitKeys, ...explicitKeys]));
428
+ }
429
+ /** Shippers belonging to one client share this bounded operation registry. */
430
+ forOperation(eventId, properties, owner) {
431
+ if (!eventId) return this.snapshot(properties);
432
+ let operation = this.operations.get(eventId);
433
+ if (!operation) {
434
+ if (this.operations.size >= 1e4) this.operationOverflow = true;
435
+ if (this.operationOverflow) return this.mergeSnapshot({}, properties);
436
+ operation = {
437
+ snapshot: this.snapshot(properties),
438
+ owners: /* @__PURE__ */ new Set(),
439
+ unowned: owner === void 0,
440
+ explicitKeys: appGitExplicitKeys(properties)
441
+ };
442
+ this.operations.set(eventId, operation);
443
+ } else if (properties && APP_GIT_KEYS.some((key) => own(properties, key))) {
444
+ const explicitKeys = /* @__PURE__ */ new Set([...this.explicitKeys, ...operation.explicitKeys]);
445
+ operation.snapshot = this.mergeSnapshot(operation.snapshot, properties, explicitKeys);
446
+ for (const key of appGitExplicitKeys(properties)) operation.explicitKeys.add(key);
447
+ }
448
+ if (!owner) operation.unowned = true;
449
+ if (owner) operation.owners.add(owner);
450
+ return operation.snapshot;
451
+ }
452
+ releaseOperation(eventId, owner) {
453
+ const operation = this.operations.get(eventId);
454
+ if (!operation) return;
455
+ operation.owners.delete(owner);
456
+ if (operation.owners.size === 0 && !operation.unowned) this.operations.delete(eventId);
457
+ }
458
+ finishOperation(eventId) {
459
+ this.operations.delete(eventId);
460
+ }
461
+ dispose() {
462
+ var _a;
463
+ this.disposed = true;
464
+ try {
465
+ (_a = this.cancel) == null ? void 0 : _a.call(this);
466
+ } catch (e) {
467
+ }
468
+ }
469
+ };
470
+ var AppGitContext = AppGitContextImpl;
471
+ function createAppGitContext(options, runtime = {}) {
472
+ return new AppGitContext(options, runtime);
473
+ }
474
+ function withAppGitProperties(properties, snapshot) {
475
+ try {
476
+ const merged = { ...properties };
477
+ for (const key of APP_GIT_KEYS)
478
+ if (!own(merged, key) && own(snapshot, key)) merged[key] = snapshot[key];
479
+ return merged;
480
+ } catch (e) {
481
+ return properties != null ? properties : {};
482
+ }
483
+ }
484
+ function withAppGitAttributes(attributes, snapshot) {
485
+ try {
486
+ const present = new Set(attributes.flatMap((attr) => attr ? [attr.key] : []));
487
+ const added = [];
488
+ for (const key of APP_GIT_KEYS) {
489
+ if (present.has(key) || present.has(`ai.telemetry.metadata.${key}`) || present.has(`traceloop.association.properties.${key}`))
490
+ continue;
491
+ const value = snapshot[key];
492
+ if (typeof value === "string") added.push({ key, value: { stringValue: value } });
493
+ else if (typeof value === "boolean") added.push({ key, value: { boolValue: value } });
494
+ }
495
+ return added.length ? [...attributes, ...added] : attributes;
496
+ } catch (e) {
497
+ return attributes;
498
+ }
499
+ }
500
+ function appGitPropertiesFromAttributes(attributes) {
501
+ var _a, _b, _c;
502
+ const properties = {};
503
+ try {
504
+ for (const attr of attributes) {
505
+ if (!attr) continue;
506
+ for (const key of APP_GIT_KEYS) {
507
+ if (attr.key === key || attr.key === `ai.telemetry.metadata.${key}` || attr.key === `traceloop.association.properties.${key}`) {
508
+ properties[key] = (_c = (_b = (_a = attr.value.stringValue) != null ? _a : attr.value.boolValue) != null ? _b : attr.value.intValue) != null ? _c : null;
509
+ }
510
+ }
511
+ }
512
+ } catch (e) {
513
+ }
514
+ return properties;
515
+ }
2
516
  function getCrypto() {
3
517
  const c = globalThis.crypto;
4
518
  return c;
@@ -53,6 +567,25 @@ function base64Encode(bytes) {
53
567
  }
54
568
  return out;
55
569
  }
570
+ function base64ToHex(value) {
571
+ if (!value) return "";
572
+ const maybeBuffer = globalThis.Buffer;
573
+ if (maybeBuffer) {
574
+ return maybeBuffer.from(value, "base64").toString("hex");
575
+ }
576
+ const atobFn = globalThis.atob;
577
+ if (typeof atobFn !== "function") return "";
578
+ try {
579
+ const binary = atobFn(value);
580
+ let hex = "";
581
+ for (let i = 0; i < binary.length; i++) {
582
+ hex += (binary.charCodeAt(i) & 255).toString(16).padStart(2, "0");
583
+ }
584
+ return hex;
585
+ } catch (e) {
586
+ return "";
587
+ }
588
+ }
56
589
  function generateId() {
57
590
  return randomUUID();
58
591
  }
@@ -87,7 +620,7 @@ function runWithTracingSuppressed(fn) {
87
620
  var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
88
621
  var MAX_RETRY_DELAY_MS = 3e4;
89
622
  function wait(ms) {
90
- return new Promise((resolve) => setTimeout(resolve, ms));
623
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
91
624
  }
92
625
  function formatEndpoint(endpoint) {
93
626
  if (!endpoint) return void 0;
@@ -124,9 +657,9 @@ async function raceWithTimeout(promise, timeoutMs) {
124
657
  () => true,
125
658
  () => true
126
659
  ),
127
- new Promise((resolve) => {
660
+ new Promise((resolve2) => {
128
661
  var _a;
129
- timer = setTimeout(() => resolve(false), Math.max(0, timeoutMs));
662
+ timer = setTimeout(() => resolve2(false), Math.max(0, timeoutMs));
130
663
  (_a = timer.unref) == null ? void 0 : _a.call(timer);
131
664
  })
132
665
  ]);
@@ -197,6 +730,7 @@ async function postJson(url, body, headers, opts) {
197
730
  const resp = await runWithTracingSuppressed(
198
731
  () => fetch(url, {
199
732
  method: "POST",
733
+ redirect: headers["X-Raindrop-Replay-Id"] !== void 0 ? "error" : "follow",
200
734
  headers: {
201
735
  "Content-Type": "application/json",
202
736
  ...headers
@@ -365,26 +899,29 @@ function resolveLocalDebuggerBaseUrl(baseUrl) {
365
899
  if (shouldAutoEnableLocalWorkshop()) return DEFAULT_LOCAL_WORKSHOP_URL;
366
900
  return null;
367
901
  }
902
+ var LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS = 2e3;
368
903
  function mirrorTraceExportToLocalDebugger(body, options = {}) {
369
904
  var _a;
370
905
  const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
371
- if (!baseUrl) return;
372
- void postJson(`${baseUrl}traces`, body, {}, {
906
+ if (!baseUrl) return Promise.resolve();
907
+ return postJson(`${baseUrl}traces`, body, {}, {
373
908
  maxAttempts: 1,
374
909
  debug: (_a = options.debug) != null ? _a : false,
375
- sdkName: options.sdkName
910
+ sdkName: options.sdkName,
911
+ timeoutMs: LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS
376
912
  }).catch(() => {
377
913
  });
378
914
  }
379
915
  function mirrorPartialEventToLocalDebugger(event, options = {}) {
380
916
  var _a;
381
917
  const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
382
- if (!baseUrl) return;
918
+ if (!baseUrl) return Promise.resolve();
383
919
  const headers = options.writeKey ? { Authorization: `Bearer ${options.writeKey}` } : {};
384
- void postJson(`${baseUrl}events/track_partial`, event, headers, {
920
+ return postJson(`${baseUrl}events/track_partial`, event, headers, {
385
921
  maxAttempts: 1,
386
922
  debug: (_a = options.debug) != null ? _a : false,
387
- sdkName: options.sdkName
923
+ sdkName: options.sdkName,
924
+ timeoutMs: LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS
388
925
  }).catch(() => {
389
926
  });
390
927
  }
@@ -409,6 +946,13 @@ function projectIdHeaders(projectId) {
409
946
  }
410
947
  var SHUTDOWN_DEADLINE_MS = 1e4;
411
948
  var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
949
+ function appGitOwnerId(prefix) {
950
+ try {
951
+ return `${prefix}:${randomUUID()}`;
952
+ } catch (e) {
953
+ return `${prefix}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
954
+ }
955
+ }
412
956
  function mergePatches(target, source) {
413
957
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
414
958
  const out = { ...target, ...source };
@@ -458,22 +1002,25 @@ function eventTelemetryProperties(patch) {
458
1002
  }
459
1003
  var EventShipper = class {
460
1004
  constructor(opts) {
1005
+ this.appGitOwner = appGitOwnerId("event");
461
1006
  this.buffers = /* @__PURE__ */ new Map();
462
1007
  this.sticky = /* @__PURE__ */ new Map();
463
1008
  this.timers = /* @__PURE__ */ new Map();
464
1009
  this.inFlight = /* @__PURE__ */ new Set();
465
1010
  this.hasShutdown = false;
466
- var _a, _b, _c, _d, _e, _f, _g, _h;
467
- this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
468
- this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
1011
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1012
+ this.appGitContext = (_a = opts.appGitContext) != null ? _a : createAppGitContext(opts.appGit);
1013
+ this.ownsAppGitContext = opts.appGitContext === void 0;
1014
+ this.writeKey = (_b = opts.writeKey) == null ? void 0 : _b.trim();
1015
+ this.baseUrl = (_c = formatEndpoint(opts.endpoint)) != null ? _c : "https://api.raindrop.ai/v1/";
469
1016
  this.enabled = opts.enabled !== false;
470
1017
  this.debug = opts.debug;
471
- this.partialFlushMs = (_c = opts.partialFlushMs) != null ? _c : 1e3;
472
- this.sdkName = (_d = opts.sdkName) != null ? _d : "core";
1018
+ this.partialFlushMs = (_d = opts.partialFlushMs) != null ? _d : 1e3;
1019
+ this.sdkName = (_e = opts.sdkName) != null ? _e : "core";
473
1020
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
474
- this.defaultEventName = (_e = opts.defaultEventName) != null ? _e : "ai_generation";
1021
+ this.defaultEventName = (_f = opts.defaultEventName) != null ? _f : "ai_generation";
475
1022
  this.maxTextFieldCharsOpt = opts.maxTextFieldChars;
476
- this.localDebuggerUrl = (_f = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _f : void 0;
1023
+ this.localDebuggerUrl = (_g = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _g : void 0;
477
1024
  if (this.debug && this.localDebuggerUrl) {
478
1025
  console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
479
1026
  }
@@ -484,8 +1031,8 @@ var EventShipper = class {
484
1031
  const isNode = typeof process !== "undefined" && typeof process.version === "string";
485
1032
  this.context = {
486
1033
  library: {
487
- name: (_g = opts.libraryName) != null ? _g : "@raindrop-ai/core",
488
- version: (_h = opts.libraryVersion) != null ? _h : "0.0.0"
1034
+ name: (_h = opts.libraryName) != null ? _h : "@raindrop-ai/core",
1035
+ version: (_i = opts.libraryVersion) != null ? _i : "0.0.0"
489
1036
  },
490
1037
  metadata: {
491
1038
  jsRuntime: isNode ? "node" : "web",
@@ -493,6 +1040,9 @@ var EventShipper = class {
493
1040
  }
494
1041
  };
495
1042
  }
1043
+ ownAppGitContextForShutdown() {
1044
+ this.ownsAppGitContext = true;
1045
+ }
496
1046
  isDebugEnabled() {
497
1047
  return this.debug;
498
1048
  }
@@ -541,6 +1091,15 @@ var EventShipper = class {
541
1091
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
542
1092
  if (!this.enabled) return;
543
1093
  if (!eventId || !eventId.trim()) return;
1094
+ const capturedSticky = this.sticky.get(eventId);
1095
+ const eventAlreadyKnown = capturedSticky !== void 0 || this.buffers.has(eventId);
1096
+ const destination = currentReplayTraceDestination();
1097
+ const cloudReplay = destination !== void 0 && destination.kind !== "workshop";
1098
+ if ((capturedSticky == null ? void 0 : capturedSticky.replayOnly) === true || !eventAlreadyKnown && cloudReplay) {
1099
+ if (patch.isPending === false) this.sticky.delete(eventId);
1100
+ else this.sticky.set(eventId, { ...capturedSticky, replayOnly: true });
1101
+ return;
1102
+ }
544
1103
  const maxChars = resolveMaxTextFieldChars(this.maxTextFieldCharsOpt);
545
1104
  if (typeof patch.input === "string" && patch.input.length > maxChars) {
546
1105
  patch = { ...patch, input: capText(patch.input, maxChars) };
@@ -562,6 +1121,13 @@ var EventShipper = class {
562
1121
  }
563
1122
  const sticky = (_c = this.sticky.get(eventId)) != null ? _c : {};
564
1123
  const existing = (_d = this.buffers.get(eventId)) != null ? _d : {};
1124
+ patch = {
1125
+ ...patch,
1126
+ properties: withAppGitProperties(
1127
+ patch.properties,
1128
+ this.appGitContext.forOperation(eventId, patch.properties, this.appGitOwner)
1129
+ )
1130
+ };
565
1131
  const merged = mergePatches(existing, patch);
566
1132
  merged.isPending = (_g = (_f = (_e = patch.isPending) != null ? _e : existing.isPending) != null ? _f : sticky.isPending) != null ? _g : true;
567
1133
  this.buffers.set(eventId, merged);
@@ -575,6 +1141,8 @@ var EventShipper = class {
575
1141
  if (t) clearTimeout(t);
576
1142
  if (merged.isPending === false) {
577
1143
  await this.flushOne(eventId);
1144
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(eventId, this.appGitOwner);
1145
+ else this.appGitContext.finishOperation(eventId);
578
1146
  return;
579
1147
  }
580
1148
  const timeout = setTimeout(() => {
@@ -599,15 +1167,21 @@ var EventShipper = class {
599
1167
  try {
600
1168
  for (const t of this.timers.values()) clearTimeout(t);
601
1169
  this.timers.clear();
1170
+ for (const [eventId, sticky] of this.sticky) {
1171
+ if (sticky.replayOnly) this.sticky.delete(eventId);
1172
+ }
602
1173
  const settled = await raceWithTimeout(this.flush(), SHUTDOWN_DEADLINE_MS);
603
1174
  if (!settled) this.warnShutdownDrop("in-flight request(s) at shutdown");
604
1175
  } finally {
605
1176
  this.shutdownDeadlineAt = void 0;
1177
+ if (this.ownsAppGitContext) this.appGitContext.dispose();
606
1178
  }
607
1179
  }
608
1180
  async trackSignal(signal) {
609
1181
  var _a, _b;
610
1182
  if (!this.enabled) return;
1183
+ const destination = currentReplayTraceDestination();
1184
+ if (destination && destination.kind !== "workshop") return;
611
1185
  const body = [
612
1186
  {
613
1187
  event_id: signal.eventId,
@@ -642,6 +1216,8 @@ var EventShipper = class {
642
1216
  }
643
1217
  async identify(users) {
644
1218
  if (!this.enabled) return;
1219
+ const destination = currentReplayTraceDestination();
1220
+ if (destination && destination.kind !== "workshop") return;
645
1221
  const list = Array.isArray(users) ? users : [users];
646
1222
  const body = list.filter((user) => {
647
1223
  if (!(user == null ? void 0 : user.userId) || !user.userId.trim()) {
@@ -694,8 +1270,9 @@ var EventShipper = class {
694
1270
  this.buffers.delete(eventId);
695
1271
  if (!accumulated) return;
696
1272
  const sticky = (_a = this.sticky.get(eventId)) != null ? _a : {};
697
- const eventName = (_c = (_b = accumulated.eventName) != null ? _b : sticky.eventName) != null ? _c : this.defaultEventName;
698
- const userId = (_d = accumulated.userId) != null ? _d : sticky.userId;
1273
+ const isPending = (_c = (_b = accumulated.isPending) != null ? _b : sticky.isPending) != null ? _c : true;
1274
+ const eventName = (_e = (_d = accumulated.eventName) != null ? _d : sticky.eventName) != null ? _e : this.defaultEventName;
1275
+ const userId = (_f = accumulated.userId) != null ? _f : sticky.userId;
699
1276
  if (!userId) {
700
1277
  if (this.debug) {
701
1278
  console.warn(`${this.prefix} skipping track_partial for ${eventId}: missing userId`);
@@ -703,14 +1280,13 @@ var EventShipper = class {
703
1280
  this.sticky.delete(eventId);
704
1281
  return;
705
1282
  }
706
- const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
1283
+ const { wizardSession, ...restProperties } = (_g = accumulated.properties) != null ? _g : {};
707
1284
  let telemetryProperties = {};
708
1285
  try {
709
1286
  telemetryProperties = eventTelemetryProperties(accumulated);
710
1287
  } catch (e) {
711
1288
  }
712
- const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
713
- const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
1289
+ const convoId = (_h = accumulated.convoId) != null ? _h : sticky.convoId;
714
1290
  const payload = {
715
1291
  event_id: eventId,
716
1292
  user_id: userId,
@@ -752,29 +1328,30 @@ var EventShipper = class {
752
1328
  endpoint: url
753
1329
  });
754
1330
  }
755
- if (this.localDebuggerUrl) {
756
- mirrorPartialEventToLocalDebugger(payload, {
757
- baseUrl: this.localDebuggerUrl,
758
- writeKey: this.writeKey,
759
- debug: this.debug,
760
- sdkName: this.sdkName
761
- });
762
- }
1331
+ const mirror = this.localDebuggerUrl ? mirrorPartialEventToLocalDebugger(payload, {
1332
+ baseUrl: this.localDebuggerUrl,
1333
+ writeKey: this.writeKey,
1334
+ debug: this.debug,
1335
+ sdkName: this.sdkName
1336
+ }) : void 0;
763
1337
  if (!this.writeKey) {
764
1338
  if (!isPending) this.sticky.delete(eventId);
1339
+ if (mirror) await mirror;
765
1340
  return;
766
1341
  }
767
1342
  const opts = this.requestOpts();
768
1343
  if (!opts) {
769
1344
  this.warnShutdownDrop(`track_partial ${eventId}`);
770
1345
  if (!isPending) this.sticky.delete(eventId);
1346
+ if (mirror) await mirror;
771
1347
  return;
772
1348
  }
773
1349
  const p = postJson(url, payload, this.requestHeaders(), opts);
774
- this.inFlight.add(p);
1350
+ const combined = mirror ? Promise.all([mirror, p]).then(() => void 0) : p;
1351
+ this.inFlight.add(combined);
775
1352
  try {
776
1353
  try {
777
- await p;
1354
+ await combined;
778
1355
  if (this.debug) {
779
1356
  console.log(`${this.prefix} sent track_partial ${eventId} (${eventName})`);
780
1357
  }
@@ -786,7 +1363,7 @@ var EventShipper = class {
786
1363
  );
787
1364
  }
788
1365
  } finally {
789
- this.inFlight.delete(p);
1366
+ this.inFlight.delete(combined);
790
1367
  }
791
1368
  if (!isPending) {
792
1369
  this.sticky.delete(eventId);
@@ -1039,6 +1616,13 @@ function redactJsonAttributeValue(key, value) {
1039
1616
  if (scrubbedJson === json) return void 0;
1040
1617
  return { stringValue: scrubbedJson };
1041
1618
  }
1619
+ function appGitOwnerId2(prefix) {
1620
+ try {
1621
+ return `${prefix}:${randomUUID()}`;
1622
+ } catch (e) {
1623
+ return `${prefix}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
1624
+ }
1625
+ }
1042
1626
  function identityAttrs(args) {
1043
1627
  return [
1044
1628
  attrString("ai.telemetry.metadata.raindrop.ai.userId", args.userId),
@@ -1061,23 +1645,30 @@ function applyOtelSpanAttributeLimit(limit) {
1061
1645
  }
1062
1646
  var TraceShipper = class {
1063
1647
  constructor(opts) {
1648
+ this.appGitOwner = appGitOwnerId2("trace");
1649
+ this.appGitEventIds = /* @__PURE__ */ new WeakMap();
1650
+ this.appGitActiveSpans = /* @__PURE__ */ new Map();
1651
+ this.appGitCaptured = /* @__PURE__ */ new WeakSet();
1652
+ this.appGitAdded = /* @__PURE__ */ new WeakMap();
1064
1653
  this.queue = [];
1065
1654
  this.inFlight = /* @__PURE__ */ new Set();
1066
1655
  this.hasShutdown = false;
1067
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1068
- this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
1069
- this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
1656
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1657
+ this.appGitContext = (_a = opts.appGitContext) != null ? _a : createAppGitContext(opts.appGit);
1658
+ this.ownsAppGitContext = opts.appGitContext === void 0;
1659
+ this.writeKey = (_b = opts.writeKey) == null ? void 0 : _b.trim();
1660
+ this.baseUrl = (_c = formatEndpoint(opts.endpoint)) != null ? _c : "https://api.raindrop.ai/v1/";
1070
1661
  this.enabled = opts.enabled !== false;
1071
1662
  this.debug = opts.debug;
1072
1663
  this.debugSpans = opts.debugSpans === true;
1073
- this.flushIntervalMs = (_c = opts.flushIntervalMs) != null ? _c : 1e3;
1074
- this.maxBatchSize = (_d = opts.maxBatchSize) != null ? _d : 50;
1075
- this.maxQueueSize = (_e = opts.maxQueueSize) != null ? _e : 5e3;
1076
- this.sdkName = (_f = opts.sdkName) != null ? _f : "core";
1664
+ this.flushIntervalMs = (_d = opts.flushIntervalMs) != null ? _d : 1e3;
1665
+ this.maxBatchSize = (_e = opts.maxBatchSize) != null ? _e : 50;
1666
+ this.maxQueueSize = (_f = opts.maxQueueSize) != null ? _f : 5e3;
1667
+ this.sdkName = (_g = opts.sdkName) != null ? _g : "core";
1077
1668
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
1078
- this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
1079
- this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
1080
- this.localDebuggerUrl = (_i = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _i : void 0;
1669
+ this.serviceName = (_h = opts.serviceName) != null ? _h : "raindrop.core";
1670
+ this.serviceVersion = (_i = opts.serviceVersion) != null ? _i : "0.0.0";
1671
+ this.localDebuggerUrl = (_j = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _j : void 0;
1081
1672
  if (this.debug && this.localDebuggerUrl) {
1082
1673
  console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
1083
1674
  }
@@ -1141,7 +1732,10 @@ var TraceShipper = class {
1141
1732
  try {
1142
1733
  const result = this.transformSpanHook(current);
1143
1734
  if (result === null) return null;
1144
- if (result !== void 0) current = result;
1735
+ if (result !== void 0) {
1736
+ copyReplayTraceDestination(current, result);
1737
+ current = result;
1738
+ }
1145
1739
  } catch (err) {
1146
1740
  if (this.debug) {
1147
1741
  const msg = err instanceof Error ? err.message : String(err);
@@ -1151,13 +1745,19 @@ var TraceShipper = class {
1151
1745
  }
1152
1746
  }
1153
1747
  try {
1154
- current = normalizeModelUsageSpan(current);
1748
+ const normalized = normalizeModelUsageSpan(current);
1749
+ copyReplayTraceDestination(current, normalized);
1750
+ current = normalized;
1155
1751
  } catch (e) {
1156
1752
  }
1157
1753
  if (!this.disableDefaultRedaction) {
1158
- current = defaultTransformSpan(current);
1754
+ const redacted = defaultTransformSpan(current);
1755
+ copyReplayTraceDestination(current, redacted);
1756
+ current = redacted;
1159
1757
  }
1160
- return this.capSpanAttributes(current);
1758
+ const capped = this.capSpanAttributes(current);
1759
+ copyReplayTraceDestination(current, capped);
1760
+ return capped;
1161
1761
  }
1162
1762
  isDebugEnabled() {
1163
1763
  return this.debug;
@@ -1169,46 +1769,84 @@ var TraceShipper = class {
1169
1769
  return { ...this.authHeaders(), ...projectIdHeaders(this.projectId) };
1170
1770
  }
1171
1771
  startSpan(args) {
1172
- var _a, _b;
1772
+ var _a, _b, _c;
1173
1773
  const ids = createSpanIds(args.parent);
1174
1774
  const started = (_a = args.startTimeUnixNano) != null ? _a : nowUnixNanoString();
1175
1775
  const attrs = [
1176
1776
  attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
1177
1777
  ...identityAttrs(args),
1178
- attrString("ai.operationId", args.operationId)
1778
+ attrString("ai.operationId", args.operationId),
1779
+ ...Object.entries(evalScopeAttributes()).map(([key, value]) => attrString(key, value))
1179
1780
  ];
1180
1781
  if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
1181
- const span = { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
1182
- this.mirrorToLocalDebugger(
1183
- buildOtlpSpan({
1184
- ids: span.ids,
1185
- name: span.name,
1186
- startTimeUnixNano: span.startTimeUnixNano,
1187
- endTimeUnixNano: span.startTimeUnixNano,
1188
- // placeholder — will be updated on endSpan
1189
- attributes: span.attributes,
1190
- status: { code: SpanStatusCode.UNSET }
1191
- })
1192
- );
1782
+ const tracksAppGit = this.appGitActiveSpans.has(args.eventId) || this.appGitActiveSpans.size < 1e4;
1783
+ const appGitOverrides = appGitPropertiesFromAttributes(attrs);
1784
+ const span = {
1785
+ ids,
1786
+ name: args.name,
1787
+ startTimeUnixNano: started,
1788
+ attributes: withAppGitAttributes(
1789
+ attrs,
1790
+ this.appGitContext.forOperation(args.eventId, appGitOverrides, this.appGitOwner)
1791
+ )
1792
+ };
1793
+ rememberReplayTraceDestination(span);
1794
+ this.appGitCaptured.add(span);
1795
+ this.appGitEventIds.set(span, args.eventId);
1796
+ if (tracksAppGit) {
1797
+ this.appGitActiveSpans.set(args.eventId, ((_c = this.appGitActiveSpans.get(args.eventId)) != null ? _c : 0) + 1);
1798
+ }
1799
+ this.appGitAdded.set(span, new Set(span.attributes.filter((attr) => !attrs.includes(attr))));
1800
+ const openSpan = buildOtlpSpan({
1801
+ ids: span.ids,
1802
+ name: span.name,
1803
+ startTimeUnixNano: span.startTimeUnixNano,
1804
+ endTimeUnixNano: span.startTimeUnixNano,
1805
+ // placeholder — will be updated on endSpan
1806
+ attributes: span.attributes,
1807
+ status: { code: SpanStatusCode.UNSET }
1808
+ });
1809
+ copyReplayTraceDestination(span, openSpan);
1810
+ this.mirrorToLocalDebugger(openSpan);
1193
1811
  return span;
1194
1812
  }
1195
- mirrorToLocalDebugger(span) {
1196
- if (!this.localDebuggerUrl) return;
1813
+ mirrorToLocalDebugger(span, completed = false) {
1814
+ const destination = replayTraceDestinationFor(span);
1815
+ if (destination && destination.kind !== "workshop") return;
1816
+ const localDebuggerUrl = (destination == null ? void 0 : destination.kind) === "workshop" ? destination.url : this.localDebuggerUrl;
1817
+ if (!localDebuggerUrl) return;
1197
1818
  const redacted = this.redactSpan(span);
1198
1819
  if (redacted === null) return;
1820
+ if (completed && (destination == null ? void 0 : destination.kind) === "workshop") {
1821
+ recordReplayExportedSpan(
1822
+ destination,
1823
+ base64ToHex(redacted.spanId),
1824
+ base64ToHex(redacted.traceId)
1825
+ );
1826
+ }
1199
1827
  const body = buildExportTraceServiceRequest([redacted], this.serviceName, this.serviceVersion);
1200
- mirrorTraceExportToLocalDebugger(body, {
1201
- baseUrl: this.localDebuggerUrl,
1828
+ const p = mirrorTraceExportToLocalDebugger(body, {
1829
+ baseUrl: localDebuggerUrl,
1202
1830
  debug: false,
1203
1831
  sdkName: this.sdkName
1204
1832
  });
1833
+ this.inFlight.add(p);
1834
+ void p.finally(() => {
1835
+ this.inFlight.delete(p);
1836
+ });
1205
1837
  }
1206
1838
  endSpan(span, extra) {
1207
- var _a, _b;
1839
+ var _a, _b, _c;
1208
1840
  if (span.endTimeUnixNano) return;
1209
1841
  span.endTimeUnixNano = (_a = extra == null ? void 0 : extra.endTimeUnixNano) != null ? _a : nowUnixNanoString();
1210
1842
  if ((_b = extra == null ? void 0 : extra.attributes) == null ? void 0 : _b.length) {
1843
+ const overrides = appGitPropertiesFromAttributes(extra.attributes);
1844
+ const eventId2 = this.appGitEventIds.get(span);
1845
+ const snapshot = eventId2 ? this.appGitContext.forOperation(eventId2, overrides, this.appGitOwner) : overrides;
1846
+ const added = this.appGitAdded.get(span);
1847
+ 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));
1211
1848
  span.attributes.push(...extra.attributes);
1849
+ span.attributes = withAppGitAttributes(span.attributes, snapshot);
1212
1850
  }
1213
1851
  let status = extra == null ? void 0 : extra.status;
1214
1852
  if (!status && (extra == null ? void 0 : extra.error) !== void 0) {
@@ -1223,30 +1861,65 @@ var TraceShipper = class {
1223
1861
  attributes: span.attributes,
1224
1862
  status
1225
1863
  });
1864
+ copyReplayTraceDestination(span, otlp);
1865
+ this.appGitCaptured.add(otlp);
1226
1866
  this.enqueue(otlp);
1227
- this.mirrorToLocalDebugger(otlp);
1867
+ this.mirrorToLocalDebugger(otlp, true);
1868
+ const eventId = this.appGitEventIds.get(span);
1869
+ if (eventId && this.appGitActiveSpans.has(eventId)) {
1870
+ const remaining = ((_c = this.appGitActiveSpans.get(eventId)) != null ? _c : 1) - 1;
1871
+ if (remaining > 0) this.appGitActiveSpans.set(eventId, remaining);
1872
+ else {
1873
+ this.appGitActiveSpans.delete(eventId);
1874
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(eventId, this.appGitOwner);
1875
+ else if (this.ownsAppGitContext) this.appGitContext.finishOperation(eventId);
1876
+ }
1877
+ }
1228
1878
  }
1229
1879
  createSpan(args) {
1230
1880
  var _a;
1231
1881
  const ids = createSpanIds(args.parent);
1232
1882
  const attrs = [
1233
1883
  attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
1234
- ...identityAttrs(args)
1884
+ ...identityAttrs(args),
1885
+ ...Object.entries(evalScopeAttributes()).map(([key, value]) => attrString(key, value))
1235
1886
  ];
1236
1887
  if ((_a = args.attributes) == null ? void 0 : _a.length) attrs.push(...args.attributes);
1888
+ const tracksAppGit = !this.appGitActiveSpans.has(args.eventId);
1237
1889
  const otlp = buildOtlpSpan({
1238
1890
  ids,
1239
1891
  name: args.name,
1240
1892
  startTimeUnixNano: args.startTimeUnixNano,
1241
1893
  endTimeUnixNano: args.endTimeUnixNano,
1242
- attributes: attrs,
1894
+ attributes: withAppGitAttributes(
1895
+ attrs,
1896
+ this.appGitContext.forOperation(
1897
+ args.eventId,
1898
+ appGitPropertiesFromAttributes(attrs),
1899
+ this.appGitOwner
1900
+ )
1901
+ ),
1243
1902
  status: args.status
1244
1903
  });
1904
+ rememberReplayTraceDestination(otlp);
1905
+ this.appGitCaptured.add(otlp);
1906
+ if (tracksAppGit) {
1907
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(args.eventId, this.appGitOwner);
1908
+ else if (this.ownsAppGitContext) this.appGitContext.finishOperation(args.eventId);
1909
+ }
1245
1910
  this.enqueue(otlp);
1246
- this.mirrorToLocalDebugger(otlp);
1911
+ this.mirrorToLocalDebugger(otlp, true);
1247
1912
  }
1248
1913
  enqueue(span) {
1914
+ var _a;
1249
1915
  if (!this.enabled) return;
1916
+ const attributes = (_a = span.attributes) != null ? _a : [];
1917
+ const enriched = this.appGitCaptured.has(span) ? attributes : withAppGitAttributes(attributes, this.appGitContext.snapshot(appGitPropertiesFromAttributes(attributes)));
1918
+ if (enriched !== attributes) {
1919
+ const original = span;
1920
+ span = { ...span, attributes: enriched.filter((attr) => attr !== void 0) };
1921
+ copyReplayTraceDestination(original, span);
1922
+ }
1250
1923
  if (this.debugSpans) {
1251
1924
  const short = (s) => s ? s.slice(-8) : "none";
1252
1925
  console.log(
@@ -1257,6 +1930,13 @@ var TraceShipper = class {
1257
1930
  }
1258
1931
  const redacted = this.redactSpan(span);
1259
1932
  if (redacted === null) return;
1933
+ const destination = replayTraceDestinationFor(redacted);
1934
+ recordReplayExportedSpan(
1935
+ destination,
1936
+ base64ToHex(redacted.spanId),
1937
+ base64ToHex(redacted.traceId)
1938
+ );
1939
+ if ((destination == null ? void 0 : destination.kind) === "workshop") return;
1260
1940
  if (this.queue.length >= this.maxQueueSize) {
1261
1941
  this.queue.shift();
1262
1942
  }
@@ -1275,47 +1955,67 @@ var TraceShipper = class {
1275
1955
  }
1276
1956
  }
1277
1957
  async flush() {
1278
- if (!this.enabled) return;
1958
+ var _a;
1959
+ if (!this.enabled) {
1960
+ await Promise.all([...this.inFlight].map((p) => p.catch(() => {
1961
+ })));
1962
+ return;
1963
+ }
1279
1964
  if (this.timer) {
1280
1965
  clearTimeout(this.timer);
1281
1966
  this.timer = void 0;
1282
1967
  }
1283
1968
  while (this.queue.length > 0) {
1284
1969
  const batch = this.queue.splice(0, this.maxBatchSize);
1285
- if (!this.writeKey) continue;
1286
- const opts = this.requestOpts();
1287
- if (!opts) {
1288
- rateLimitedLog(
1289
- `${this.prefix}.shutdown_deadline`,
1290
- () => console.warn(
1291
- `${this.prefix} shutdown flush deadline exceeded; dropping ${batch.length} spans`
1292
- )
1293
- );
1294
- continue;
1970
+ const groups = /* @__PURE__ */ new Map();
1971
+ for (const span of batch) {
1972
+ const destination = replayTraceDestinationFor(span);
1973
+ const spans = groups.get(destination);
1974
+ if (spans) spans.push(span);
1975
+ else groups.set(destination, [span]);
1295
1976
  }
1296
- const body = buildExportTraceServiceRequest(batch, this.serviceName, this.serviceVersion);
1297
- const url = `${this.baseUrl}traces`;
1298
- if (this.debug) {
1299
- console.log(`${this.prefix} sending traces batch`, {
1300
- spans: batch.length,
1301
- endpoint: url
1302
- });
1303
- }
1304
- const p = postJson(url, body, this.requestHeaders(), opts);
1305
- this.inFlight.add(p);
1306
- try {
1307
- try {
1308
- await p;
1309
- if (this.debug) console.log(`${this.prefix} sent ${batch.length} spans`);
1310
- } catch (err) {
1311
- const msg = err instanceof Error ? err.message : String(err);
1977
+ for (const [destination, spans] of groups) {
1978
+ if (!destination && !this.writeKey) continue;
1979
+ if ((destination == null ? void 0 : destination.kind) === "workshop") continue;
1980
+ const opts = this.requestOpts();
1981
+ if (!opts) {
1312
1982
  rateLimitedLog(
1313
- `${this.prefix}.send_spans_failed`,
1314
- () => console.warn(`${this.prefix} failed to send ${batch.length} spans: ${msg}`)
1983
+ `${this.prefix}.shutdown_deadline`,
1984
+ () => console.warn(
1985
+ `${this.prefix} shutdown flush deadline exceeded; dropping ${spans.length} spans`
1986
+ )
1315
1987
  );
1988
+ continue;
1989
+ }
1990
+ const body = buildExportTraceServiceRequest(spans, this.serviceName, this.serviceVersion);
1991
+ const url = destination ? replayTraceUrl(destination.url) : `${this.baseUrl}traces`;
1992
+ const headers = destination ? {
1993
+ Authorization: `Bearer ${destination.apiKey}`,
1994
+ "X-Raindrop-Replay-Id": destination.replayId,
1995
+ "X-Raindrop-Project-Id": (_a = destination.projectId) != null ? _a : "default"
1996
+ } : this.requestHeaders();
1997
+ if (this.debug) {
1998
+ console.log(`${this.prefix} sending traces batch`, {
1999
+ spans: spans.length,
2000
+ endpoint: url
2001
+ });
2002
+ }
2003
+ const p = postJson(url, body, headers, opts);
2004
+ this.inFlight.add(p);
2005
+ try {
2006
+ try {
2007
+ await p;
2008
+ if (this.debug) console.log(`${this.prefix} sent ${spans.length} spans`);
2009
+ } catch (err) {
2010
+ const msg = err instanceof Error ? err.message : String(err);
2011
+ rateLimitedLog(
2012
+ `${this.prefix}.send_spans_failed`,
2013
+ () => console.warn(`${this.prefix} failed to send ${spans.length} spans: ${msg}`)
2014
+ );
2015
+ }
2016
+ } finally {
2017
+ this.inFlight.delete(p);
1316
2018
  }
1317
- } finally {
1318
- this.inFlight.delete(p);
1319
2019
  }
1320
2020
  }
1321
2021
  }
@@ -1358,17 +2058,165 @@ var TraceShipper = class {
1358
2058
  if (!settled) {
1359
2059
  rateLimitedLog(
1360
2060
  `${this.prefix}.shutdown_deadline`,
1361
- () => console.warn(`${this.prefix} shutdown flush deadline exceeded; abandoning in-flight spans`)
2061
+ () => console.warn(
2062
+ `${this.prefix} shutdown flush deadline exceeded; abandoning in-flight spans`
2063
+ )
1362
2064
  );
1363
2065
  }
1364
2066
  } finally {
1365
2067
  this.shutdownDeadlineAt = void 0;
2068
+ if (this.ownsAppGitContext) this.appGitContext.dispose();
1366
2069
  }
1367
2070
  }
1368
2071
  };
1369
2072
 
1370
2073
  // ../core/dist/index.node.js
1371
2074
  import { AsyncLocalStorage } from "async_hooks";
2075
+ import { execFile } from "child_process";
2076
+ import { resolve } from "path";
2077
+ var resolveLocal = (sourceDirectory, detectBranch, completed) => {
2078
+ const cwd = sourceDirectory ? resolve(sourceDirectory) : process.cwd();
2079
+ let cancelled = false;
2080
+ let active;
2081
+ let deadlineTimer;
2082
+ const deadline = Date.now() + 1e3;
2083
+ const run = (args, done) => {
2084
+ if (cancelled) return;
2085
+ const remaining = deadline - Date.now();
2086
+ if (remaining <= 0) {
2087
+ done(void 0);
2088
+ return;
2089
+ }
2090
+ try {
2091
+ active = execFile(
2092
+ "git",
2093
+ args,
2094
+ {
2095
+ cwd,
2096
+ encoding: "utf8",
2097
+ maxBuffer: 4096,
2098
+ windowsHide: true,
2099
+ env: {
2100
+ ...process.env,
2101
+ // The selected application cwd, not the invoking shell's Git plumbing, owns identity.
2102
+ GIT_DIR: void 0,
2103
+ GIT_WORK_TREE: void 0,
2104
+ GIT_COMMON_DIR: void 0,
2105
+ GIT_NAMESPACE: void 0,
2106
+ GIT_INDEX_FILE: void 0,
2107
+ GIT_OBJECT_DIRECTORY: void 0,
2108
+ GIT_ALTERNATE_OBJECT_DIRECTORIES: void 0,
2109
+ GIT_CONFIG_PARAMETERS: void 0,
2110
+ GIT_CONFIG_COUNT: "0",
2111
+ GIT_TERMINAL_PROMPT: "0",
2112
+ GIT_OPTIONAL_LOCKS: "0"
2113
+ }
2114
+ },
2115
+ (error, stdout) => {
2116
+ clearTimeout(deadlineTimer);
2117
+ deadlineTimer = void 0;
2118
+ active = void 0;
2119
+ if (!cancelled) {
2120
+ try {
2121
+ done(error ? void 0 : stdout.trim());
2122
+ } catch (e) {
2123
+ }
2124
+ }
2125
+ }
2126
+ );
2127
+ active.unref();
2128
+ if (active.stdout && "unref" in active.stdout && typeof active.stdout.unref === "function")
2129
+ active.stdout.unref();
2130
+ if (active.stderr && "unref" in active.stderr && typeof active.stderr.unref === "function")
2131
+ active.stderr.unref();
2132
+ deadlineTimer = setTimeout(() => {
2133
+ try {
2134
+ active == null ? void 0 : active.kill("SIGKILL");
2135
+ } catch (e) {
2136
+ }
2137
+ }, remaining);
2138
+ deadlineTimer.unref();
2139
+ } catch (e) {
2140
+ try {
2141
+ done(void 0);
2142
+ } catch (e2) {
2143
+ }
2144
+ }
2145
+ };
2146
+ const scheduled = setTimeout(() => {
2147
+ try {
2148
+ run(["rev-parse", "HEAD"], (rawSha) => {
2149
+ const commitSha = validAppCommitSha(rawSha);
2150
+ if (!commitSha) {
2151
+ completed({});
2152
+ return;
2153
+ }
2154
+ run(["-c", "core.fsmonitor=false", "status", "--porcelain"], (status) => {
2155
+ const finish = (branch) => {
2156
+ run(["rev-parse", "HEAD"], (finalSha) => {
2157
+ const coherent = validAppCommitSha(finalSha) === commitSha;
2158
+ completed({
2159
+ commitSha,
2160
+ ...coherent && status !== void 0 ? { commitDirty: status !== "" } : {},
2161
+ ...coherent && branch && branch !== "HEAD" ? { branch } : {}
2162
+ });
2163
+ });
2164
+ };
2165
+ if (detectBranch) run(["symbolic-ref", "--quiet", "--short", "HEAD"], finish);
2166
+ else finish();
2167
+ });
2168
+ });
2169
+ } catch (e) {
2170
+ completed({});
2171
+ }
2172
+ }, 0);
2173
+ scheduled.unref();
2174
+ return () => {
2175
+ cancelled = true;
2176
+ clearTimeout(scheduled);
2177
+ clearTimeout(deadlineTimer);
2178
+ try {
2179
+ active == null ? void 0 : active.kill("SIGKILL");
2180
+ } catch (e) {
2181
+ }
2182
+ };
2183
+ };
2184
+ function createAppGitContext2(options, runtime = {}) {
2185
+ return new AppGitContext(options, { ...runtime, resolveLocal });
2186
+ }
2187
+ function hasDestination(options) {
2188
+ var _a;
2189
+ if (options.enabled === false) return false;
2190
+ return Boolean(((_a = options.writeKey) == null ? void 0 : _a.trim()) || resolveLocalDebuggerBaseUrl(options.localDebuggerUrl));
2191
+ }
2192
+ var EventShipper2 = class extends EventShipper {
2193
+ constructor(options) {
2194
+ var _a;
2195
+ const ownsAppGitContext = options.appGitContext === void 0;
2196
+ const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
2197
+ try {
2198
+ super({ ...options, appGitContext });
2199
+ } catch (error) {
2200
+ if (ownsAppGitContext) appGitContext.dispose();
2201
+ throw error;
2202
+ }
2203
+ if (ownsAppGitContext) this.ownAppGitContextForShutdown();
2204
+ }
2205
+ };
2206
+ var TraceShipper2 = class extends TraceShipper {
2207
+ constructor(options) {
2208
+ var _a;
2209
+ const ownsAppGitContext = options.appGitContext === void 0;
2210
+ const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
2211
+ try {
2212
+ super({ ...options, appGitContext });
2213
+ } catch (error) {
2214
+ if (ownsAppGitContext) appGitContext.dispose();
2215
+ throw error;
2216
+ }
2217
+ this.ownsAppGitContext = ownsAppGitContext;
2218
+ }
2219
+ };
1372
2220
  globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = AsyncLocalStorage;
1373
2221
  var SUPPRESS_TRACING_KEY = /* @__PURE__ */ Symbol.for(
1374
2222
  "OpenTelemetry SDK Context Key SUPPRESS_TRACING"
@@ -1433,7 +2281,20 @@ function loadConfig(projectDirectory) {
1433
2281
  debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_g = merged.debug) != null ? _g : false,
1434
2282
  captureSystemPrompt: process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] !== void 0 ? process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] === "true" : (_h = merged.capture_system_prompt) != null ? _h : false,
1435
2283
  eventMetadata,
1436
- localWorkshopUrl: resolveLocalWorkshopUrl(merged.local_workshop_url)
2284
+ localWorkshopUrl: resolveLocalWorkshopUrl(merged.local_workshop_url),
2285
+ appGit: mapAppGit(merged.app_git)
2286
+ };
2287
+ }
2288
+ function mapAppGit(value) {
2289
+ if (value === false) return false;
2290
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
2291
+ return {
2292
+ commitSha: "commit_sha" in value && (typeof value.commit_sha === "string" || value.commit_sha === null) ? value.commit_sha : void 0,
2293
+ commitDirty: "commit_dirty" in value && (typeof value.commit_dirty === "boolean" || value.commit_dirty === null) ? value.commit_dirty : void 0,
2294
+ branch: "branch" in value && (typeof value.branch === "string" || value.branch === null) ? value.branch : void 0,
2295
+ detectBranch: "detect_branch" in value && typeof value.detect_branch === "boolean" ? value.detect_branch : void 0,
2296
+ sourceDirectory: "source_directory" in value && typeof value.source_directory === "string" ? value.source_directory : void 0,
2297
+ autoDetect: "auto_detect" in value && typeof value.auto_detect === "boolean" ? value.auto_detect : void 0
1437
2298
  };
1438
2299
  }
1439
2300
  function resolveLocalWorkshopUrl(fileValue) {
@@ -1450,7 +2311,7 @@ function resolveLocalWorkshopUrl(fileValue) {
1450
2311
  // package.json
1451
2312
  var package_default = {
1452
2313
  name: "@raindrop-ai/opencode-plugin",
1453
- version: "0.1.3",
2314
+ version: "0.1.4",
1454
2315
  description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
1455
2316
  type: "module",
1456
2317
  main: "dist/index.js",
@@ -1521,7 +2382,7 @@ var PLUGIN_NAME = package_default.name;
1521
2382
  var PLUGIN_VERSION = package_default.version;
1522
2383
 
1523
2384
  // src/shipper.ts
1524
- var EventShipper2 = class extends EventShipper {
2385
+ var EventShipper3 = class extends EventShipper2 {
1525
2386
  constructor(opts) {
1526
2387
  var _a, _b, _c, _d;
1527
2388
  super({
@@ -1533,7 +2394,7 @@ var EventShipper2 = class extends EventShipper {
1533
2394
  });
1534
2395
  }
1535
2396
  };
1536
- var TraceShipper2 = class extends TraceShipper {
2397
+ var TraceShipper3 = class extends TraceShipper2 {
1537
2398
  constructor(opts) {
1538
2399
  var _a, _b, _c;
1539
2400
  super({
@@ -1691,11 +2552,11 @@ function createSessionParentMapHelpers({
1691
2552
  }) {
1692
2553
  function applyChildSessionParentToState(childSessionId) {
1693
2554
  const parentInfo = mapChildSessionToParent2.get(childSessionId);
1694
- const state = sessions2.get(childSessionId);
1695
- if (!parentInfo || !state) return;
1696
- state.parentId = parentInfo.parentId;
1697
- state.parentTaskSpanIds = parentInfo.parentTaskSpanIds;
1698
- state.parentEventContext = parentInfo.eventContext;
2555
+ const state2 = sessions2.get(childSessionId);
2556
+ if (!parentInfo || !state2) return;
2557
+ state2.parentId = parentInfo.parentId;
2558
+ state2.parentTaskSpanIds = parentInfo.parentTaskSpanIds;
2559
+ state2.parentEventContext = parentInfo.eventContext;
1699
2560
  }
1700
2561
  function queuePendingChildByCallKey(key, childSessionId) {
1701
2562
  var _a;
@@ -1791,10 +2652,10 @@ function markTaskCallFinished(sessionID, callID) {
1791
2652
  running.delete(callID);
1792
2653
  if (running.size === 0) runningTaskCallsBySession.delete(sessionID);
1793
2654
  }
1794
- function endPendingToolSpanWithError(state, callID, tool, toolCallArgs, errorMessage, traceShipper) {
1795
- const startInfo = state.toolSpanStarts.get(callID);
2655
+ function endPendingToolSpanWithError(state2, callID, tool, toolCallArgs, errorMessage, traceShipper) {
2656
+ const startInfo = state2.toolSpanStarts.get(callID);
1796
2657
  if (!startInfo) return false;
1797
- state.toolSpanStarts.delete(callID);
2658
+ state2.toolSpanStarts.delete(callID);
1798
2659
  const error = new Error(errorMessage);
1799
2660
  const endAttrs = [
1800
2661
  attrString("ai.toolCall.args", toolCallArgs),
@@ -1894,17 +2755,17 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
1894
2755
  if (info == null || typeof info !== "object")
1895
2756
  throw new Error("session.created: props.info is required");
1896
2757
  const parentID = info["parentID"];
1897
- let state = sessions.get(sessionID);
1898
- if (!state) {
1899
- state = createSessionState(sessionID);
1900
- sessions.set(sessionID, state);
2758
+ let state2 = sessions.get(sessionID);
2759
+ if (!state2) {
2760
+ state2 = createSessionState(sessionID);
2761
+ sessions.set(sessionID, state2);
1901
2762
  }
1902
- state.parentId = parentID;
1903
- if (state.parentId) mapChildSessionToParent.set(sessionID, { parentId: state.parentId });
2763
+ state2.parentId = parentID;
2764
+ if (state2.parentId) mapChildSessionToParent.set(sessionID, { parentId: state2.parentId });
1904
2765
  } else if (event.type === "session.compacted") {
1905
- const state = sessions.get(String(sessionID));
1906
- if (!state) return;
1907
- state.isCompacting = true;
2766
+ const state2 = sessions.get(String(sessionID));
2767
+ if (!state2) return;
2768
+ state2.isCompacting = true;
1908
2769
  } else if (event.type === "message.part.updated") {
1909
2770
  const part = props["part"];
1910
2771
  if (part == null || typeof part !== "object")
@@ -1916,10 +2777,10 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
1916
2777
  throw new Error("message.part.updated: part.sessionID is required");
1917
2778
  if (messageId == null || messageId === "")
1918
2779
  throw new Error("message.part.updated: part.messageID is required");
1919
- const state = sessions.get(partSessionID);
1920
- if (!state) return;
2780
+ const state2 = sessions.get(partSessionID);
2781
+ if (!state2) return;
1921
2782
  if (partObj["type"] === "text" && typeof partObj["text"] === "string") {
1922
- state.outputParts.set(messageId, capText2(partObj["text"]));
2783
+ state2.outputParts.set(messageId, capText2(partObj["text"]));
1923
2784
  } else if (partObj["type"] === "tool" && messageId) {
1924
2785
  const tool = partObj["tool"];
1925
2786
  const callID = partObj["callID"];
@@ -1951,7 +2812,7 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
1951
2812
  const input = toolState["input"];
1952
2813
  const toolCallArgs = input === void 0 ? void 0 : typeof input === "string" ? capText2(input) : boundedStringify(input);
1953
2814
  if (endPendingToolSpanWithError(
1954
- state,
2815
+ state2,
1955
2816
  callID,
1956
2817
  tool,
1957
2818
  toolCallArgs,
@@ -1962,7 +2823,7 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
1962
2823
  }
1963
2824
  }
1964
2825
  } else if (partObj["type"] === "reasoning" && typeof partObj["text"] === "string") {
1965
- state.reasoningParts.set(messageId, capText2(partObj["text"]));
2826
+ state2.reasoningParts.set(messageId, capText2(partObj["text"]));
1966
2827
  }
1967
2828
  } else if (event.type === "message.updated") {
1968
2829
  const msgInfo = props["info"];
@@ -1982,10 +2843,10 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
1982
2843
  throw new Error("message.updated: info.time is required");
1983
2844
  const timeObj = time;
1984
2845
  if (timeObj["completed"] == null) return;
1985
- const state = sessions.get(msgSessionID);
1986
- if (!state || !state.currentEventId || !state.currentRootSpan) return;
1987
- if (state.processedMessages.has(messageId)) return;
1988
- state.processedMessages.add(messageId);
2846
+ const state2 = sessions.get(msgSessionID);
2847
+ if (!state2 || !state2.currentEventId || !state2.currentRootSpan) return;
2848
+ if (state2.processedMessages.has(messageId)) return;
2849
+ state2.processedMessages.add(messageId);
1989
2850
  const tokens = info2["tokens"];
1990
2851
  if (tokens == null || typeof tokens !== "object")
1991
2852
  throw new Error("message.updated: info.tokens is required");
@@ -2002,13 +2863,13 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
2002
2863
  );
2003
2864
  const modelName = `${providerID}/${modelID}`;
2004
2865
  const finishReason = info2["finish"];
2005
- const outputText = state.outputParts.get(messageId);
2006
- const reasoningText = state.reasoningParts.get(messageId);
2866
+ const outputText = state2.outputParts.get(messageId);
2867
+ const reasoningText = state2.reasoningParts.get(messageId);
2007
2868
  const isToolCallsCompletion = finishReason === "tool-calls";
2008
2869
  if (outputText !== void 0 && outputText.trim().length > 0) {
2009
- state.turnOutputParts.push(outputText);
2870
+ state2.turnOutputParts.push(outputText);
2010
2871
  }
2011
- state.turnOutputTokens += outputTokens;
2872
+ state2.turnOutputTokens += outputTokens;
2012
2873
  if (outputText === void 0 && !isToolCallsCompletion) return;
2013
2874
  const msgError = info2["error"];
2014
2875
  const errorForSpan = msgError ? (() => {
@@ -2028,17 +2889,17 @@ type: ${name != null ? name : "UnknownError"}`;
2028
2889
  attrString("ai.response.text", responseText),
2029
2890
  ...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
2030
2891
  ];
2031
- if (state.currentSystemPrompt) {
2892
+ if (state2.currentSystemPrompt) {
2032
2893
  llmAttrs.push(
2033
2894
  attrString("gen_ai.prompt.0.role", "system"),
2034
- attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
2895
+ attrString("gen_ai.prompt.0.content", state2.currentSystemPrompt)
2035
2896
  );
2036
2897
  }
2037
- const llmParent = state.parentId && state.parentTaskSpanIds ? state.parentTaskSpanIds : state.currentRootSpan.ids;
2898
+ const llmParent = state2.parentId && state2.parentTaskSpanIds ? state2.parentTaskSpanIds : state2.currentRootSpan.ids;
2038
2899
  const llmSpan = traceShipper.startSpan({
2039
2900
  name: modelName,
2040
2901
  parent: llmParent,
2041
- eventId: state.currentEventId,
2902
+ eventId: state2.currentEventId,
2042
2903
  attributes: llmAttrs
2043
2904
  });
2044
2905
  if (typeof timeObj["created"] === "number") {
@@ -2049,40 +2910,40 @@ type: ${name != null ? name : "UnknownError"}`;
2049
2910
  return;
2050
2911
  }
2051
2912
  if (outputText === void 0) return;
2052
- const turnOutputText = capText2(state.turnOutputParts.join("\n\n"));
2053
- const rootSpan = state.currentRootSpan;
2054
- const isCompaction = state.isCompacting === true;
2055
- if (state.parentId) {
2056
- const userInput = unwrapQuotes(state.currentInput);
2913
+ const turnOutputText = capText2(state2.turnOutputParts.join("\n\n"));
2914
+ const rootSpan = state2.currentRootSpan;
2915
+ const isCompaction = state2.isCompacting === true;
2916
+ if (state2.parentId) {
2917
+ const userInput = unwrapQuotes(state2.currentInput);
2057
2918
  const llmAttrs = [
2058
2919
  attrString("ai.operationId", "generateText"),
2059
2920
  attrString("ai.prompt", userInput),
2060
2921
  attrString(
2061
2922
  "ai.prompt.messages",
2062
- buildPromptMessages(state.currentSystemPrompt, state.currentInput)
2923
+ buildPromptMessages(state2.currentSystemPrompt, state2.currentInput)
2063
2924
  ),
2064
2925
  attrString("ai.response.text", turnOutputText),
2065
2926
  ...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
2066
2927
  ];
2067
- if (state.currentSystemPrompt) {
2928
+ if (state2.currentSystemPrompt) {
2068
2929
  llmAttrs.push(
2069
2930
  attrString("gen_ai.prompt.0.role", "system"),
2070
- attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
2931
+ attrString("gen_ai.prompt.0.content", state2.currentSystemPrompt)
2071
2932
  );
2072
2933
  }
2073
- if (!state.parentTaskSpanIds) {
2934
+ if (!state2.parentTaskSpanIds) {
2074
2935
  traceShipper.endSpan(rootSpan, {
2075
2936
  error: "Missing strict parent task for child session"
2076
2937
  });
2077
- state.currentRootSpan = void 0;
2078
- state.currentEventId = void 0;
2938
+ state2.currentRootSpan = void 0;
2939
+ state2.currentEventId = void 0;
2079
2940
  await traceShipper.flush();
2080
2941
  return;
2081
2942
  }
2082
2943
  const finalLlmSpan = traceShipper.startSpan({
2083
2944
  name: modelName,
2084
- parent: state.parentTaskSpanIds,
2085
- eventId: state.currentEventId,
2945
+ parent: state2.parentTaskSpanIds,
2946
+ eventId: state2.currentEventId,
2086
2947
  attributes: llmAttrs
2087
2948
  });
2088
2949
  if (typeof timeObj["created"] === "number") {
@@ -2092,19 +2953,19 @@ type: ${name != null ? name : "UnknownError"}`;
2092
2953
  traceShipper.endSpan(rootSpan, {
2093
2954
  attributes: [
2094
2955
  attrString("is_subagent", "true"),
2095
- attrString("parent_session_id", state.parentId)
2956
+ attrString("parent_session_id", state2.parentId)
2096
2957
  ],
2097
2958
  error: errorForSpan
2098
2959
  });
2099
2960
  } else {
2100
2961
  rootSpan.name = isCompaction ? "ai.compaction" : modelName;
2101
- const userInput = unwrapQuotes(state.currentInput);
2962
+ const userInput = unwrapQuotes(state2.currentInput);
2102
2963
  const rootAttrs = [
2103
2964
  attrString("ai.operationId", "generateText"),
2104
2965
  attrString("ai.prompt", userInput),
2105
2966
  attrString(
2106
2967
  "ai.prompt.messages",
2107
- buildPromptMessages(state.currentSystemPrompt, state.currentInput)
2968
+ buildPromptMessages(state2.currentSystemPrompt, state2.currentInput)
2108
2969
  ),
2109
2970
  attrString("ai.response.text", turnOutputText),
2110
2971
  ...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
@@ -2113,10 +2974,10 @@ type: ${name != null ? name : "UnknownError"}`;
2113
2974
  rootAttrs.push(attrString("is_compaction", "true"));
2114
2975
  }
2115
2976
  rootAttrs.push(attrString("message_id", messageId));
2116
- if (state.currentSystemPrompt) {
2977
+ if (state2.currentSystemPrompt) {
2117
2978
  rootAttrs.push(
2118
2979
  attrString("gen_ai.prompt.0.role", "system"),
2119
- attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
2980
+ attrString("gen_ai.prompt.0.content", state2.currentSystemPrompt)
2120
2981
  );
2121
2982
  }
2122
2983
  traceShipper.endSpan(rootSpan, {
@@ -2124,24 +2985,24 @@ type: ${name != null ? name : "UnknownError"}`;
2124
2985
  error: errorForSpan
2125
2986
  });
2126
2987
  if (isCompaction) {
2127
- state.isCompacting = false;
2988
+ state2.isCompacting = false;
2128
2989
  }
2129
2990
  }
2130
- state.currentRootSpan = void 0;
2991
+ state2.currentRootSpan = void 0;
2131
2992
  const hasAssistantResponse = turnOutputText.trim().length > 0;
2132
2993
  if (!hasAssistantResponse && !msgError) {
2133
2994
  await traceShipper.flush();
2134
- state.currentEventId = void 0;
2995
+ state2.currentEventId = void 0;
2135
2996
  return;
2136
2997
  }
2137
- if (!state.parentId) {
2138
- await eventShipper.finish(state.currentEventId, {
2139
- userId: (_d = (_c = state.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state.sessionId,
2998
+ if (!state2.parentId) {
2999
+ await eventShipper.finish(state2.currentEventId, {
3000
+ userId: (_d = (_c = state2.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state2.sessionId,
2140
3001
  model: modelID,
2141
3002
  output: msgError ? void 0 : turnOutputText,
2142
3003
  usage: {
2143
3004
  promptTokens: inputTokens,
2144
- completionTokens: state.turnOutputTokens
3005
+ completionTokens: state2.turnOutputTokens
2145
3006
  },
2146
3007
  error: msgError ? {
2147
3008
  name: msgError.name,
@@ -2156,35 +3017,35 @@ type: ${name != null ? name : "UnknownError"}`;
2156
3017
  });
2157
3018
  }
2158
3019
  await traceShipper.flush();
2159
- state.currentEventId = void 0;
3020
+ state2.currentEventId = void 0;
2160
3021
  } else if (event.type === "session.idle") {
2161
3022
  if (!sessionID) return;
2162
- const state = sessions.get(String(sessionID));
2163
- if (!state) return;
2164
- if (state.currentRootSpan) {
2165
- traceShipper.endSpan(state.currentRootSpan);
2166
- state.currentRootSpan = void 0;
3023
+ const state2 = sessions.get(String(sessionID));
3024
+ if (!state2) return;
3025
+ if (state2.currentRootSpan) {
3026
+ traceShipper.endSpan(state2.currentRootSpan);
3027
+ state2.currentRootSpan = void 0;
2167
3028
  }
2168
- if (state.currentEventId) {
2169
- state.currentEventId = void 0;
3029
+ if (state2.currentEventId) {
3030
+ state2.currentEventId = void 0;
2170
3031
  }
2171
- state.isCompacting = false;
3032
+ state2.isCompacting = false;
2172
3033
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
2173
- if (state.parentId) {
3034
+ if (state2.parentId) {
2174
3035
  cleanupSessionParentMap(String(sessionID));
2175
3036
  sessions.delete(String(sessionID));
2176
3037
  } else {
2177
3038
  }
2178
3039
  } else if (event.type === "session.deleted") {
2179
3040
  if (!sessionID) return;
2180
- const state = sessions.get(String(sessionID));
2181
- if (!state) return;
2182
- if (state.currentRootSpan) {
2183
- traceShipper.endSpan(state.currentRootSpan);
2184
- state.currentRootSpan = void 0;
3041
+ const state2 = sessions.get(String(sessionID));
3042
+ if (!state2) return;
3043
+ if (state2.currentRootSpan) {
3044
+ traceShipper.endSpan(state2.currentRootSpan);
3045
+ state2.currentRootSpan = void 0;
2185
3046
  }
2186
- if (state.currentEventId) {
2187
- state.currentEventId = void 0;
3047
+ if (state2.currentEventId) {
3048
+ state2.currentEventId = void 0;
2188
3049
  }
2189
3050
  cleanupSessionParentMap(String(sessionID));
2190
3051
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
@@ -2193,8 +3054,8 @@ type: ${name != null ? name : "UnknownError"}`;
2193
3054
  const errorSessionID = (_h = props["sessionID"]) != null ? _h : sessionID;
2194
3055
  if (errorSessionID === void 0 || errorSessionID === "")
2195
3056
  throw new Error("session.error: missing sessionID");
2196
- const state = sessions.get(String(errorSessionID));
2197
- if (!state) return;
3057
+ const state2 = sessions.get(String(errorSessionID));
3058
+ if (!state2) return;
2198
3059
  const errorObj = props["error"];
2199
3060
  if (errorObj == null) throw new Error("session.error: missing error object");
2200
3061
  const errorName = errorObj.name;
@@ -2204,12 +3065,12 @@ type: ${name != null ? name : "UnknownError"}`;
2204
3065
  const errorStr = `${errorMessage != null ? errorMessage : errorName}
2205
3066
 
2206
3067
  type: ${errorName != null ? errorName : "UnknownError"}`;
2207
- if (state.currentRootSpan) {
2208
- traceShipper.endSpan(state.currentRootSpan, { error: errorStr });
2209
- state.currentRootSpan = void 0;
3068
+ if (state2.currentRootSpan) {
3069
+ traceShipper.endSpan(state2.currentRootSpan, { error: errorStr });
3070
+ state2.currentRootSpan = void 0;
2210
3071
  }
2211
- if (state.currentEventId) {
2212
- state.currentEventId = void 0;
3072
+ if (state2.currentEventId) {
3073
+ state2.currentEventId = void 0;
2213
3074
  }
2214
3075
  cleanupSessionParentMap(String(errorSessionID));
2215
3076
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
@@ -2229,15 +3090,15 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2229
3090
  var _a, _b, _c, _d, _e, _f, _g;
2230
3091
  try {
2231
3092
  const { sessionID } = messageInput;
2232
- let state = sessions.get(sessionID);
2233
- if (!state) {
2234
- state = createSessionState(sessionID);
2235
- sessions.set(sessionID, state);
3093
+ let state2 = sessions.get(sessionID);
3094
+ if (!state2) {
3095
+ state2 = createSessionState(sessionID);
3096
+ sessions.set(sessionID, state2);
2236
3097
  }
2237
3098
  applyChildSessionParentToState(sessionID);
2238
- if (state.currentRootSpan) {
2239
- traceShipper.endSpan(state.currentRootSpan);
2240
- state.currentRootSpan = void 0;
3099
+ if (state2.currentRootSpan) {
3100
+ traceShipper.endSpan(state2.currentRootSpan);
3101
+ state2.currentRootSpan = void 0;
2241
3102
  }
2242
3103
  if (output == null) throw new Error("chat.message: output is required");
2243
3104
  const parts = output.parts;
@@ -2268,39 +3129,39 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2268
3129
  }
2269
3130
  }
2270
3131
  }
2271
- state.eventMetadata = {
3132
+ state2.eventMetadata = {
2272
3133
  ...baseMeta,
2273
3134
  ...promptMeta,
2274
3135
  properties: baseMeta.properties || promptMeta.properties ? { ...(_a = baseMeta.properties) != null ? _a : {}, ...(_b = promptMeta.properties) != null ? _b : {} } : void 0
2275
3136
  };
2276
3137
  const userText = capText2(textParts.join("\n"));
2277
- state.currentInput = userText;
2278
- state.turnOutputParts = [];
2279
- state.turnOutputTokens = 0;
2280
- if (state.parentId) {
2281
- if (!state.parentTaskSpanIds || !state.parentEventContext) {
3138
+ state2.currentInput = userText;
3139
+ state2.turnOutputParts = [];
3140
+ state2.turnOutputTokens = 0;
3141
+ if (state2.parentId) {
3142
+ if (!state2.parentTaskSpanIds || !state2.parentEventContext) {
2282
3143
  return;
2283
3144
  }
2284
- state.currentEventId = state.parentEventContext.eventId;
2285
- state.currentRootSpan = traceShipper.startSpan({
3145
+ state2.currentEventId = state2.parentEventContext.eventId;
3146
+ state2.currentRootSpan = traceShipper.startSpan({
2286
3147
  name: "Subagent",
2287
- parent: state.parentTaskSpanIds,
2288
- eventId: state.currentEventId,
3148
+ parent: state2.parentTaskSpanIds,
3149
+ eventId: state2.currentEventId,
2289
3150
  attributes: [
2290
3151
  attrString("workspace", worktree),
2291
3152
  attrString("directory", directory),
2292
3153
  attrString("hostname", hostname),
2293
3154
  attrString("os", os),
2294
3155
  attrString("is_subagent", "true"),
2295
- attrString("parent_session_id", state.parentId)
3156
+ attrString("parent_session_id", state2.parentId)
2296
3157
  ]
2297
3158
  });
2298
3159
  return;
2299
3160
  }
2300
- state.currentEventId = generateId();
2301
- state.currentRootSpan = traceShipper.startSpan({
2302
- name: state.isCompacting ? "ai.compaction" : "ai.event",
2303
- eventId: state.currentEventId,
3161
+ state2.currentEventId = generateId();
3162
+ state2.currentRootSpan = traceShipper.startSpan({
3163
+ name: state2.isCompacting ? "ai.compaction" : "ai.event",
3164
+ eventId: state2.currentEventId,
2304
3165
  attributes: [
2305
3166
  attrString("workspace", worktree),
2306
3167
  attrString("directory", directory),
@@ -2308,11 +3169,11 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2308
3169
  attrString("os", os)
2309
3170
  ]
2310
3171
  });
2311
- await eventShipper.patch(state.currentEventId, {
3172
+ await eventShipper.patch(state2.currentEventId, {
2312
3173
  isPending: true,
2313
- userId: (_d = (_c = state.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state.sessionId,
2314
- convoId: state.sessionId,
2315
- eventName: (_f = (_e = state.eventMetadata) == null ? void 0 : _e.eventName) != null ? _f : config.eventName,
3174
+ userId: (_d = (_c = state2.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state2.sessionId,
3175
+ convoId: state2.sessionId,
3176
+ eventName: (_f = (_e = state2.eventMetadata) == null ? void 0 : _e.eventName) != null ? _f : config.eventName,
2316
3177
  input: userText,
2317
3178
  ...newAttachments.length > 0 ? { attachments: newAttachments } : {},
2318
3179
  properties: {
@@ -2321,7 +3182,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2321
3182
  hostname,
2322
3183
  os,
2323
3184
  plugin_version: PLUGIN_VERSION,
2324
- ...(_g = state.eventMetadata) == null ? void 0 : _g.properties
3185
+ ...(_g = state2.eventMetadata) == null ? void 0 : _g.properties
2325
3186
  }
2326
3187
  });
2327
3188
  } catch (err) {
@@ -2335,16 +3196,16 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2335
3196
  var _a, _b, _c;
2336
3197
  try {
2337
3198
  const { tool, sessionID, callID } = toolInput;
2338
- const state = sessions.get(sessionID);
2339
- if (!state || !state.currentEventId) return;
2340
- const spanParent = state.parentId && state.parentTaskSpanIds ? state.parentTaskSpanIds : (_a = state.currentRootSpan) == null ? void 0 : _a.ids;
3199
+ const state2 = sessions.get(sessionID);
3200
+ if (!state2 || !state2.currentEventId) return;
3201
+ const spanParent = state2.parentId && state2.parentTaskSpanIds ? state2.parentTaskSpanIds : (_a = state2.currentRootSpan) == null ? void 0 : _a.ids;
2341
3202
  if (!spanParent) return;
2342
3203
  const startTimeUnixNano = nowUnixNanoString();
2343
3204
  if (tool === "task") {
2344
3205
  const liveTaskSpan = traceShipper.startSpan({
2345
3206
  name: "ai.toolCall",
2346
3207
  parent: spanParent,
2347
- eventId: state.currentEventId,
3208
+ eventId: state2.currentEventId,
2348
3209
  attributes: [
2349
3210
  attrString("ai.operationId", "ai.toolCall"),
2350
3211
  attrString("ai.toolCall.name", tool),
@@ -2355,9 +3216,9 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2355
3216
  const ctx = {
2356
3217
  ids: liveTaskSpan.ids,
2357
3218
  eventContext: {
2358
- eventId: state.currentEventId,
2359
- userId: (_c = (_b = state.eventMetadata) == null ? void 0 : _b.userId) != null ? _c : state.sessionId,
2360
- convoId: state.sessionId
3219
+ eventId: state2.currentEventId,
3220
+ userId: (_c = (_b = state2.eventMetadata) == null ? void 0 : _b.userId) != null ? _c : state2.sessionId,
3221
+ convoId: state2.sessionId
2361
3222
  }
2362
3223
  };
2363
3224
  taskContexts.set(callKey(sessionID, callID), ctx);
@@ -2368,18 +3229,18 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2368
3229
  }
2369
3230
  running.add(callID);
2370
3231
  resolvePendingChildrenForCall(sessionID, callID, "tool.execute.before");
2371
- state.toolSpanStarts.set(callID, {
3232
+ state2.toolSpanStarts.set(callID, {
2372
3233
  startTimeUnixNano,
2373
3234
  parent: spanParent,
2374
- eventId: state.currentEventId,
3235
+ eventId: state2.currentEventId,
2375
3236
  name: tool,
2376
3237
  liveSpan: liveTaskSpan
2377
3238
  });
2378
3239
  } else {
2379
- state.toolSpanStarts.set(callID, {
3240
+ state2.toolSpanStarts.set(callID, {
2380
3241
  startTimeUnixNano,
2381
3242
  parent: spanParent,
2382
- eventId: state.currentEventId,
3243
+ eventId: state2.currentEventId,
2383
3244
  name: tool
2384
3245
  });
2385
3246
  }
@@ -2396,13 +3257,13 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2396
3257
  "tool.execute.after": async (toolInput, result) => {
2397
3258
  try {
2398
3259
  const { tool, sessionID, callID, args } = toolInput;
2399
- const state = sessions.get(sessionID);
2400
- if (!state || !state.currentEventId) return;
3260
+ const state2 = sessions.get(sessionID);
3261
+ if (!state2 || !state2.currentEventId) return;
2401
3262
  if (args === void 0 || args === null)
2402
3263
  throw new Error("tool.execute.after: args is required");
2403
3264
  const toolCallArgs = typeof args === "string" ? capText2(args) : boundedStringify(args);
2404
- const startInfo = state.toolSpanStarts.get(callID);
2405
- state.toolSpanStarts.delete(callID);
3265
+ const startInfo = state2.toolSpanStarts.get(callID);
3266
+ state2.toolSpanStarts.delete(callID);
2406
3267
  const resultMetadata = result.metadata;
2407
3268
  const childSessionId = resultMetadata == null ? void 0 : resultMetadata["sessionId"];
2408
3269
  if (tool === "task" && childSessionId) {
@@ -2455,9 +3316,9 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2455
3316
  try {
2456
3317
  const sessionID = input.sessionID;
2457
3318
  if (!sessionID) return;
2458
- const state = sessions.get(sessionID);
2459
- if (state) {
2460
- state.isCompacting = true;
3319
+ const state2 = sessions.get(sessionID);
3320
+ if (state2) {
3321
+ state2.isCompacting = true;
2461
3322
  }
2462
3323
  } catch (err) {
2463
3324
  rateLimitedErrorLog(
@@ -2474,15 +3335,15 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2474
3335
  if (!config.captureSystemPrompt) return;
2475
3336
  const sessionID = input.sessionID;
2476
3337
  if (!sessionID) return;
2477
- let state = sessions.get(sessionID);
2478
- if (!state) {
2479
- state = createSessionState(sessionID);
2480
- sessions.set(sessionID, state);
3338
+ let state2 = sessions.get(sessionID);
3339
+ if (!state2) {
3340
+ state2 = createSessionState(sessionID);
3341
+ sessions.set(sessionID, state2);
2481
3342
  }
2482
3343
  const MAX_SYSTEM_PROMPT_LENGTH = 32768;
2483
3344
  const TRUNCATION_MARKER3 = "\n...[truncated]";
2484
3345
  const joined = output.system.join("\n\n");
2485
- state.currentSystemPrompt = joined.length > MAX_SYSTEM_PROMPT_LENGTH ? joined.slice(0, MAX_SYSTEM_PROMPT_LENGTH - TRUNCATION_MARKER3.length) + TRUNCATION_MARKER3 : joined;
3346
+ state2.currentSystemPrompt = joined.length > MAX_SYSTEM_PROMPT_LENGTH ? joined.slice(0, MAX_SYSTEM_PROMPT_LENGTH - TRUNCATION_MARKER3.length) + TRUNCATION_MARKER3 : joined;
2486
3347
  } catch (err) {
2487
3348
  rateLimitedErrorLog(
2488
3349
  "experimental.chat.system.transform",
@@ -2494,7 +3355,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
2494
3355
  }
2495
3356
 
2496
3357
  // src/index.ts
2497
- function createRaindropHandle(eventShipper, traceShipper) {
3358
+ function createRaindropHandle(eventShipper, traceShipper, appGitContext) {
2498
3359
  return {
2499
3360
  users: {
2500
3361
  async identify(users) {
@@ -2505,12 +3366,19 @@ function createRaindropHandle(eventShipper, traceShipper) {
2505
3366
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
2506
3367
  },
2507
3368
  async shutdown() {
2508
- await Promise.all([eventShipper.shutdown(), traceShipper.shutdown()]);
3369
+ try {
3370
+ await Promise.all([eventShipper.shutdown(), traceShipper.shutdown()]);
3371
+ } finally {
3372
+ try {
3373
+ appGitContext.dispose();
3374
+ } catch (e) {
3375
+ }
3376
+ }
2509
3377
  }
2510
3378
  };
2511
3379
  }
2512
- async function plugin(input) {
2513
- var _a;
3380
+ async function plugin(input, opts = {}) {
3381
+ var _a, _b, _c;
2514
3382
  const config = loadConfig(input.directory);
2515
3383
  function appLog(level, message) {
2516
3384
  console.log(`[raindrop-ai/opencode-plugin] [${level}] ${message}`);
@@ -2532,21 +3400,28 @@ async function plugin(input) {
2532
3400
  ].filter(Boolean);
2533
3401
  appLog("info", `Raindrop tracing enabled \u2014 destinations: ${destinations.join(", ")}`);
2534
3402
  }
2535
- const eventShipper = new EventShipper2({
3403
+ const configuredAppGit = (_a = opts.appGit) != null ? _a : config.appGit;
3404
+ const appGitContext = createAppGitContext2(
3405
+ ((_b = config.writeKey) == null ? void 0 : _b.trim()) || hasLocalDestination ? configuredAppGit : false,
3406
+ { allowLocalGit: false }
3407
+ );
3408
+ const eventShipper = new EventShipper3({
2536
3409
  writeKey: config.writeKey,
2537
3410
  endpoint: config.endpoint,
2538
3411
  debug: config.debug,
2539
3412
  projectId: config.projectId,
2540
- localDebuggerUrl: config.localWorkshopUrl
3413
+ localDebuggerUrl: config.localWorkshopUrl,
3414
+ appGitContext
2541
3415
  });
2542
- const traceShipper = new TraceShipper2({
3416
+ const traceShipper = new TraceShipper3({
2543
3417
  writeKey: config.writeKey,
2544
3418
  endpoint: config.endpoint,
2545
3419
  debug: config.debug,
2546
3420
  projectId: config.projectId,
2547
- localDebuggerUrl: config.localWorkshopUrl
3421
+ localDebuggerUrl: config.localWorkshopUrl,
3422
+ appGitContext
2548
3423
  });
2549
- const worktree = (_a = input.worktree) != null ? _a : input.directory;
3424
+ const worktree = (_c = input.worktree) != null ? _c : input.directory;
2550
3425
  const hooks = createHooks(
2551
3426
  config,
2552
3427
  worktree,
@@ -2554,7 +3429,7 @@ async function plugin(input) {
2554
3429
  eventShipper,
2555
3430
  traceShipper
2556
3431
  );
2557
- return { ...hooks, raindrop: createRaindropHandle(eventShipper, traceShipper) };
3432
+ return { ...hooks, raindrop: createRaindropHandle(eventShipper, traceShipper, appGitContext) };
2558
3433
  }
2559
3434
  export {
2560
3435
  plugin as default