@pinta-ai/pinta-opencode 0.5.0 → 0.7.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.0
4
+
5
+ - Telemetry now names each tool span by the opencode hook it arrived on
6
+ (`opencode.hook` = `tool.execute.before` / `tool.execute.after` / `event`) —
7
+ the same string the guard leg already sends as `method` — and reports
8
+ `opencode.cwd`, which the guard leg already sent and this leg never did.
9
+
10
+ Before this, the two halves of one tool call described it differently
11
+ (`kind: "tool.before"` vs `method: "tool.execute.before"`) and the ingest
12
+ parser dropped **every** span this plugin emitted, so opencode activity was
13
+ guarded but never recorded. The parser side was widened first
14
+ (`@pinta-ai/guard-runtime` 0.27.0) so already-installed copies of this plugin
15
+ are recorded too; this release makes new installs speak the aligned names
16
+ from the start.
17
+
18
+ Tool fields follow the same vocabulary as the other adapters:
19
+ `tool_name` / `tool_input` / `tool_response` / `tool_use_id`. Nothing is sent
20
+ under two names — the parser accepts the old spelling on behalf of installed
21
+ copies, and a field carried twice is a field whose copies can disagree.
22
+
23
+ The redaction policy tracks the renamed keys, so shell secrets in
24
+ `tool_input` / `tool_response` are still masked.
25
+
26
+ ## 0.5.1
27
+
28
+ - Bump `@pinta-ai/core` `^0.3.0` → `^0.5.0` (devDependency, bundled
29
+ into `dist/` at build). Pulls in the oversized-flush fix (pinta-manager#180
30
+ follow-up): the in-memory retry buffer now flushes in 900 KiB chunks instead
31
+ of one unbounded POST, spans are capped at 800 KiB at build time, and a
32
+ payload that alone exceeds the POST budget is dropped with a diagnostic
33
+ instead of poisoning every later flush. No adapter source change was needed.
34
+
3
35
  ## 0.4.0
4
36
 
