agent-inspect 6.31.2 → 6.31.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +1 -1
  3. package/SECURITY.md +2 -0
  4. package/docs/GETTING-STARTED.md +2 -0
  5. package/docs/SAFE-TRACE-SHARING.md +1 -0
  6. package/package.json +1 -1
  7. package/packages/cli/dist/{chunk-SJ6FRNOE.mjs → chunk-LKEPABND.mjs} +86 -80
  8. package/packages/cli/dist/chunk-LKEPABND.mjs.map +1 -0
  9. package/packages/cli/dist/index.cjs +406 -93
  10. package/packages/cli/dist/index.cjs.map +1 -1
  11. package/packages/cli/dist/index.mjs +314 -16
  12. package/packages/cli/dist/index.mjs.map +1 -1
  13. package/packages/cli/dist/{src-YNEJOPRA.mjs → src-4WYF5RFI.mjs} +3 -3
  14. package/packages/cli/dist/{src-YNEJOPRA.mjs.map → src-4WYF5RFI.mjs.map} +1 -1
  15. package/packages/core/dist/advanced.cjs +97 -30
  16. package/packages/core/dist/advanced.cjs.map +1 -1
  17. package/packages/core/dist/advanced.mjs +13 -13
  18. package/packages/core/dist/checks.cjs +51 -49
  19. package/packages/core/dist/checks.cjs.map +1 -1
  20. package/packages/core/dist/checks.mjs +5 -5
  21. package/packages/core/dist/{chunk-PBNBQRXV.mjs → chunk-2KJR6X4V.mjs} +9 -9
  22. package/packages/core/dist/chunk-2KJR6X4V.mjs.map +1 -0
  23. package/packages/core/dist/{chunk-26YJSETN.mjs → chunk-7DHSWDKB.mjs} +19 -6
  24. package/packages/core/dist/chunk-7DHSWDKB.mjs.map +1 -0
  25. package/packages/core/dist/{chunk-BGF5JDJN.mjs → chunk-INE5IWLN.mjs} +3 -3
  26. package/packages/core/dist/{chunk-BGF5JDJN.mjs.map → chunk-INE5IWLN.mjs.map} +1 -1
  27. package/packages/core/dist/{chunk-ZFJ2ICTC.mjs → chunk-MTMTXTJL.mjs} +5 -5
  28. package/packages/core/dist/{chunk-ZFJ2ICTC.mjs.map → chunk-MTMTXTJL.mjs.map} +1 -1
  29. package/packages/core/dist/{chunk-KWBO36PH.mjs → chunk-NY4ILMXK.mjs} +4 -4
  30. package/packages/core/dist/{chunk-KWBO36PH.mjs.map → chunk-NY4ILMXK.mjs.map} +1 -1
  31. package/packages/core/dist/{chunk-WN5PT4GV.mjs → chunk-OSGNGRHF.mjs} +3 -3
  32. package/packages/core/dist/{chunk-WN5PT4GV.mjs.map → chunk-OSGNGRHF.mjs.map} +1 -1
  33. package/packages/core/dist/{chunk-CBPWLHNQ.mjs → chunk-PKDBFBJ7.mjs} +5 -76
  34. package/packages/core/dist/chunk-PKDBFBJ7.mjs.map +1 -0
  35. package/packages/core/dist/{chunk-VU6O5QAH.mjs → chunk-VLVCLAPB.mjs} +83 -5
  36. package/packages/core/dist/chunk-VLVCLAPB.mjs.map +1 -0
  37. package/packages/core/dist/exporters.cjs +224 -8
  38. package/packages/core/dist/exporters.cjs.map +1 -1
  39. package/packages/core/dist/exporters.mjs +125 -11
  40. package/packages/core/dist/exporters.mjs.map +1 -1
  41. package/packages/core/dist/index.cjs +97 -8
  42. package/packages/core/dist/index.cjs.map +1 -1
  43. package/packages/core/dist/index.mjs +6 -6
  44. package/packages/core/dist/logs.cjs +80 -2
  45. package/packages/core/dist/logs.cjs.map +1 -1
  46. package/packages/core/dist/logs.d.cts +2 -0
  47. package/packages/core/dist/logs.d.ts +2 -0
  48. package/packages/core/dist/logs.mjs +2 -2
  49. package/packages/core/dist/readers.cjs +2 -0
  50. package/packages/core/dist/readers.cjs.map +1 -1
  51. package/packages/core/dist/readers.mjs +2 -2
  52. package/packages/core/dist/writers.cjs +96 -8
  53. package/packages/core/dist/writers.cjs.map +1 -1
  54. package/packages/core/dist/writers.mjs +7 -8
  55. package/packages/core/dist/writers.mjs.map +1 -1
  56. package/packages/cli/dist/chunk-SJ6FRNOE.mjs.map +0 -1
  57. package/packages/core/dist/chunk-26YJSETN.mjs.map +0 -1
  58. package/packages/core/dist/chunk-CBPWLHNQ.mjs.map +0 -1
  59. package/packages/core/dist/chunk-PBNBQRXV.mjs.map +0 -1
  60. package/packages/core/dist/chunk-VU6O5QAH.mjs.map +0 -1
