agent-inspect 1.1.0 → 1.3.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.
@@ -7,12 +7,11 @@ var url = require('url');
7
7
  var commander = require('commander');
8
8
  var promises = require('fs/promises');
9
9
  var crypto = require('crypto');
10
- var nanoid = require('nanoid');
11
10
  var os = require('os');
12
11
  var async_hooks = require('async_hooks');
13
12
  var readline = require('readline');
14
- var chalk2 = require('chalk');
15
- var process$1 = require('process');
13
+ var process2 = require('process');
14
+ var tty = require('tty');
16
15
 
17
16
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
18
17
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -20,7 +19,8 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
20
19
  var path__default = /*#__PURE__*/_interopDefault(path);
21
20
  var crypto__default = /*#__PURE__*/_interopDefault(crypto);
22
21
  var os__default = /*#__PURE__*/_interopDefault(os);
23
- var chalk2__default = /*#__PURE__*/_interopDefault(chalk2);
22
+ var process2__default = /*#__PURE__*/_interopDefault(process2);
23
+ var tty__default = /*#__PURE__*/_interopDefault(tty);
24
24
 
25
25
  // packages/core/src/types.ts
26
26
  var STEP_TYPES = [
@@ -60,6 +60,86 @@ function isTraceEvent(value) {
60
60
  return false;
61
61
  }
62
62
  }
63
+
64
+ // packages/core/src/logs/tree-builder.ts
65
+ function inc(map, key) {
66
+ map[key] = (map[key] ?? 0) + 1;
67
+ }
68
+ function computeRunStatus(events) {
69
+ let hasRunning = false;
70
+ for (const e of events) {
71
+ if (e.status === "error") return "error";
72
+ if (e.status === "running") hasRunning = true;
73
+ }
74
+ if (hasRunning) return "running";
75
+ return "ok";
76
+ }
77
+ var TreeBuilder = class {
78
+ constructor(options) {
79
+ void options?.config;
80
+ }
81
+ build(events) {
82
+ const byRun = /* @__PURE__ */ new Map();
83
+ for (const e of events) {
84
+ if (!byRun.has(e.runId)) byRun.set(e.runId, []);
85
+ byRun.get(e.runId).push(e);
86
+ }
87
+ const out = [];
88
+ for (const [runId, runEvents] of byRun.entries()) {
89
+ const sorted = [...runEvents].sort((a, b) => a.timestamp - b.timestamp);
90
+ const nodes = /* @__PURE__ */ new Map();
91
+ for (const e of sorted) {
92
+ nodes.set(e.eventId, { event: e, children: [], depth: 0 });
93
+ }
94
+ const roots = [];
95
+ for (const node of nodes.values()) {
96
+ const parentId = node.event.parentId;
97
+ if (parentId && nodes.has(parentId)) {
98
+ nodes.get(parentId).children.push(node);
99
+ } else {
100
+ roots.push(node);
101
+ }
102
+ }
103
+ const assignDepth = (n, depth) => {
104
+ n.depth = depth;
105
+ for (const c of n.children) assignDepth(c, depth + 1);
106
+ };
107
+ for (const r of roots) assignDepth(r, 0);
108
+ const confidenceBreakdown = {
109
+ explicit: 0,
110
+ correlated: 0,
111
+ heuristic: 0,
112
+ unknown: 0
113
+ };
114
+ const kinds = {};
115
+ for (const e of sorted) {
116
+ inc(confidenceBreakdown, e.confidence);
117
+ kinds[e.kind] = (kinds[e.kind] ?? 0) + 1;
118
+ }
119
+ const startedAt = sorted.length > 0 ? sorted[0].timestamp : void 0;
120
+ const endedAt = sorted.length > 0 ? sorted[sorted.length - 1].timestamp : void 0;
121
+ const status = computeRunStatus(sorted);
122
+ const durationMs = startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt && status !== "running" ? endedAt - startedAt : void 0;
123
+ const name = sorted.find((e) => e.kind === "RUN")?.name;
124
+ out.push({
125
+ runId,
126
+ name,
127
+ status,
128
+ startedAt,
129
+ endedAt: status === "running" ? void 0 : endedAt,
130
+ durationMs,
131
+ children: roots,
132
+ metadata: {
133
+ totalEvents: sorted.length,
134
+ confidenceBreakdown,
135
+ kinds
136
+ }
137
+ });
138
+ }
139
+ out.sort((a, b) => (b.startedAt ?? 0) - (a.startedAt ?? 0));
140
+ return out;
141
+ }
142
+ };
63
143
  function isRecord2(v) {
64
144
  return typeof v === "object" && v !== null && !Array.isArray(v);
65
145
  }
@@ -398,7 +478,7 @@ function stableHash(value) {
398
478
  const h = crypto__default.default.createHash("sha256").update(value, "utf8").digest("hex");
399
479
  return h.slice(0, 8);
400
480
  }