5
37
  - Consolidate the duplicated low-level utilities (`guard`, `otlp`, `redact`,
package/dist/index.mjs CHANGED
@@ -37,19 +37,23 @@ var require_redact = __commonJS({
37
37
  "use strict";
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.PATTERNS = exports.MAX_BYTES = void 0;
40
+ exports.truncateTo = truncateTo;
40
41
  exports.truncate = truncate;
41
42
  exports.collectMatches = collectMatches;
42
43
  exports.resolveOverlaps = resolveOverlaps;
43
44
  exports.applyMatches = applyMatches;
44
45
  exports.redact = redact;
45
46
  exports.MAX_BYTES = 102400;
46
- function truncate(input) {
47
+ function truncateTo(input, maxBytes) {
47
48
  const buf = Buffer.from(input, "utf-8");
48
- if (buf.length <= exports.MAX_BYTES)
49
+ if (buf.length <= maxBytes)
49
50
  return input;
50
- const head = buf.subarray(0, exports.MAX_BYTES).toString("utf-8");
51
+ const head = buf.subarray(0, Math.max(0, maxBytes)).toString("utf-8");
51
52
  return `${head}\u2026[TRUNCATED:${buf.length}]`;
52
53
  }
54
+ function truncate(input) {
55
+ return truncateTo(input, exports.MAX_BYTES);
56
+ }
53
57
  exports.PATTERNS = [
54
58
  { type: "aws_access_key", regex: /AKIA[0-9A-Z]{16}/g },
55
59
  {
@@ -175,6 +179,7 @@ var require_otlp = __commonJS({
175
179
  return mod && mod.__esModule ? mod : { "default": mod };
176
180
  };
177
181
  Object.defineProperty(exports, "__esModule", { value: true });
182
+ exports.MAX_SPAN_BYTES = void 0;
178
183
  exports.ulidToTraceId = ulidToTraceId2;
179
184
  exports.newSpanId = newSpanId;
180
185
  exports.snakeCase = snakeCase;
@@ -182,6 +187,7 @@ var require_otlp = __commonJS({
182
187
  exports.attrsFromRecord = attrsFromRecord2;
183
188
  exports.guardAttrs = guardAttrs;
184
189
  exports.clientAttrs = clientAttrs;
190
+ exports.enforceSpanBudget = enforceSpanBudget;
185
191
  exports.buildPayload = buildPayload2;
186
192
  exports.mergeBatch = mergeBatch2;
187
193
  var crypto_1 = __importDefault(__require("crypto"));
@@ -271,6 +277,35 @@ var require_otlp = __commonJS({
271
277
  { key: "pinta.client.op", value: { stringValue: timing.op } }
272
278
  ];
273
279
  }
280
+ exports.MAX_SPAN_BYTES = 800 * 1024;
281
+ function byteLen(value) {
282
+ const json = JSON.stringify(value);
283
+ return json === void 0 ? 0 : Buffer.byteLength(json, "utf-8");
284
+ }
285
+ var MIN_ATTR_KEEP_BYTES = 1024;
286
+ function enforceSpanBudget(span, maxBytes = exports.MAX_SPAN_BYTES) {
287
+ let size = byteLen(span);
288
+ for (let pass = 0; pass < 100 && size > maxBytes; pass++) {
289
+ let largestValue = null;
290
+ let largest = 0;
291
+ for (const attr of span.attributes) {
292
+ if (!("stringValue" in attr.value))
293
+ continue;
294
+ const bytes = Buffer.byteLength(attr.value.stringValue, "utf-8");
295
+ if (bytes > largest) {
296
+ largest = bytes;
297
+ largestValue = attr.value;
298
+ }
299
+ }
300
+ if (largestValue === null || largest <= MIN_ATTR_KEEP_BYTES)
301
+ break;
302
+ const overshoot = size - maxBytes;
303
+ const target = Math.max(MIN_ATTR_KEEP_BYTES, largest - overshoot - 64);
304
+ largestValue.stringValue = (0, redact_js_1.truncateTo)(largestValue.stringValue, target);
305
+ size = byteLen(span);
306
+ }
307
+ return span;
308
+ }
274
309
  function buildPayload2(args) {
275
310
  const ts = args.now ?? Date.now();
276
311
  const tsNano = (BigInt(ts) * 1000000n).toString();
@@ -289,6 +324,7 @@ var require_otlp = __commonJS({
289
324
  endTimeUnixNano: tsNano,
290
325
  attributes: attrs
291
326
  };
327
+ enforceSpanBudget(span);
292
328
  return {
293
329
  resourceSpans: [
294
330
  {
@@ -325,13 +361,7 @@ var require_guard = __commonJS({
325
361
  failOpenReason
326
362
  };
327
363
  }
328
- function sleep2(ms) {
329
- return new Promise((_, reject) => setTimeout(() => {
330
- const err = new Error("Guard request timed out");
331
- err.name = "TimeoutError";
332
- reject(err);
333
- }, ms));
334
- }
364
+ var VALID_DECISIONS = /* @__PURE__ */ new Set(["ALLOW", "DENY", "REVIEW"]);
335
365
  async function evaluateGuard2(input, endpoint, opts = {}) {
336
366
  if (!endpoint)
337
367
  return null;
@@ -339,39 +369,64 @@ var require_guard = __commonJS({
339
369
  return null;
340
370
  const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
341
371
  const start = Date.now();
372
+ const controller = new AbortController();
373
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
342
374
  try {
343
- const res = await Promise.race([
344
- fetch(endpoint, {
345
- method: "POST",
346
- headers: {
347
- "content-type": "application/json",
348
- "user-agent": opts.userAgent ?? DEFAULT_UA,
349
- "x-pinta-relay-token": opts.token ?? ""
350
- },
351
- body: JSON.stringify({ input })
352
- }),
353
- sleep2(timeoutMs)
354
- ]);
375
+ const res = await fetch(endpoint, {
376
+ method: "POST",
377
+ headers: {
378
+ "content-type": "application/json",
379
+ "user-agent": opts.userAgent ?? DEFAULT_UA,
380
+ "x-pinta-relay-token": opts.token ?? ""
381
+ },
382
+ body: JSON.stringify({ input }),
383
+ signal: controller.signal
384
+ });
355
385
  if (res.status !== 200) {
356
386
  return failOpen2(Date.now() - start, "error");
357
387
  }
358
388
  const body = await res.json();
389
+ const durationMsOk = body?.durationMs === void 0 || typeof body.durationMs === "number" && Number.isFinite(body.durationMs);
390
+ if (!body || !VALID_DECISIONS.has(body.decision) || !durationMsOk) {
391
+ return failOpen2(Date.now() - start, "error");
392
+ }
359
393
  const clientRttMs = Date.now() - start;
360
394
  return {
361
395
  decision: body.decision,
362
- reason: body.reason,
396
+ reason: body.reason ?? null,
363
397
  userMessage: body.userMessage ?? null,
364
398
  durationMs: body.durationMs ?? clientRttMs,
365
399
  clientRttMs
366
400
  };
367
401
  } catch (err) {
368
- const reason = err.name === "TimeoutError" ? "timeout" : "error";
402
+ const name = err.name;
403
+ const reason = name === "AbortError" || name === "TimeoutError" ? "timeout" : "error";
369
404
  return failOpen2(Date.now() - start, reason);
405
+ } finally {
406
+ clearTimeout(timer);
370
407
  }
371
408
  }
372
409
  }
373
410
  });
374
411
 
412
+ // node_modules/@pinta-ai/core/dist/atomic-write.js
413
+ var require_atomic_write = __commonJS({
414
+ "node_modules/@pinta-ai/core/dist/atomic-write.js"(exports) {
415
+ "use strict";
416
+ var __importDefault = exports && exports.__importDefault || function(mod) {
417
+ return mod && mod.__esModule ? mod : { "default": mod };
418
+ };
419
+ Object.defineProperty(exports, "__esModule", { value: true });
420
+ exports.atomicWriteFileSync = atomicWriteFileSync;
421
+ var fs_1 = __importDefault(__require("fs"));
422
+ function atomicWriteFileSync(finalPath, data) {
423
+ const tmpPath = `${finalPath}.${process.pid}.tmp`;
424
+ fs_1.default.writeFileSync(tmpPath, data);
425
+ fs_1.default.renameSync(tmpPath, finalPath);
426
+ }
427
+ }
428
+ });
429
+
375
430
  // node_modules/@pinta-ai/core/dist/retry-queue.js
376
431
  var require_retry_queue = __commonJS({
377
432
  "node_modules/@pinta-ai/core/dist/retry-queue.js"(exports) {
@@ -383,6 +438,7 @@ var require_retry_queue = __commonJS({
383
438
  exports.MemoryRetryQueue = exports.DiskRetryQueue = void 0;
384
439
  var fs_1 = __importDefault(__require("fs"));
385
440
  var path_1 = __importDefault(__require("path"));
441
+ var atomic_write_js_1 = require_atomic_write();
386
442
  var MAX_ENTRIES = 1e3;
387
443
  var LOCK_TIMEOUT_MS = 50;
388
444
  var LOCK_POLL_MS = 5;
@@ -419,7 +475,10 @@ var require_retry_queue = __commonJS({
419
475
  if (!line.trim())
420
476
  continue;
421
477
  try {
422
- out.push(JSON.parse(line));
478
+ const parsed = JSON.parse(line);
479
+ if (Array.isArray(parsed?.payload?.resourceSpans)) {
480
+ out.push(parsed);
481
+ }
423
482
  } catch {
424
483
  }
425
484
  }
@@ -437,7 +496,7 @@ var require_retry_queue = __commonJS({
437
496
  return;
438
497
  }
439
498
  fs_1.default.mkdirSync(path_1.default.dirname(this.filePath), { recursive: true });
440
- fs_1.default.writeFileSync(this.filePath, entries.map((e) => JSON.stringify(e)).join("\n") + "\n");
499
+ (0, atomic_write_js_1.atomicWriteFileSync)(this.filePath, entries.map((e) => JSON.stringify(e)).join("\n") + "\n");
441
500
  } catch (err) {
442
501
  process.stderr.write(`[${this.logPrefix}] retry-queue rewrite failed: ${err}
443
502
  `);
@@ -449,7 +508,13 @@ var require_retry_queue = __commonJS({
449
508
  */
450
509
  tryAcquireLock() {
451
510
  const start = Date.now();
452
- fs_1.default.mkdirSync(path_1.default.dirname(this.lockPath), { recursive: true });
511
+ try {
512
+ fs_1.default.mkdirSync(path_1.default.dirname(this.lockPath), { recursive: true });
513
+ } catch (err) {
514
+ process.stderr.write(`[${this.logPrefix}] retry-queue lock mkdir failed: ${err}
515
+ `);
516
+ return false;
517
+ }
453
518
  while (Date.now() - start < LOCK_TIMEOUT_MS) {
454
519
  try {
455
520
  const fd = fs_1.default.openSync(this.lockPath, "wx");
@@ -522,13 +587,41 @@ var require_transport = __commonJS({
522
587
  "node_modules/@pinta-ai/core/dist/transport.js"(exports) {
523
588
  "use strict";
524
589
  Object.defineProperty(exports, "__esModule", { value: true });
525
- exports.MemoryTransport = exports.DiskTransport = void 0;
590
+ exports.MemoryTransport = exports.DiskTransport = exports.MAX_POST_BYTES = void 0;
526
591
  exports.parseHeadersEnv = parseHeadersEnv2;
527
592
  exports.envOptionsResolver = envOptionsResolver;
528
593
  exports.postOtlp = postOtlp;
529
594
  var retry_queue_js_1 = require_retry_queue();
530
595
  var otlp_js_1 = require_otlp();
531
596
  var TIMEOUT_MS = 5e3;
597
+ exports.MAX_POST_BYTES = 900 * 1024;
598
+ function payloadBytes(payload) {
599
+ const json = JSON.stringify(payload);
600
+ return json === void 0 ? 0 : Buffer.byteLength(json, "utf-8");
601
+ }
602
+ function chunkByBytes(items, sizeOf, maxBytes) {
603
+ const chunks = [];
604
+ const oversize = [];
605
+ let current = [];
606
+ let currentBytes = 0;
607
+ for (const item of items) {
608
+ const bytes = sizeOf(item);
609
+ if (bytes > maxBytes) {
610
+ oversize.push(item);
611
+ continue;
612
+ }
613
+ if (current.length > 0 && currentBytes + bytes > maxBytes) {
614
+ chunks.push(current);
615
+ current = [];
616
+ currentBytes = 0;
617
+ }
618
+ current.push(item);
619
+ currentBytes += bytes;
620
+ }
621
+ if (current.length > 0)
622
+ chunks.push(current);
623
+ return { chunks, oversize };
624
+ }
532
625
  function parseHeadersEnv2(raw) {
533
626
  if (!raw)
534
627
  return {};
@@ -601,10 +694,18 @@ var require_transport = __commonJS({
601
694
  const opts = this.resolveOptions();
602
695
  if (!opts)
603
696
  return;
697
+ if (this.dropIfOversized(payload))
698
+ return;
604
699
  const ok = await postOtlp(payload, opts, this.logPrefix);
605
700
  if (!ok)
606
701
  this.queue.enqueue(payload);
607
702
  }
703
+ /**
704
+ * Drain the backlog in POST-budget-sized chunks. On a mid-flush failure the
705
+ * unsent tail stays queued for the next flush — earlier chunks that already
706
+ * landed are not re-sent (at-most-once per flush attempt, unchanged from the
707
+ * pre-chunking behavior where the whole batch either landed or stayed).
708
+ */
608
709
  async flush() {
609
710
  const opts = this.resolveOptions();
610
711
  if (!opts)
@@ -615,14 +716,36 @@ var require_transport = __commonJS({
615
716
  const entries = this.queue.readAll();
616
717
  if (entries.length === 0)
617
718
  return;
618
- const merged = (0, otlp_js_1.mergeBatch)(entries.map((e) => e.payload));
619
- const ok = await postOtlp(merged, opts, this.logPrefix);
620
- if (ok)
621
- this.queue.rewrite([]);
719
+ const { chunks, oversize } = chunkByBytes(entries, (e) => payloadBytes(e.payload), exports.MAX_POST_BYTES);
720
+ if (oversize.length > 0) {
721
+ process.stderr.write(`[${this.logPrefix}] dropping ${oversize.length} oversized retry ${oversize.length === 1 ? "entry" : "entries"} (each > ${exports.MAX_POST_BYTES} bytes \u2014 the backend caps the request body, so they can never be delivered)
722
+ `);
723
+ }
724
+ const ordered = [].concat(...chunks);
725
+ let sent = 0;
726
+ for (const chunk of chunks) {
727
+ const ok = await postOtlp((0, otlp_js_1.mergeBatch)(chunk.map((e) => e.payload)), opts, this.logPrefix);
728
+ if (!ok)
729
+ break;
730
+ sent += chunk.length;
731
+ }
732
+ this.queue.rewrite(ordered.slice(sent));
733
+ } catch (err) {
734
+ process.stderr.write(`[${this.logPrefix}] flush failed: ${err?.message ?? String(err)}
735
+ `);
622
736
  } finally {
623
737
  this.queue.release();
624
738
  }
625
739
  }
740
+ /** True (and logged) when the payload alone exceeds the POST budget. */
741
+ dropIfOversized(payload) {
742
+ const bytes = payloadBytes(payload);
743
+ if (bytes <= exports.MAX_POST_BYTES)
744
+ return false;
745
+ process.stderr.write(`[${this.logPrefix}] dropping oversized span payload (${bytes} > ${exports.MAX_POST_BYTES} bytes) \u2014 undeliverable, not queued
746
+ `);
747
+ return true;
748
+ }
626
749
  };
627
750
  exports.DiskTransport = DiskTransport;
628
751
  var MemoryTransport2 = class {
@@ -637,10 +760,16 @@ var require_transport = __commonJS({
637
760
  const opts = this.resolveOptions();
638
761
  if (!opts)
639
762
  return;
763
+ if (payloadBytes(payload) > exports.MAX_POST_BYTES) {
764
+ process.stderr.write(`[${this.logPrefix}] dropping oversized span payload (> ${exports.MAX_POST_BYTES} bytes) \u2014 undeliverable, not buffered
765
+ `);
766
+ return;
767
+ }
640
768
  const ok = await postOtlp(payload, opts, this.logPrefix);
641
769
  if (!ok)
642
770
  this.queue.enqueue(payload);
643
771
  }
772
+ /** Chunked drain — see DiskTransport.flush; the unsent tail is re-buffered. */
644
773
  async flush() {
645
774
  const opts = this.resolveOptions();
646
775
  if (!opts)
@@ -648,11 +777,21 @@ var require_transport = __commonJS({
648
777
  const buffered = this.queue.drain();
649
778
  if (buffered.length === 0)
650
779
  return;
651
- const merged = (0, otlp_js_1.mergeBatch)(buffered);
652
- const ok = await postOtlp(merged, opts, this.logPrefix);
653
- if (!ok)
654
- for (const p of buffered)
655
- this.queue.enqueue(p);
780
+ const { chunks, oversize } = chunkByBytes(buffered, payloadBytes, exports.MAX_POST_BYTES);
781
+ if (oversize.length > 0) {
782
+ process.stderr.write(`[${this.logPrefix}] dropping ${oversize.length} oversized buffered ${oversize.length === 1 ? "payload" : "payloads"} (each > ${exports.MAX_POST_BYTES} bytes \u2014 undeliverable)
783
+ `);
784
+ }
785
+ const ordered = [].concat(...chunks);
786
+ let sent = 0;
787
+ for (const chunk of chunks) {
788
+ const ok = await postOtlp((0, otlp_js_1.mergeBatch)(chunk), opts, this.logPrefix);
789
+ if (!ok)
790
+ break;
791
+ sent += chunk.length;
792
+ }
793
+ for (const p of ordered.slice(sent))
794
+ this.queue.enqueue(p);
656
795
  }
657
796
  };
658
797
  exports.MemoryTransport = MemoryTransport2;
@@ -672,6 +811,7 @@ var require_trace = __commonJS({
672
811
  var fs_1 = __importDefault(__require("fs"));
673
812
  var path_1 = __importDefault(__require("path"));
674
813
  var crypto_1 = __importDefault(__require("crypto"));
814
+ var atomic_write_js_1 = require_atomic_write();
675
815
  var CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
676
816
  function generateUlid() {
677
817
  const now = Date.now();
@@ -713,8 +853,13 @@ var require_trace = __commonJS({
713
853
  return this.newTrace();
714
854
  }
715
855
  save(traceId) {
716
- fs_1.default.mkdirSync(path_1.default.dirname(this.tracePath), { recursive: true });
717
- fs_1.default.writeFileSync(this.tracePath, JSON.stringify({ traceId }));
856
+ try {
857
+ fs_1.default.mkdirSync(path_1.default.dirname(this.tracePath), { recursive: true });
858
+ (0, atomic_write_js_1.atomicWriteFileSync)(this.tracePath, JSON.stringify({ traceId }));
859
+ } catch (err) {
860
+ process.stderr.write(`[pinta-core] trace persistence failed: ${err}
861
+ `);
862
+ }
718
863
  }
719
864
  };
720
865
  exports.TraceManager = TraceManager;
@@ -733,6 +878,7 @@ var require_session_trace = __commonJS({
733
878
  var fs_1 = __importDefault(__require("fs"));
734
879
  var path_1 = __importDefault(__require("path"));
735
880
  var trace_js_1 = require_trace();
881
+ var atomic_write_js_1 = require_atomic_write();
736
882
  var DEFAULT_MAX_SESSIONS = 200;
737
883
  var DiskSessionTraceManager = class {
738
884
  tracePath;
@@ -756,7 +902,7 @@ var require_session_trace = __commonJS({
756
902
  fs_1.default.mkdirSync(path_1.default.dirname(this.tracePath), { recursive: true });
757
903
  const entries = Object.entries(map);
758
904
  const capped = entries.length > this.maxSessions ? Object.fromEntries(entries.slice(-this.maxSessions)) : map;
759
- fs_1.default.writeFileSync(this.tracePath, JSON.stringify(capped));
905
+ (0, atomic_write_js_1.atomicWriteFileSync)(this.tracePath, JSON.stringify(capped));
760
906
  } catch {
761
907
  }
762
908
  }
@@ -863,7 +1009,7 @@ var require_dist = __commonJS({
863
1009
  "node_modules/@pinta-ai/core/dist/index.js"(exports) {
864
1010
  "use strict";
865
1011
  Object.defineProperty(exports, "__esModule", { value: true });
866
- exports.loadEnvFile = exports.parseEnvFile = exports.envFilePath = exports.MemorySessionTraceManager = exports.DiskSessionTraceManager = exports.generateUlid = exports.TraceManager = exports.parseHeadersEnv = exports.envOptionsResolver = exports.postOtlp = exports.MemoryTransport = exports.DiskTransport = exports.MemoryRetryQueue = exports.DiskRetryQueue = exports.evaluateGuard = exports.mergeBatch = exports.buildPayload = exports.clientAttrs = exports.guardAttrs = exports.attrsFromRecord = exports.toOtlpValue = exports.snakeCase = exports.newSpanId = exports.ulidToTraceId = exports.MAX_BYTES = exports.PATTERNS = exports.applyMatches = exports.resolveOverlaps = exports.collectMatches = exports.truncate = exports.redact = void 0;
1012
+ exports.loadEnvFile = exports.parseEnvFile = exports.envFilePath = exports.MemorySessionTraceManager = exports.DiskSessionTraceManager = exports.generateUlid = exports.TraceManager = exports.MAX_POST_BYTES = exports.parseHeadersEnv = exports.envOptionsResolver = exports.postOtlp = exports.MemoryTransport = exports.DiskTransport = exports.MemoryRetryQueue = exports.DiskRetryQueue = exports.evaluateGuard = exports.MAX_SPAN_BYTES = exports.enforceSpanBudget = exports.mergeBatch = exports.buildPayload = exports.clientAttrs = exports.guardAttrs = exports.attrsFromRecord = exports.toOtlpValue = exports.snakeCase = exports.newSpanId = exports.ulidToTraceId = exports.MAX_BYTES = exports.PATTERNS = exports.applyMatches = exports.resolveOverlaps = exports.collectMatches = exports.truncateTo = exports.truncate = exports.redact = void 0;
867
1013
  var redact_js_1 = require_redact();
868
1014
  Object.defineProperty(exports, "redact", { enumerable: true, get: function() {
869
1015
  return redact_js_1.redact;
@@ -871,6 +1017,9 @@ var require_dist = __commonJS({
871
1017
  Object.defineProperty(exports, "truncate", { enumerable: true, get: function() {
872
1018
  return redact_js_1.truncate;
873
1019
  } });
1020
+ Object.defineProperty(exports, "truncateTo", { enumerable: true, get: function() {
1021
+ return redact_js_1.truncateTo;
1022
+ } });
874
1023
  Object.defineProperty(exports, "collectMatches", { enumerable: true, get: function() {
875
1024
  return redact_js_1.collectMatches;
876
1025
  } });
@@ -914,6 +1063,12 @@ var require_dist = __commonJS({
914
1063
  Object.defineProperty(exports, "mergeBatch", { enumerable: true, get: function() {
915
1064
  return otlp_js_1.mergeBatch;
916
1065
  } });
1066
+ Object.defineProperty(exports, "enforceSpanBudget", { enumerable: true, get: function() {
1067
+ return otlp_js_1.enforceSpanBudget;
1068
+ } });
1069
+ Object.defineProperty(exports, "MAX_SPAN_BYTES", { enumerable: true, get: function() {
1070
+ return otlp_js_1.MAX_SPAN_BYTES;
1071
+ } });
917
1072
  var guard_js_1 = require_guard();
918
1073
  Object.defineProperty(exports, "evaluateGuard", { enumerable: true, get: function() {
919
1074
  return guard_js_1.evaluateGuard;
@@ -941,6 +1096,9 @@ var require_dist = __commonJS({
941
1096
  Object.defineProperty(exports, "parseHeadersEnv", { enumerable: true, get: function() {
942
1097
  return transport_js_1.parseHeadersEnv;
943
1098
  } });
1099
+ Object.defineProperty(exports, "MAX_POST_BYTES", { enumerable: true, get: function() {
1100
+ return transport_js_1.MAX_POST_BYTES;
1101
+ } });
944
1102
  var trace_js_1 = require_trace();
945
1103
  Object.defineProperty(exports, "TraceManager", { enumerable: true, get: function() {
946
1104
  return trace_js_1.TraceManager;
@@ -1033,7 +1191,7 @@ var import_core4 = __toESM(require_dist(), 1);
1033
1191
  // src/core/guard.ts
1034
1192
  var import_core5 = __toESM(require_dist(), 1);
1035
1193
  var DEFAULT_TIMEOUT_MS = 50;
1036
- var GUARD_UA = "pinta-opencode/0.5.0";
1194
+ var GUARD_UA = "pinta-opencode/0.7.0";
1037
1195
  function evaluateGuard(input, endpoint, opts = {}) {
1038
1196
  return (0, import_core5.evaluateGuard)(input, endpoint, {
1039
1197
  timeoutMs: opts.timeoutMs ?? DEFAULT_TIMEOUT_MS,
@@ -1046,15 +1204,26 @@ function evaluateGuard(input, endpoint, opts = {}) {
1046
1204
  // src/core/otlp.ts
1047
1205
  var import_core6 = __toESM(require_dist(), 1);
1048
1206
  import os from "os";
1049
- var SDK_VERSION = "0.5.0";
1207
+ var cachedProcessOwner;
1208
+ function processOwner() {
1209
+ if (cachedProcessOwner === void 0) {
1210
+ try {
1211
+ cachedProcessOwner = os.userInfo().username;
1212
+ } catch {
1213
+ cachedProcessOwner = process.env.USER ?? process.env.LOGNAME ?? (typeof process.getuid === "function" ? String(process.getuid()) : "unknown");
1214
+ }
1215
+ }
1216
+ return cachedProcessOwner;
1217
+ }
1218
+ var SDK_VERSION = "0.7.0";
1050
1219
  var SKIP_REDACT_KEYS = /* @__PURE__ */ new Set([
1051
- "opencode.kind",
1220
+ "opencode.hook",
1052
1221
  "opencode.event_type",
1053
- "opencode.tool",
1222
+ "opencode.tool_name",
1054
1223
  "opencode.session_id",
1055
1224
  "opencode.sessionID",
1056
- "opencode.call_id",
1057
- "opencode.callID",
1225
+ "opencode.tool_use_id",
1226
+ "opencode.cwd",
1058
1227
  "opencode.agent",
1059
1228
  "opencode.model",
1060
1229
  "opencode.exit",
@@ -1062,10 +1231,8 @@ var SKIP_REDACT_KEYS = /* @__PURE__ */ new Set([
1062
1231
  "opencode.title"
1063
1232
  ]);
1064
1233
  var BASH_CONTEXT_KEYS = /* @__PURE__ */ new Set([
1065
- "opencode.args",
1066
- "opencode.input",
1067
- "opencode.output",
1068
- "opencode.tool_input"
1234
+ "opencode.tool_input",
1235
+ "opencode.tool_response"
1069
1236
  ]);
1070
1237
  var ATTR_POLICY = {
1071
1238
  skipRedactKeys: SKIP_REDACT_KEYS,
@@ -1084,7 +1251,7 @@ function resourceAttrs(serviceVersion) {
1084
1251
  { key: "telemetry.sdk.language", value: { stringValue: "nodejs" } },
1085
1252
  { key: "telemetry.sdk.version", value: { stringValue: SDK_VERSION } },
1086
1253
  { key: "process.pid", value: { intValue: process.pid } },
1087
- { key: "process.owner", value: { stringValue: os.userInfo().username } },
1254
+ { key: "process.owner", value: { stringValue: processOwner() } },
1088
1255
  { key: "host.name", value: { stringValue: os.hostname() } },
1089
1256
  { key: "host.arch", value: { stringValue: os.arch() } }
1090
1257
  ];
@@ -1118,9 +1285,10 @@ var Telemetry = class {
1118
1285
  const props = ev.properties ?? {};
1119
1286
  const sessionId = typeof props.sessionID === "string" ? props.sessionID : void 0;
1120
1287
  await this.emit(`opencode.event.${ev.type ?? "unknown"}`, sessionId, {
1121
- kind: "event",
1288
+ hook: "event",
1122
1289
  event_type: ev.type,
1123
1290
  session_id: sessionId,
1291
+ cwd: process.cwd(),
1124
1292
  ...props
1125
1293
  });
1126
1294
  if (ev.type === "session.idle") await this.transport.flush();
@@ -1130,7 +1298,7 @@ var Telemetry = class {
1130
1298
  await this.emit(
1131
1299
  "opencode.tool.before",
1132
1300
  input.sessionID,
1133
- { ...toolIdentity("tool.before", input), args },
1301
+ { ...toolIdentity("tool.execute.before", input), tool_input: args },
1134
1302
  guard
1135
1303
  );
1136
1304
  }
@@ -1138,16 +1306,22 @@ var Telemetry = class {
1138
1306
  async toolAfter(input, output) {
1139
1307
  const meta = output.metadata ?? {};
1140
1308
  await this.emit("opencode.tool.after", input.sessionID, {
1141
- ...toolIdentity("tool.after", input),
1309
+ ...toolIdentity("tool.execute.after", input),
1142
1310
  title: output.title,
1143
- output: output.output,
1311
+ tool_response: output.output,
1144
1312
  exit: meta.exit,
1145
1313
  truncated: meta.truncated
1146
1314
  });
1147
1315
  }
1148
1316
  };
1149
- function toolIdentity(kind, input) {
1150
- return { kind, tool: input.tool, session_id: input.sessionID, call_id: input.callID };
1317
+ function toolIdentity(hook, input) {
1318
+ return {
1319
+ hook,
1320
+ tool_name: input.tool,
1321
+ session_id: input.sessionID,
1322
+ tool_use_id: input.callID,
1323
+ cwd: process.cwd()
1324
+ };
1151
1325
  }
1152
1326
 
1153
1327
  // src/plugin.ts
@@ -1176,6 +1350,8 @@ var PintaOpencode = async (_input, options) => {
1176
1350
  {
1177
1351
  spanId: input.sessionID,
1178
1352
  toolName: input.tool,
1353
+ method: "tool.execute.before",
1354
+ cwd: process.cwd(),
1179
1355
  toolInput: args,
1180
1356
  rawTextFields: { toolInput: safeStringify(args) }
1181
1357
  },
@@ -1228,7 +1404,7 @@ import path2 from "node:path";
1228
1404
 
1229
1405
  // src/lifecycle/snapshot.ts
1230
1406
  import { execFile } from "node:child_process";
1231
- import { copyFile, mkdtemp, stat } from "node:fs/promises";
1407
+ import { copyFile, mkdtemp, rm, stat } from "node:fs/promises";
1232
1408
  import { tmpdir } from "node:os";
1233
1409
  import path from "node:path";
1234
1410
  import { promisify } from "node:util";
@@ -1238,7 +1414,10 @@ var DEFAULT_MAX_RETRIES = 3;
1238
1414
  var sqlite3Probe;
1239
1415
  function detectSqlite3() {
1240
1416
  if (sqlite3Probe === void 0) {
1241
- sqlite3Probe = execFileAsync("sqlite3", ["-version"]).then(() => "sqlite3").catch(() => null);
1417
+ sqlite3Probe = execFileAsync("sqlite3", ["-version"]).then(() => "sqlite3").catch(() => null).then((result) => {
1418
+ if (result === null) sqlite3Probe = void 0;
1419
+ return result;
1420
+ });
1242
1421
  }
1243
1422
  return sqlite3Probe;
1244
1423
  }
@@ -1252,22 +1431,28 @@ async function backupViaCli(sqlite3Path, dbPath, outPath) {
1252
1431
  const backupCmd = `.backup '${outPath.replace(/'/g, "''")}'`;
1253
1432
  await execFileAsync(sqlite3Path, ["-cmd", ".timeout 5000", dbPath, backupCmd]);
1254
1433
  }
1255
- async function quiesceCopy(file, outDir, stableMs, maxRetries) {
1434
+ async function quiesceCopy(file, outDir, stableMs, maxRetries, deadlineMs) {
1256
1435
  const dbPath = file.absPath;
1257
1436
  const outDbPath = path.join(outDir, path.basename(dbPath));
1437
+ const deadline = Date.now() + deadlineMs;
1258
1438
  let lastErr;
1259
1439
  for (let attempt = 0; attempt < maxRetries; attempt++) {
1260
1440
  try {
1261
1441
  let before = await stat(dbPath);
1262
- while (true) {
1442
+ let stable = false;
1443
+ while (Date.now() < deadline) {
1263
1444
  await sleep(stableMs);
1264
1445
  const now = await stat(dbPath);
1265
- if (now.mtimeMs === before.mtimeMs && now.size === before.size) break;
1446
+ if (now.mtimeMs === before.mtimeMs && now.size === before.size) {
1447
+ stable = true;
1448
+ break;
1449
+ }
1266
1450
  before = now;
1267
1451
  }
1268
1452
  await copyFile(dbPath, outDbPath);
1269
1453
  await copyIfPresent(`${dbPath}-wal`, `${outDbPath}-wal`);
1270
1454
  await copyIfPresent(`${dbPath}-shm`, `${outDbPath}-shm`);
1455
+ if (!stable) return outDbPath;
1271
1456
  const after = await stat(dbPath);
1272
1457
  if (after.mtimeMs === before.mtimeMs && after.size === before.size) {
1273
1458
  return outDbPath;
@@ -1275,6 +1460,7 @@ async function quiesceCopy(file, outDir, stableMs, maxRetries) {
1275
1460
  } catch (err) {
1276
1461
  lastErr = err;
1277
1462
  }
1463
+ if (Date.now() >= deadline) break;
1278
1464
  }
1279
1465
  try {
1280
1466
  await stat(outDbPath);
@@ -1293,17 +1479,24 @@ async function snapshot(file, opts = {}) {
1293
1479
  const base = opts.tmpDir ?? tmpdir();
1294
1480
  const stableMs = opts.stableMs ?? DEFAULT_STABLE_MS;
1295
1481
  const maxRetries = opts.maxRetries ?? DEFAULT_MAX_RETRIES;
1482
+ const deadlineMs = opts.deadlineMs ?? Math.max(stableMs * maxRetries * 3, 15e3);
1296
1483
  const sqlite3Path = opts.sqlite3Path === void 0 ? await detectSqlite3() : opts.sqlite3Path;
1297
1484
  const outDir = await makeSnapshotDir(base);
1298
- if (sqlite3Path) {
1299
- const outPath = path.join(outDir, `${path.basename(file.absPath)}.snapshot`);
1300
- try {
1301
- await backupViaCli(sqlite3Path, file.absPath, outPath);
1302
- return outPath;
1303
- } catch {
1485
+ try {
1486
+ if (sqlite3Path) {
1487
+ const outPath = path.join(outDir, `${path.basename(file.absPath)}.snapshot`);
1488
+ try {
1489
+ await backupViaCli(sqlite3Path, file.absPath, outPath);
1490
+ return outPath;
1491
+ } catch {
1492
+ }
1304
1493
  }
1494
+ return await quiesceCopy(file, outDir, stableMs, maxRetries, deadlineMs);
1495
+ } catch (err) {
1496
+ await rm(outDir, { recursive: true, force: true }).catch(() => {
1497
+ });
1498
+ throw err;
1305
1499
  }
1306
- return quiesceCopy(file, outDir, stableMs, maxRetries);
1307
1500
  }
1308
1501
 
1309
1502
  // src/lifecycle/scanner.ts
package/dist/plugin.js CHANGED
@@ -1,14 +1,21 @@
1
1
  import { createRequire as __pintaCreateRequire } from 'module'; const require = __pintaCreateRequire(import.meta.url);
2
- var Ue=Object.create;var ne=Object.defineProperty;var Ze=Object.getOwnPropertyDescriptor;var Ke=Object.getOwnPropertyNames;var Xe=Object.getPrototypeOf,Ye=Object.prototype.hasOwnProperty;var p=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var y=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var ze=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Ke(e))!Ye.call(t,s)&&s!==r&&ne(t,s,{get:()=>e[s],enumerable:!(n=Ze(e,s))||n.enumerable});return t};var b=(t,e,r)=>(r=t!=null?Ue(Xe(t)):{},ze(e||!t||!t.__esModule?ne(r,"default",{value:t,enumerable:!0}):r,t));var N=y(c=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});c.PATTERNS=c.MAX_BYTES=void 0;c.truncate=Je;c.collectMatches=se;c.resolveOverlaps=oe;c.applyMatches=ie;c.redact=He;c.MAX_BYTES=102400;function Je(t){let e=Buffer.from(t,"utf-8");return e.length<=c.MAX_BYTES?t:`${e.subarray(0,c.MAX_BYTES).toString("utf-8")}\u2026[TRUNCATED:${e.length}]`}c.PATTERNS=[{type:"aws_access_key",regex:/AKIA[0-9A-Z]{16}/g},{type:"aws_secret_key",regex:/(?:aws[_-]?secret(?:[_-]?(?:access)?[_-]?key)?)\s*[:=]\s*["']?([A-Za-z0-9/+=]{40})(?![A-Za-z0-9/+=])/gi,captureGroup:1},{type:"gcp_service_account",regex:/\{[\s\S]{0,200}?"type"\s*:\s*"service_account"[\s\S]*?\}/g},{type:"github_token",regex:/gh[pousr]_[A-Za-z0-9]{36,}/g},{type:"gitlab_token",regex:/glpat-[A-Za-z0-9_-]{20}/g},{type:"slack_token",regex:/xox[abrsp]-[0-9A-Za-z-]{10,}/g},{type:"openai_key",regex:/sk-(?:proj-)?[A-Za-z0-9_-]{40,}/g},{type:"anthropic_key",regex:/sk-ant-[A-Za-z0-9_-]{50,}/g},{type:"stripe_key",regex:/(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9]{20,}/g},{type:"jwt",regex:/eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g},{type:"private_key_block",regex:/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g},{type:"bearer_token",regex:/bearer\s+([A-Za-z0-9._~+/=-]{12,})/gi,captureGroup:1},{type:"basic_auth",regex:/basic\s+([A-Za-z0-9+/=]{12,})/gi,captureGroup:1},{type:"db_url_password",regex:/\b(?:postgres|postgresql|mysql|mariadb|mongodb(?:\+srv)?|redis):\/\/[^:\s/]+:([^@\s]+)@/gi,captureGroup:1},{type:"cli_password_flag",regex:/(?:--password|--pass|--pwd)[=\s]([^\s'"]+)/g,captureGroup:1},{type:"cli_password_short",regex:/\s-p([^\s'"]+)/g,captureGroup:1,requireContext:"bash"},{type:"env_var_secret",regex:/^(?:export\s+)?([A-Z][A-Z0-9_]*(?:KEY|SECRET|TOKEN|PASSWORD|PASSWD|PWD|API_KEY)[A-Z0-9_]*)\s*=\s*["']?([^\s"'\n]+)/gm,captureGroup:2}];function se(t,e){let r=[];for(let n of c.PATTERNS){if(n.requireContext&&n.requireContext!==e.context)continue;let s=new RegExp(n.regex.source,n.regex.flags),i;for(;(i=s.exec(t))!==null;){let a=n.captureGroup??0,u=i[a];if(u===void 0){i.index===s.lastIndex&&s.lastIndex++;continue}let f=i.index,g=i.index+i[0].length,M=f+i[0].indexOf(u),$e=M+u.length;r.push({start:f,end:g,replaceStart:M,replaceEnd:$e,type:n.type}),i.index===s.lastIndex&&s.lastIndex++}}return r}function oe(t){let e=[...t].sort((s,i)=>s.start!==i.start?s.start-i.start:i.end-i.start-(s.end-s.start)),r=[],n=-1;for(let s of e)s.start<n||(r.push(s),n=s.end);return r}function ie(t,e){let r=[...e].sort((s,i)=>i.replaceStart-s.replaceStart),n=t;for(let s of r)n=n.slice(0,s.replaceStart)+`[REDACTED:${s.type}]`+n.slice(s.replaceEnd);return n}function He(t,e={}){if(t.length===0)return t;let r=se(t,e);if(r.length===0)return t;let n=oe(r);return ie(t,n)}});var q=y(d=>{"use strict";var Qe=d&&d.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(d,"__esModule",{value:!0});d.ulidToTraceId=ce;d.newSpanId=le;d.snakeCase=tt;d.toOtlpValue=de;d.attrsFromRecord=rt;d.guardAttrs=pe;d.clientAttrs=fe;d.buildPayload=nt;d.mergeBatch=st;var We=Qe(p("crypto")),ae=N(),et="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function ce(t){if(t.length!==26)throw new Error(`ulidToTraceId: expected 26 chars, got ${t.length}`);let e=0n;for(let n of t){let s=et.indexOf(n);if(s<0)throw new Error(`ulidToTraceId: invalid Crockford char "${n}"`);e=e<<5n|BigInt(s)}let r=(1n<<128n)-1n;return e&=r,e.toString(16).padStart(32,"0")}function le(){return We.default.randomBytes(8).toString("hex")}function tt(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/([A-Z])([A-Z][a-z])/g,"$1_$2").toLowerCase()}var ue=new Set;function R(t,e,r){let n=(0,ae.truncate)(e);if((r.skipRedactKeys??ue).has(t))return n;let s=(r.bashContextKeys??ue).has(t)?"bash":void 0;return(0,ae.redact)(n,{context:s})}function de(t,e,r={}){if(e==null)return null;switch(typeof e){case"string":return{stringValue:R(t,e,r)};case"boolean":return{boolValue:e};case"number":return Number.isInteger(e)?{intValue:e}:{doubleValue:e};case"object":try{return{stringValue:R(t,JSON.stringify(e),r)}}catch{return{stringValue:R(t,String(e),r)}}default:return{stringValue:R(t,String(e),r)}}}function rt(t,e,r={}){let n=[];for(let[s,i]of Object.entries(t)){let a=`${e}.${s}`,u=de(a,i,r);u!==null&&n.push({key:a,value:u})}return n}function pe(t){let e=[{key:"pinta.guard.decision",value:{stringValue:t.decision.toLowerCase()}},{key:"pinta.guard.duration_ms",value:{intValue:t.durationMs}}];return t.reason&&e.push({key:"pinta.guard.matched_rule",value:{stringValue:t.reason}}),t.failOpenReason&&e.push({key:"pinta.guard.fail_open_reason",value:{stringValue:t.failOpenReason}}),e}function fe(t){return[{key:"pinta.client.rtt_ms",value:Number.isInteger(t.rttMs)?{intValue:t.rttMs}:{doubleValue:t.rttMs}},{key:"pinta.client.op",value:{stringValue:t.op}}]}function nt(t){let e=t.now??Date.now(),r=(BigInt(e)*1000000n).toString(),n=[...t.attributes];t.guard&&n.push(...pe(t.guard));let s=t.clientTiming??(t.guard?.clientRttMs!==void 0?{op:"guard",rttMs:t.guard.clientRttMs}:null);s&&n.push(...fe(s));let i={traceId:ce(t.traceId),spanId:le(),name:t.spanName,kind:t.spanKind??1,startTimeUnixNano:r,endTimeUnixNano:r,attributes:n};return{resourceSpans:[{resource:{attributes:t.resource},scopeSpans:[{scope:t.scope,spans:[i]}]}]}}function st(t){let e=[];for(let r of t)e.push(...r.resourceSpans);return{resourceSpans:e}}});var ye=y(C=>{"use strict";Object.defineProperty(C,"__esModule",{value:!0});C.evaluateGuard=ut;var ot=1e4,it="pinta-core";function ge(t,e){return{decision:"ALLOW",reason:null,userMessage:null,durationMs:t,clientRttMs:t,failOpenReason:e}}function at(t){return new Promise((e,r)=>setTimeout(()=>{let n=new Error("Guard request timed out");n.name="TimeoutError",r(n)},t))}async function ut(t,e,r={}){if(!e||r.disabled)return null;let n=r.timeoutMs??ot,s=Date.now();try{let i=await Promise.race([fetch(e,{method:"POST",headers:{"content-type":"application/json","user-agent":r.userAgent??it,"x-pinta-relay-token":r.token??""},body:JSON.stringify({input:t})}),at(n)]);if(i.status!==200)return ge(Date.now()-s,"error");let a=await i.json(),u=Date.now()-s;return{decision:a.decision,reason:a.reason,userMessage:a.userMessage??null,durationMs:a.durationMs??u,clientRttMs:u}}catch(i){let a=i.name==="TimeoutError"?"timeout":"error";return ge(Date.now()-s,a)}}});var V=y(m=>{"use strict";var he=m&&m.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(m,"__esModule",{value:!0});m.MemoryRetryQueue=m.DiskRetryQueue=void 0;var l=he(p("fs")),x=he(p("path")),I=1e3,ct=50,lt=5,F=class{filePath;lockPath;logPrefix;constructor(e,r){this.filePath=x.default.join(e,"failed-spans.jsonl"),this.lockPath=this.filePath+".lock",this.logPrefix=r}enqueue(e){try{l.default.mkdirSync(x.default.dirname(this.filePath),{recursive:!0});let r=JSON.stringify({savedAt:new Date().toISOString(),payload:e})+`
3
- `;l.default.appendFileSync(this.filePath,r),this.trim()}catch(r){process.stderr.write(`[${this.logPrefix}] retry-queue enqueue failed: ${r}
4
- `)}}readAll(){try{let e=l.default.readFileSync(this.filePath,"utf-8"),r=[];for(let n of e.split(`
5
- `))if(n.trim())try{r.push(JSON.parse(n))}catch{}return r}catch{return[]}}rewrite(e){try{if(e.length===0){l.default.existsSync(this.filePath)&&l.default.unlinkSync(this.filePath);return}l.default.mkdirSync(x.default.dirname(this.filePath),{recursive:!0}),l.default.writeFileSync(this.filePath,e.map(r=>JSON.stringify(r)).join(`
2
+ var et=Object.create;var ae=Object.defineProperty;var tt=Object.getOwnPropertyDescriptor;var rt=Object.getOwnPropertyNames;var nt=Object.getPrototypeOf,ot=Object.prototype.hasOwnProperty;var h=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var _=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var st=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of rt(e))!ot.call(t,o)&&o!==r&&ae(t,o,{get:()=>e[o],enumerable:!(n=tt(e,o))||n.enumerable});return t};var E=(t,e,r)=>(r=t!=null?et(nt(t)):{},st(e||!t||!t.__esModule?ae(r,"default",{value:t,enumerable:!0}):r,t));var C=_(f=>{"use strict";Object.defineProperty(f,"__esModule",{value:!0});f.PATTERNS=f.MAX_BYTES=void 0;f.truncateTo=ue;f.truncate=it;f.collectMatches=ce;f.resolveOverlaps=le;f.applyMatches=de;f.redact=at;f.MAX_BYTES=102400;function ue(t,e){let r=Buffer.from(t,"utf-8");return r.length<=e?t:`${r.subarray(0,Math.max(0,e)).toString("utf-8")}\u2026[TRUNCATED:${r.length}]`}function it(t){return ue(t,f.MAX_BYTES)}f.PATTERNS=[{type:"aws_access_key",regex:/AKIA[0-9A-Z]{16}/g},{type:"aws_secret_key",regex:/(?:aws[_-]?secret(?:[_-]?(?:access)?[_-]?key)?)\s*[:=]\s*["']?([A-Za-z0-9/+=]{40})(?![A-Za-z0-9/+=])/gi,captureGroup:1},{type:"gcp_service_account",regex:/\{[\s\S]{0,200}?"type"\s*:\s*"service_account"[\s\S]*?\}/g},{type:"github_token",regex:/gh[pousr]_[A-Za-z0-9]{36,}/g},{type:"gitlab_token",regex:/glpat-[A-Za-z0-9_-]{20}/g},{type:"slack_token",regex:/xox[abrsp]-[0-9A-Za-z-]{10,}/g},{type:"openai_key",regex:/sk-(?:proj-)?[A-Za-z0-9_-]{40,}/g},{type:"anthropic_key",regex:/sk-ant-[A-Za-z0-9_-]{50,}/g},{type:"stripe_key",regex:/(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9]{20,}/g},{type:"jwt",regex:/eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g},{type:"private_key_block",regex:/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g},{type:"bearer_token",regex:/bearer\s+([A-Za-z0-9._~+/=-]{12,})/gi,captureGroup:1},{type:"basic_auth",regex:/basic\s+([A-Za-z0-9+/=]{12,})/gi,captureGroup:1},{type:"db_url_password",regex:/\b(?:postgres|postgresql|mysql|mariadb|mongodb(?:\+srv)?|redis):\/\/[^:\s/]+:([^@\s]+)@/gi,captureGroup:1},{type:"cli_password_flag",regex:/(?:--password|--pass|--pwd)[=\s]([^\s'"]+)/g,captureGroup:1},{type:"cli_password_short",regex:/\s-p([^\s'"]+)/g,captureGroup:1,requireContext:"bash"},{type:"env_var_secret",regex:/^(?:export\s+)?([A-Z][A-Z0-9_]*(?:KEY|SECRET|TOKEN|PASSWORD|PASSWD|PWD|API_KEY)[A-Z0-9_]*)\s*=\s*["']?([^\s"'\n]+)/gm,captureGroup:2}];function ce(t,e){let r=[];for(let n of f.PATTERNS){if(n.requireContext&&n.requireContext!==e.context)continue;let o=new RegExp(n.regex.source,n.regex.flags),i;for(;(i=o.exec(t))!==null;){let u=n.captureGroup??0,a=i[u];if(a===void 0){i.index===o.lastIndex&&o.lastIndex++;continue}let c=i.index,d=i.index+i[0].length,P=c+i[0].indexOf(a),Qe=P+a.length;r.push({start:c,end:d,replaceStart:P,replaceEnd:Qe,type:n.type}),i.index===o.lastIndex&&o.lastIndex++}}return r}function le(t){let e=[...t].sort((o,i)=>o.start!==i.start?o.start-i.start:i.end-i.start-(o.end-o.start)),r=[],n=-1;for(let o of e)o.start<n||(r.push(o),n=o.end);return r}function de(t,e){let r=[...e].sort((o,i)=>i.replaceStart-o.replaceStart),n=t;for(let o of r)n=n.slice(0,o.replaceStart)+`[REDACTED:${o.type}]`+n.slice(o.replaceEnd);return n}function at(t,e={}){if(t.length===0)return t;let r=ce(t,e);if(r.length===0)return t;let n=le(r);return de(t,n)}});var V=_(p=>{"use strict";var ut=p&&p.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(p,"__esModule",{value:!0});p.MAX_SPAN_BYTES=void 0;p.ulidToTraceId=he;p.newSpanId=ye;p.snakeCase=dt;p.toOtlpValue=_e;p.attrsFromRecord=pt;p.guardAttrs=me;p.clientAttrs=Te;p.enforceSpanBudget=Oe;p.buildPayload=ft;p.mergeBatch=gt;var ct=ut(h("crypto")),F=C(),lt="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function he(t){if(t.length!==26)throw new Error(`ulidToTraceId: expected 26 chars, got ${t.length}`);let e=0n;for(let n of t){let o=lt.indexOf(n);if(o<0)throw new Error(`ulidToTraceId: invalid Crockford char "${n}"`);e=e<<5n|BigInt(o)}let r=(1n<<128n)-1n;return e&=r,e.toString(16).padStart(32,"0")}function ye(){return ct.default.randomBytes(8).toString("hex")}function dt(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/([A-Z])([A-Z][a-z])/g,"$1_$2").toLowerCase()}var pe=new Set;function R(t,e,r){let n=(0,F.truncate)(e);if((r.skipRedactKeys??pe).has(t))return n;let o=(r.bashContextKeys??pe).has(t)?"bash":void 0;return(0,F.redact)(n,{context:o})}function _e(t,e,r={}){if(e==null)return null;switch(typeof e){case"string":return{stringValue:R(t,e,r)};case"boolean":return{boolValue:e};case"number":return Number.isInteger(e)?{intValue:e}:{doubleValue:e};case"object":try{return{stringValue:R(t,JSON.stringify(e),r)}}catch{return{stringValue:R(t,String(e),r)}}default:return{stringValue:R(t,String(e),r)}}}function pt(t,e,r={}){let n=[];for(let[o,i]of Object.entries(t)){let u=`${e}.${o}`,a=_e(u,i,r);a!==null&&n.push({key:u,value:a})}return n}function me(t){let e=[{key:"pinta.guard.decision",value:{stringValue:t.decision.toLowerCase()}},{key:"pinta.guard.duration_ms",value:{intValue:t.durationMs}}];return t.reason&&e.push({key:"pinta.guard.matched_rule",value:{stringValue:t.reason}}),t.failOpenReason&&e.push({key:"pinta.guard.fail_open_reason",value:{stringValue:t.failOpenReason}}),e}function Te(t){return[{key:"pinta.client.rtt_ms",value:Number.isInteger(t.rttMs)?{intValue:t.rttMs}:{doubleValue:t.rttMs}},{key:"pinta.client.op",value:{stringValue:t.op}}]}p.MAX_SPAN_BYTES=800*1024;function fe(t){let e=JSON.stringify(t);return e===void 0?0:Buffer.byteLength(e,"utf-8")}var ge=1024;function Oe(t,e=p.MAX_SPAN_BYTES){let r=fe(t);for(let n=0;n<100&&r>e;n++){let o=null,i=0;for(let c of t.attributes){if(!("stringValue"in c.value))continue;let d=Buffer.byteLength(c.value.stringValue,"utf-8");d>i&&(i=d,o=c.value)}if(o===null||i<=ge)break;let u=r-e,a=Math.max(ge,i-u-64);o.stringValue=(0,F.truncateTo)(o.stringValue,a),r=fe(t)}return t}function ft(t){let e=t.now??Date.now(),r=(BigInt(e)*1000000n).toString(),n=[...t.attributes];t.guard&&n.push(...me(t.guard));let o=t.clientTiming??(t.guard?.clientRttMs!==void 0?{op:"guard",rttMs:t.guard.clientRttMs}:null);o&&n.push(...Te(o));let i={traceId:he(t.traceId),spanId:ye(),name:t.spanName,kind:t.spanKind??1,startTimeUnixNano:r,endTimeUnixNano:r,attributes:n};return Oe(i),{resourceSpans:[{resource:{attributes:t.resource},scopeSpans:[{scope:t.scope,spans:[i]}]}]}}function gt(t){let e=[];for(let r of t)e.push(...r.resourceSpans);return{resourceSpans:e}}});var Pe=_(G=>{"use strict";Object.defineProperty(G,"__esModule",{value:!0});G.evaluateGuard=mt;var ht=1e4,yt="pinta-core";function L(t,e){return{decision:"ALLOW",reason:null,userMessage:null,durationMs:t,clientRttMs:t,failOpenReason:e}}var _t=new Set(["ALLOW","DENY","REVIEW"]);async function mt(t,e,r={}){if(!e||r.disabled)return null;let n=r.timeoutMs??ht,o=Date.now(),i=new AbortController,u=setTimeout(()=>i.abort(),n);try{let a=await fetch(e,{method:"POST",headers:{"content-type":"application/json","user-agent":r.userAgent??yt,"x-pinta-relay-token":r.token??""},body:JSON.stringify({input:t}),signal:i.signal});if(a.status!==200)return L(Date.now()-o,"error");let c=await a.json(),d=c?.durationMs===void 0||typeof c.durationMs=="number"&&Number.isFinite(c.durationMs);if(!c||!_t.has(c.decision)||!d)return L(Date.now()-o,"error");let P=Date.now()-o;return{decision:c.decision,reason:c.reason??null,userMessage:c.userMessage??null,durationMs:c.durationMs??P,clientRttMs:P}}catch(a){let c=a.name,d=c==="AbortError"||c==="TimeoutError"?"timeout":"error";return L(Date.now()-o,d)}finally{clearTimeout(u)}}});var I=_(w=>{"use strict";var Tt=w&&w.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(w,"__esModule",{value:!0});w.atomicWriteFileSync=Ot;var ve=Tt(h("fs"));function Ot(t,e){let r=`${t}.${process.pid}.tmp`;ve.default.writeFileSync(r,e),ve.default.renameSync(r,t)}});var z=_(m=>{"use strict";var Se=m&&m.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(m,"__esModule",{value:!0});m.MemoryRetryQueue=m.DiskRetryQueue=void 0;var g=Se(h("fs")),D=Se(h("path")),Pt=I(),j=1e3,vt=50,St=5,X=class{filePath;lockPath;logPrefix;constructor(e,r){this.filePath=D.default.join(e,"failed-spans.jsonl"),this.lockPath=this.filePath+".lock",this.logPrefix=r}enqueue(e){try{g.default.mkdirSync(D.default.dirname(this.filePath),{recursive:!0});let r=JSON.stringify({savedAt:new Date().toISOString(),payload:e})+`
3
+ `;g.default.appendFileSync(this.filePath,r),this.trim()}catch(r){process.stderr.write(`[${this.logPrefix}] retry-queue enqueue failed: ${r}
4
+ `)}}readAll(){try{let e=g.default.readFileSync(this.filePath,"utf-8"),r=[];for(let n of e.split(`
5
+ `))if(n.trim())try{let o=JSON.parse(n);Array.isArray(o?.payload?.resourceSpans)&&r.push(o)}catch{}return r}catch{return[]}}rewrite(e){try{if(e.length===0){g.default.existsSync(this.filePath)&&g.default.unlinkSync(this.filePath);return}g.default.mkdirSync(D.default.dirname(this.filePath),{recursive:!0}),(0,Pt.atomicWriteFileSync)(this.filePath,e.map(r=>JSON.stringify(r)).join(`
6
6
  `)+`
7
7
  `)}catch(r){process.stderr.write(`[${this.logPrefix}] retry-queue rewrite failed: ${r}
8
- `)}}tryAcquireLock(){let e=Date.now();for(l.default.mkdirSync(x.default.dirname(this.lockPath),{recursive:!0});Date.now()-e<ct;)try{let r=l.default.openSync(this.lockPath,"wx");return l.default.writeSync(r,String(process.pid)),l.default.closeSync(r),!0}catch(r){if(r?.code!=="EEXIST")return process.stderr.write(`[${this.logPrefix}] retry-queue lock open failed: ${r}
9
- `),!1;try{let i=l.default.statSync(this.lockPath);if(Date.now()-i.mtimeMs>3e4){l.default.unlinkSync(this.lockPath);continue}}catch{}let n=lt,s=Date.now()+n;for(;Date.now()<s;);}return!1}release(){try{l.default.unlinkSync(this.lockPath)}catch{}}trim(){let e=this.readAll();if(e.length<=I)return;let r=e.length-I;process.stderr.write(`[${this.logPrefix}] retry-queue full, dropping ${r} oldest entries
10
- `),this.rewrite(e.slice(r))}};m.DiskRetryQueue=F;var G=class{entries=[];enqueue(e){this.entries.push(e),this.entries.length>I&&this.entries.splice(0,this.entries.length-I)}drain(){let e=this.entries;return this.entries=[],e}get size(){return this.entries.length}};m.MemoryRetryQueue=G});var Pe=y(h=>{"use strict";Object.defineProperty(h,"__esModule",{value:!0});h.MemoryTransport=h.DiskTransport=void 0;h.parseHeadersEnv=Oe;h.envOptionsResolver=Te;h.postOtlp=k;var _e=V(),me=q(),dt=5e3;function Oe(t){if(!t)return{};if(typeof t=="object")return{...t};let e={};for(let r of t.split(",")){let[n,...s]=r.split("=");n&&s.length>0&&(e[n.trim()]=s.join("=").trim())}return e}function Te(){let t=process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,e=process.env.OTEL_EXPORTER_OTLP_ENDPOINT,r;return t?r=t.replace(/\/+$/,""):e&&(r=e.replace(/\/+$/,"")+"/v1/traces"),r?{endpoint:r,headers:Oe(process.env.OTEL_EXPORTER_OTLP_HEADERS)}:null}async function k(t,e,r){let n=new AbortController,s=setTimeout(()=>n.abort(),dt);try{let i=await fetch(e.endpoint,{method:"POST",headers:{"Content-Type":"application/json",...e.headers},body:JSON.stringify(t),signal:n.signal});if(!i.ok){let a="";try{a=(await i.text()).slice(0,200)}catch{}let u=i.status===401||i.status===403?" \u2014 check OTEL_EXPORTER_OTLP_HEADERS (relay token)":i.status===404?" \u2014 check OTEL_EXPORTER_OTLP_TRACES_ENDPOINT path":i.status>=500?" \u2014 collector may be down":"";return process.stderr.write(`[${r}] OTLP POST ${i.status} ${e.endpoint}${u}${a?` body=${a}`:""}
8
+ `)}}tryAcquireLock(){let e=Date.now();try{g.default.mkdirSync(D.default.dirname(this.lockPath),{recursive:!0})}catch(r){return process.stderr.write(`[${this.logPrefix}] retry-queue lock mkdir failed: ${r}
9
+ `),!1}for(;Date.now()-e<vt;)try{let r=g.default.openSync(this.lockPath,"wx");return g.default.writeSync(r,String(process.pid)),g.default.closeSync(r),!0}catch(r){if(r?.code!=="EEXIST")return process.stderr.write(`[${this.logPrefix}] retry-queue lock open failed: ${r}
10
+ `),!1;try{let i=g.default.statSync(this.lockPath);if(Date.now()-i.mtimeMs>3e4){g.default.unlinkSync(this.lockPath);continue}}catch{}let n=St,o=Date.now()+n;for(;Date.now()<o;);}return!1}release(){try{g.default.unlinkSync(this.lockPath)}catch{}}trim(){let e=this.readAll();if(e.length<=j)return;let r=e.length-j;process.stderr.write(`[${this.logPrefix}] retry-queue full, dropping ${r} oldest entries
11
+ `),this.rewrite(e.slice(r))}};m.DiskRetryQueue=X;var Y=class{entries=[];enqueue(e){this.entries.push(e),this.entries.length>j&&this.entries.splice(0,this.entries.length-j)}drain(){let e=this.entries;return this.entries=[],e}get size(){return this.entries.length}};m.MemoryRetryQueue=Y});var Me=_(l=>{"use strict";Object.defineProperty(l,"__esModule",{value:!0});l.MemoryTransport=l.DiskTransport=l.MAX_POST_BYTES=void 0;l.parseHeadersEnv=ke;l.envOptionsResolver=we;l.postOtlp=M;var be=z(),Ee=V(),bt=5e3;l.MAX_POST_BYTES=900*1024;function N(t){let e=JSON.stringify(t);return e===void 0?0:Buffer.byteLength(e,"utf-8")}function Ae(t,e,r){let n=[],o=[],i=[],u=0;for(let a of t){let c=e(a);if(c>r){o.push(a);continue}i.length>0&&u+c>r&&(n.push(i),i=[],u=0),i.push(a),u+=c}return i.length>0&&n.push(i),{chunks:n,oversize:o}}function ke(t){if(!t)return{};if(typeof t=="object")return{...t};let e={};for(let r of t.split(",")){let[n,...o]=r.split("=");n&&o.length>0&&(e[n.trim()]=o.join("=").trim())}return e}function we(){let t=process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,e=process.env.OTEL_EXPORTER_OTLP_ENDPOINT,r;return t?r=t.replace(/\/+$/,""):e&&(r=e.replace(/\/+$/,"")+"/v1/traces"),r?{endpoint:r,headers:ke(process.env.OTEL_EXPORTER_OTLP_HEADERS)}:null}async function M(t,e,r){let n=new AbortController,o=setTimeout(()=>n.abort(),bt);try{let i=await fetch(e.endpoint,{method:"POST",headers:{"Content-Type":"application/json",...e.headers},body:JSON.stringify(t),signal:n.signal});if(!i.ok){let u="";try{u=(await i.text()).slice(0,200)}catch{}let a=i.status===401||i.status===403?" \u2014 check OTEL_EXPORTER_OTLP_HEADERS (relay token)":i.status===404?" \u2014 check OTEL_EXPORTER_OTLP_TRACES_ENDPOINT path":i.status>=500?" \u2014 collector may be down":"";return process.stderr.write(`[${r}] OTLP POST ${i.status} ${e.endpoint}${a}${u?` body=${u}`:""}
11
12
  `),!1}return!0}catch(i){return process.stderr.write(`[${r}] OTLP POST failed: ${i.message??String(i)}
12
- `),!1}finally{clearTimeout(s)}}var L=class{queue;logPrefix;resolveOptions;constructor(e){this.queue=new _e.DiskRetryQueue(e.pluginData,e.logPrefix),this.logPrefix=e.logPrefix,this.resolveOptions=e.resolveOptions??Te}async send(e){let r=this.resolveOptions();if(!r)return;await k(e,r,this.logPrefix)||this.queue.enqueue(e)}async flush(){let e=this.resolveOptions();if(e&&this.queue.tryAcquireLock())try{let r=this.queue.readAll();if(r.length===0)return;let n=(0,me.mergeBatch)(r.map(i=>i.payload));await k(n,e,this.logPrefix)&&this.queue.rewrite([])}finally{this.queue.release()}}};h.DiskTransport=L;var B=class{queue=new _e.MemoryRetryQueue;logPrefix;resolveOptions;constructor(e){this.logPrefix=e.logPrefix,this.resolveOptions=e.resolveOptions}async send(e){let r=this.resolveOptions();if(!r)return;await k(e,r,this.logPrefix)||this.queue.enqueue(e)}async flush(){let e=this.resolveOptions();if(!e)return;let r=this.queue.drain();if(r.length===0)return;let n=(0,me.mergeBatch)(r);if(!await k(n,e,this.logPrefix))for(let i of r)this.queue.enqueue(i)}};h.MemoryTransport=B});var X=y(T=>{"use strict";var K=T&&T.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(T,"__esModule",{value:!0});T.TraceManager=void 0;T.generateUlid=ve;var $=K(p("fs")),pt=K(p("path")),ft=K(p("crypto")),U="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function ve(){let t=Date.now(),e="",r=t;for(let i=0;i<10;i++)e=U[r&31]+e,r=Math.floor(r/32);let n=ft.default.randomBytes(10),s="";for(let i=0;i<10;i++)s+=U[n[i]&31];for(;s.length<16;)s+=U[0];return e+s}var Z=class{tracePath;constructor(e){this.tracePath=e}newTrace(){let e=ve();return this.save(e),e}currentTrace(){try{let e=$.default.readFileSync(this.tracePath,"utf-8"),{traceId:r}=JSON.parse(e);if(r)return r}catch{}return this.newTrace()}save(e){$.default.mkdirSync(pt.default.dirname(this.tracePath),{recursive:!0}),$.default.writeFileSync(this.tracePath,JSON.stringify({traceId:e}))}};T.TraceManager=Z});var ke=y(O=>{"use strict";var Ee=O&&O.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(O,"__esModule",{value:!0});O.MemorySessionTraceManager=O.DiskSessionTraceManager=void 0;var Y=Ee(p("fs")),gt=Ee(p("path")),be=X(),Se=200,z=class{tracePath;maxSessions;constructor(e,r={}){this.tracePath=e,this.maxSessions=r.maxSessions??Se}read(){try{let e=JSON.parse(Y.default.readFileSync(this.tracePath,"utf-8"));if(e&&typeof e=="object"&&!("traceId"in e))return e}catch{}return{}}write(e){try{Y.default.mkdirSync(gt.default.dirname(this.tracePath),{recursive:!0});let r=Object.entries(e),n=r.length>this.maxSessions?Object.fromEntries(r.slice(-this.maxSessions)):e;Y.default.writeFileSync(this.tracePath,JSON.stringify(n))}catch{}}newTrace(e){let r=e||"default",n=(0,be.generateUlid)(),s=this.read();return s[r]=n,this.write(s),n}currentTrace(e){let r=e||"default",n=this.read()[r];return n||this.newTrace(r)}};O.DiskSessionTraceManager=z;var J=class{map=new Map;maxSessions;constructor(e={}){this.maxSessions=e.maxSessions??Se}newTrace(e){let r=e||"default",n=(0,be.generateUlid)();if(this.map.set(r,n),this.map.size>this.maxSessions){let s=this.map.keys().next().value;s!==void 0&&this.map.delete(s)}return n}currentTrace(e){let r=e||"default";return this.map.get(r)??this.newTrace(r)}};O.MemorySessionTraceManager=J});var Me=y(P=>{"use strict";var H=P&&P.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(P,"__esModule",{value:!0});P.envFilePath=_t;P.parseEnvFile=Ae;P.loadEnvFile=mt;var yt=H(p("node:fs")),ht=H(p("node:os")),we=H(p("node:path"));function _t(t,e,r){let n=r?process.env[r]:void 0,s=n&&n.length>0?n:we.default.join(ht.default.homedir(),t);return we.default.join(s,e)}function Ae(t){let e={};for(let r of t.split(`
13
- `)){let n=r.trim();if(!n||n.startsWith("#"))continue;let s=n.indexOf("=");if(s<0)continue;let i=n.slice(0,s).trim(),a=n.slice(s+1).trim();(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))&&(a=a.slice(1,-1)),i&&(e[i]=a)}return e}function mt(t){let e;try{e=yt.default.readFileSync(t,"utf-8")}catch{return}let r=Ae(e);for(let[n,s]of Object.entries(r))process.env[n]===void 0&&(process.env[n]=s)}});var E=y(o=>{"use strict";Object.defineProperty(o,"__esModule",{value:!0});o.loadEnvFile=o.parseEnvFile=o.envFilePath=o.MemorySessionTraceManager=o.DiskSessionTraceManager=o.generateUlid=o.TraceManager=o.parseHeadersEnv=o.envOptionsResolver=o.postOtlp=o.MemoryTransport=o.DiskTransport=o.MemoryRetryQueue=o.DiskRetryQueue=o.evaluateGuard=o.mergeBatch=o.buildPayload=o.clientAttrs=o.guardAttrs=o.attrsFromRecord=o.toOtlpValue=o.snakeCase=o.newSpanId=o.ulidToTraceId=o.MAX_BYTES=o.PATTERNS=o.applyMatches=o.resolveOverlaps=o.collectMatches=o.truncate=o.redact=void 0;var v=N();Object.defineProperty(o,"redact",{enumerable:!0,get:function(){return v.redact}});Object.defineProperty(o,"truncate",{enumerable:!0,get:function(){return v.truncate}});Object.defineProperty(o,"collectMatches",{enumerable:!0,get:function(){return v.collectMatches}});Object.defineProperty(o,"resolveOverlaps",{enumerable:!0,get:function(){return v.resolveOverlaps}});Object.defineProperty(o,"applyMatches",{enumerable:!0,get:function(){return v.applyMatches}});Object.defineProperty(o,"PATTERNS",{enumerable:!0,get:function(){return v.PATTERNS}});Object.defineProperty(o,"MAX_BYTES",{enumerable:!0,get:function(){return v.MAX_BYTES}});var _=q();Object.defineProperty(o,"ulidToTraceId",{enumerable:!0,get:function(){return _.ulidToTraceId}});Object.defineProperty(o,"newSpanId",{enumerable:!0,get:function(){return _.newSpanId}});Object.defineProperty(o,"snakeCase",{enumerable:!0,get:function(){return _.snakeCase}});Object.defineProperty(o,"toOtlpValue",{enumerable:!0,get:function(){return _.toOtlpValue}});Object.defineProperty(o,"attrsFromRecord",{enumerable:!0,get:function(){return _.attrsFromRecord}});Object.defineProperty(o,"guardAttrs",{enumerable:!0,get:function(){return _.guardAttrs}});Object.defineProperty(o,"clientAttrs",{enumerable:!0,get:function(){return _.clientAttrs}});Object.defineProperty(o,"buildPayload",{enumerable:!0,get:function(){return _.buildPayload}});Object.defineProperty(o,"mergeBatch",{enumerable:!0,get:function(){return _.mergeBatch}});var Ot=ye();Object.defineProperty(o,"evaluateGuard",{enumerable:!0,get:function(){return Ot.evaluateGuard}});var Re=V();Object.defineProperty(o,"DiskRetryQueue",{enumerable:!0,get:function(){return Re.DiskRetryQueue}});Object.defineProperty(o,"MemoryRetryQueue",{enumerable:!0,get:function(){return Re.MemoryRetryQueue}});var w=Pe();Object.defineProperty(o,"DiskTransport",{enumerable:!0,get:function(){return w.DiskTransport}});Object.defineProperty(o,"MemoryTransport",{enumerable:!0,get:function(){return w.MemoryTransport}});Object.defineProperty(o,"postOtlp",{enumerable:!0,get:function(){return w.postOtlp}});Object.defineProperty(o,"envOptionsResolver",{enumerable:!0,get:function(){return w.envOptionsResolver}});Object.defineProperty(o,"parseHeadersEnv",{enumerable:!0,get:function(){return w.parseHeadersEnv}});var xe=X();Object.defineProperty(o,"TraceManager",{enumerable:!0,get:function(){return xe.TraceManager}});Object.defineProperty(o,"generateUlid",{enumerable:!0,get:function(){return xe.generateUlid}});var Ie=ke();Object.defineProperty(o,"DiskSessionTraceManager",{enumerable:!0,get:function(){return Ie.DiskSessionTraceManager}});Object.defineProperty(o,"MemorySessionTraceManager",{enumerable:!0,get:function(){return Ie.MemorySessionTraceManager}});var Q=Me();Object.defineProperty(o,"envFilePath",{enumerable:!0,get:function(){return Q.envFilePath}});Object.defineProperty(o,"parseEnvFile",{enumerable:!0,get:function(){return Q.parseEnvFile}});Object.defineProperty(o,"loadEnvFile",{enumerable:!0,get:function(){return Q.loadEnvFile}})});var je=b(E(),1);var A=b(E(),1);function Tt(){return(0,A.envFilePath)(".config/opencode","pinta-opencode.env","OPENCODE_CONFIG_DIR")}function De(t=Tt()){(0,A.loadEnvFile)(t)}function W(...t){return t.find(e=>e)||void 0}function Pt(t){let e=W(t.endpoint,process.env.PINTA_OPENCODE_ENDPOINT,process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT);if(e)return e.replace(/\/+$/,"");let r=process.env.OTEL_EXPORTER_OTLP_ENDPOINT;if(r)return r.replace(/\/+$/,"")+"/v1/traces"}function Ne(t={}){De();let e=W(t.token,process.env.PINTA_OPENCODE_TOKEN),r=(0,je.parseHeadersEnv)(t.headers??process.env.PINTA_OPENCODE_HEADERS??process.env.OTEL_EXPORTER_OTLP_HEADERS);e&&!Object.keys(r).some(s=>s.toLowerCase()==="x-pinta-relay-token")&&(r["x-pinta-relay-token"]=e);let n=t.guardTimeoutMs??(Number(process.env.PINTA_OPENCODE_GUARD_TIMEOUT_MS)||50);return{endpoint:Pt(t),headers:r,guardEndpoint:W(t.guard,process.env.PINTA_OPENCODE_GUARD),relayToken:e,guardTimeoutMs:n,guardDisabled:process.env.PINTA_OPENCODE_GUARD_DISABLED==="1",serviceVersion:process.env.OPENCODE_VERSION||"unknown"}}var qe=b(E(),1),D=class extends qe.MemoryTransport{constructor(e){super({logPrefix:"pinta-opencode",resolveOptions:()=>e.endpoint?{endpoint:e.endpoint,headers:e.headers}:null})}};var ee=b(E(),1);var Ce=b(E(),1),vt=50,Et="pinta-opencode/0.5.0";function Fe(t,e,r={}){return(0,Ce.evaluateGuard)(t,e,{timeoutMs:r.timeoutMs??vt,token:r.token,disabled:r.disabled,userAgent:Et})}var S=b(E(),1);import te from"os";var Ge="0.5.0",bt=new Set(["opencode.kind","opencode.event_type","opencode.tool","opencode.session_id","opencode.sessionID","opencode.call_id","opencode.callID","opencode.agent","opencode.model","opencode.exit","opencode.truncated","opencode.title"]),St=new Set(["opencode.args","opencode.input","opencode.output","opencode.tool_input"]),kt={skipRedactKeys:bt,bashContextKeys:St};function wt(t){let e=[{key:"ingest.type",value:{stringValue:"opencode"}}];return e.push(...(0,S.attrsFromRecord)(t,"opencode",kt)),e}function At(t){return[{key:"service.name",value:{stringValue:"opencode"}},{key:"service.version",value:{stringValue:t}},{key:"telemetry.sdk.name",value:{stringValue:"pinta-opencode"}},{key:"telemetry.sdk.language",value:{stringValue:"nodejs"}},{key:"telemetry.sdk.version",value:{stringValue:Ge}},{key:"process.pid",value:{intValue:process.pid}},{key:"process.owner",value:{stringValue:te.userInfo().username}},{key:"host.name",value:{stringValue:te.hostname()}},{key:"host.arch",value:{stringValue:te.arch()}}]}function Ve(t){return(0,S.buildPayload)({traceId:t.traceId,spanName:t.name,attributes:wt(t.fields),resource:At(t.serviceVersion),scope:{name:"pinta-opencode",version:Ge},now:t.now,guard:t.guard})}var j=class{constructor(e,r,n){this.transport=e;this.trace=r;this.config=n}async emit(e,r,n,s){let i=this.trace.currentTrace(r),a=Ve({name:e,traceId:i,fields:n,guard:s,serviceVersion:this.config.serviceVersion});await this.transport.send(a)}async lifecycle(e){let r=e.properties??{},n=typeof r.sessionID=="string"?r.sessionID:void 0;await this.emit(`opencode.event.${e.type??"unknown"}`,n,{kind:"event",event_type:e.type,session_id:n,...r}),e.type==="session.idle"&&await this.transport.flush()}async toolBefore(e,r,n){await this.emit("opencode.tool.before",e.sessionID,{...Le("tool.before",e),args:r},n)}async toolAfter(e,r){let n=r.metadata??{};await this.emit("opencode.tool.after",e.sessionID,{...Le("tool.after",e),title:r.title,output:r.output,exit:n.exit,truncated:n.truncated})}};function Le(t,e){return{kind:t,tool:e.tool,session_id:e.sessionID,call_id:e.callID}}function Be(t,e){process.stderr.write(`[pinta-opencode] ${t}: ${e?.message??String(e)}
14
- `)}function re(t,e){return async(...r)=>{try{await e(...r)}catch(n){Be(t,n)}}}var Mt=async(t,e)=>{let r=Ne(e??{}),n=new D({endpoint:r.endpoint,headers:r.headers}),s=new ee.MemorySessionTraceManager,i=new j(n,s,r);async function a(u,f){let g=null;try{g=await Fe({spanId:u.sessionID,toolName:u.tool,toolInput:f,rawTextFields:{toolInput:Rt(f)}},r.guardEndpoint,{timeoutMs:r.guardTimeoutMs,token:r.relayToken,disabled:r.guardDisabled}),await i.toolBefore(u,f,g)}catch(M){Be("tool.execute.before",M)}return g}return{"chat.message":re("chat.message",async u=>{s.newTrace(u?.sessionID)}),event:re("event",async u=>{u?.event&&await i.lifecycle(u.event)}),"tool.execute.before":async(u,f)=>{let g=await a(u,f?.args);if(g?.decision==="DENY")throw new Error(g.userMessage??g.reason??"guard_deny")},"tool.execute.after":re("tool.execute.after",(u,f)=>i.toolAfter(u,f))}};function Rt(t){try{return typeof t=="string"?t:JSON.stringify(t)??""}catch{return String(t)}}var rr=Mt;export{Mt as PintaOpencode,rr as default};
13
+ `),!1}finally{clearTimeout(o)}}var U=class{queue;logPrefix;resolveOptions;constructor(e){this.queue=new be.DiskRetryQueue(e.pluginData,e.logPrefix),this.logPrefix=e.logPrefix,this.resolveOptions=e.resolveOptions??we}async send(e){let r=this.resolveOptions();if(!r||this.dropIfOversized(e))return;await M(e,r,this.logPrefix)||this.queue.enqueue(e)}async flush(){let e=this.resolveOptions();if(e&&this.queue.tryAcquireLock())try{let r=this.queue.readAll();if(r.length===0)return;let{chunks:n,oversize:o}=Ae(r,a=>N(a.payload),l.MAX_POST_BYTES);o.length>0&&process.stderr.write(`[${this.logPrefix}] dropping ${o.length} oversized retry ${o.length===1?"entry":"entries"} (each > ${l.MAX_POST_BYTES} bytes \u2014 the backend caps the request body, so they can never be delivered)
14
+ `);let i=[].concat(...n),u=0;for(let a of n){if(!await M((0,Ee.mergeBatch)(a.map(d=>d.payload)),e,this.logPrefix))break;u+=a.length}this.queue.rewrite(i.slice(u))}catch(r){process.stderr.write(`[${this.logPrefix}] flush failed: ${r?.message??String(r)}
15
+ `)}finally{this.queue.release()}}dropIfOversized(e){let r=N(e);return r<=l.MAX_POST_BYTES?!1:(process.stderr.write(`[${this.logPrefix}] dropping oversized span payload (${r} > ${l.MAX_POST_BYTES} bytes) \u2014 undeliverable, not queued
16
+ `),!0)}};l.DiskTransport=U;var Z=class{queue=new be.MemoryRetryQueue;logPrefix;resolveOptions;constructor(e){this.logPrefix=e.logPrefix,this.resolveOptions=e.resolveOptions}async send(e){let r=this.resolveOptions();if(!r)return;if(N(e)>l.MAX_POST_BYTES){process.stderr.write(`[${this.logPrefix}] dropping oversized span payload (> ${l.MAX_POST_BYTES} bytes) \u2014 undeliverable, not buffered
17
+ `);return}await M(e,r,this.logPrefix)||this.queue.enqueue(e)}async flush(){let e=this.resolveOptions();if(!e)return;let r=this.queue.drain();if(r.length===0)return;let{chunks:n,oversize:o}=Ae(r,N,l.MAX_POST_BYTES);o.length>0&&process.stderr.write(`[${this.logPrefix}] dropping ${o.length} oversized buffered ${o.length===1?"payload":"payloads"} (each > ${l.MAX_POST_BYTES} bytes \u2014 undeliverable)
18
+ `);let i=[].concat(...n),u=0;for(let a of n){if(!await M((0,Ee.mergeBatch)(a),e,this.logPrefix))break;u+=a.length}for(let a of i.slice(u))this.queue.enqueue(a)}};l.MemoryTransport=Z});var H=_(v=>{"use strict";var J=v&&v.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(v,"__esModule",{value:!0});v.TraceManager=void 0;v.generateUlid=Re;var xe=J(h("fs")),Et=J(h("path")),At=J(h("crypto")),kt=I(),K="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function Re(){let t=Date.now(),e="",r=t;for(let i=0;i<10;i++)e=K[r&31]+e,r=Math.floor(r/32);let n=At.default.randomBytes(10),o="";for(let i=0;i<10;i++)o+=K[n[i]&31];for(;o.length<16;)o+=K[0];return e+o}var W=class{tracePath;constructor(e){this.tracePath=e}newTrace(){let e=Re();return this.save(e),e}currentTrace(){try{let e=xe.default.readFileSync(this.tracePath,"utf-8"),{traceId:r}=JSON.parse(e);if(r)return r}catch{}return this.newTrace()}save(e){try{xe.default.mkdirSync(Et.default.dirname(this.tracePath),{recursive:!0}),(0,kt.atomicWriteFileSync)(this.tracePath,JSON.stringify({traceId:e}))}catch(r){process.stderr.write(`[pinta-core] trace persistence failed: ${r}
19
+ `)}}};v.TraceManager=W});var Be=_(T=>{"use strict";var De=T&&T.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(T,"__esModule",{value:!0});T.MemorySessionTraceManager=T.DiskSessionTraceManager=void 0;var Ie=De(h("fs")),wt=De(h("path")),je=H(),Mt=I(),Ne=200,Q=class{tracePath;maxSessions;constructor(e,r={}){this.tracePath=e,this.maxSessions=r.maxSessions??Ne}read(){try{let e=JSON.parse(Ie.default.readFileSync(this.tracePath,"utf-8"));if(e&&typeof e=="object"&&!("traceId"in e))return e}catch{}return{}}write(e){try{Ie.default.mkdirSync(wt.default.dirname(this.tracePath),{recursive:!0});let r=Object.entries(e),n=r.length>this.maxSessions?Object.fromEntries(r.slice(-this.maxSessions)):e;(0,Mt.atomicWriteFileSync)(this.tracePath,JSON.stringify(n))}catch{}}newTrace(e){let r=e||"default",n=(0,je.generateUlid)(),o=this.read();return o[r]=n,this.write(o),n}currentTrace(e){let r=e||"default",n=this.read()[r];return n||this.newTrace(r)}};T.DiskSessionTraceManager=Q;var ee=class{map=new Map;maxSessions;constructor(e={}){this.maxSessions=e.maxSessions??Ne}newTrace(e){let r=e||"default",n=(0,je.generateUlid)();if(this.map.set(r,n),this.map.size>this.maxSessions){let o=this.map.keys().next().value;o!==void 0&&this.map.delete(o)}return n}currentTrace(e){let r=e||"default";return this.map.get(r)??this.newTrace(r)}};T.MemorySessionTraceManager=ee});var Ce=_(S=>{"use strict";var te=S&&S.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(S,"__esModule",{value:!0});S.envFilePath=It;S.parseEnvFile=$e;S.loadEnvFile=Dt;var xt=te(h("node:fs")),Rt=te(h("node:os")),qe=te(h("node:path"));function It(t,e,r){let n=r?process.env[r]:void 0,o=n&&n.length>0?n:qe.default.join(Rt.default.homedir(),t);return qe.default.join(o,e)}function $e(t){let e={};for(let r of t.split(`
20
+ `)){let n=r.trim();if(!n||n.startsWith("#"))continue;let o=n.indexOf("=");if(o<0)continue;let i=n.slice(0,o).trim(),u=n.slice(o+1).trim();(u.startsWith('"')&&u.endsWith('"')||u.startsWith("'")&&u.endsWith("'"))&&(u=u.slice(1,-1)),i&&(e[i]=u)}return e}function Dt(t){let e;try{e=xt.default.readFileSync(t,"utf-8")}catch{return}let r=$e(e);for(let[n,o]of Object.entries(r))process.env[n]===void 0&&(process.env[n]=o)}});var b=_(s=>{"use strict";Object.defineProperty(s,"__esModule",{value:!0});s.loadEnvFile=s.parseEnvFile=s.envFilePath=s.MemorySessionTraceManager=s.DiskSessionTraceManager=s.generateUlid=s.TraceManager=s.MAX_POST_BYTES=s.parseHeadersEnv=s.envOptionsResolver=s.postOtlp=s.MemoryTransport=s.DiskTransport=s.MemoryRetryQueue=s.DiskRetryQueue=s.evaluateGuard=s.MAX_SPAN_BYTES=s.enforceSpanBudget=s.mergeBatch=s.buildPayload=s.clientAttrs=s.guardAttrs=s.attrsFromRecord=s.toOtlpValue=s.snakeCase=s.newSpanId=s.ulidToTraceId=s.MAX_BYTES=s.PATTERNS=s.applyMatches=s.resolveOverlaps=s.collectMatches=s.truncateTo=s.truncate=s.redact=void 0;var O=C();Object.defineProperty(s,"redact",{enumerable:!0,get:function(){return O.redact}});Object.defineProperty(s,"truncate",{enumerable:!0,get:function(){return O.truncate}});Object.defineProperty(s,"truncateTo",{enumerable:!0,get:function(){return O.truncateTo}});Object.defineProperty(s,"collectMatches",{enumerable:!0,get:function(){return O.collectMatches}});Object.defineProperty(s,"resolveOverlaps",{enumerable:!0,get:function(){return O.resolveOverlaps}});Object.defineProperty(s,"applyMatches",{enumerable:!0,get:function(){return O.applyMatches}});Object.defineProperty(s,"PATTERNS",{enumerable:!0,get:function(){return O.PATTERNS}});Object.defineProperty(s,"MAX_BYTES",{enumerable:!0,get:function(){return O.MAX_BYTES}});var y=V();Object.defineProperty(s,"ulidToTraceId",{enumerable:!0,get:function(){return y.ulidToTraceId}});Object.defineProperty(s,"newSpanId",{enumerable:!0,get:function(){return y.newSpanId}});Object.defineProperty(s,"snakeCase",{enumerable:!0,get:function(){return y.snakeCase}});Object.defineProperty(s,"toOtlpValue",{enumerable:!0,get:function(){return y.toOtlpValue}});Object.defineProperty(s,"attrsFromRecord",{enumerable:!0,get:function(){return y.attrsFromRecord}});Object.defineProperty(s,"guardAttrs",{enumerable:!0,get:function(){return y.guardAttrs}});Object.defineProperty(s,"clientAttrs",{enumerable:!0,get:function(){return y.clientAttrs}});Object.defineProperty(s,"buildPayload",{enumerable:!0,get:function(){return y.buildPayload}});Object.defineProperty(s,"mergeBatch",{enumerable:!0,get:function(){return y.mergeBatch}});Object.defineProperty(s,"enforceSpanBudget",{enumerable:!0,get:function(){return y.enforceSpanBudget}});Object.defineProperty(s,"MAX_SPAN_BYTES",{enumerable:!0,get:function(){return y.MAX_SPAN_BYTES}});var jt=Pe();Object.defineProperty(s,"evaluateGuard",{enumerable:!0,get:function(){return jt.evaluateGuard}});var Fe=z();Object.defineProperty(s,"DiskRetryQueue",{enumerable:!0,get:function(){return Fe.DiskRetryQueue}});Object.defineProperty(s,"MemoryRetryQueue",{enumerable:!0,get:function(){return Fe.MemoryRetryQueue}});var A=Me();Object.defineProperty(s,"DiskTransport",{enumerable:!0,get:function(){return A.DiskTransport}});Object.defineProperty(s,"MemoryTransport",{enumerable:!0,get:function(){return A.MemoryTransport}});Object.defineProperty(s,"postOtlp",{enumerable:!0,get:function(){return A.postOtlp}});Object.defineProperty(s,"envOptionsResolver",{enumerable:!0,get:function(){return A.envOptionsResolver}});Object.defineProperty(s,"parseHeadersEnv",{enumerable:!0,get:function(){return A.parseHeadersEnv}});Object.defineProperty(s,"MAX_POST_BYTES",{enumerable:!0,get:function(){return A.MAX_POST_BYTES}});var Ve=H();Object.defineProperty(s,"TraceManager",{enumerable:!0,get:function(){return Ve.TraceManager}});Object.defineProperty(s,"generateUlid",{enumerable:!0,get:function(){return Ve.generateUlid}});var Le=Be();Object.defineProperty(s,"DiskSessionTraceManager",{enumerable:!0,get:function(){return Le.DiskSessionTraceManager}});Object.defineProperty(s,"MemorySessionTraceManager",{enumerable:!0,get:function(){return Le.MemorySessionTraceManager}});var re=Ce();Object.defineProperty(s,"envFilePath",{enumerable:!0,get:function(){return re.envFilePath}});Object.defineProperty(s,"parseEnvFile",{enumerable:!0,get:function(){return re.parseEnvFile}});Object.defineProperty(s,"loadEnvFile",{enumerable:!0,get:function(){return re.loadEnvFile}})});var Xe=E(b(),1);var x=E(b(),1);function Nt(){return(0,x.envFilePath)(".config/opencode","pinta-opencode.env","OPENCODE_CONFIG_DIR")}function Ge(t=Nt()){(0,x.loadEnvFile)(t)}function ne(...t){return t.find(e=>e)||void 0}function Bt(t){let e=ne(t.endpoint,process.env.PINTA_OPENCODE_ENDPOINT,process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT);if(e)return e.replace(/\/+$/,"");let r=process.env.OTEL_EXPORTER_OTLP_ENDPOINT;if(r)return r.replace(/\/+$/,"")+"/v1/traces"}function Ye(t={}){Ge();let e=ne(t.token,process.env.PINTA_OPENCODE_TOKEN),r=(0,Xe.parseHeadersEnv)(t.headers??process.env.PINTA_OPENCODE_HEADERS??process.env.OTEL_EXPORTER_OTLP_HEADERS);e&&!Object.keys(r).some(o=>o.toLowerCase()==="x-pinta-relay-token")&&(r["x-pinta-relay-token"]=e);let n=t.guardTimeoutMs??(Number(process.env.PINTA_OPENCODE_GUARD_TIMEOUT_MS)||50);return{endpoint:Bt(t),headers:r,guardEndpoint:ne(t.guard,process.env.PINTA_OPENCODE_GUARD),relayToken:e,guardTimeoutMs:n,guardDisabled:process.env.PINTA_OPENCODE_GUARD_DISABLED==="1",serviceVersion:process.env.OPENCODE_VERSION||"unknown"}}var ze=E(b(),1),B=class extends ze.MemoryTransport{constructor(e){super({logPrefix:"pinta-opencode",resolveOptions:()=>e.endpoint?{endpoint:e.endpoint,headers:e.headers}:null})}};var oe=E(b(),1);var Ue=E(b(),1),qt=50,$t="pinta-opencode/0.7.0";function Ze(t,e,r={}){return(0,Ue.evaluateGuard)(t,e,{timeoutMs:r.timeoutMs??qt,token:r.token,disabled:r.disabled,userAgent:$t})}var k=E(b(),1);import se from"os";var q;function Ct(){if(q===void 0)try{q=se.userInfo().username}catch{q=process.env.USER??process.env.LOGNAME??(typeof process.getuid=="function"?String(process.getuid()):"unknown")}return q}var Ke="0.7.0",Ft=new Set(["opencode.hook","opencode.event_type","opencode.tool_name","opencode.session_id","opencode.sessionID","opencode.tool_use_id","opencode.cwd","opencode.agent","opencode.model","opencode.exit","opencode.truncated","opencode.title"]),Vt=new Set(["opencode.tool_input","opencode.tool_response"]),Lt={skipRedactKeys:Ft,bashContextKeys:Vt};function Gt(t){let e=[{key:"ingest.type",value:{stringValue:"opencode"}}];return e.push(...(0,k.attrsFromRecord)(t,"opencode",Lt)),e}function Xt(t){return[{key:"service.name",value:{stringValue:"opencode"}},{key:"service.version",value:{stringValue:t}},{key:"telemetry.sdk.name",value:{stringValue:"pinta-opencode"}},{key:"telemetry.sdk.language",value:{stringValue:"nodejs"}},{key:"telemetry.sdk.version",value:{stringValue:Ke}},{key:"process.pid",value:{intValue:process.pid}},{key:"process.owner",value:{stringValue:Ct()}},{key:"host.name",value:{stringValue:se.hostname()}},{key:"host.arch",value:{stringValue:se.arch()}}]}function We(t){return(0,k.buildPayload)({traceId:t.traceId,spanName:t.name,attributes:Gt(t.fields),resource:Xt(t.serviceVersion),scope:{name:"pinta-opencode",version:Ke},now:t.now,guard:t.guard})}var $=class{constructor(e,r,n){this.transport=e;this.trace=r;this.config=n}async emit(e,r,n,o){let i=this.trace.currentTrace(r),u=We({name:e,traceId:i,fields:n,guard:o,serviceVersion:this.config.serviceVersion});await this.transport.send(u)}async lifecycle(e){let r=e.properties??{},n=typeof r.sessionID=="string"?r.sessionID:void 0;await this.emit(`opencode.event.${e.type??"unknown"}`,n,{hook:"event",event_type:e.type,session_id:n,cwd:process.cwd(),...r}),e.type==="session.idle"&&await this.transport.flush()}async toolBefore(e,r,n){await this.emit("opencode.tool.before",e.sessionID,{...Je("tool.execute.before",e),tool_input:r},n)}async toolAfter(e,r){let n=r.metadata??{};await this.emit("opencode.tool.after",e.sessionID,{...Je("tool.execute.after",e),title:r.title,tool_response:r.output,exit:n.exit,truncated:n.truncated})}};function Je(t,e){return{hook:t,tool_name:e.tool,session_id:e.sessionID,tool_use_id:e.callID,cwd:process.cwd()}}function He(t,e){process.stderr.write(`[pinta-opencode] ${t}: ${e?.message??String(e)}
21
+ `)}function ie(t,e){return async(...r)=>{try{await e(...r)}catch(n){He(t,n)}}}var Yt=async(t,e)=>{let r=Ye(e??{}),n=new B({endpoint:r.endpoint,headers:r.headers}),o=new oe.MemorySessionTraceManager,i=new $(n,o,r);async function u(a,c){let d=null;try{d=await Ze({spanId:a.sessionID,toolName:a.tool,method:"tool.execute.before",cwd:process.cwd(),toolInput:c,rawTextFields:{toolInput:zt(c)}},r.guardEndpoint,{timeoutMs:r.guardTimeoutMs,token:r.relayToken,disabled:r.guardDisabled}),await i.toolBefore(a,c,d)}catch(P){He("tool.execute.before",P)}return d}return{"chat.message":ie("chat.message",async a=>{o.newTrace(a?.sessionID)}),event:ie("event",async a=>{a?.event&&await i.lifecycle(a.event)}),"tool.execute.before":async(a,c)=>{let d=await u(a,c?.args);if(d?.decision==="DENY")throw new Error(d.userMessage??d.reason??"guard_deny")},"tool.execute.after":ie("tool.execute.after",(a,c)=>i.toolAfter(a,c))}};function zt(t){try{return typeof t=="string"?t:JSON.stringify(t)??""}catch{return String(t)}}var Tr=Yt;export{Yt as PintaOpencode,Tr as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pinta-ai/pinta-opencode",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "OTLP forwarder + guard for opencode (in-process plugin)",
5
5
  "type": "module",
6
6
  "main": "dist/plugin.js",
@@ -36,7 +36,7 @@
36
36
  "prepublishOnly": "npm run build"
37
37
  },
38
38
  "devDependencies": {
39
- "@pinta-ai/core": "^0.3.0",
39
+ "@pinta-ai/core": "^0.6.0",
40
40
  "@types/node": "^22.0.0",
41
41
  "esbuild": "0.24.2",
42
42
  "typescript": "^5.7.0",