@@ -1,10 +1,10 @@
1
- import { buildRunWhatSummary, renderRunWhat, renderTimeline, buildRunTimeline } from './chunk-KWBO36PH.mjs';
2
- import { summarizeObservedOutcomes, extractOutcomesFromTraceEvents, renderObservedOutcomesMarkdown, renderObservedOutcomesHtml } from './chunk-BGF5JDJN.mjs';
1
+ import { buildRunWhatSummary, renderRunWhat, renderTimeline, buildRunTimeline } from './chunk-NY4ILMXK.mjs';
2
+ import { summarizeObservedOutcomes, extractOutcomesFromTraceEvents, renderObservedOutcomesMarkdown, renderObservedOutcomesHtml } from './chunk-INE5IWLN.mjs';
3
3
  import { escapeHtml, flattenTree, safeString, compactAttributes, stableJson, escapeMarkdown, zeroKinds } from './chunk-CAWPF22J.mjs';
4
4
  export { compactAttributes, escapeHtml, escapeMarkdown, flattenTree, safeString, stableJson, summarizeTree } from './chunk-CAWPF22J.mjs';
5
- import { resolveRedactionProfile, applyProfileMetadataCaps, truncateStringForProfile } from './chunk-PBNBQRXV.mjs';
6
- import { Redactor } from './chunk-VU6O5QAH.mjs';
7
- import './chunk-26YJSETN.mjs';
5
+ import { resolveRedactionProfile, applyProfileMetadataCaps, truncateStringForProfile, stringContainsHighConfidenceCredential } from './chunk-2KJR6X4V.mjs';
6
+ import { Redactor, DEFAULT_REDACT_KEYS, isCredentialSensitiveKey } from './chunk-VLVCLAPB.mjs';
7
+ import './chunk-7DHSWDKB.mjs';
8
8
  import './chunk-EE5Z2GQ3.mjs';
9
9
  import './chunk-7TGZLWEE.mjs';
10
10
  import crypto from 'crypto';
@@ -12,6 +12,99 @@ import crypto from 'crypto';
12
12
  // packages/core/src/exporters/types.ts
13
13
  var EXPORT_PAYLOAD_VERSION = "0.1.2";
14
14
 
