@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 +32 -0
- package/dist/index.mjs +263 -70
- package/dist/plugin.js +17 -10
- package/package.json +2 -2
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
|
|
47
|
+
function truncateTo(input, maxBytes) {
|
|
47
48
|
const buf = Buffer.from(input, "utf-8");
|
|
48
|
-
if (buf.length <=
|
|
49
|
+
if (buf.length <= maxBytes)
|
|
49
50
|
return input;
|
|
50
|
-
const head = buf.subarray(0,
|
|
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
|
-
|
|
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
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
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
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
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
|
-
|
|
717
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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.
|
|
1220
|
+
"opencode.hook",
|
|
1052
1221
|
"opencode.event_type",
|
|
1053
|
-
"opencode.
|
|
1222
|
+
"opencode.tool_name",
|
|
1054
1223
|
"opencode.session_id",
|
|
1055
1224
|
"opencode.sessionID",
|
|
1056
|
-
"opencode.
|
|
1057
|
-
"opencode.
|
|
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.
|
|
1066
|
-
"opencode.
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
1311
|
+
tool_response: output.output,
|
|
1144
1312
|
exit: meta.exit,
|
|
1145
1313
|
truncated: meta.truncated
|
|
1146
1314
|
});
|
|
1147
1315
|
}
|
|
1148
1316
|
};
|
|
1149
|
-
function toolIdentity(
|
|
1150
|
-
return {
|
|
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
|
-
|
|
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)
|
|
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
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
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
|
|
3
|
-
`;
|
|
4
|
-
`)}}readAll(){try{let e=
|
|
5
|
-
`))if(n.trim())try{
|
|
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();
|
|
9
|
-
`),!1
|
|
10
|
-
`)
|
|
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(
|
|
13
|
-
`)
|
|
14
|
-
`)}
|
|
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.
|
|
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.
|
|
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",
|