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.
@@ -4,13 +4,12 @@ import path from 'path';
4
4
  import { fileURLToPath } from 'url';
5
5
  import { Command, Option } from 'commander';
6
6
  import { unlink, stat, mkdir, writeFile, appendFile, readdir, readFile, open } from 'fs/promises';
7
- import crypto from 'crypto';
8
- import { nanoid } from 'nanoid';
7
+ import crypto, { webcrypto } from 'crypto';
9
8
  import os from 'os';
10
9
  import { AsyncLocalStorage } from 'async_hooks';
11
10
  import { createInterface } from 'readline';
12
- import chalk2 from 'chalk';
13
- import { stdin, stdout } from 'process';
11
+ import process2, { stdin, stdout } from 'process';
12
+ import tty from 'tty';
14
13
 
15
14
  // packages/core/src/types.ts
16
15
  var STEP_TYPES = [
@@ -50,6 +49,86 @@ function isTraceEvent(value) {
50
49
  return false;
51
50
  }
52
51
  }
52
+
53
+ // packages/core/src/logs/tree-builder.ts
54
+ function inc(map, key) {
55
+ map[key] = (map[key] ?? 0) + 1;
56
+ }
57
+ function computeRunStatus(events) {
58
+ let hasRunning = false;
59
+ for (const e of events) {
60
+ if (e.status === "error") return "error";
61
+ if (e.status === "running") hasRunning = true;
62
+ }
63
+ if (hasRunning) return "running";
64
+ return "ok";
65
+ }
66
+ var TreeBuilder = class {
67
+ constructor(options) {
68
+ void options?.config;
69
+ }
70
+ build(events) {
71
+ const byRun = /* @__PURE__ */ new Map();
72
+ for (const e of events) {
73
+ if (!byRun.has(e.runId)) byRun.set(e.runId, []);
74
+ byRun.get(e.runId).push(e);
75
+ }
76
+ const out = [];
77
+ for (const [runId, runEvents] of byRun.entries()) {
78
+ const sorted = [...runEvents].sort((a, b) => a.timestamp - b.timestamp);
79
+ const nodes = /* @__PURE__ */ new Map();
80
+ for (const e of sorted) {
81
+ nodes.set(e.eventId, { event: e, children: [], depth: 0 });
82
+ }
83
+ const roots = [];
84
+ for (const node of nodes.values()) {
85
+ const parentId = node.event.parentId;
86
+ if (parentId && nodes.has(parentId)) {
87
+ nodes.get(parentId).children.push(node);
88
+ } else {
89
+ roots.push(node);
90
+ }
91
+ }
92
+ const assignDepth = (n, depth) => {
93
+ n.depth = depth;
94
+ for (const c of n.children) assignDepth(c, depth + 1);
95
+ };
96
+ for (const r of roots) assignDepth(r, 0);
97
+ const confidenceBreakdown = {
98
+ explicit: 0,
99
+ correlated: 0,
100
+ heuristic: 0,
101
+ unknown: 0
102
+ };
103
+ const kinds = {};
104
+ for (const e of sorted) {
105
+ inc(confidenceBreakdown, e.confidence);
106
+ kinds[e.kind] = (kinds[e.kind] ?? 0) + 1;
107
+ }
108
+ const startedAt = sorted.length > 0 ? sorted[0].timestamp : void 0;
109
+ const endedAt = sorted.length > 0 ? sorted[sorted.length - 1].timestamp : void 0;
110
+ const status = computeRunStatus(sorted);
111
+ const durationMs = startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt && status !== "running" ? endedAt - startedAt : void 0;
112
+ const name = sorted.find((e) => e.kind === "RUN")?.name;
113
+ out.push({
114
+ runId,
115
+ name,
116
+ status,
117
+ startedAt,
118
+ endedAt: status === "running" ? void 0 : endedAt,
119
+ durationMs,
120
+ children: roots,
121
+ metadata: {
122
+ totalEvents: sorted.length,
123
+ confidenceBreakdown,
124
+ kinds
125
+ }
126
+ });
127
+ }
128
+ out.sort((a, b) => (b.startedAt ?? 0) - (a.startedAt ?? 0));
129
+ return out;
130
+ }
131
+ };
53
132
  function isRecord2(v) {
54
133
  return typeof v === "object" && v !== null && !Array.isArray(v);
55
134
  }
@@ -388,7 +467,7 @@ function stableHash(value) {
388
467
  const h = crypto.createHash("sha256").update(value, "utf8").digest("hex");
389
468
  return h.slice(0, 8);
390
469
  }