15
+ // packages/core/src/safety/url-redaction.ts
16
+ var HTTP_URL = /^https?:\/\/[^\s]+$/i;
17
+ var UUID_SEGMENT = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
18
+ var HEX_SEGMENT = /^[0-9a-f]{12,}$/i;
19
+ var NUMERIC_SEGMENT = /^\d{5,}$/;
20
+ var OPAQUE_SEGMENT = /^[A-Za-z0-9_-]{20,}$/;
21
+ function looksLikeHttpUrl(value) {
22
+ return HTTP_URL.test(value.trim());
23
+ }
24
+ function parseHttpUrl(value) {
25
+ try {
26
+ const url = new URL(value.trim());
27
+ return url.protocol === "http:" || url.protocol === "https:" ? url : void 0;
28
+ } catch {
29
+ return void 0;
30
+ }
31
+ }
32
+ function isIdentifierSegment(segment) {
33
+ if (UUID_SEGMENT.test(segment)) return true;
34
+ if (HEX_SEGMENT.test(segment)) return true;
35
+ if (NUMERIC_SEGMENT.test(segment)) return true;
36
+ return OPAQUE_SEGMENT.test(segment) && /\d/.test(segment) && /[A-Za-z]/.test(segment);
37
+ }
38
+ function decodeParam(value) {
39
+ try {
40
+ return decodeURIComponent(value.replace(/\+/g, " "));
41
+ } catch {
42
+ return value;
43
+ }
44
+ }
45
+ function redactParams(raw, options, replacement) {
46
+ let redacted = false;
47
+ const parts = raw.split("&").map((part) => {
48
+ if (part.length === 0) return part;
49
+ const separator = part.indexOf("=");
50
+ if (separator < 0) return part;
51
+ const rawKey = part.slice(0, separator);
52
+ const rawValue = part.slice(separator + 1);
53
+ const key = decodeParam(rawKey);
54
+ const value = decodeParam(rawValue);
55
+ if (isCredentialSensitiveKey(key, options.sensitiveKeys) || options.isSensitiveValue(value)) {
56
+ redacted = true;
57
+ return `${rawKey}=${replacement}`;
58
+ }
59
+ return part;
60
+ });
61
+ return { value: parts.join("&"), redacted };
62
+ }
63
+ function redactUrlString(value, options) {
64
+ const unchanged = {
65
+ value,
66
+ credentialRedacted: false,
67
+ identifiersMasked: false
68
+ };
69
+ if (!looksLikeHttpUrl(value)) return unchanged;
70
+ const url = parseHttpUrl(value);
71
+ if (!url) return unchanged;
72
+ const replacement = options.replacement ?? "[REDACTED]";
73
+ const idPlaceholder = options.idPlaceholder ?? "[id]";
74
+ let credentialRedacted = url.username.length > 0 || url.password.length > 0;
75
+ let identifiersMasked = false;
76
+ let pathname = url.pathname;
77
+ if (options.maskPathIds === true) {
78
+ pathname = url.pathname.split("/").map((segment) => {
79
+ if (segment.length === 0 || !isIdentifierSegment(decodeParam(segment))) {
80
+ return segment;
81
+ }
82
+ identifiersMasked = true;
83
+ return idPlaceholder;
84
+ }).join("/");
85
+ }
86
+ let search = "";
87
+ if (url.search.length > 1) {
88
+ const params = redactParams(url.search.slice(1), options, replacement);
89
+ if (params.redacted) credentialRedacted = true;
90
+ search = `?${params.value}`;
91
+ } else if (url.search.length === 1) {
92
+ search = "?";
93
+ }
94
+ let hash = url.hash;
95
+ if (url.hash.includes("=")) {
96
+ const params = redactParams(url.hash.slice(1), options, replacement);
97
+ if (params.redacted) credentialRedacted = true;
98
+ hash = `#${params.value}`;
99
+ }
100
+ if (!credentialRedacted && !identifiersMasked) return unchanged;
101
+ return {
102
+ value: `${url.protocol}//${url.host}${pathname}${search}${hash}`,
103
+ credentialRedacted,
104
+ identifiersMasked
105
+ };
106
+ }
107
+
15
108
  // packages/core/src/exporters/redact-export.ts
16
109
  function isRecord(value) {
17
110
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -29,21 +122,34 @@ function deepClone(value) {
29
122
  }
30
123
  return out;
31
124
  }