401
- function compileRules(rules) {
481
+ function compileRules(rules, extraKeys) {
402
482
  const out = /* @__PURE__ */ new Map();
403
483
  const set = (r) => {
404
484
  const k = toKey(r.key);
@@ -407,6 +487,11 @@ function compileRules(rules) {
407
487
  for (const k of DEFAULT_REDACT_KEYS) {
408
488
  set({ key: k, strategy: "full" });
409
489
  }
490
+ for (const k of extraKeys ?? []) {
491
+ if (typeof k === "string" && k.length > 0) {
492
+ set({ key: k, strategy: "full" });
493
+ }
494
+ }
410
495
  for (const r of rules ?? []) {
411
496
  if (typeof r === "string") {
412
497
  set({ key: r, strategy: "full" });
@@ -424,7 +509,7 @@ function compileRules(rules) {
424
509
  var Redactor = class {
425
510
  #rules;
426
511
  constructor(options) {
427
- this.#rules = compileRules(options?.rules);
512
+ this.#rules = compileRules(options?.rules, options?.extraKeys);
428
513
  }
429
514
  redactValue(key, value) {
430
515
  const k = toKey(key);
@@ -466,6 +551,36 @@ var Redactor = class {
466
551
  return value;
467
552
  }
468
553
  };
554
+
555
+ // node_modules/.pnpm/nanoid@5.1.11/node_modules/nanoid/url-alphabet/index.js
556
+ var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
557
+
558
+ // node_modules/.pnpm/nanoid@5.1.11/node_modules/nanoid/index.js
559
+ var POOL_SIZE_MULTIPLIER = 128;
560
+ var pool;
561
+ var poolOffset;
562
+ function fillPool(bytes) {
563
+ if (bytes < 0 || bytes > 1024) throw new RangeError("Wrong ID size");
564
+ if (!pool || pool.length < bytes) {
565
+ pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
566
+ crypto.webcrypto.getRandomValues(pool);
567
+ poolOffset = 0;
568
+ } else if (poolOffset + bytes > pool.length) {
569
+ crypto.webcrypto.getRandomValues(pool);
570
+ poolOffset = 0;
571
+ }
572
+ poolOffset += bytes;
573
+ }
574
+ function nanoid(size = 21) {
575
+ fillPool(size |= 0);
576
+ let id = "";
577
+ for (let i = poolOffset - size; i < poolOffset; i++) {
578
+ id += urlAlphabet[pool[i] & 63];
579
+ }
580
+ return id;
581
+ }
582
+
583
+ // packages/core/src/logs/normalizer.ts
469
584
  function isFiniteNumber(v) {
470
585
  return typeof v === "number" && Number.isFinite(v);
471
586
  }
@@ -600,7 +715,7 @@ var EventNormalizer = class {
600
715
  attributes[k] = v;
601
716
  }
602
717
  const event = {
603
- eventId: nanoid.nanoid(10),
718
+ eventId: nanoid(10),
604
719
  runId,
605
720
  ...parentId ? { parentId } : {},
606
721
  name,
@@ -646,86 +761,6 @@ var EventNormalizer = class {
646
761
  }
647
762
  };
648
763
 
649
- // packages/core/src/logs/tree-builder.ts
650
- function inc(map, key) {
651
- map[key] = (map[key] ?? 0) + 1;
652
- }
653
- function computeRunStatus(events) {
654
- let hasRunning = false;
655
- for (const e of events) {
656
- if (e.status === "error") return "error";
657
- if (e.status === "running") hasRunning = true;
658
- }
659
- if (hasRunning) return "running";
660
- return "ok";
661
- }
662
- var TreeBuilder = class {
663
- constructor(options) {
664
- void options?.config;
665
- }
666
- build(events) {
667
- const byRun = /* @__PURE__ */ new Map();
668
- for (const e of events) {
669
- if (!byRun.has(e.runId)) byRun.set(e.runId, []);
670
- byRun.get(e.runId).push(e);
671
- }
672
- const out = [];
673
- for (const [runId, runEvents] of byRun.entries()) {
674
- const sorted = [...runEvents].sort((a, b) => a.timestamp - b.timestamp);
675
- const nodes = /* @__PURE__ */ new Map();
676
- for (const e of sorted) {
677
- nodes.set(e.eventId, { event: e, children: [], depth: 0 });
678
- }
679
- const roots = [];
680
- for (const node of nodes.values()) {
681
- const parentId = node.event.parentId;
682
- if (parentId && nodes.has(parentId)) {
683
- nodes.get(parentId).children.push(node);
684
- } else {
685
- roots.push(node);
686
- }
687
- }
688
- const assignDepth = (n, depth) => {
689
- n.depth = depth;
690
- for (const c of n.children) assignDepth(c, depth + 1);
691
- };
692
- for (const r of roots) assignDepth(r, 0);
693
- const confidenceBreakdown = {
694
- explicit: 0,
695
- correlated: 0,
696
- heuristic: 0,
697
- unknown: 0
698
- };
699
- const kinds = {};
700
- for (const e of sorted) {
701
- inc(confidenceBreakdown, e.confidence);
702
- kinds[e.kind] = (kinds[e.kind] ?? 0) + 1;
703
- }
704
- const startedAt = sorted.length > 0 ? sorted[0].timestamp : void 0;
705
- const endedAt = sorted.length > 0 ? sorted[sorted.length - 1].timestamp : void 0;
706
- const status = computeRunStatus(sorted);
707
- const durationMs = startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt && status !== "running" ? endedAt - startedAt : void 0;
708
- const name = sorted.find((e) => e.kind === "RUN")?.name;
709
- out.push({
710
- runId,
711
- name,
712
- status,
713
- startedAt,
714
- endedAt: status === "running" ? void 0 : endedAt,
715
- durationMs,
716
- children: roots,
717
- metadata: {
718
- totalEvents: sorted.length,
719
- confidenceBreakdown,
720
- kinds
721
- }
722
- });
723
- }
724
- out.sort((a, b) => (b.startedAt ?? 0) - (a.startedAt ?? 0));
725
- return out;
726
- }
727
- };
728
-
729
764
  // packages/core/src/logs/tree-renderer.ts
730
765
  function truncate(v, max) {
731
766
  if (v.length <= max) return v;
@@ -1065,7 +1100,7 @@ var FALLBACK_TRACE_DIR = path__default.default.join(
1065
1100
  );
1066
1101
  var MAX_NAME_LENGTH = 100;
1067
1102
  function createStepId() {
1068
- return `step_${nanoid.nanoid(10)}`;
1103
+ return `step_${nanoid(10)}`;
1069
1104
  }
1070
1105
  function formatDuration2(ms) {
1071
1106
  return formatDuration(ms);
@@ -1176,6 +1211,91 @@ function warn(message, error) {
1176
1211
  }
1177
1212
  console.warn(`${base}: ${formatError(error).message}`);
1178
1213
  }
1214
+
1215
+ // packages/core/src/redaction-profiles.ts
1216
+ var SHARE_PROFILE_EXTRA_KEYS = [
1217
+ "userEmail",
1218
+ "customerEmail",
1219
+ "phone",
1220
+ "phoneNumber",
1221
+ "address",
1222
+ "ip",
1223
+ "ipAddress",
1224
+ "sessionId",
1225
+ "requestId",
1226
+ "correlationId",
1227
+ "decisionId",
1228
+ "groupId",
1229
+ "customerId",
1230
+ "userId",
1231
+ "accountId",
1232
+ "tenantId",
1233
+ "orgId",
1234
+ "organizationId",
1235
+ "traceId",
1236
+ "spanId",
1237
+ "parentSpanId"
1238
+ ];
1239
+ var STRICT_PROFILE_EXTRA_KEYS = [
1240
+ "prompt",
1241
+ "completion",
1242
+ "input",
1243
+ "output",
1244
+ "inputPreview",
1245
+ "outputPreview",
1246
+ "message",
1247
+ "messages",
1248
+ "transcript",
1249
+ "context",
1250
+ "document",
1251
+ "documents",
1252
+ "chunk",
1253
+ "chunks",
1254
+ "retrieval",
1255
+ "query"
1256
+ ];
1257
+ function resolveRedactionProfile(profile = "local") {
1258
+ switch (profile) {
1259
+ case "local":
1260
+ return { profile: "local", extraKeys: [] };
1261
+ case "share":
1262
+ return {
1263
+ profile: "share",
1264
+ extraKeys: SHARE_PROFILE_EXTRA_KEYS,
1265
+ maxMetadataValueLengthCap: 500,
1266
+ maxPreviewLengthCap: 200
1267
+ };
1268
+ case "strict":
1269
+ return {
1270
+ profile: "strict",
1271
+ extraKeys: [...SHARE_PROFILE_EXTRA_KEYS, ...STRICT_PROFILE_EXTRA_KEYS],
1272
+ maxMetadataValueLengthCap: 200,
1273
+ maxPreviewLengthCap: 80
1274
+ };
1275
+ default:
1276
+ return { profile: "local", extraKeys: [] };
1277
+ }
1278
+ }
1279
+ function isPreviewKey(key) {
1280
+ return key.toLowerCase().includes("preview");
1281
+ }
1282
+ function applyProfileMetadataCaps(maxMetadataValueLength, maxPreviewLength, resolved) {
1283
+ let meta = maxMetadataValueLength;
1284
+ let preview = maxPreviewLength;
1285
+ if (resolved.maxMetadataValueLengthCap !== void 0) {
1286
+ meta = Math.min(meta, resolved.maxMetadataValueLengthCap);
1287
+ }
1288
+ if (resolved.maxPreviewLengthCap !== void 0) {
1289
+ preview = Math.min(preview, resolved.maxPreviewLengthCap);
1290
+ }
1291
+ return { maxMetadataValueLength: meta, maxPreviewLength: preview };
1292
+ }
1293
+ function truncateStringForProfile(value, key, maxMetadataValueLength, maxPreviewLength) {
1294
+ const max = isPreviewKey(key) ? maxPreviewLength : maxMetadataValueLength;
1295
+ if (max <= 0) return "\u2026";
1296
+ if (value.length <= max) return value;
1297
+ return `${value.slice(0, max)}\u2026`;
1298
+ }
1179
1299
  function isRecord6(value) {
1180
1300
  return typeof value === "object" && value !== null && !Array.isArray(value);
1181
1301
  }
@@ -1326,7 +1446,7 @@ var DEFAULT_MAX_EVENT_BYTES = 65536;
1326
1446
  function isRecord7(value) {
1327
1447
  return typeof value === "object" && value !== null && !Array.isArray(value);
1328
1448
  }
1329
- function isPreviewKey(key) {
1449
+ function isPreviewKey2(key) {
1330
1450
  return key.toLowerCase().includes("preview");
1331
1451
  }
1332
1452
  function truncateString(value, maxLen) {
@@ -1343,11 +1463,28 @@ function resolveTraceSafetyOptions(options) {
1343
1463
  {
1344
1464
  redactEnabled = true;
1345
1465
  }
1466
+ const profile = options?.redactionProfile ?? "local";
1467
+ const resolvedProfile = resolveRedactionProfile(profile);
1468
+ const userMaxMetadata = "undefined" === "number" && Number.isFinite(options.maxMetadataValueLength) && options.maxMetadataValueLength >= 0 ? Math.floor(options.maxMetadataValueLength) : void 0;
1469
+ const userMaxPreview = "undefined" === "number" && Number.isFinite(options.maxPreviewLength) && options.maxPreviewLength >= 0 ? Math.floor(options.maxPreviewLength) : void 0;
1470
+ let maxMetadataValueLength = userMaxMetadata ?? DEFAULT_MAX_METADATA_VALUE_LENGTH;
1471
+ let maxPreviewLength = userMaxPreview ?? DEFAULT_MAX_PREVIEW_LENGTH;
1472
+ if (redactEnabled && profile !== "local") {
1473
+ const capped = applyProfileMetadataCaps(
1474
+ maxMetadataValueLength,
1475
+ maxPreviewLength,
1476
+ resolvedProfile
1477
+ );
1478
+ maxMetadataValueLength = capped.maxMetadataValueLength;
1479
+ maxPreviewLength = capped.maxPreviewLength;
1480
+ }
1346
1481
  return {
1347
1482
  redactEnabled,
1348
1483
  redactionRules,
1349
- maxMetadataValueLength: "undefined" === "number" && Number.isFinite(options.maxMetadataValueLength) && options.maxMetadataValueLength >= 0 ? Math.floor(options.maxMetadataValueLength) : DEFAULT_MAX_METADATA_VALUE_LENGTH,
1350
- maxPreviewLength: "undefined" === "number" && Number.isFinite(options.maxPreviewLength) && options.maxPreviewLength >= 0 ? Math.floor(options.maxPreviewLength) : DEFAULT_MAX_PREVIEW_LENGTH,
1484
+ redactionProfile: profile,
1485
+ profileExtraKeys: redactEnabled ? resolvedProfile.extraKeys : [],
1486
+ maxMetadataValueLength,
1487
+ maxPreviewLength,
1351
1488
  maxEventBytes: "undefined" === "number" && Number.isFinite(options.maxEventBytes) && options.maxEventBytes > 0 ? Math.floor(options.maxEventBytes) : DEFAULT_MAX_EVENT_BYTES
1352
1489
  };
1353
1490
  }
@@ -1355,7 +1492,7 @@ function boundMetadataValue(key, value, opts, seen, depth) {
1355
1492
  if (depth > 32) return "[MaxDepth]";
1356
1493
  if (value === null || typeof value !== "object") {
1357
1494
  if (typeof value === "string") {
1358
- const max = isPreviewKey(key) ? opts.maxPreviewLength : opts.maxMetadataValueLength;
1495
+ const max = isPreviewKey2(key) ? opts.maxPreviewLength : opts.maxMetadataValueLength;
1359
1496
  return truncateString(value, max);
1360
1497
  }
1361
1498
  return value;
@@ -1381,7 +1518,10 @@ function boundMetadataValue(key, value, opts, seen, depth) {
1381
1518
  }
1382
1519
  function redactMetadata(metadata, opts) {
1383
1520
  if (!opts.redactEnabled) return { ...metadata };
1384
- const redactor = new Redactor({ rules: opts.redactionRules });
1521
+ const redactor = new Redactor({
1522
+ rules: opts.redactionRules,
1523
+ extraKeys: opts.profileExtraKeys
1524
+ });
1385
1525
  return redactor.redactRecord(metadata);
1386
1526
  }
1387
1527
  function prepareMetadataForDisk(metadata, opts) {
@@ -2396,6 +2536,498 @@ function diffRuns(left, right, options) {
2396
2536
  };
2397
2537
  return { summary, differences };
2398
2538
  }
2539
+
2540
+ // node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js
2541
+ var ANSI_BACKGROUND_OFFSET = 10;
2542
+ var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
2543
+ var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
2544
+ var wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
2545
+ var styles = {
2546
+ modifier: {
2547
+ reset: [0, 0],
2548
+ // 21 isn't widely supported and 22 does the same thing
2549
+ bold: [1, 22],
2550
+ dim: [2, 22],
2551
+ italic: [3, 23],
2552
+ underline: [4, 24],
2553
+ overline: [53, 55],
2554
+ inverse: [7, 27],
2555
+ hidden: [8, 28],
2556
+ strikethrough: [9, 29]
2557
+ },
2558
+ color: {
2559
+ black: [30, 39],
2560
+ red: [31, 39],
2561
+ green: [32, 39],
2562
+ yellow: [33, 39],
2563
+ blue: [34, 39],
2564
+ magenta: [35, 39],
2565
+ cyan: [36, 39],
2566
+ white: [37, 39],
2567
+ // Bright color
2568
+ blackBright: [90, 39],
2569
+ gray: [90, 39],
2570
+ // Alias of `blackBright`
2571
+ grey: [90, 39],
2572
+ // Alias of `blackBright`
2573
+ redBright: [91, 39],
2574
+ greenBright: [92, 39],
2575
+ yellowBright: [93, 39],
2576
+ blueBright: [94, 39],
2577
+ magentaBright: [95, 39],
2578
+ cyanBright: [96, 39],
2579
+ whiteBright: [97, 39]
2580
+ },
2581
+ bgColor: {
2582
+ bgBlack: [40, 49],
2583
+ bgRed: [41, 49],
2584
+ bgGreen: [42, 49],
2585
+ bgYellow: [43, 49],
2586
+ bgBlue: [44, 49],
2587
+ bgMagenta: [45, 49],
2588
+ bgCyan: [46, 49],
2589
+ bgWhite: [47, 49],
2590
+ // Bright color
2591
+ bgBlackBright: [100, 49],
2592
+ bgGray: [100, 49],
2593
+ // Alias of `bgBlackBright`
2594
+ bgGrey: [100, 49],
2595
+ // Alias of `bgBlackBright`
2596
+ bgRedBright: [101, 49],
2597
+ bgGreenBright: [102, 49],
2598
+ bgYellowBright: [103, 49],
2599
+ bgBlueBright: [104, 49],
2600
+ bgMagentaBright: [105, 49],
2601
+ bgCyanBright: [106, 49],
2602
+ bgWhiteBright: [107, 49]
2603
+ }
2604
+ };
2605
+ Object.keys(styles.modifier);
2606
+ var foregroundColorNames = Object.keys(styles.color);
2607
+ var backgroundColorNames = Object.keys(styles.bgColor);
2608
+ [...foregroundColorNames, ...backgroundColorNames];
2609
+ function assembleStyles() {
2610
+ const codes = /* @__PURE__ */ new Map();
2611
+ for (const [groupName, group] of Object.entries(styles)) {
2612
+ for (const [styleName, style] of Object.entries(group)) {
2613
+ styles[styleName] = {
2614
+ open: `\x1B[${style[0]}m`,
2615
+ close: `\x1B[${style[1]}m`
2616
+ };
2617
+ group[styleName] = styles[styleName];
2618
+ codes.set(style[0], style[1]);
2619
+ }
2620
+ Object.defineProperty(styles, groupName, {
2621
+ value: group,
2622
+ enumerable: false
2623
+ });
2624
+ }
2625
+ Object.defineProperty(styles, "codes", {
2626
+ value: codes,
2627
+ enumerable: false
2628
+ });
2629
+ styles.color.close = "\x1B[39m";
2630
+ styles.bgColor.close = "\x1B[49m";
2631
+ styles.color.ansi = wrapAnsi16();
2632
+ styles.color.ansi256 = wrapAnsi256();
2633
+ styles.color.ansi16m = wrapAnsi16m();
2634
+ styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
2635
+ styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
2636
+ styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
2637
+ Object.defineProperties(styles, {
2638
+ rgbToAnsi256: {
2639
+ value(red, green, blue) {
2640
+ if (red === green && green === blue) {
2641
+ if (red < 8) {
2642
+ return 16;
2643
+ }
2644
+ if (red > 248) {
2645
+ return 231;
2646
+ }
2647
+ return Math.round((red - 8) / 247 * 24) + 232;
2648
+ }
2649
+ return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
2650
+ },
2651
+ enumerable: false
2652
+ },
2653
+ hexToRgb: {
2654
+ value(hex) {
2655
+ const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
2656
+ if (!matches) {
2657
+ return [0, 0, 0];
2658
+ }
2659
+ let [colorString] = matches;
2660
+ if (colorString.length === 3) {
2661
+ colorString = [...colorString].map((character) => character + character).join("");
2662
+ }
2663
+ const integer = Number.parseInt(colorString, 16);
2664
+ return [
2665
+ /* eslint-disable no-bitwise */
2666
+ integer >> 16 & 255,
2667
+ integer >> 8 & 255,
2668
+ integer & 255
2669
+ /* eslint-enable no-bitwise */
2670
+ ];
2671
+ },
2672
+ enumerable: false
2673
+ },
2674
+ hexToAnsi256: {
2675
+ value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
2676
+ enumerable: false
2677
+ },
2678
+ ansi256ToAnsi: {
2679
+ value(code) {
2680
+ if (code < 8) {
2681
+ return 30 + code;
2682
+ }
2683
+ if (code < 16) {
2684
+ return 90 + (code - 8);
2685
+ }
2686
+ let red;
2687
+ let green;
2688
+ let blue;
2689
+ if (code >= 232) {
2690
+ red = ((code - 232) * 10 + 8) / 255;
2691
+ green = red;
2692
+ blue = red;
2693
+ } else {
2694
+ code -= 16;
2695
+ const remainder = code % 36;
2696
+ red = Math.floor(code / 36) / 5;
2697
+ green = Math.floor(remainder / 6) / 5;
2698
+ blue = remainder % 6 / 5;
2699
+ }
2700
+ const value = Math.max(red, green, blue) * 2;
2701
+ if (value === 0) {
2702
+ return 30;
2703
+ }
2704
+ let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
2705
+ if (value === 2) {
2706
+ result += 60;
2707
+ }
2708
+ return result;
2709
+ },
2710
+ enumerable: false
2711
+ },
2712
+ rgbToAnsi: {
2713
+ value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
2714
+ enumerable: false
2715
+ },
2716
+ hexToAnsi: {
2717
+ value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
2718
+ enumerable: false
2719
+ }
2720
+ });
2721
+ return styles;
2722
+ }
2723
+ var ansiStyles = assembleStyles();
2724
+ var ansi_styles_default = ansiStyles;
2725
+ function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2__default.default.argv) {
2726
+ const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
2727
+ const position = argv.indexOf(prefix + flag);
2728
+ const terminatorPosition = argv.indexOf("--");
2729
+ return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
2730
+ }
2731
+ var { env } = process2__default.default;
2732
+ var flagForceColor;
2733
+ if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
2734
+ flagForceColor = 0;
2735
+ } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
2736
+ flagForceColor = 1;
2737
+ }
2738
+ function envForceColor() {
2739
+ if ("FORCE_COLOR" in env) {
2740
+ if (env.FORCE_COLOR === "true") {
2741
+ return 1;
2742
+ }
2743
+ if (env.FORCE_COLOR === "false") {
2744
+ return 0;
2745
+ }
2746
+ return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
2747
+ }
2748
+ }
2749
+ function translateLevel(level) {
2750
+ if (level === 0) {
2751
+ return false;
2752
+ }
2753
+ return {
2754
+ level,
2755
+ hasBasic: true,
2756
+ has256: level >= 2,
2757
+ has16m: level >= 3
2758
+ };
2759
+ }
2760
+ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
2761
+ const noFlagForceColor = envForceColor();
2762
+ if (noFlagForceColor !== void 0) {
2763
+ flagForceColor = noFlagForceColor;
2764
+ }
2765
+ const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
2766
+ if (forceColor === 0) {
2767
+ return 0;
2768
+ }
2769
+ if (sniffFlags) {
2770
+ if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
2771
+ return 3;
2772
+ }
2773
+ if (hasFlag("color=256")) {
2774
+ return 2;
2775
+ }
2776
+ }
2777
+ if ("TF_BUILD" in env && "AGENT_NAME" in env) {
2778
+ return 1;
2779
+ }
2780
+ if (haveStream && !streamIsTTY && forceColor === void 0) {
2781
+ return 0;
2782
+ }
2783
+ const min = forceColor || 0;
2784
+ if (env.TERM === "dumb") {
2785
+ return min;
2786
+ }
2787
+ if (process2__default.default.platform === "win32") {
2788
+ const osRelease = os__default.default.release().split(".");
2789
+ if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
2790
+ return Number(osRelease[2]) >= 14931 ? 3 : 2;
2791
+ }
2792
+ return 1;
2793
+ }
2794
+ if ("CI" in env) {
2795
+ if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) {
2796
+ return 3;
2797
+ }
2798
+ if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
2799
+ return 1;
2800
+ }
2801
+ return min;
2802
+ }
2803
+ if ("TEAMCITY_VERSION" in env) {
2804
+ return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
2805
+ }
2806
+ if (env.COLORTERM === "truecolor") {
2807
+ return 3;
2808
+ }
2809
+ if (env.TERM === "xterm-kitty") {
2810
+ return 3;
2811
+ }
2812
+ if (env.TERM === "xterm-ghostty") {
2813
+ return 3;
2814
+ }
2815
+ if (env.TERM === "wezterm") {
2816
+ return 3;
2817
+ }
2818
+ if ("TERM_PROGRAM" in env) {
2819
+ const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
2820
+ switch (env.TERM_PROGRAM) {
2821
+ case "iTerm.app": {
2822
+ return version >= 3 ? 3 : 2;
2823
+ }
2824
+ case "Apple_Terminal": {
2825
+ return 2;
2826
+ }
2827
+ }
2828
+ }
2829
+ if (/-256(color)?$/i.test(env.TERM)) {
2830
+ return 2;
2831
+ }
2832
+ if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
2833
+ return 1;
2834
+ }
2835
+ if ("COLORTERM" in env) {
2836
+ return 1;
2837
+ }
2838
+ return min;
2839
+ }
2840
+ function createSupportsColor(stream, options = {}) {
2841
+ const level = _supportsColor(stream, {
2842
+ streamIsTTY: stream && stream.isTTY,
2843
+ ...options
2844
+ });
2845
+ return translateLevel(level);
2846
+ }
2847
+ var supportsColor = {
2848
+ stdout: createSupportsColor({ isTTY: tty__default.default.isatty(1) }),
2849
+ stderr: createSupportsColor({ isTTY: tty__default.default.isatty(2) })
2850
+ };
2851
+ var supports_color_default = supportsColor;
2852
+
2853
+ // node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/utilities.js
2854
+ function stringReplaceAll(string, substring, replacer) {
2855
+ let index = string.indexOf(substring);
2856
+ if (index === -1) {
2857
+ return string;
2858
+ }
2859
+ const substringLength = substring.length;
2860
+ let endIndex = 0;
2861
+ let returnValue = "";
2862
+ do {
2863
+ returnValue += string.slice(endIndex, index) + substring + replacer;
2864
+ endIndex = index + substringLength;
2865
+ index = string.indexOf(substring, endIndex);
2866
+ } while (index !== -1);
2867
+ returnValue += string.slice(endIndex);
2868
+ return returnValue;
2869
+ }
2870
+ function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
2871
+ let endIndex = 0;
2872
+ let returnValue = "";
2873
+ do {
2874
+ const gotCR = string[index - 1] === "\r";
2875
+ returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
2876
+ endIndex = index + 1;
2877
+ index = string.indexOf("\n", endIndex);
2878
+ } while (index !== -1);
2879
+ returnValue += string.slice(endIndex);
2880
+ return returnValue;
2881
+ }
2882
+
2883
+ // node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/index.js
2884
+ var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
2885
+ var GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
2886
+ var STYLER = /* @__PURE__ */ Symbol("STYLER");
2887
+ var IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
2888
+ var levelMapping = [
2889
+ "ansi",
2890
+ "ansi",
2891
+ "ansi256",
2892
+ "ansi16m"
2893
+ ];
2894
+ var styles2 = /* @__PURE__ */ Object.create(null);
2895
+ var applyOptions = (object, options = {}) => {
2896
+ if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
2897
+ throw new Error("The `level` option should be an integer from 0 to 3");
2898
+ }
2899
+ const colorLevel = stdoutColor ? stdoutColor.level : 0;
2900
+ object.level = options.level === void 0 ? colorLevel : options.level;
2901
+ };
2902
+ var chalkFactory = (options) => {
2903
+ const chalk2 = (...strings) => strings.join(" ");
2904
+ applyOptions(chalk2, options);
2905
+ Object.setPrototypeOf(chalk2, createChalk.prototype);
2906
+ return chalk2;
2907
+ };
2908
+ function createChalk(options) {
2909
+ return chalkFactory(options);
2910
+ }
2911
+ Object.setPrototypeOf(createChalk.prototype, Function.prototype);
2912
+ for (const [styleName, style] of Object.entries(ansi_styles_default)) {
2913
+ styles2[styleName] = {
2914
+ get() {
2915
+ const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
2916
+ Object.defineProperty(this, styleName, { value: builder });
2917
+ return builder;
2918
+ }
2919
+ };
2920
+ }
2921
+ styles2.visible = {
2922
+ get() {
2923
+ const builder = createBuilder(this, this[STYLER], true);
2924
+ Object.defineProperty(this, "visible", { value: builder });
2925
+ return builder;
2926
+ }
2927
+ };
2928
+ var getModelAnsi = (model, level, type, ...arguments_) => {
2929
+ if (model === "rgb") {
2930
+ if (level === "ansi16m") {
2931
+ return ansi_styles_default[type].ansi16m(...arguments_);
2932
+ }
2933
+ if (level === "ansi256") {
2934
+ return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
2935
+ }
2936
+ return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
2937
+ }
2938
+ if (model === "hex") {
2939
+ return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
2940
+ }
2941
+ return ansi_styles_default[type][model](...arguments_);
2942
+ };
2943
+ var usedModels = ["rgb", "hex", "ansi256"];
2944
+ for (const model of usedModels) {
2945
+ styles2[model] = {
2946
+ get() {
2947
+ const { level } = this;
2948
+ return function(...arguments_) {
2949
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
2950
+ return createBuilder(this, styler, this[IS_EMPTY]);
2951
+ };
2952
+ }
2953
+ };
2954
+ const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
2955
+ styles2[bgModel] = {
2956
+ get() {
2957
+ const { level } = this;
2958
+ return function(...arguments_) {
2959
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
2960
+ return createBuilder(this, styler, this[IS_EMPTY]);
2961
+ };
2962
+ }
2963
+ };
2964
+ }
2965
+ var proto = Object.defineProperties(() => {
2966
+ }, {
2967
+ ...styles2,
2968
+ level: {
2969
+ enumerable: true,
2970
+ get() {
2971
+ return this[GENERATOR].level;
2972
+ },
2973
+ set(level) {
2974
+ this[GENERATOR].level = level;
2975
+ }
2976
+ }
2977
+ });
2978
+ var createStyler = (open2, close, parent) => {
2979
+ let openAll;
2980
+ let closeAll;
2981
+ if (parent === void 0) {
2982
+ openAll = open2;
2983
+ closeAll = close;
2984
+ } else {
2985
+ openAll = parent.openAll + open2;
2986
+ closeAll = close + parent.closeAll;
2987
+ }
2988
+ return {
2989
+ open: open2,
2990
+ close,
2991
+ openAll,
2992
+ closeAll,
2993
+ parent
2994
+ };
2995
+ };
2996
+ var createBuilder = (self, _styler, _isEmpty) => {
2997
+ const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
2998
+ Object.setPrototypeOf(builder, proto);
2999
+ builder[GENERATOR] = self;
3000
+ builder[STYLER] = _styler;
3001
+ builder[IS_EMPTY] = _isEmpty;
3002
+ return builder;
3003
+ };
3004
+ var applyStyle = (self, string) => {
3005
+ if (self.level <= 0 || !string) {
3006
+ return self[IS_EMPTY] ? "" : string;
3007
+ }
3008
+ let styler = self[STYLER];
3009
+ if (styler === void 0) {
3010
+ return string;
3011
+ }
3012
+ const { openAll, closeAll } = styler;
3013
+ if (string.includes("\x1B")) {
3014
+ while (styler !== void 0) {
3015
+ string = stringReplaceAll(string, styler.close, styler.open);
3016
+ styler = styler.parent;
3017
+ }
3018
+ }
3019
+ const lfIndex = string.indexOf("\n");
3020
+ if (lfIndex !== -1) {
3021
+ string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
3022
+ }
3023
+ return openAll + string + closeAll;
3024
+ };
3025
+ Object.defineProperties(createChalk.prototype, styles2);
3026
+ var chalk = createChalk();
3027
+ createChalk({ level: stderrColor ? stderrColor.level : 0 });
3028
+ var source_default = chalk;
3029
+
3030
+ // packages/core/src/diff/renderer.ts
2399
3031
  function formatPath(path7) {
2400
3032
  if (path7 === void 0 || path7.path.length === 0) {
2401
3033
  return "(run)";
@@ -2476,6 +3108,8 @@ function diffTraceEvents(leftEvents, rightEvents, options) {
2476
3108
  const right = manualTraceEventsToComparableRun(rightEvents);
2477
3109
  return diffRuns(left, right, options);
2478
3110
  }
3111
+
3112
+ // packages/core/src/terminal.ts
2479
3113
  var TERMINAL_INDENT = " ";
2480
3114
  var MAX_TERMINAL_NAME_LENGTH = 80;
2481
3115
  var MAX_TERMINAL_DEPTH = 10;
@@ -2501,24 +3135,24 @@ function formatTerminalName(name) {
2501
3135
  return truncateName(name, MAX_TERMINAL_NAME_LENGTH);
2502
3136
  }
2503
3137
  function getStatusIcon(status) {
2504
- if (status === "success") return chalk2__default.default.green("\u2714");
2505
- if (status === "error") return chalk2__default.default.red("\u2716");
2506
- return chalk2__default.default.yellow("\u23F3");
3138
+ if (status === "success") return source_default.green("\u2714");
3139
+ if (status === "error") return source_default.red("\u2716");
3140
+ return source_default.yellow("\u23F3");
2507
3141
  }
2508
3142
  function renderStepLine(name, durationMs, status, depth) {
2509
3143
  try {
2510
3144
  const nm = formatTerminalName(name);
2511
3145
  const ind = getIndent(depth ?? 0);
2512
3146
  if (status === "running" && durationMs === void 0) {
2513
- return `${ind}${chalk2__default.default.yellow("\u23F3")} ${nm}`;
3147
+ return `${ind}${source_default.yellow("\u23F3")} ${nm}`;
2514
3148
  }
2515
3149
  const hasDur = durationMs !== void 0 && Number.isFinite(durationMs);
2516
3150
  const dur = hasDur ? formatDuration2(durationMs) : void 0;
2517
3151
  if (status === "running") {
2518
- return dur !== void 0 ? `${ind}${chalk2__default.default.yellow("\u23F3")} ${nm} (${dur})` : `${ind}${chalk2__default.default.yellow("\u23F3")} ${nm}`;
3152
+ return dur !== void 0 ? `${ind}${source_default.yellow("\u23F3")} ${nm} (${dur})` : `${ind}${source_default.yellow("\u23F3")} ${nm}`;
2519
3153
  }
2520
3154
  if (!hasDur || dur === void 0) {
2521
- return `${ind}${chalk2__default.default.yellow("\u23F3")} ${nm}`;
3155
+ return `${ind}${source_default.yellow("\u23F3")} ${nm}`;
2522
3156
  }
2523
3157
  if (status === "success") {
2524
3158
  return `${ind}${getStatusIcon("success")} ${nm} (${dur})`;
@@ -2694,6 +3328,134 @@ Object.assign(stepImpl, {
2694
3328
  // packages/core/src/exporters/types.ts
2695
3329
  var EXPORT_PAYLOAD_VERSION = "0.1.2";
2696
3330
 
3331
+ // packages/core/src/exporters/redact-export.ts
3332
+ function isRecord9(value) {
3333
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3334
+ }
3335
+ function deepClone(value) {
3336
+ if (value === null || typeof value !== "object") {
3337
+ return value;
3338
+ }
3339
+ if (Array.isArray(value)) {
3340
+ return value.map((item) => deepClone(item));
3341
+ }
3342
+ const out = {};
3343
+ for (const [k, v] of Object.entries(value)) {
3344
+ out[k] = deepClone(v);
3345
+ }
3346
+ return out;
3347
+ }
3348
+ function boundAttributeValues(record, maxMetadataValueLength, maxPreviewLength, seen, depth) {
3349
+ if (depth > 32) {
3350
+ return { truncated: true, reason: "maxDepth" };
3351
+ }
3352
+ const out = {};
3353
+ for (const [key, value] of Object.entries(record)) {
3354
+ out[key] = boundValue(value, key, maxMetadataValueLength, maxPreviewLength, seen, depth);
3355
+ }
3356
+ return out;
3357
+ }
3358
+ function boundValue(value, key, maxMetadataValueLength, maxPreviewLength, seen, depth) {
3359
+ if (value === null || typeof value !== "object") {
3360
+ if (typeof value === "string") {
3361
+ return truncateStringForProfile(
3362
+ value,
3363
+ key,
3364
+ maxMetadataValueLength,
3365
+ maxPreviewLength
3366
+ );
3367
+ }
3368
+ return value;
3369
+ }
3370
+ if (seen.has(value)) return "[Circular]";
3371
+ seen.add(value);
3372
+ if (Array.isArray(value)) {
3373
+ return value.slice(0, 50).map(
3374
+ (item, index) => boundValue(
3375
+ item,
3376
+ String(index),
3377
+ maxMetadataValueLength,
3378
+ maxPreviewLength,
3379
+ seen,
3380
+ depth + 1
3381
+ )
3382
+ );
3383
+ }
3384
+ return boundAttributeValues(
3385
+ value,
3386
+ maxMetadataValueLength,
3387
+ maxPreviewLength,
3388
+ seen,
3389
+ depth + 1
3390
+ );
3391
+ }
3392
+ function redactEventAttributes(attrs, redactor, maxMetadataValueLength, maxPreviewLength) {
3393
+ if (!attrs || Object.keys(attrs).length === 0) {
3394
+ return attrs;
3395
+ }
3396
+ const redacted = redactor.redactRecord(attrs);
3397
+ const seen = /* @__PURE__ */ new WeakSet();
3398
+ const bounded = boundAttributeValues(
3399
+ redacted,
3400
+ maxMetadataValueLength,
3401
+ maxPreviewLength,
3402
+ seen,
3403
+ 0
3404
+ );
3405
+ const err = bounded.error;
3406
+ if (isRecord9(err) && typeof err.message === "string") {
3407
+ bounded.error = {
3408
+ ...err,
3409
+ message: truncateStringForProfile(
3410
+ err.message,
3411
+ "message",
3412
+ maxMetadataValueLength,
3413
+ maxPreviewLength
3414
+ ),
3415
+ ...typeof err.stack === "string" ? {
3416
+ stack: truncateStringForProfile(
3417
+ err.stack,
3418
+ "stack",
3419
+ maxMetadataValueLength,
3420
+ maxPreviewLength
3421
+ )
3422
+ } : {}
3423
+ };
3424
+ }
3425
+ return bounded;
3426
+ }
3427
+ function redactRunTreeForExport(tree, options) {
3428
+ const profile = options?.redactionProfile ?? "local";
3429
+ if (profile === "local") {
3430
+ return deepClone(tree);
3431
+ }
3432
+ const resolved = resolveRedactionProfile(profile);
3433
+ const { maxMetadataValueLength, maxPreviewLength } = applyProfileMetadataCaps(
3434
+ 2e3,
3435
+ 500,
3436
+ resolved
3437
+ );
3438
+ const redactor = new Redactor({ extraKeys: resolved.extraKeys });
3439
+ const clone = deepClone(tree);
3440
+ function walk(nodes) {
3441
+ for (const node of nodes) {
3442
+ if (node.event.attributes !== void 0) {
3443
+ node.event.attributes = redactEventAttributes(
3444
+ node.event.attributes,
3445
+ redactor,
3446
+ maxMetadataValueLength,
3447
+ maxPreviewLength
3448
+ );
3449
+ }
3450
+ if (node.children.length > 0) {
3451
+ walk(node.children);
3452
+ }
3453
+ }
3454
+ }
3455
+ walk(clone.children);
3456
+ return clone;
3457
+ }
3458
+
2697
3459
  // packages/core/src/exporters/html-exporter.ts
2698
3460
  function renderTreeHtml(nodes, ulClass = "tree") {
2699
3461
  if (nodes.length === 0) return "";
@@ -3428,20 +4190,22 @@ function mergeExportDefaults(options) {
3428
4190
  includeErrors: options.includeErrors ?? true,
3429
4191
  pretty: options.pretty,
3430
4192
  redacted: options.redacted,
3431
- maxAttributeLength: options.maxAttributeLength
4193
+ maxAttributeLength: options.maxAttributeLength,
4194
+ redactionProfile: options.redactionProfile ?? "local"
3432
4195
  };
3433
4196
  }
3434
4197
  function exportRunTree(tree, options) {
3435
4198
  const opts = mergeExportDefaults(options);
4199
+ const exportTree = opts.redactionProfile === "local" ? tree : redactRunTreeForExport(tree, { redactionProfile: opts.redactionProfile });
3436
4200
  switch (opts.format) {
3437
4201
  case "markdown":
3438
- return exportMarkdown(tree, opts);
4202
+ return exportMarkdown(exportTree, opts);
3439
4203
  case "html":
3440
- return exportHtml(tree, opts);
4204
+ return exportHtml(exportTree, opts);
3441
4205
  case "openinference":
3442
- return exportOpenInference(tree, opts);
4206
+ return exportOpenInference(exportTree, opts);
3443
4207
  case "otlp-json":
3444
- return exportOtlpJson(tree, opts);
4208
+ return exportOtlpJson(exportTree, opts);
3445
4209
  default: {
3446
4210
  const _x = opts.format;
3447
4211
  throw new Error(`Unsupported export format: ${String(_x)}`);
@@ -3571,7 +4335,7 @@ function stableSortNewestFirst(a, b) {
3571
4335
  }
3572
4336
  async function confirmDeletion(count) {
3573
4337
  const { createInterface: createInterface2 } = await import('readline/promises');
3574
- const rl = createInterface2({ input: process$1.stdin, output: process$1.stdout });
4338
+ const rl = createInterface2({ input: process2.stdin, output: process2.stdout });
3575
4339
  try {
3576
4340
  const answer = await rl.question(
3577
4341
  `Delete ${count} AgentInspect trace file(s)? Type "yes" to continue: `
@@ -3664,7 +4428,7 @@ async function clean(options = {}) {
3664
4428
  return;
3665
4429
  }
3666
4430
  if (options.yes !== true) {
3667
- if (process$1.stdin.isTTY !== true) {
4431
+ if (process2.stdin.isTTY !== true) {
3668
4432
  console.error(
3669
4433
  "Refusing to delete without --yes in a non-interactive terminal."
3670
4434
  );
@@ -4074,7 +4838,7 @@ function sleep(ms) {
4074
4838
  }
4075
4839
  async function* readStdinLines() {
4076
4840
  const { createInterface: createInterface2 } = await import('readline');
4077
- const rl = createInterface2({ input: process$1.stdin, crlfDelay: Infinity });
4841
+ const rl = createInterface2({ input: process2.stdin, crlfDelay: Infinity });
4078
4842
  try {
4079
4843
  for await (const line of rl) {
4080
4844
  yield line;
@@ -4277,6 +5041,15 @@ async function tail(options = {}) {
4277
5041
  process.exitCode = 1;
4278
5042
  }
4279
5043
  }
5044
+ function parseRedactionProfile(s) {
5045
+ const v = (s ?? "local").trim().toLowerCase();
5046
+ if (v === "local" || v === "share" || v === "strict") {
5047
+ return v;
5048
+ }
5049
+ throw new Error(
5050
+ `Unsupported --redaction-profile "${s ?? ""}". Use local, share, or strict.`
5051
+ );
5052
+ }
4280
5053
  function parseExportFormat(s) {
4281
5054
  const v = (s ?? "markdown").trim().toLowerCase();
4282
5055
  if (v === "markdown" || v === "html" || v === "openinference" || v === "otlp-json") {
@@ -4294,8 +5067,10 @@ async function exportCommand(runId, options = {}) {
4294
5067
  return;
4295
5068
  }
4296
5069
  let format;
5070
+ let redactionProfile;
4297
5071
  try {
4298
5072
  format = parseExportFormat(options.format);
5073
+ redactionProfile = parseRedactionProfile(options.redactionProfile);
4299
5074
  } catch (e) {
4300
5075
  const msg = e instanceof Error ? e.message : String(e);
4301
5076
  console.error(msg);
@@ -4334,7 +5109,8 @@ Trace directory: ${traceDir}`);
4334
5109
  includeErrors: options.noErrors === true ? false : true,
4335
5110
  pretty: true,
4336
5111
  redacted: true,
4337
- maxAttributeLength: 500
5112
+ maxAttributeLength: 500,
5113
+ redactionProfile
4338
5114
  };
4339
5115
  const result = exportRunTree(tree, exportOpts);
4340
5116
  const validation = options.validate === true ? validateExport(result) : void 0;
@@ -4567,7 +5343,12 @@ function createCliProgram() {
4567
5343
  "openinference",
4568
5344
  "otlp-json"
4569
5345
  ])
4570
- ).option("-o, --output <path>", "write export to file (creates parent dirs)").option("--json", "emit JSON wrapper about the export (includes content when writing to stdout)").option("--validate", "validate exported payload shape after generation").option("--include-attributes", "include bounded attributes (review before sharing)").option("--no-metadata", "omit summary / metadata sections").option("--no-errors", "omit error sections").action((runId, opts) => {
5346
+ ).option("-o, --output <path>", "write export to file (creates parent dirs)").option("--json", "emit JSON wrapper about the export (includes content when writing to stdout)").option("--validate", "validate exported payload shape after generation").option("--include-attributes", "include bounded attributes (review before sharing)").option("--no-metadata", "omit summary / metadata sections").option("--no-errors", "omit error sections").addOption(
5347
+ new commander.Option(
5348
+ "--redaction-profile <profile>",
5349
+ "redaction profile for exported copies: local, share, strict (default: local)"
5350
+ ).choices(["local", "share", "strict"])
5351
+ ).action((runId, opts) => {
4571
5352
  runCommand(() => exportCommand(runId, opts));
4572
5353
  });
4573
5354
  program.command("diff").description("Compare two local AgentInspect JSONL traces (read-only)").argument("<left-run-id>", "first run id").argument("<right-run-id>", "second run id").option("--dir <path>", "trace directory").option("--json", "print diff result as JSON").option("--ignore-duration", "omit duration comparisons").option(