391
- function compileRules(rules) {
470
+ function compileRules(rules, extraKeys) {
392
471
  const out = /* @__PURE__ */ new Map();
393
472
  const set = (r) => {
394
473
  const k = toKey(r.key);
@@ -397,6 +476,11 @@ function compileRules(rules) {
397
476
  for (const k of DEFAULT_REDACT_KEYS) {
398
477
  set({ key: k, strategy: "full" });
399
478
  }
479
+ for (const k of extraKeys ?? []) {
480
+ if (typeof k === "string" && k.length > 0) {
481
+ set({ key: k, strategy: "full" });
482
+ }
483
+ }
400
484
  for (const r of rules ?? []) {
401
485
  if (typeof r === "string") {
402
486
  set({ key: r, strategy: "full" });
@@ -414,7 +498,7 @@ function compileRules(rules) {
414
498
  var Redactor = class {
415
499
  #rules;
416
500
  constructor(options) {
417
- this.#rules = compileRules(options?.rules);
501
+ this.#rules = compileRules(options?.rules, options?.extraKeys);
418
502
  }
419
503
  redactValue(key, value) {
420
504
  const k = toKey(key);
@@ -456,6 +540,36 @@ var Redactor = class {
456
540
  return value;
457
541
  }
458
542
  };
543
+
544
+ // node_modules/.pnpm/nanoid@5.1.11/node_modules/nanoid/url-alphabet/index.js
545
+ var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
546
+
547
+ // node_modules/.pnpm/nanoid@5.1.11/node_modules/nanoid/index.js
548
+ var POOL_SIZE_MULTIPLIER = 128;
549
+ var pool;
550
+ var poolOffset;
551
+ function fillPool(bytes) {
552
+ if (bytes < 0 || bytes > 1024) throw new RangeError("Wrong ID size");
553
+ if (!pool || pool.length < bytes) {
554
+ pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
555
+ webcrypto.getRandomValues(pool);
556
+ poolOffset = 0;
557
+ } else if (poolOffset + bytes > pool.length) {
558
+ webcrypto.getRandomValues(pool);
559
+ poolOffset = 0;
560
+ }
561
+ poolOffset += bytes;
562
+ }
563
+ function nanoid(size = 21) {
564
+ fillPool(size |= 0);
565
+ let id = "";
566
+ for (let i = poolOffset - size; i < poolOffset; i++) {
567
+ id += urlAlphabet[pool[i] & 63];
568
+ }
569
+ return id;
570
+ }
571
+
572
+ // packages/core/src/logs/normalizer.ts
459
573
  function isFiniteNumber(v) {
460
574
  return typeof v === "number" && Number.isFinite(v);
461
575
  }
@@ -636,86 +750,6 @@ var EventNormalizer = class {
636
750
  }
637
751
  };
638
752
 
639
- // packages/core/src/logs/tree-builder.ts
640
- function inc(map, key) {
641
- map[key] = (map[key] ?? 0) + 1;
642
- }
643
- function computeRunStatus(events) {
644
- let hasRunning = false;
645
- for (const e of events) {
646
- if (e.status === "error") return "error";
647
- if (e.status === "running") hasRunning = true;
648
- }
649
- if (hasRunning) return "running";
650
- return "ok";
651
- }
652
- var TreeBuilder = class {
653
- constructor(options) {
654
- void options?.config;
655
- }
656
- build(events) {
657
- const byRun = /* @__PURE__ */ new Map();
658
- for (const e of events) {
659
- if (!byRun.has(e.runId)) byRun.set(e.runId, []);
660
- byRun.get(e.runId).push(e);
661
- }
662
- const out = [];
663
- for (const [runId, runEvents] of byRun.entries()) {
664
- const sorted = [...runEvents].sort((a, b) => a.timestamp - b.timestamp);
665
- const nodes = /* @__PURE__ */ new Map();
666
- for (const e of sorted) {
667
- nodes.set(e.eventId, { event: e, children: [], depth: 0 });
668
- }
669
- const roots = [];
670
- for (const node of nodes.values()) {
671
- const parentId = node.event.parentId;
672
- if (parentId && nodes.has(parentId)) {
673
- nodes.get(parentId).children.push(node);
674
- } else {
675
- roots.push(node);
676
- }
677
- }
678
- const assignDepth = (n, depth) => {
679
- n.depth = depth;
680
- for (const c of n.children) assignDepth(c, depth + 1);
681
- };
682
- for (const r of roots) assignDepth(r, 0);
683
- const confidenceBreakdown = {
684
- explicit: 0,
685
- correlated: 0,
686
- heuristic: 0,
687
- unknown: 0
688
- };
689
- const kinds = {};
690
- for (const e of sorted) {
691
- inc(confidenceBreakdown, e.confidence);
692
- kinds[e.kind] = (kinds[e.kind] ?? 0) + 1;
693
- }
694
- const startedAt = sorted.length > 0 ? sorted[0].timestamp : void 0;
695
- const endedAt = sorted.length > 0 ? sorted[sorted.length - 1].timestamp : void 0;
696
- const status = computeRunStatus(sorted);
697
- const durationMs = startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt && status !== "running" ? endedAt - startedAt : void 0;
698
- const name = sorted.find((e) => e.kind === "RUN")?.name;
699
- out.push({
700
- runId,
701
- name,
702
- status,
703
- startedAt,
704
- endedAt: status === "running" ? void 0 : endedAt,
705
- durationMs,
706
- children: roots,
707
- metadata: {
708
- totalEvents: sorted.length,
709
- confidenceBreakdown,
710
- kinds
711
- }
712
- });
713
- }
714
- out.sort((a, b) => (b.startedAt ?? 0) - (a.startedAt ?? 0));
715
- return out;
716
- }
717
- };
718
-
719
753
  // packages/core/src/logs/tree-renderer.ts
720
754
  function truncate(v, max) {
721
755
  if (v.length <= max) return v;
@@ -1166,6 +1200,91 @@ function warn(message, error) {
1166
1200
  }
1167
1201
  console.warn(`${base}: ${formatError(error).message}`);
1168
1202
  }
1203
+
1204
+ // packages/core/src/redaction-profiles.ts
1205
+ var SHARE_PROFILE_EXTRA_KEYS = [
1206
+ "userEmail",
1207
+ "customerEmail",
1208
+ "phone",
1209
+ "phoneNumber",
1210
+ "address",
1211
+ "ip",
1212
+ "ipAddress",
1213
+ "sessionId",
1214
+ "requestId",
1215
+ "correlationId",
1216
+ "decisionId",
1217
+ "groupId",
1218
+ "customerId",
1219
+ "userId",
1220
+ "accountId",
1221
+ "tenantId",
1222
+ "orgId",
1223
+ "organizationId",
1224
+ "traceId",
1225
+ "spanId",
1226
+ "parentSpanId"
1227
+ ];
1228
+ var STRICT_PROFILE_EXTRA_KEYS = [
1229
+ "prompt",
1230
+ "completion",
1231
+ "input",
1232
+ "output",
1233
+ "inputPreview",
1234
+ "outputPreview",
1235
+ "message",
1236
+ "messages",
1237
+ "transcript",
1238
+ "context",
1239
+ "document",
1240
+ "documents",
1241
+ "chunk",
1242
+ "chunks",
1243
+ "retrieval",
1244
+ "query"
1245
+ ];
1246
+ function resolveRedactionProfile(profile = "local") {
1247
+ switch (profile) {
1248
+ case "local":
1249
+ return { profile: "local", extraKeys: [] };
1250
+ case "share":
1251
+ return {
1252
+ profile: "share",
1253
+ extraKeys: SHARE_PROFILE_EXTRA_KEYS,
1254
+ maxMetadataValueLengthCap: 500,
1255
+ maxPreviewLengthCap: 200
1256
+ };
1257
+ case "strict":
1258
+ return {
1259
+ profile: "strict",
1260
+ extraKeys: [...SHARE_PROFILE_EXTRA_KEYS, ...STRICT_PROFILE_EXTRA_KEYS],
1261
+ maxMetadataValueLengthCap: 200,
1262
+ maxPreviewLengthCap: 80
1263
+ };
1264
+ default:
1265
+ return { profile: "local", extraKeys: [] };
1266
+ }
1267
+ }
1268
+ function isPreviewKey(key) {
1269
+ return key.toLowerCase().includes("preview");
1270
+ }
1271
+ function applyProfileMetadataCaps(maxMetadataValueLength, maxPreviewLength, resolved) {
1272
+ let meta = maxMetadataValueLength;
1273
+ let preview = maxPreviewLength;
1274
+ if (resolved.maxMetadataValueLengthCap !== void 0) {
1275
+ meta = Math.min(meta, resolved.maxMetadataValueLengthCap);
1276
+ }
1277
+ if (resolved.maxPreviewLengthCap !== void 0) {
1278
+ preview = Math.min(preview, resolved.maxPreviewLengthCap);
1279
+ }
1280
+ return { maxMetadataValueLength: meta, maxPreviewLength: preview };
1281
+ }
1282
+ function truncateStringForProfile(value, key, maxMetadataValueLength, maxPreviewLength) {
1283
+ const max = isPreviewKey(key) ? maxPreviewLength : maxMetadataValueLength;
1284
+ if (max <= 0) return "\u2026";
1285
+ if (value.length <= max) return value;
1286
+ return `${value.slice(0, max)}\u2026`;
1287
+ }
1169
1288
  function isRecord6(value) {
1170
1289
  return typeof value === "object" && value !== null && !Array.isArray(value);
1171
1290
  }
@@ -1316,7 +1435,7 @@ var DEFAULT_MAX_EVENT_BYTES = 65536;
1316
1435
  function isRecord7(value) {
1317
1436
  return typeof value === "object" && value !== null && !Array.isArray(value);
1318
1437
  }
1319
- function isPreviewKey(key) {
1438
+ function isPreviewKey2(key) {
1320
1439
  return key.toLowerCase().includes("preview");
1321
1440
  }
1322
1441
  function truncateString(value, maxLen) {
@@ -1333,11 +1452,28 @@ function resolveTraceSafetyOptions(options) {
1333
1452
  {
1334
1453
  redactEnabled = true;
1335
1454
  }
1455
+ const profile = options?.redactionProfile ?? "local";
1456
+ const resolvedProfile = resolveRedactionProfile(profile);
1457
+ const userMaxMetadata = "undefined" === "number" && Number.isFinite(options.maxMetadataValueLength) && options.maxMetadataValueLength >= 0 ? Math.floor(options.maxMetadataValueLength) : void 0;
1458
+ const userMaxPreview = "undefined" === "number" && Number.isFinite(options.maxPreviewLength) && options.maxPreviewLength >= 0 ? Math.floor(options.maxPreviewLength) : void 0;
1459
+ let maxMetadataValueLength = userMaxMetadata ?? DEFAULT_MAX_METADATA_VALUE_LENGTH;
1460
+ let maxPreviewLength = userMaxPreview ?? DEFAULT_MAX_PREVIEW_LENGTH;
1461
+ if (redactEnabled && profile !== "local") {
1462
+ const capped = applyProfileMetadataCaps(
1463
+ maxMetadataValueLength,
1464
+ maxPreviewLength,
1465
+ resolvedProfile
1466
+ );
1467
+ maxMetadataValueLength = capped.maxMetadataValueLength;
1468
+ maxPreviewLength = capped.maxPreviewLength;
1469
+ }
1336
1470
  return {
1337
1471
  redactEnabled,
1338
1472
  redactionRules,
1339
- maxMetadataValueLength: "undefined" === "number" && Number.isFinite(options.maxMetadataValueLength) && options.maxMetadataValueLength >= 0 ? Math.floor(options.maxMetadataValueLength) : DEFAULT_MAX_METADATA_VALUE_LENGTH,
1340
- maxPreviewLength: "undefined" === "number" && Number.isFinite(options.maxPreviewLength) && options.maxPreviewLength >= 0 ? Math.floor(options.maxPreviewLength) : DEFAULT_MAX_PREVIEW_LENGTH,
1473
+ redactionProfile: profile,
1474
+ profileExtraKeys: redactEnabled ? resolvedProfile.extraKeys : [],
1475
+ maxMetadataValueLength,
1476
+ maxPreviewLength,
1341
1477
  maxEventBytes: "undefined" === "number" && Number.isFinite(options.maxEventBytes) && options.maxEventBytes > 0 ? Math.floor(options.maxEventBytes) : DEFAULT_MAX_EVENT_BYTES
1342
1478
  };
1343
1479
  }
@@ -1345,7 +1481,7 @@ function boundMetadataValue(key, value, opts, seen, depth) {
1345
1481
  if (depth > 32) return "[MaxDepth]";
1346
1482
  if (value === null || typeof value !== "object") {
1347
1483
  if (typeof value === "string") {
1348
- const max = isPreviewKey(key) ? opts.maxPreviewLength : opts.maxMetadataValueLength;
1484
+ const max = isPreviewKey2(key) ? opts.maxPreviewLength : opts.maxMetadataValueLength;
1349
1485
  return truncateString(value, max);
1350
1486
  }
1351
1487
  return value;
@@ -1371,7 +1507,10 @@ function boundMetadataValue(key, value, opts, seen, depth) {
1371
1507
  }
1372
1508
  function redactMetadata(metadata, opts) {
1373
1509
  if (!opts.redactEnabled) return { ...metadata };
1374
- const redactor = new Redactor({ rules: opts.redactionRules });
1510
+ const redactor = new Redactor({
1511
+ rules: opts.redactionRules,
1512
+ extraKeys: opts.profileExtraKeys
1513
+ });
1375
1514
  return redactor.redactRecord(metadata);
1376
1515
  }
1377
1516
  function prepareMetadataForDisk(metadata, opts) {
@@ -2386,6 +2525,498 @@ function diffRuns(left, right, options) {
2386
2525
  };
2387
2526
  return { summary, differences };
2388
2527
  }
2528
+
2529
+ // node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js
2530
+ var ANSI_BACKGROUND_OFFSET = 10;
2531
+ var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
2532
+ var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
2533
+ var wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
2534
+ var styles = {
2535
+ modifier: {
2536
+ reset: [0, 0],
2537
+ // 21 isn't widely supported and 22 does the same thing
2538
+ bold: [1, 22],
2539
+ dim: [2, 22],
2540
+ italic: [3, 23],
2541
+ underline: [4, 24],
2542
+ overline: [53, 55],
2543
+ inverse: [7, 27],
2544
+ hidden: [8, 28],
2545
+ strikethrough: [9, 29]
2546
+ },
2547
+ color: {
2548
+ black: [30, 39],
2549
+ red: [31, 39],
2550
+ green: [32, 39],
2551
+ yellow: [33, 39],
2552
+ blue: [34, 39],
2553
+ magenta: [35, 39],
2554
+ cyan: [36, 39],
2555
+ white: [37, 39],
2556
+ // Bright color
2557
+ blackBright: [90, 39],
2558
+ gray: [90, 39],
2559
+ // Alias of `blackBright`
2560
+ grey: [90, 39],
2561
+ // Alias of `blackBright`
2562
+ redBright: [91, 39],
2563
+ greenBright: [92, 39],
2564
+ yellowBright: [93, 39],
2565
+ blueBright: [94, 39],
2566
+ magentaBright: [95, 39],
2567
+ cyanBright: [96, 39],
2568
+ whiteBright: [97, 39]
2569
+ },
2570
+ bgColor: {
2571
+ bgBlack: [40, 49],
2572
+ bgRed: [41, 49],
2573
+ bgGreen: [42, 49],
2574
+ bgYellow: [43, 49],
2575
+ bgBlue: [44, 49],
2576
+ bgMagenta: [45, 49],
2577
+ bgCyan: [46, 49],
2578
+ bgWhite: [47, 49],
2579
+ // Bright color
2580
+ bgBlackBright: [100, 49],
2581
+ bgGray: [100, 49],
2582
+ // Alias of `bgBlackBright`
2583
+ bgGrey: [100, 49],
2584
+ // Alias of `bgBlackBright`
2585
+ bgRedBright: [101, 49],
2586
+ bgGreenBright: [102, 49],
2587
+ bgYellowBright: [103, 49],
2588
+ bgBlueBright: [104, 49],
2589
+ bgMagentaBright: [105, 49],
2590
+ bgCyanBright: [106, 49],
2591
+ bgWhiteBright: [107, 49]
2592
+ }
2593
+ };
2594
+ Object.keys(styles.modifier);
2595
+ var foregroundColorNames = Object.keys(styles.color);
2596
+ var backgroundColorNames = Object.keys(styles.bgColor);
2597
+ [...foregroundColorNames, ...backgroundColorNames];
2598
+ function assembleStyles() {
2599
+ const codes = /* @__PURE__ */ new Map();
2600
+ for (const [groupName, group] of Object.entries(styles)) {
2601
+ for (const [styleName, style] of Object.entries(group)) {
2602
+ styles[styleName] = {
2603
+ open: `\x1B[${style[0]}m`,
2604
+ close: `\x1B[${style[1]}m`
2605
+ };
2606
+ group[styleName] = styles[styleName];
2607
+ codes.set(style[0], style[1]);
2608
+ }
2609
+ Object.defineProperty(styles, groupName, {
2610
+ value: group,
2611
+ enumerable: false
2612
+ });
2613
+ }
2614
+ Object.defineProperty(styles, "codes", {
2615
+ value: codes,
2616
+ enumerable: false
2617
+ });
2618
+ styles.color.close = "\x1B[39m";
2619
+ styles.bgColor.close = "\x1B[49m";
2620
+ styles.color.ansi = wrapAnsi16();
2621
+ styles.color.ansi256 = wrapAnsi256();
2622
+ styles.color.ansi16m = wrapAnsi16m();
2623
+ styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
2624
+ styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
2625
+ styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
2626
+ Object.defineProperties(styles, {
2627
+ rgbToAnsi256: {
2628
+ value(red, green, blue) {
2629
+ if (red === green && green === blue) {
2630
+ if (red < 8) {
2631
+ return 16;
2632
+ }
2633
+ if (red > 248) {
2634
+ return 231;
2635
+ }
2636
+ return Math.round((red - 8) / 247 * 24) + 232;
2637
+ }
2638
+ return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
2639
+ },
2640
+ enumerable: false
2641
+ },
2642
+ hexToRgb: {
2643
+ value(hex) {
2644
+ const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
2645
+ if (!matches) {
2646
+ return [0, 0, 0];
2647
+ }
2648
+ let [colorString] = matches;
2649
+ if (colorString.length === 3) {
2650
+ colorString = [...colorString].map((character) => character + character).join("");
2651
+ }
2652
+ const integer = Number.parseInt(colorString, 16);
2653
+ return [
2654
+ /* eslint-disable no-bitwise */
2655
+ integer >> 16 & 255,
2656
+ integer >> 8 & 255,
2657
+ integer & 255
2658
+ /* eslint-enable no-bitwise */
2659
+ ];
2660
+ },
2661
+ enumerable: false
2662
+ },
2663
+ hexToAnsi256: {
2664
+ value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
2665
+ enumerable: false
2666
+ },
2667
+ ansi256ToAnsi: {
2668
+ value(code) {
2669
+ if (code < 8) {
2670
+ return 30 + code;
2671
+ }
2672
+ if (code < 16) {
2673
+ return 90 + (code - 8);
2674
+ }
2675
+ let red;
2676
+ let green;
2677
+ let blue;
2678
+ if (code >= 232) {
2679
+ red = ((code - 232) * 10 + 8) / 255;
2680
+ green = red;
2681
+ blue = red;
2682
+ } else {
2683
+ code -= 16;
2684
+ const remainder = code % 36;
2685
+ red = Math.floor(code / 36) / 5;
2686
+ green = Math.floor(remainder / 6) / 5;
2687
+ blue = remainder % 6 / 5;
2688
+ }
2689
+ const value = Math.max(red, green, blue) * 2;
2690
+ if (value === 0) {
2691
+ return 30;
2692
+ }
2693
+ let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
2694
+ if (value === 2) {
2695
+ result += 60;
2696
+ }
2697
+ return result;
2698
+ },
2699
+ enumerable: false
2700
+ },
2701
+ rgbToAnsi: {
2702
+ value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
2703
+ enumerable: false
2704
+ },
2705
+ hexToAnsi: {
2706
+ value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
2707
+ enumerable: false
2708
+ }
2709
+ });
2710
+ return styles;
2711
+ }
2712
+ var ansiStyles = assembleStyles();
2713
+ var ansi_styles_default = ansiStyles;
2714
+ function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
2715
+ const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
2716
+ const position = argv.indexOf(prefix + flag);
2717
+ const terminatorPosition = argv.indexOf("--");
2718
+ return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
2719
+ }
2720
+ var { env } = process2;
2721
+ var flagForceColor;
2722
+ if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
2723
+ flagForceColor = 0;
2724
+ } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
2725
+ flagForceColor = 1;
2726
+ }
2727
+ function envForceColor() {
2728
+ if ("FORCE_COLOR" in env) {
2729
+ if (env.FORCE_COLOR === "true") {
2730
+ return 1;
2731
+ }
2732
+ if (env.FORCE_COLOR === "false") {
2733
+ return 0;
2734
+ }
2735
+ return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
2736
+ }
2737
+ }
2738
+ function translateLevel(level) {
2739
+ if (level === 0) {
2740
+ return false;
2741
+ }
2742
+ return {
2743
+ level,
2744
+ hasBasic: true,
2745
+ has256: level >= 2,
2746
+ has16m: level >= 3
2747
+ };
2748
+ }
2749
+ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
2750
+ const noFlagForceColor = envForceColor();
2751
+ if (noFlagForceColor !== void 0) {
2752
+ flagForceColor = noFlagForceColor;
2753
+ }
2754
+ const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
2755
+ if (forceColor === 0) {
2756
+ return 0;
2757
+ }
2758
+ if (sniffFlags) {
2759
+ if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
2760
+ return 3;
2761
+ }
2762
+ if (hasFlag("color=256")) {
2763
+ return 2;
2764
+ }
2765
+ }
2766
+ if ("TF_BUILD" in env && "AGENT_NAME" in env) {
2767
+ return 1;
2768
+ }
2769
+ if (haveStream && !streamIsTTY && forceColor === void 0) {
2770
+ return 0;
2771
+ }
2772
+ const min = forceColor || 0;
2773
+ if (env.TERM === "dumb") {
2774
+ return min;
2775
+ }
2776
+ if (process2.platform === "win32") {
2777
+ const osRelease = os.release().split(".");
2778
+ if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
2779
+ return Number(osRelease[2]) >= 14931 ? 3 : 2;
2780
+ }
2781
+ return 1;
2782
+ }
2783
+ if ("CI" in env) {
2784
+ if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) {
2785
+ return 3;
2786
+ }
2787
+ if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
2788
+ return 1;
2789
+ }
2790
+ return min;
2791
+ }
2792
+ if ("TEAMCITY_VERSION" in env) {
2793
+ return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
2794
+ }
2795
+ if (env.COLORTERM === "truecolor") {
2796
+ return 3;
2797
+ }
2798
+ if (env.TERM === "xterm-kitty") {
2799
+ return 3;
2800
+ }
2801
+ if (env.TERM === "xterm-ghostty") {
2802
+ return 3;
2803
+ }
2804
+ if (env.TERM === "wezterm") {
2805
+ return 3;
2806
+ }
2807
+ if ("TERM_PROGRAM" in env) {
2808
+ const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
2809
+ switch (env.TERM_PROGRAM) {
2810
+ case "iTerm.app": {
2811
+ return version >= 3 ? 3 : 2;
2812
+ }
2813
+ case "Apple_Terminal": {
2814
+ return 2;
2815
+ }
2816
+ }
2817
+ }
2818
+ if (/-256(color)?$/i.test(env.TERM)) {
2819
+ return 2;
2820
+ }
2821
+ if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
2822
+ return 1;
2823
+ }
2824
+ if ("COLORTERM" in env) {
2825
+ return 1;
2826
+ }
2827
+ return min;
2828
+ }
2829
+ function createSupportsColor(stream, options = {}) {
2830
+ const level = _supportsColor(stream, {
2831
+ streamIsTTY: stream && stream.isTTY,
2832
+ ...options
2833
+ });
2834
+ return translateLevel(level);
2835
+ }
2836
+ var supportsColor = {
2837
+ stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
2838
+ stderr: createSupportsColor({ isTTY: tty.isatty(2) })
2839
+ };
2840
+ var supports_color_default = supportsColor;
2841
+
2842
+ // node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/utilities.js
2843
+ function stringReplaceAll(string, substring, replacer) {
2844
+ let index = string.indexOf(substring);
2845
+ if (index === -1) {
2846
+ return string;
2847
+ }
2848
+ const substringLength = substring.length;
2849
+ let endIndex = 0;
2850
+ let returnValue = "";
2851
+ do {
2852
+ returnValue += string.slice(endIndex, index) + substring + replacer;
2853
+ endIndex = index + substringLength;
2854
+ index = string.indexOf(substring, endIndex);
2855
+ } while (index !== -1);
2856
+ returnValue += string.slice(endIndex);
2857
+ return returnValue;
2858
+ }
2859
+ function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
2860
+ let endIndex = 0;
2861
+ let returnValue = "";
2862
+ do {
2863
+ const gotCR = string[index - 1] === "\r";
2864
+ returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
2865
+ endIndex = index + 1;
2866
+ index = string.indexOf("\n", endIndex);
2867
+ } while (index !== -1);
2868
+ returnValue += string.slice(endIndex);
2869
+ return returnValue;
2870
+ }
2871
+
2872
+ // node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/index.js
2873
+ var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
2874
+ var GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
2875
+ var STYLER = /* @__PURE__ */ Symbol("STYLER");
2876
+ var IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
2877
+ var levelMapping = [
2878
+ "ansi",
2879
+ "ansi",
2880
+ "ansi256",
2881
+ "ansi16m"
2882
+ ];
2883
+ var styles2 = /* @__PURE__ */ Object.create(null);
2884
+ var applyOptions = (object, options = {}) => {
2885
+ if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
2886
+ throw new Error("The `level` option should be an integer from 0 to 3");
2887
+ }
2888
+ const colorLevel = stdoutColor ? stdoutColor.level : 0;
2889
+ object.level = options.level === void 0 ? colorLevel : options.level;
2890
+ };
2891
+ var chalkFactory = (options) => {
2892
+ const chalk2 = (...strings) => strings.join(" ");
2893
+ applyOptions(chalk2, options);
2894
+ Object.setPrototypeOf(chalk2, createChalk.prototype);
2895
+ return chalk2;
2896
+ };
2897
+ function createChalk(options) {
2898
+ return chalkFactory(options);
2899
+ }
2900
+ Object.setPrototypeOf(createChalk.prototype, Function.prototype);
2901
+ for (const [styleName, style] of Object.entries(ansi_styles_default)) {
2902
+ styles2[styleName] = {
2903
+ get() {
2904
+ const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
2905
+ Object.defineProperty(this, styleName, { value: builder });
2906
+ return builder;
2907
+ }
2908
+ };
2909
+ }
2910
+ styles2.visible = {
2911
+ get() {
2912
+ const builder = createBuilder(this, this[STYLER], true);
2913
+ Object.defineProperty(this, "visible", { value: builder });
2914
+ return builder;
2915
+ }
2916
+ };
2917
+ var getModelAnsi = (model, level, type, ...arguments_) => {
2918
+ if (model === "rgb") {
2919
+ if (level === "ansi16m") {
2920
+ return ansi_styles_default[type].ansi16m(...arguments_);
2921
+ }
2922
+ if (level === "ansi256") {
2923
+ return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
2924
+ }
2925
+ return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
2926
+ }
2927
+ if (model === "hex") {
2928
+ return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
2929
+ }
2930
+ return ansi_styles_default[type][model](...arguments_);
2931
+ };
2932
+ var usedModels = ["rgb", "hex", "ansi256"];
2933
+ for (const model of usedModels) {
2934
+ styles2[model] = {
2935
+ get() {
2936
+ const { level } = this;
2937
+ return function(...arguments_) {
2938
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
2939
+ return createBuilder(this, styler, this[IS_EMPTY]);
2940
+ };
2941
+ }
2942
+ };
2943
+ const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
2944
+ styles2[bgModel] = {
2945
+ get() {
2946
+ const { level } = this;
2947
+ return function(...arguments_) {
2948
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
2949
+ return createBuilder(this, styler, this[IS_EMPTY]);
2950
+ };
2951
+ }
2952
+ };
2953
+ }
2954
+ var proto = Object.defineProperties(() => {
2955
+ }, {
2956
+ ...styles2,
2957
+ level: {
2958
+ enumerable: true,
2959
+ get() {
2960
+ return this[GENERATOR].level;
2961
+ },
2962
+ set(level) {
2963
+ this[GENERATOR].level = level;
2964
+ }
2965
+ }
2966
+ });
2967
+ var createStyler = (open2, close, parent) => {
2968
+ let openAll;
2969
+ let closeAll;
2970
+ if (parent === void 0) {
2971
+ openAll = open2;
2972
+ closeAll = close;
2973
+ } else {
2974
+ openAll = parent.openAll + open2;
2975
+ closeAll = close + parent.closeAll;
2976
+ }
2977
+ return {
2978
+ open: open2,
2979
+ close,
2980
+ openAll,
2981
+ closeAll,
2982
+ parent
2983
+ };
2984
+ };
2985
+ var createBuilder = (self, _styler, _isEmpty) => {
2986
+ const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
2987
+ Object.setPrototypeOf(builder, proto);
2988
+ builder[GENERATOR] = self;
2989
+ builder[STYLER] = _styler;
2990
+ builder[IS_EMPTY] = _isEmpty;
2991
+ return builder;
2992
+ };
2993
+ var applyStyle = (self, string) => {
2994
+ if (self.level <= 0 || !string) {
2995
+ return self[IS_EMPTY] ? "" : string;
2996
+ }
2997
+ let styler = self[STYLER];
2998
+ if (styler === void 0) {
2999
+ return string;
3000
+ }
3001
+ const { openAll, closeAll } = styler;
3002
+ if (string.includes("\x1B")) {
3003
+ while (styler !== void 0) {
3004
+ string = stringReplaceAll(string, styler.close, styler.open);
3005
+ styler = styler.parent;
3006
+ }
3007
+ }
3008
+ const lfIndex = string.indexOf("\n");
3009
+ if (lfIndex !== -1) {
3010
+ string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
3011
+ }
3012
+ return openAll + string + closeAll;
3013
+ };
3014
+ Object.defineProperties(createChalk.prototype, styles2);
3015
+ var chalk = createChalk();
3016
+ createChalk({ level: stderrColor ? stderrColor.level : 0 });
3017
+ var source_default = chalk;
3018
+
3019
+ // packages/core/src/diff/renderer.ts
2389
3020
  function formatPath(path7) {
2390
3021
  if (path7 === void 0 || path7.path.length === 0) {
2391
3022
  return "(run)";
@@ -2466,6 +3097,8 @@ function diffTraceEvents(leftEvents, rightEvents, options) {
2466
3097
  const right = manualTraceEventsToComparableRun(rightEvents);
2467
3098
  return diffRuns(left, right, options);
2468
3099
  }
3100
+
3101
+ // packages/core/src/terminal.ts
2469
3102
  var TERMINAL_INDENT = " ";
2470
3103
  var MAX_TERMINAL_NAME_LENGTH = 80;
2471
3104
  var MAX_TERMINAL_DEPTH = 10;
@@ -2491,24 +3124,24 @@ function formatTerminalName(name) {
2491
3124
  return truncateName(name, MAX_TERMINAL_NAME_LENGTH);
2492
3125
  }
2493
3126
  function getStatusIcon(status) {
2494
- if (status === "success") return chalk2.green("\u2714");
2495
- if (status === "error") return chalk2.red("\u2716");
2496
- return chalk2.yellow("\u23F3");
3127
+ if (status === "success") return source_default.green("\u2714");
3128
+ if (status === "error") return source_default.red("\u2716");
3129
+ return source_default.yellow("\u23F3");
2497
3130
  }
2498
3131
  function renderStepLine(name, durationMs, status, depth) {
2499
3132
  try {
2500
3133
  const nm = formatTerminalName(name);
2501
3134
  const ind = getIndent(depth ?? 0);
2502
3135
  if (status === "running" && durationMs === void 0) {
2503
- return `${ind}${chalk2.yellow("\u23F3")} ${nm}`;
3136
+ return `${ind}${source_default.yellow("\u23F3")} ${nm}`;
2504
3137
  }
2505
3138
  const hasDur = durationMs !== void 0 && Number.isFinite(durationMs);
2506
3139
  const dur = hasDur ? formatDuration2(durationMs) : void 0;
2507
3140
  if (status === "running") {
2508
- return dur !== void 0 ? `${ind}${chalk2.yellow("\u23F3")} ${nm} (${dur})` : `${ind}${chalk2.yellow("\u23F3")} ${nm}`;
3141
+ return dur !== void 0 ? `${ind}${source_default.yellow("\u23F3")} ${nm} (${dur})` : `${ind}${source_default.yellow("\u23F3")} ${nm}`;
2509
3142
  }
2510
3143
  if (!hasDur || dur === void 0) {
2511
- return `${ind}${chalk2.yellow("\u23F3")} ${nm}`;
3144
+ return `${ind}${source_default.yellow("\u23F3")} ${nm}`;
2512
3145
  }
2513
3146
  if (status === "success") {
2514
3147
  return `${ind}${getStatusIcon("success")} ${nm} (${dur})`;
@@ -2684,6 +3317,134 @@ Object.assign(stepImpl, {
2684
3317
  // packages/core/src/exporters/types.ts
2685
3318
  var EXPORT_PAYLOAD_VERSION = "0.1.2";
2686
3319
 
3320
+ // packages/core/src/exporters/redact-export.ts
3321
+ function isRecord9(value) {
3322
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3323
+ }
3324
+ function deepClone(value) {
3325
+ if (value === null || typeof value !== "object") {
3326
+ return value;
3327
+ }
3328
+ if (Array.isArray(value)) {
3329
+ return value.map((item) => deepClone(item));
3330
+ }
3331
+ const out = {};
3332
+ for (const [k, v] of Object.entries(value)) {
3333
+ out[k] = deepClone(v);
3334
+ }
3335
+ return out;
3336
+ }
3337
+ function boundAttributeValues(record, maxMetadataValueLength, maxPreviewLength, seen, depth) {
3338
+ if (depth > 32) {
3339
+ return { truncated: true, reason: "maxDepth" };
3340
+ }
3341
+ const out = {};
3342
+ for (const [key, value] of Object.entries(record)) {
3343
+ out[key] = boundValue(value, key, maxMetadataValueLength, maxPreviewLength, seen, depth);
3344
+ }
3345
+ return out;
3346
+ }
3347
+ function boundValue(value, key, maxMetadataValueLength, maxPreviewLength, seen, depth) {
3348
+ if (value === null || typeof value !== "object") {
3349
+ if (typeof value === "string") {
3350
+ return truncateStringForProfile(
3351
+ value,
3352
+ key,
3353
+ maxMetadataValueLength,
3354
+ maxPreviewLength
3355
+ );
3356
+ }
3357
+ return value;
3358
+ }
3359
+ if (seen.has(value)) return "[Circular]";
3360
+ seen.add(value);
3361
+ if (Array.isArray(value)) {
3362
+ return value.slice(0, 50).map(
3363
+ (item, index) => boundValue(
3364
+ item,
3365
+ String(index),
3366
+ maxMetadataValueLength,
3367
+ maxPreviewLength,
3368
+ seen,
3369
+ depth + 1
3370
+ )
3371
+ );
3372
+ }
3373
+ return boundAttributeValues(
3374
+ value,
3375
+ maxMetadataValueLength,
3376
+ maxPreviewLength,
3377
+ seen,
3378
+ depth + 1
3379
+ );
3380
+ }
3381
+ function redactEventAttributes(attrs, redactor, maxMetadataValueLength, maxPreviewLength) {
3382
+ if (!attrs || Object.keys(attrs).length === 0) {
3383
+ return attrs;
3384
+ }
3385
+ const redacted = redactor.redactRecord(attrs);
3386
+ const seen = /* @__PURE__ */ new WeakSet();
3387
+ const bounded = boundAttributeValues(
3388
+ redacted,
3389
+ maxMetadataValueLength,
3390
+ maxPreviewLength,
3391
+ seen,
3392
+ 0
3393
+ );
3394
+ const err = bounded.error;
3395
+ if (isRecord9(err) && typeof err.message === "string") {
3396
+ bounded.error = {
3397
+ ...err,
3398
+ message: truncateStringForProfile(
3399
+ err.message,
3400
+ "message",
3401
+ maxMetadataValueLength,
3402
+ maxPreviewLength
3403
+ ),
3404
+ ...typeof err.stack === "string" ? {
3405
+ stack: truncateStringForProfile(
3406
+ err.stack,
3407
+ "stack",
3408
+ maxMetadataValueLength,
3409
+ maxPreviewLength
3410
+ )
3411
+ } : {}
3412
+ };
3413
+ }
3414
+ return bounded;
3415
+ }
3416
+ function redactRunTreeForExport(tree, options) {
3417
+ const profile = options?.redactionProfile ?? "local";
3418
+ if (profile === "local") {
3419
+ return deepClone(tree);
3420
+ }
3421
+ const resolved = resolveRedactionProfile(profile);
3422
+ const { maxMetadataValueLength, maxPreviewLength } = applyProfileMetadataCaps(
3423
+ 2e3,
3424
+ 500,
3425
+ resolved
3426
+ );
3427
+ const redactor = new Redactor({ extraKeys: resolved.extraKeys });
3428
+ const clone = deepClone(tree);
3429
+ function walk(nodes) {
3430
+ for (const node of nodes) {
3431
+ if (node.event.attributes !== void 0) {
3432
+ node.event.attributes = redactEventAttributes(
3433
+ node.event.attributes,
3434
+ redactor,
3435
+ maxMetadataValueLength,
3436
+ maxPreviewLength
3437
+ );
3438
+ }
3439
+ if (node.children.length > 0) {
3440
+ walk(node.children);
3441
+ }
3442
+ }
3443
+ }
3444
+ walk(clone.children);
3445
+ return clone;
3446
+ }
3447
+
2687
3448
  // packages/core/src/exporters/html-exporter.ts
2688
3449
  function renderTreeHtml(nodes, ulClass = "tree") {
2689
3450
  if (nodes.length === 0) return "";
@@ -3418,20 +4179,22 @@ function mergeExportDefaults(options) {
3418
4179
  includeErrors: options.includeErrors ?? true,
3419
4180
  pretty: options.pretty,
3420
4181
  redacted: options.redacted,
3421
- maxAttributeLength: options.maxAttributeLength
4182
+ maxAttributeLength: options.maxAttributeLength,
4183
+ redactionProfile: options.redactionProfile ?? "local"
3422
4184
  };
3423
4185
  }
3424
4186
  function exportRunTree(tree, options) {
3425
4187
  const opts = mergeExportDefaults(options);
4188
+ const exportTree = opts.redactionProfile === "local" ? tree : redactRunTreeForExport(tree, { redactionProfile: opts.redactionProfile });
3426
4189
  switch (opts.format) {
3427
4190
  case "markdown":
3428
- return exportMarkdown(tree, opts);
4191
+ return exportMarkdown(exportTree, opts);
3429
4192
  case "html":
3430
- return exportHtml(tree, opts);
4193
+ return exportHtml(exportTree, opts);
3431
4194
  case "openinference":
3432
- return exportOpenInference(tree, opts);
4195
+ return exportOpenInference(exportTree, opts);
3433
4196
  case "otlp-json":
3434
- return exportOtlpJson(tree, opts);
4197
+ return exportOtlpJson(exportTree, opts);
3435
4198
  default: {
3436
4199
  const _x = opts.format;
3437
4200
  throw new Error(`Unsupported export format: ${String(_x)}`);
@@ -4267,6 +5030,15 @@ async function tail(options = {}) {
4267
5030
  process.exitCode = 1;
4268
5031
  }
4269
5032
  }
5033
+ function parseRedactionProfile(s) {
5034
+ const v = (s ?? "local").trim().toLowerCase();
5035
+ if (v === "local" || v === "share" || v === "strict") {
5036
+ return v;
5037
+ }
5038
+ throw new Error(
5039
+ `Unsupported --redaction-profile "${s ?? ""}". Use local, share, or strict.`
5040
+ );
5041
+ }
4270
5042
  function parseExportFormat(s) {
4271
5043
  const v = (s ?? "markdown").trim().toLowerCase();
4272
5044
  if (v === "markdown" || v === "html" || v === "openinference" || v === "otlp-json") {
@@ -4284,8 +5056,10 @@ async function exportCommand(runId, options = {}) {
4284
5056
  return;
4285
5057
  }
4286
5058
  let format;
5059
+ let redactionProfile;
4287
5060
  try {
4288
5061
  format = parseExportFormat(options.format);
5062
+ redactionProfile = parseRedactionProfile(options.redactionProfile);
4289
5063
  } catch (e) {
4290
5064
  const msg = e instanceof Error ? e.message : String(e);
4291
5065
  console.error(msg);
@@ -4324,7 +5098,8 @@ Trace directory: ${traceDir}`);
4324
5098
  includeErrors: options.noErrors === true ? false : true,
4325
5099
  pretty: true,
4326
5100
  redacted: true,
4327
- maxAttributeLength: 500
5101
+ maxAttributeLength: 500,
5102
+ redactionProfile
4328
5103
  };
4329
5104
  const result = exportRunTree(tree, exportOpts);
4330
5105
  const validation = options.validate === true ? validateExport(result) : void 0;
@@ -4557,7 +5332,12 @@ function createCliProgram() {
4557
5332
  "openinference",
4558
5333
  "otlp-json"
4559
5334
  ])
4560
- ).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) => {
5335
+ ).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(
5336
+ new Option(
5337
+ "--redaction-profile <profile>",
5338
+ "redaction profile for exported copies: local, share, strict (default: local)"
5339
+ ).choices(["local", "share", "strict"])
5340
+ ).action((runId, opts) => {
4561
5341
  runCommand(() => exportCommand(runId, opts));
4562
5342
  });
4563
5343
  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(