32
- function boundAttributeValues(record, maxMetadataValueLength, maxPreviewLength, seen, depth) {
125
+ function boundAttributeValues(record, sensitiveKeys, maxMetadataValueLength, maxPreviewLength, seen, depth) {
33
126
  if (depth > 32) {
34
127
  return { truncated: true, reason: "maxDepth" };
35
128
  }
36
129
  const out = {};
37
130
  for (const [key, value] of Object.entries(record)) {
38
- out[key] = boundValue(value, key, maxMetadataValueLength, maxPreviewLength, seen, depth);
131
+ out[key] = boundValue(
132
+ value,
133
+ key,
134
+ sensitiveKeys,
135
+ maxMetadataValueLength,
136
+ maxPreviewLength,
137
+ seen,
138
+ depth
139
+ );
39
140
  }
40
141
  return out;
41
142
  }
42
- function boundValue(value, key, maxMetadataValueLength, maxPreviewLength, seen, depth) {
143
+ function boundValue(value, key, sensitiveKeys, maxMetadataValueLength, maxPreviewLength, seen, depth) {
43
144
  if (value === null || typeof value !== "object") {
44
145
  if (typeof value === "string") {
146
+ const rewritten = redactUrlString(value, {
147
+ sensitiveKeys,
148
+ isSensitiveValue: stringContainsHighConfidenceCredential,
149
+ maskPathIds: true
150
+ }).value;
45
151
  return truncateStringForProfile(
46
- value,
152
+ stringContainsHighConfidenceCredential(rewritten) ? "[REDACTED]" : rewritten,
47
153
  key,
48
154
  maxMetadataValueLength,
49
155
  maxPreviewLength
@@ -58,6 +164,7 @@ function boundValue(value, key, maxMetadataValueLength, maxPreviewLength, seen,
58
164
  (item, index) => boundValue(
59
165
  item,
60
166
  String(index),
167
+ sensitiveKeys,
61
168
  maxMetadataValueLength,
62
169
  maxPreviewLength,
63
170
  seen,
@@ -67,6 +174,7 @@ function boundValue(value, key, maxMetadataValueLength, maxPreviewLength, seen,
67
174
  }
68
175
  return boundAttributeValues(
69
176
  value,
177
+ sensitiveKeys,
70
178
  maxMetadataValueLength,
71
179
  maxPreviewLength,
72
180
  seen,
@@ -81,6 +189,7 @@ function redactEventAttributes(attrs, redactor, maxMetadataValueLength, maxPrevi
81
189
  const seen = /* @__PURE__ */ new WeakSet();
82
190
  const bounded = boundAttributeValues(
83
191
  redacted,
192
+ [...DEFAULT_REDACT_KEYS, ...redactor.sensitiveKeys],
84
193
  maxMetadataValueLength,
85
194
  maxPreviewLength,
86
195
  seen,
@@ -651,6 +760,11 @@ function exportOpenInference(tree, options) {
651
760
  function hexFrom2(seed, byteLen) {
652
761
  return crypto.createHash("sha256").update(seed, "utf8").digest("hex").slice(0, byteLen * 2);
653
762
  }
763
+ function unixNano2(ms) {
764
+ const whole = Math.trunc(ms);
765
+ const fractionNs = Math.round((ms - whole) * 1e6);
766
+ return BigInt(whole) * 1000000n + BigInt(fractionNs);
767
+ }
654
768
  function stringAttr(key, value) {
655
769
  return { key, value: { stringValue: value } };
656
770
  }
@@ -684,10 +798,10 @@ function exportOtlpJson(tree, options) {
684
798
  const ev = n.event;
685
799
  const spanId = hexFrom2(`${tree.runId}:${ev.eventId}`, 8);
686
800
  const parentSpanId = ev.parentId ? hexFrom2(`${tree.runId}:${ev.parentId}`, 8) : void 0;
687
- const startNs = String(Math.round(ev.timestamp * 1e6));
801
+ const startNs = String(unixNano2(ev.timestamp));
688
802
  let endNs;
689
803
  if (ev.durationMs !== void 0 && Number.isFinite(ev.durationMs)) {
690
- endNs = String(Math.round(ev.timestamp * 1e6 + ev.durationMs * 1e6));
804
+ endNs = String(unixNano2(ev.timestamp) + unixNano2(ev.durationMs));
691
805
  }
692
806
  const attrs = [
693
807
  stringAttr("agent_inspect.kind", ev.kind),