@tangle-network/agent-eval 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +119 -0
- package/README.md +2 -1
- package/dist/adapters/http.d.ts +2 -2
- package/dist/{agreement-irr-BTjDN0i6.js → agreement-irr-w-t3XUTD.js} +2 -2
- package/dist/{agreement-irr-BTjDN0i6.js.map → agreement-irr-w-t3XUTD.js.map} +1 -1
- package/dist/analyst/index.d.ts +7 -7
- package/dist/analyst/index.js +11 -11
- package/dist/{analyze-runs-C-pP1sK9.d.ts → analyze-runs-BYyMShsj.d.ts} +2 -2
- package/dist/{analyze-runs-C-pP1sK9.d.ts.map → analyze-runs-BYyMShsj.d.ts.map} +1 -1
- package/dist/{analyze-runs-Ck68mbgj.js → analyze-runs-Da7P_Mc5.js} +9 -10
- package/dist/{analyze-runs-Ck68mbgj.js.map → analyze-runs-Da7P_Mc5.js.map} +1 -1
- package/dist/{benchmark-command-DWkc5mzq.js → benchmark-command-BeDZB3BQ.js} +11 -11
- package/dist/{benchmark-command-DWkc5mzq.js.map → benchmark-command-BeDZB3BQ.js.map} +1 -1
- package/dist/benchmarks/index.d.ts +4 -4
- package/dist/benchmarks/index.js +5 -5
- package/dist/builder-eval/index.js +1 -1
- package/dist/{calibration-6usfVYYo.js → calibration-DLzckXnn.js} +2 -2
- package/dist/{calibration-6usfVYYo.js.map → calibration-DLzckXnn.js.map} +1 -1
- package/dist/campaign/index.d.ts +5 -5
- package/dist/campaign/index.js +10 -10
- package/dist/{campaign-DdOgQfp8.js → campaign-DKZiYHUq.js} +15 -15
- package/dist/{campaign-DdOgQfp8.js.map → campaign-DKZiYHUq.js.map} +1 -1
- package/dist/{campaign-evidence-MjCjkb5a.js → campaign-evidence-BICB3a9Z.js} +3 -3
- package/dist/{campaign-evidence-MjCjkb5a.js.map → campaign-evidence-BICB3a9Z.js.map} +1 -1
- package/dist/{chat-client-CO3uB33i.js → chat-client-D0me8iwq.js} +2 -2
- package/dist/{chat-client-CO3uB33i.js.map → chat-client-D0me8iwq.js.map} +1 -1
- package/dist/{chat-json-call-8yUv4LFO.js → chat-json-call-C473CwTt.js} +2 -2
- package/dist/{chat-json-call-8yUv4LFO.js.map → chat-json-call-C473CwTt.js.map} +1 -1
- package/dist/cli.js +7 -7
- package/dist/{cluster-bootstrap-SbaeM44s.js → cluster-bootstrap-hNXESoc1.js} +2 -2
- package/dist/{cluster-bootstrap-SbaeM44s.js.map → cluster-bootstrap-hNXESoc1.js.map} +1 -1
- package/dist/{completion-verifier-rqbMh5-4.js → completion-verifier-ClmJV_Yc.js} +2 -2
- package/dist/{completion-verifier-rqbMh5-4.js.map → completion-verifier-ClmJV_Yc.js.map} +1 -1
- package/dist/contract/index.d.ts +8 -8
- package/dist/contract/index.js +13 -13
- package/dist/{decision-point-lhMgODOR.js → decision-point-CErE7GnP.js} +6 -6
- package/dist/decision-point-CErE7GnP.js.map +1 -0
- package/dist/{default-registry-B1DstPYg.d.ts → default-registry-DKlKVXMx.d.ts} +22 -6
- package/dist/default-registry-DKlKVXMx.d.ts.map +1 -0
- package/dist/{default-registry-C1tPEjZ4.js → default-registry-gmDeN0KT.js} +38 -7
- package/dist/default-registry-gmDeN0KT.js.map +1 -0
- package/dist/{define-agent-eval-CAffiFbN.d.ts → define-agent-eval-B9zPWFSK.d.ts} +6 -6
- package/dist/{define-agent-eval-CAffiFbN.d.ts.map → define-agent-eval-B9zPWFSK.d.ts.map} +1 -1
- package/dist/{define-agent-eval-Cc15qGik.js → define-agent-eval-BVhGn7VV.js} +6 -6
- package/dist/{define-agent-eval-Cc15qGik.js.map → define-agent-eval-BVhGn7VV.js.map} +1 -1
- package/dist/{descriptive-cPwITVfy.js → descriptive-BTzLL-aj.js} +46 -3
- package/dist/descriptive-BTzLL-aj.js.map +1 -0
- package/dist/diagnosis/index.d.ts +2 -2
- package/dist/diagnosis/index.js +2 -2
- package/dist/{dspy-rlm-engine-jDiWkul6.js → dspy-rlm-engine-C0zR2xiM.js} +2 -2
- package/dist/{dspy-rlm-engine-jDiWkul6.js.map → dspy-rlm-engine-C0zR2xiM.js.map} +1 -1
- package/dist/{eval-campaign-C_mNDshv.js → eval-campaign-DVqiBoXR.js} +3 -3
- package/dist/{eval-campaign-C_mNDshv.js.map → eval-campaign-DVqiBoXR.js.map} +1 -1
- package/dist/{evaluation-BPqUvZ66.d.ts → evaluation-B0-KVXaV.d.ts} +4 -2
- package/dist/evaluation-B0-KVXaV.d.ts.map +1 -0
- package/dist/{evaluation-B8H3GYej.js → evaluation-BBI37mRe.js} +2 -1
- package/dist/evaluation-BBI37mRe.js.map +1 -0
- package/dist/evaluation.d.ts +1 -1
- package/dist/evaluation.js +1 -1
- package/dist/{exact-types-D98BKpxo.d.ts → exact-types-CIViGj98.d.ts} +3 -3
- package/dist/{exact-types-D98BKpxo.d.ts.map → exact-types-CIViGj98.d.ts.map} +1 -1
- package/dist/experiment/index.d.ts +1 -1
- package/dist/experiment/index.js +9 -8
- package/dist/experiment/index.js.map +1 -1
- package/dist/{exporters-B5Ze_RKh.d.ts → exporters-BYBG9b1n.d.ts} +2 -2
- package/dist/{exporters-B5Ze_RKh.d.ts.map → exporters-BYBG9b1n.d.ts.map} +1 -1
- package/dist/{external-optimizer-process-BRVmaDFe.js → external-optimizer-process-DKgrrX0J.js} +2 -2
- package/dist/{external-optimizer-process-BRVmaDFe.js.map → external-optimizer-process-DKgrrX0J.js.map} +1 -1
- package/dist/{external-optimizer-subprocess-U616hV_l.js → external-optimizer-subprocess-wzMaA0oN.js} +2 -2
- package/dist/{external-optimizer-subprocess-U616hV_l.js.map → external-optimizer-subprocess-wzMaA0oN.js.map} +1 -1
- package/dist/{feedback-trajectory-SBGncrCP.d.ts → feedback-trajectory-Ck7K7AhK.d.ts} +2 -2
- package/dist/{feedback-trajectory-SBGncrCP.d.ts.map → feedback-trajectory-Ck7K7AhK.d.ts.map} +1 -1
- package/dist/{findings-store-B75Dspaq.js → findings-store-DNSvmy8U.js} +4 -4
- package/dist/{findings-store-B75Dspaq.js.map → findings-store-DNSvmy8U.js.map} +1 -1
- package/dist/fuzz.js +1 -1
- package/dist/{index-CUjeTDPv.d.ts → index-Bn-P_XAl.d.ts} +4 -4
- package/dist/{index-CUjeTDPv.d.ts.map → index-Bn-P_XAl.d.ts.map} +1 -1
- package/dist/{index-B7v2QHlD.d.ts → index-BwutH5i7.d.ts} +4 -4
- package/dist/{index-B7v2QHlD.d.ts.map → index-BwutH5i7.d.ts.map} +1 -1
- package/dist/{index-aDPVYBIM.d.ts → index-ByJ20lyu.d.ts} +7 -7
- package/dist/{index-aDPVYBIM.d.ts.map → index-ByJ20lyu.d.ts.map} +1 -1
- package/dist/{index-DUn0GNiZ.d.ts → index-CtcCSO1Y.d.ts} +4 -4
- package/dist/{index-DUn0GNiZ.d.ts.map → index-CtcCSO1Y.d.ts.map} +1 -1
- package/dist/index.d.ts +17 -17
- package/dist/index.js +38 -43
- package/dist/index.js.map +1 -1
- package/dist/{judge-calibration-DGqlfWW8.js → judge-calibration-D93UCm1k.js} +2 -2
- package/dist/{judge-calibration-DGqlfWW8.js.map → judge-calibration-D93UCm1k.js.map} +1 -1
- package/dist/{judge-gate-Di_6bifh.js → judge-gate-C9sLLJ-v.js} +3 -3
- package/dist/{judge-gate-Di_6bifh.js.map → judge-gate-C9sLLJ-v.js.map} +1 -1
- package/dist/kind-factory-VKysp1ds.js.map +1 -1
- package/dist/{llm-client-kJ9EOqjt.js → llm-client-BdSiZ4qz.js} +2 -2
- package/dist/{llm-client-kJ9EOqjt.js.map → llm-client-BdSiZ4qz.js.map} +1 -1
- package/dist/{llm-judge-D6JtIqiU.js → llm-judge-BYBLxREr.js} +14 -14
- package/dist/{llm-judge-D6JtIqiU.js.map → llm-judge-BYBLxREr.js.map} +1 -1
- package/dist/{matrix-CBUzIZs4.d.ts → matrix-4DcRFJ7Q.d.ts} +2 -2
- package/dist/{matrix-CBUzIZs4.d.ts.map → matrix-4DcRFJ7Q.d.ts.map} +1 -1
- package/dist/{internal-v6XfOeJW.js → mean-DDFhslBt.js} +48 -2
- package/dist/mean-DDFhslBt.js.map +1 -0
- package/dist/meta-eval/index.js +7 -7
- package/dist/multishot/golden/index.d.ts +1 -1
- package/dist/multishot/index.d.ts +2 -2
- package/dist/openapi.json +1 -1
- package/dist/{outcome-observations-D4snOtUb.js → outcome-observations-ahbNtxuP.js} +3 -3
- package/dist/{outcome-observations-D4snOtUb.js.map → outcome-observations-ahbNtxuP.js.map} +1 -1
- package/dist/{paired-arms-D5H_58e8.js → paired-arms-C0Vd9bGG.js} +4 -4
- package/dist/{paired-arms-D5H_58e8.js.map → paired-arms-C0Vd9bGG.js.map} +1 -1
- package/dist/{paired-binary-BR0nwHOA.js → paired-binary-B477lksS.js} +2 -2
- package/dist/{paired-binary-BR0nwHOA.js.map → paired-binary-B477lksS.js.map} +1 -1
- package/dist/{paired-promotion-decision-BiVumgvM.js → paired-promotion-decision-5Pl_qJLX.js} +3 -3
- package/dist/{paired-promotion-decision-BiVumgvM.js.map → paired-promotion-decision-5Pl_qJLX.js.map} +1 -1
- package/dist/{paired-tests-C2zUqgUW.js → paired-tests-kASEKpc-.js} +3 -37
- package/dist/paired-tests-kASEKpc-.js.map +1 -0
- package/dist/{pareto-7_LEmYGG.js → pareto-DY_x3HHg.js} +7 -7
- package/dist/{pareto-7_LEmYGG.js.map → pareto-DY_x3HHg.js.map} +1 -1
- package/dist/pipelines/index.d.ts +1 -1
- package/dist/pipelines/index.js +1 -1
- package/dist/{power-and-mde-CHvyDO_H.js → power-and-mde-CRxepy8y.js} +3 -3
- package/dist/{power-and-mde-CHvyDO_H.js.map → power-and-mde-CRxepy8y.js.map} +1 -1
- package/dist/{promotion-policy-D7B4_jEZ.js → promotion-policy-f79oklG_.js} +4 -4
- package/dist/{promotion-policy-D7B4_jEZ.js.map → promotion-policy-f79oklG_.js.map} +1 -1
- package/dist/{proposal-findings-WFQrxnfe.js → proposal-findings-duV5flPv.js} +2 -2
- package/dist/{proposal-findings-WFQrxnfe.js.map → proposal-findings-duV5flPv.js.map} +1 -1
- package/dist/{raw-provider-sink-DDLkP_eF.js → raw-provider-sink-RbaEv2vB.js} +2 -2
- package/dist/{raw-provider-sink-DDLkP_eF.js.map → raw-provider-sink-RbaEv2vB.js.map} +1 -1
- package/dist/{redact-C_wzC4c_.d.ts → redact-jrT0APTU.d.ts} +50 -35
- package/dist/redact-jrT0APTU.d.ts.map +1 -0
- package/dist/{redact-D6APJS1d.js → redact-zp_ILC4l.js} +92 -33
- package/dist/redact-zp_ILC4l.js.map +1 -0
- package/dist/redaction.d.ts +2 -0
- package/dist/redaction.js +1 -0
- package/dist/{registry-dhdDoAV8.d.ts → registry-CMtGAxOw.d.ts} +2 -2
- package/dist/{registry-dhdDoAV8.d.ts.map → registry-CMtGAxOw.d.ts.map} +1 -1
- package/dist/{release-confidence-CTUJz5mM.js → release-confidence--1iP-d3x.js} +2 -2
- package/dist/{release-confidence-CTUJz5mM.js.map → release-confidence--1iP-d3x.js.map} +1 -1
- package/dist/{render-pfAZ7IR4.js → render-aB58Be3N.js} +2 -2
- package/dist/{render-pfAZ7IR4.js.map → render-aB58Be3N.js.map} +1 -1
- package/dist/reporting.js +5 -5
- package/dist/{reward-hacking-Bjk3MAjh.js → reward-hacking-D-Vi9-fE.js} +3 -3
- package/dist/{reward-hacking-Bjk3MAjh.js.map → reward-hacking-D-Vi9-fE.js.map} +1 -1
- package/dist/rl.d.ts +3 -3
- package/dist/rl.js +9 -9
- package/dist/rollout/index.d.ts +4 -4
- package/dist/rollout/index.js +1 -1
- package/dist/{rollout-BhkMpAJT.js → rollout-BC4u-d_I.js} +3 -3
- package/dist/{rollout-BhkMpAJT.js.map → rollout-BC4u-d_I.js.map} +1 -1
- package/dist/{rubric-predictive-validity-CQp_M0vy.js → rubric-predictive-validity-BdxXDN6h.js} +2 -2
- package/dist/{rubric-predictive-validity-CQp_M0vy.js.map → rubric-predictive-validity-BdxXDN6h.js.map} +1 -1
- package/dist/{run-record-BUm-Jggo.js → run-record-B-G2Tu11.js} +2 -2
- package/dist/{run-record-BUm-Jggo.js.map → run-record-B-G2Tu11.js.map} +1 -1
- package/dist/{schema-DkFJr3Y8.d.ts → schema-CfoA9U_U.d.ts} +28 -2
- package/dist/schema-CfoA9U_U.d.ts.map +1 -0
- package/dist/search/index.d.ts +2 -2
- package/dist/search/index.js +2 -2
- package/dist/{search-kernel-CBdwFZ05.d.ts → search-kernel-BjR2Sr7w.d.ts} +2 -2
- package/dist/{search-kernel-CBdwFZ05.d.ts.map → search-kernel-BjR2Sr7w.d.ts.map} +1 -1
- package/dist/{search-summary-Bt3uuK53.js → search-summary-DedyTdiM.js} +4 -4
- package/dist/{search-summary-Bt3uuK53.js.map → search-summary-DedyTdiM.js.map} +1 -1
- package/dist/{sequential-De7BTAlV.js → sequential-Zp1tsxqI.js} +2 -2
- package/dist/{sequential-De7BTAlV.js.map → sequential-Zp1tsxqI.js.map} +1 -1
- package/dist/{server-DA6h3co5.js → server-CPKyf3bz.js} +2 -2
- package/dist/{server-DA6h3co5.js.map → server-CPKyf3bz.js.map} +1 -1
- package/dist/{skillopt-optimization-method-BKFbJEyz.js → skillopt-optimization-method-DmfZz-2d.js} +9 -9
- package/dist/{skillopt-optimization-method-BKFbJEyz.js.map → skillopt-optimization-method-DmfZz-2d.js.map} +1 -1
- package/dist/{spans-vZoW__3q.d.ts → spans-CGjHouKM.d.ts} +2 -2
- package/dist/{spans-vZoW__3q.d.ts.map → spans-CGjHouKM.d.ts.map} +1 -1
- package/dist/{statistical-heldout-C9hz_AF9.js → statistical-heldout-DYF5f10K.js} +3 -3
- package/dist/{statistical-heldout-C9hz_AF9.js.map → statistical-heldout-DYF5f10K.js.map} +1 -1
- package/dist/{statistical-heldout-Cei036nE.d.ts → statistical-heldout-bU7FBNjR.d.ts} +2 -2
- package/dist/{statistical-heldout-Cei036nE.d.ts.map → statistical-heldout-bU7FBNjR.d.ts.map} +1 -1
- package/dist/{store-tool-spans-C2g8UYm-.js → store-tool-spans-GGaCijFy.js} +19 -62
- package/dist/store-tool-spans-GGaCijFy.js.map +1 -0
- package/dist/{store-tool-spans-B3i3fl0A.d.ts → store-tool-spans-lWf6INTH.d.ts} +3 -44
- package/dist/store-tool-spans-lWf6INTH.d.ts.map +1 -0
- package/dist/{summary-report-BLnTyQKH.js → summary-report-BstMpOfy.js} +6 -7
- package/dist/{summary-report-BLnTyQKH.js.map → summary-report-BstMpOfy.js.map} +1 -1
- package/dist/supervisor-run/index.d.ts +2 -2
- package/dist/supervisor-run/index.js +1 -1
- package/dist/{systemone-Cw2txK5m.d.ts → systemone-BDVgb6XV.d.ts} +7 -9
- package/dist/systemone-BDVgb6XV.d.ts.map +1 -0
- package/dist/systemone.d.ts +2 -2
- package/dist/systemone.js +2 -2
- package/dist/{tool-waste-CLJ46AbT.js → tool-waste-CRJqOASv.js} +3 -3
- package/dist/{tool-waste-CLJ46AbT.js.map → tool-waste-CRJqOASv.js.map} +1 -1
- package/dist/trace-repair/index.js +2 -2
- package/dist/traces.d.ts +18 -39
- package/dist/traces.d.ts.map +1 -1
- package/dist/traces.js +51 -57
- package/dist/traces.js.map +1 -1
- package/dist/{tree-DnBkWXun.js → tree-C2N31CoI.js} +5 -6
- package/dist/{tree-DnBkWXun.js.map → tree-C2N31CoI.js.map} +1 -1
- package/dist/{types-C54Uk_a1.d.ts → types-BF-xQGQn.d.ts} +2 -2
- package/dist/{types-C54Uk_a1.d.ts.map → types-BF-xQGQn.d.ts.map} +1 -1
- package/dist/{types-C-aOqgt2.d.ts → types-DNB9hIXa.d.ts} +2 -2
- package/dist/{types-C-aOqgt2.d.ts.map → types-DNB9hIXa.d.ts.map} +1 -1
- package/dist/{types-0oMg7zee.d.ts → types-yofaDmQa.d.ts} +2 -2
- package/dist/{types-0oMg7zee.d.ts.map → types-yofaDmQa.d.ts.map} +1 -1
- package/dist/wire/index.d.ts +7 -7
- package/dist/wire/index.js +1 -1
- package/docs/design/statistics-decisions.md +1 -0
- package/docs/redaction.md +24 -1
- package/docs/systemone.md +6 -0
- package/package.json +7 -2
- package/dist/decision-point-lhMgODOR.js.map +0 -1
- package/dist/default-registry-B1DstPYg.d.ts.map +0 -1
- package/dist/default-registry-C1tPEjZ4.js.map +0 -1
- package/dist/descriptive-cPwITVfy.js.map +0 -1
- package/dist/evaluation-B8H3GYej.js.map +0 -1
- package/dist/evaluation-BPqUvZ66.d.ts.map +0 -1
- package/dist/internal-v6XfOeJW.js.map +0 -1
- package/dist/mean-BPuUNznQ.js +0 -16
- package/dist/mean-BPuUNznQ.js.map +0 -1
- package/dist/paired-tests-C2zUqgUW.js.map +0 -1
- package/dist/redact-C_wzC4c_.d.ts.map +0 -1
- package/dist/redact-D6APJS1d.js.map +0 -1
- package/dist/schema-DkFJr3Y8.d.ts.map +0 -1
- package/dist/store-tool-spans-B3i3fl0A.d.ts.map +0 -1
- package/dist/store-tool-spans-C2g8UYm-.js.map +0 -1
- package/dist/systemone-Cw2txK5m.d.ts.map +0 -1
|
@@ -201,6 +201,37 @@ function classifyKey(key) {
|
|
|
201
201
|
if (kind === "raw-content") return "raw-content";
|
|
202
202
|
return "personal-data";
|
|
203
203
|
}
|
|
204
|
+
/** Stateless UTF-16 ranges for String.slice. Named `secret` groups preserve surrounding syntax. */
|
|
205
|
+
function* matchValueDetector(text, detector, options = {}) {
|
|
206
|
+
if (detector.requires && !text.includes(detector.requires)) return;
|
|
207
|
+
const pattern = options.numericPolicy === "conservative" ? detector.conservativePattern ?? detector.substringPattern ?? detector.pattern : detector.substringPattern ?? detector.pattern;
|
|
208
|
+
const flags = [.../* @__PURE__ */ new Set(`${pattern.flags}gd`)].join("");
|
|
209
|
+
const quoted = detector.id !== "json-secret" && CREDENTIAL_DETECTORS.includes(detector) ? matchValueDetector(text, CREDENTIAL_DETECTORS.find((rule) => rule.id === "json-secret"), options) : void 0;
|
|
210
|
+
let enclosing;
|
|
211
|
+
let coveredUntil = -1;
|
|
212
|
+
for (const match of text.matchAll(new RegExp(pattern.source, flags))) {
|
|
213
|
+
if (detector.accept && !detector.accept(match[0], options)) continue;
|
|
214
|
+
let [start, end] = match.indices.groups?.secret ?? match.indices[0];
|
|
215
|
+
if (start < coveredUntil) continue;
|
|
216
|
+
if (quoted) {
|
|
217
|
+
while (!enclosing || enclosing.end <= start) {
|
|
218
|
+
const next = quoted.next();
|
|
219
|
+
enclosing = next.value;
|
|
220
|
+
if (next.done) break;
|
|
221
|
+
}
|
|
222
|
+
if (enclosing && enclosing.start <= start && enclosing.end >= end) ({start, end} = enclosing);
|
|
223
|
+
}
|
|
224
|
+
if (start < coveredUntil) continue;
|
|
225
|
+
coveredUntil = end;
|
|
226
|
+
yield {
|
|
227
|
+
start,
|
|
228
|
+
end
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const CREDENTIAL_ASSIGNMENT_KEY = /(?:api[_-]?key|apikey|access[_-]?key|secret[_-]?key|private[_-]?key|secret|token|password|passwd|passphrase|credentials?)/;
|
|
233
|
+
const SECRET_ASSIGNMENT = new RegExp(CREDENTIAL_ASSIGNMENT_KEY.source + "[\"']?[ \\t]*[:=][ \\t]*[\"']?(?!encrypted:)(?![$`<[{(%])(?=[^\\s\"'`,;&|]{0,512}[0-9])(?=[^\\s\"'`,;&|]{0,512}[A-Za-z])(?<secret>[^\\s\"'`,;&|]{12,512})", "i");
|
|
234
|
+
const QUOTED_CREDENTIAL_FIELD = /["'][A-Za-z0-9_.-]{0,40}?(?:api[_-]?key|apikey|access[_-]?key|secret[_-]?key|private[_-]?key|client[_-]?secret|secret|password|passwd|passphrase|credentials?|(?:access|refresh|id|auth|session|bearer|api|github|gh|slack|npm)[_-]?token)["'][ \t]*:[ \t]*/;
|
|
204
235
|
/**
|
|
205
236
|
* High-confidence credential shapes. A hit replaces the whole string. Each
|
|
206
237
|
* pattern is written without the `g` flag so `test` stays stateless.
|
|
@@ -219,7 +250,7 @@ function classifyKey(key) {
|
|
|
219
250
|
const CREDENTIAL_DETECTORS = [
|
|
220
251
|
{
|
|
221
252
|
id: "private-key",
|
|
222
|
-
pattern: /-----BEGIN [A-Z0-9 ]*PRIVATE KEY
|
|
253
|
+
pattern: /-----BEGIN ([A-Z0-9 ]*PRIVATE KEY)-----[^"'`]*?(?:-----END \1-----|(?=["'`]|$))/
|
|
223
254
|
},
|
|
224
255
|
{
|
|
225
256
|
id: "jwt",
|
|
@@ -235,7 +266,27 @@ const CREDENTIAL_DETECTORS = [
|
|
|
235
266
|
},
|
|
236
267
|
{
|
|
237
268
|
id: "anthropic-key",
|
|
238
|
-
pattern: /sk-ant-[A-Za-z0-9_-]{
|
|
269
|
+
pattern: /sk-ant-[A-Za-z0-9_-]{8,}/
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
id: "tangle-key",
|
|
273
|
+
pattern: /sk-tan-[A-Za-z0-9_-]{8,}/
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
id: "gtm-operator-key",
|
|
277
|
+
pattern: /gak_[A-Za-z0-9_-]{8,}/
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
id: "agent-app-key",
|
|
281
|
+
pattern: /lak_[A-Za-z0-9_-]{8,}/
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
id: "platform-labs-key",
|
|
285
|
+
pattern: /plabs_[A-Za-z0-9_-]{8,}/
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
id: "stripe-webhook-secret",
|
|
289
|
+
pattern: /whsec_[A-Za-z0-9]{8,}/
|
|
239
290
|
},
|
|
240
291
|
{
|
|
241
292
|
id: "provider-key",
|
|
@@ -243,7 +294,7 @@ const CREDENTIAL_DETECTORS = [
|
|
|
243
294
|
},
|
|
244
295
|
{
|
|
245
296
|
id: "stripe-key",
|
|
246
|
-
pattern: /(?:sk|rk)_(?:live|test)_[A-Za-z0-9_]{
|
|
297
|
+
pattern: /(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9_]{8,}/
|
|
247
298
|
},
|
|
248
299
|
{
|
|
249
300
|
id: "google-api-key",
|
|
@@ -251,7 +302,7 @@ const CREDENTIAL_DETECTORS = [
|
|
|
251
302
|
},
|
|
252
303
|
{
|
|
253
304
|
id: "github-token",
|
|
254
|
-
pattern: /(?:gh[pousr]_[A-Za-z0-9_]{
|
|
305
|
+
pattern: /(?:gh[pousr]_[A-Za-z0-9_]{16,}|github_pat_[A-Za-z0-9_]{16,})/
|
|
255
306
|
},
|
|
256
307
|
{
|
|
257
308
|
id: "slack-token",
|
|
@@ -267,23 +318,25 @@ const CREDENTIAL_DETECTORS = [
|
|
|
267
318
|
},
|
|
268
319
|
{
|
|
269
320
|
id: "url-credentials",
|
|
270
|
-
pattern: /\b[a-z][a-z0-9+.-]{0,31}:\/\/[^\s/:@]{1,512}:[^\s/@]{1,512}@/i
|
|
321
|
+
pattern: /\b[a-z][a-z0-9+.-]{0,31}:\/\/(?<secret>[^\s/:@]{1,512}:[^\s/@]{1,512})@/i
|
|
271
322
|
},
|
|
272
323
|
{
|
|
273
324
|
id: "url-secret-param",
|
|
274
|
-
pattern: /[?&](?:access_token|api_key|apikey|auth|token|secret|password|sig|signature|x-amz-signature|x-goog-signature)=[^&\s"'#)]{8,}/i
|
|
325
|
+
pattern: /[?&](?:access_token|api_key|apikey|auth|token|secret|password|sig|signature|x-amz-signature|x-goog-signature)=(?<secret>[^&\s"'#)]{8,})/i
|
|
275
326
|
},
|
|
276
327
|
{
|
|
277
328
|
id: "secret-assignment",
|
|
278
|
-
pattern:
|
|
329
|
+
pattern: SECRET_ASSIGNMENT,
|
|
330
|
+
substringPattern: new RegExp(SECRET_ASSIGNMENT.source.replace("{12,512}", "{12,}"), SECRET_ASSIGNMENT.flags)
|
|
279
331
|
},
|
|
280
332
|
{
|
|
281
333
|
id: "json-secret",
|
|
282
|
-
pattern:
|
|
334
|
+
pattern: new RegExp(String.raw`${QUOTED_CREDENTIAL_FIELD.source}["'](?!\[REDACTED|[$*{<])(?![^"'\r\n]* [^"'\r\n]* )(?<secret>[^"'\r\n]{3,})["']`, "i"),
|
|
335
|
+
substringPattern: new RegExp(String.raw`(?:${QUOTED_CREDENTIAL_FIELD.source}|${CREDENTIAL_ASSIGNMENT_KEY.source}[ \t]*[:=][ \t]*)(?<quote>["'])(?!\[REDACTED|[$*{<])(?<secret>(?:\\.|(?!\k<quote>)[^\\\r\n]){3,})\k<quote>`, "i")
|
|
283
336
|
},
|
|
284
337
|
{
|
|
285
338
|
id: "env-secret-assignment",
|
|
286
|
-
pattern: /\b[A-Z][A-Z0-9_]*?(?:PASSWORD|PASSWD|SECRET|PASSPHRASE|APIKEY|API_KEY|TOKEN|CREDENTIALS?)[ \t]*=[ \t]*(?!\$|<|\*|\{|%|encrypted:)[^\s"'`,;&|]{4,}/
|
|
339
|
+
pattern: /\b[A-Z][A-Z0-9_]*?(?:PASSWORD|PASSWD|SECRET|PASSPHRASE|APIKEY|API_KEY|TOKEN|CREDENTIALS?)[ \t]*=[ \t]*(?!\$|<|\*|\{|%|encrypted:)(?<secret>[^\s"'`,;&|]{4,})/
|
|
287
340
|
},
|
|
288
341
|
{
|
|
289
342
|
id: "huggingface-token",
|
|
@@ -311,10 +364,21 @@ const CREDENTIAL_DETECTORS = [
|
|
|
311
364
|
},
|
|
312
365
|
{
|
|
313
366
|
id: "cookie-header",
|
|
314
|
-
pattern: /\bcookie\s*:\s*[A-Za-z0-9_-]+=[^;\r\n]{3,}(?:;\s*[A-Za-z0-9_-]+=[^;\r\n]{3,})*/i
|
|
367
|
+
pattern: /\bcookie\s*:\s*[A-Za-z0-9_-]+=[^;\r\n]{3,}(?:;\s*[A-Za-z0-9_-]+=[^;\r\n]{3,})*/i,
|
|
368
|
+
substringPattern: /\bcookie\s*:\s*(?<secret>[A-Za-z0-9_-]+=(?:(?<quote>\\?")[^\r\n]*?\k<quote>|[^;\s"'\r\n]{3,})(?:;\s*[A-Za-z0-9_-]+=(?:(?<quote2>\\?")[^\r\n]*?\k<quote2>|[^;\s"'\r\n]{3,}))*)/i
|
|
315
369
|
}
|
|
316
370
|
];
|
|
317
|
-
|
|
371
|
+
const CARD_NUMBER = /(?<![\w-])(?:\d{13,19}|\d{4}([ -])\d{4}\1\d{4}\1\d{4}(?:\1\d{3})?|\d{4}([ -])\d{6}\2\d{5})(?![\w-])/g;
|
|
372
|
+
const PHONE_NUMBER = /(?:\+1[-.\s]?)?(?:\(\d{3}\)\s?|\b\d{3}[-.\s])\d{3}[-.\s]\d{4}\b/g;
|
|
373
|
+
const NUMERIC_PRIVACY = new RegExp(String.raw`(?<![A-Za-z0-9_])[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(?![A-Za-z0-9_])|(?<![A-Za-z0-9_.-])\d+\.\d+(?![\w.])|${CARD_NUMBER.source}|${PHONE_NUMBER.source}|(?<![A-Za-z0-9_-])\+?\d{1,3}[ \t.-](?:\(\d{1,4}\)|\d{1,4})[ \t.-](?:\d{3,4}[ \t.-]\d{3,4}|\d{5,8})(?![\w-])|(?<![A-Za-z0-9_-])\+?\d[\d().-]{8,}\d(?![A-Za-z0-9_])|(?<![A-Za-z0-9_-])\+?\d[\d\s().-]{8,}\d(?![A-Za-z0-9_])`, "gi");
|
|
374
|
+
function numericPrivacyKind(value, options = {}) {
|
|
375
|
+
if (/^[0-9a-f]{8}-[0-9a-f-]{27}$/i.test(value) || /^\d*\.\d+$/.test(value) || /\d\.\d{5,}/.test(value)) return;
|
|
376
|
+
const digits = value.replace(/\D/g, "");
|
|
377
|
+
const conservative = options.numericPolicy === "conservative";
|
|
378
|
+
if (digits.length >= 13 && digits.length <= 19 && (conservative || CARD_PREFIX.test(digits)) && luhnValid(digits, conservative)) return "card-number";
|
|
379
|
+
if (digits.length >= 10 && digits.length <= 15) return "phone";
|
|
380
|
+
}
|
|
381
|
+
/** Ordered rules. Conservative numeric scanning is explicit; core patterns keep their existing defaults. */
|
|
318
382
|
const PERSONAL_DATA_DETECTORS = [
|
|
319
383
|
{
|
|
320
384
|
id: "email",
|
|
@@ -324,11 +388,9 @@ const PERSONAL_DATA_DETECTORS = [
|
|
|
324
388
|
},
|
|
325
389
|
{
|
|
326
390
|
id: "card-number",
|
|
327
|
-
pattern:
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
return CARD_PREFIX.test(digits) && luhnValid(digits);
|
|
331
|
-
}
|
|
391
|
+
pattern: CARD_NUMBER,
|
|
392
|
+
conservativePattern: NUMERIC_PRIVACY,
|
|
393
|
+
accept: (value, options) => numericPrivacyKind(value, options) === "card-number"
|
|
332
394
|
},
|
|
333
395
|
{
|
|
334
396
|
id: "ssn",
|
|
@@ -336,10 +398,11 @@ const PERSONAL_DATA_DETECTORS = [
|
|
|
336
398
|
},
|
|
337
399
|
{
|
|
338
400
|
id: "phone",
|
|
339
|
-
pattern:
|
|
401
|
+
pattern: PHONE_NUMBER,
|
|
402
|
+
conservativePattern: NUMERIC_PRIVACY,
|
|
403
|
+
accept: (value, options) => numericPrivacyKind(value, options) === "phone"
|
|
340
404
|
}
|
|
341
405
|
];
|
|
342
|
-
/** Visa, Mastercard, Amex, Diners, JCB, Discover and UnionPay issuer prefixes. */
|
|
343
406
|
const CARD_PREFIX = /^(?:4|5[1-5]|2[2-7]|3[04-9]|6(?:011|4[4-9]|5|2))/;
|
|
344
407
|
/**
|
|
345
408
|
* Top-level domains that are file extensions: `icon@2x.png`, `worker@3.service`
|
|
@@ -384,8 +447,8 @@ function isEmailAddress(match) {
|
|
|
384
447
|
const tld = match.slice(match.lastIndexOf(".") + 1).toLowerCase();
|
|
385
448
|
return !NON_EMAIL_TLDS.has(tld);
|
|
386
449
|
}
|
|
387
|
-
function luhnValid(digits) {
|
|
388
|
-
if (/^(\d)\1+$/.test(digits)) return false;
|
|
450
|
+
function luhnValid(digits, allowRepeated = false) {
|
|
451
|
+
if (!allowRepeated && /^(\d)\1+$/.test(digits)) return false;
|
|
389
452
|
let sum = 0;
|
|
390
453
|
let double = false;
|
|
391
454
|
for (let index = digits.length - 1; index >= 0; index -= 1) {
|
|
@@ -405,16 +468,7 @@ function detectCredential(text) {
|
|
|
405
468
|
}
|
|
406
469
|
/** Personal-data detector ids that match somewhere in `text`. */
|
|
407
470
|
function detectPersonalData(text) {
|
|
408
|
-
|
|
409
|
-
for (const detector of PERSONAL_DATA_DETECTORS) {
|
|
410
|
-
if (detector.requires && !text.includes(detector.requires)) continue;
|
|
411
|
-
detector.pattern.lastIndex = 0;
|
|
412
|
-
for (const match of text.matchAll(detector.pattern)) if (!detector.accept || detector.accept(match[0])) {
|
|
413
|
-
hits.push(detector.id);
|
|
414
|
-
break;
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
return hits;
|
|
471
|
+
return PERSONAL_DATA_DETECTORS.filter((detector) => !matchValueDetector(text, detector).next().done).map((detector) => detector.id);
|
|
418
472
|
}
|
|
419
473
|
/**
|
|
420
474
|
* Every form in which a known secret can appear in a trace: as written,
|
|
@@ -491,12 +545,17 @@ function credentialIn(text, knownSecrets) {
|
|
|
491
545
|
* safety corpus with its MIT notice; `pnpm redaction:corpus` runs this module
|
|
492
546
|
* over every case.
|
|
493
547
|
*/
|
|
548
|
+
const REDACTION_PROFILES = [
|
|
549
|
+
"default",
|
|
550
|
+
"share",
|
|
551
|
+
"strict"
|
|
552
|
+
];
|
|
494
553
|
/**
|
|
495
554
|
* Version of the detector set and profile rules. Stored work that depends on
|
|
496
555
|
* redaction behavior (saved optimizer inputs, per-span redaction stamps) keys
|
|
497
556
|
* on it, so bump it whenever a detector, key list, cap or marker changes.
|
|
498
557
|
*/
|
|
499
|
-
const REDACTION_VERSION = "2.
|
|
558
|
+
const REDACTION_VERSION = "2.5.0";
|
|
500
559
|
const KIB = 1024;
|
|
501
560
|
const PROFILE_RULES = {
|
|
502
561
|
default: {
|
|
@@ -964,6 +1023,6 @@ function redactForShare(value, options = {}) {
|
|
|
964
1023
|
verdict
|
|
965
1024
|
};
|
|
966
1025
|
}
|
|
967
|
-
export {
|
|
1026
|
+
export { emptyRedactionReport as a, redactText as c, PERSONAL_DATA_DETECTORS as d, classifyKey as f, normalizeKey as g, matchValueDetector as h, combineVerdicts as i, shareAllowed as l, detectPersonalData as m, REDACTION_VERSION as n, redact as o, detectCredential as p, assessShareSafety as r, redactForShare as s, REDACTION_PROFILES as t, CREDENTIAL_DETECTORS as u };
|
|
968
1027
|
|
|
969
|
-
//# sourceMappingURL=redact-
|
|
1028
|
+
//# sourceMappingURL=redact-zp_ILC4l.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact-zp_ILC4l.js","names":[],"sources":["../src/trace/redaction/detectors.ts","../src/trace/redact.ts"],"sourcesContent":["import type { SafetyCategory } from '../redact'\n\n// ── Key classifier ───────────────────────────────────────────────────────\n\n/**\n * Canonical snake_case form of a field name, so camelCase, kebab-case, dotted\n * and snake_case spellings match one list: `userPassword`, `user-password` and\n * `user.password` all become `user_password`.\n */\nexport function normalizeKey(key: string): string {\n return key\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '_')\n .replace(/^_+|_+$/g, '')\n}\n\n/** Counts, limits and model vocabulary that contain the word \"token\" but are not credentials. */\nconst NON_CREDENTIAL_TOKEN_KEYS: ReadonlySet<string> = new Set([\n 'tokens',\n 'max_tokens',\n 'min_tokens',\n 'ls_max_tokens',\n 'token_count',\n 'token_limit',\n 'token_budget',\n 'input_tokens',\n 'output_tokens',\n 'total_tokens',\n 'cached_tokens',\n 'prompt_tokens',\n 'completion_tokens',\n 'reasoning_tokens',\n 'bos_token',\n 'eos_token',\n 'pad_token',\n 'unk_token',\n 'sep_token',\n 'cls_token',\n 'mask_token',\n 'stop_token',\n // Pagination cursors are opaque but not credentials.\n 'page_token',\n 'next_page_token',\n 'prev_page_token',\n 'next_token',\n 'continuation_token',\n 'cursor_token',\n 'sync_token',\n])\n\nconst CREDENTIAL_KEYS = [\n 'authorization',\n 'auth',\n 'cookie',\n 'api_key',\n 'apikey',\n 'api_token',\n 'access_key',\n 'secret_key',\n 'private_key',\n 'signing_key',\n 'encryption_key',\n 'master_key',\n 'session_key',\n 'client_secret',\n 'secret',\n 'password',\n 'passwd',\n 'passphrase',\n 'credential',\n 'credentials',\n 'bearer',\n 'dsn',\n 'database_url',\n 'connection_string',\n 'pat',\n] as const\n\n/** Email fields are personal data in every profile. */\nconst EMAIL_KEYS = ['email', 'email_address'] as const\n\n/** Personal-data fields removed by the share and strict profiles. */\nconst SHARE_PERSONAL_KEYS = [\n 'phone',\n 'phone_number',\n 'mobile',\n 'ip',\n 'ip_address',\n 'remote_addr',\n 'street_address',\n 'postal_address',\n 'home_address',\n 'billing_address',\n 'shipping_address',\n 'mailing_address',\n 'date_of_birth',\n 'dob',\n 'ssn',\n] as const\n\n/** Identifiers pseudonymized by the share and strict profiles. */\nconst IDENTIFIER_KEYS = [\n 'user_id',\n 'user_uuid',\n 'account_id',\n 'account_uuid',\n 'customer_id',\n 'tenant_id',\n 'org_id',\n 'organization_id',\n 'organisation_id',\n 'team_id',\n 'enduser_id',\n 'actor_id',\n 'principal_id',\n 'member_id',\n 'session_id',\n 'request_id',\n 'correlation_id',\n 'device_id',\n 'installation_id',\n] as const\n\n/** Fields that carry prompts, model output, tool payloads or other free text. Removed by `strict`. */\nconst RAW_CONTENT_KEYS = [\n 'prompt',\n 'prompts',\n 'system_prompt',\n 'completion',\n 'input',\n 'output',\n 'message',\n 'messages',\n 'content',\n 'text',\n 'thinking',\n 'reasoning',\n 'transcript',\n 'context',\n 'document',\n 'documents',\n 'chunk',\n 'chunks',\n 'retrieval',\n 'query',\n 'args',\n 'arguments',\n 'result',\n 'body',\n 'command',\n 'full_command',\n 'input_value',\n 'output_value',\n 'instructions',\n 'system_instructions',\n 'stdout',\n 'stderr',\n 'stacktrace',\n 'status_description',\n 'input_preview',\n 'output_preview',\n 'current_task',\n 'user_input',\n 'request_text',\n] as const\n\n/**\n * A key matches a list entry exactly or as a suffix (`openai_api_key`,\n * `db_password`, `tool_output`). Prefix compounds (`secret_name`,\n * `password_min_length`, `auth_type`, `content_type`) do not match: they name\n * or describe a value rather than hold it, and flagging them would make the\n * share verdict refuse ordinary traces. Value detectors still catch a\n * credential-shaped value under any key.\n */\nfunction matchesKeyList(normalized: string, keys: readonly string[]): boolean {\n for (const key of keys) {\n if (normalized === key || normalized.endsWith(`_${key}`)) return true\n }\n return false\n}\n\nfunction isTokenCredentialKey(normalized: string): boolean {\n if (NON_CREDENTIAL_TOKEN_KEYS.has(normalized)) return false\n if (normalized === 'token') return true\n // access_token and refreshToken are credentials; max_tokens and input_tokens are counts.\n if (normalized.endsWith('tokens')) return false\n return normalized.endsWith('token')\n}\n\ntype KeyClass = 'credential' | 'email' | 'share-personal' | 'identifier' | 'raw-content'\n\n/** Trace keys repeat on every span, so classifications are cached. */\nconst keyClassCache = new Map<string, KeyClass | null>()\n\nexport function classifyKeyName(key: string): KeyClass | undefined {\n const cached = keyClassCache.get(key)\n if (cached !== undefined) return cached ?? undefined\n const kind = classifyNormalizedKey(normalizeKey(key))\n if (keyClassCache.size >= 10_000) keyClassCache.clear()\n keyClassCache.set(key, kind ?? null)\n return kind\n}\n\nfunction classifyNormalizedKey(normalized: string): KeyClass | undefined {\n if (!normalized || NON_CREDENTIAL_TOKEN_KEYS.has(normalized)) return undefined\n if (isTokenCredentialKey(normalized)) return 'credential'\n if (matchesKeyList(normalized, CREDENTIAL_KEYS)) return 'credential'\n if (matchesKeyList(normalized, EMAIL_KEYS)) return 'email'\n if (matchesKeyList(normalized, SHARE_PERSONAL_KEYS)) return 'share-personal'\n if (matchesKeyList(normalized, IDENTIFIER_KEYS)) return 'identifier'\n if (matchesKeyList(normalized, RAW_CONTENT_KEYS)) return 'raw-content'\n return undefined\n}\n\n/**\n * The safety category a field name puts its value in, or undefined for an\n * ordinary field. Token counts and model limits (`inputTokens`, `max_tokens`,\n * `token_count`) and names such as `author` are not credentials.\n */\nexport function classifyKey(key: string): SafetyCategory | undefined {\n const kind = classifyKeyName(key)\n if (kind === undefined) return undefined\n if (kind === 'credential') return 'credential'\n if (kind === 'identifier') return 'identifier'\n if (kind === 'raw-content') return 'raw-content'\n return 'personal-data'\n}\n\n// ── Value detectors ──────────────────────────────────────────────────────\n\nexport interface ValueDetectorOptions {\n /** Conservative scanning treats untyped bare numbers as private; formatted preserves the core's existing policy. */\n numericPolicy?: 'formatted' | 'conservative'\n}\n\nexport interface ValueDetector {\n readonly id: string\n readonly pattern: RegExp\n readonly requires?: string\n readonly substringPattern?: RegExp\n readonly conservativePattern?: RegExp\n readonly accept?: (match: string, options?: ValueDetectorOptions) => boolean\n}\n\n/** Stateless UTF-16 ranges for String.slice. Named `secret` groups preserve surrounding syntax. */\nexport function* matchValueDetector(\n text: string,\n detector: ValueDetector,\n options: ValueDetectorOptions = {},\n): Generator<{ start: number; end: number }> {\n if (detector.requires && !text.includes(detector.requires)) return\n const pattern =\n options.numericPolicy === 'conservative'\n ? (detector.conservativePattern ?? detector.substringPattern ?? detector.pattern)\n : (detector.substringPattern ?? detector.pattern)\n const flags = [...new Set(`${pattern.flags}gd`)].join('')\n // A credential shape inside a quoted secret must remove its entire value.\n // Reuse the quoted-value rule; advance one iterator so matches stay linear.\n const quoted =\n detector.id !== 'json-secret' && CREDENTIAL_DETECTORS.includes(detector)\n ? matchValueDetector(\n text,\n CREDENTIAL_DETECTORS.find((rule) => rule.id === 'json-secret')!,\n options,\n )\n : undefined\n let enclosing: { start: number; end: number } | undefined\n let coveredUntil = -1\n for (const match of text.matchAll(new RegExp(pattern.source, flags))) {\n if (detector.accept && !detector.accept(match[0], options)) continue\n let [start, end] = match.indices!.groups?.secret ?? match.indices![0]!\n if (start < coveredUntil) continue\n if (quoted) {\n while (!enclosing || enclosing.end <= start) {\n const next = quoted.next()\n enclosing = next.value\n if (next.done) break\n }\n if (enclosing && enclosing.start <= start && enclosing.end >= end)\n ({ start, end } = enclosing)\n }\n if (start < coveredUntil) continue\n coveredUntil = end\n yield { start, end }\n }\n}\n\nconst CREDENTIAL_ASSIGNMENT_KEY =\n /(?:api[_-]?key|apikey|access[_-]?key|secret[_-]?key|private[_-]?key|secret|token|password|passwd|passphrase|credentials?)/\n\nconst SECRET_ASSIGNMENT = new RegExp(\n CREDENTIAL_ASSIGNMENT_KEY.source +\n '[\"\\']?[ \\\\t]*[:=][ \\\\t]*[\"\\']?(?!encrypted:)(?![$`<[{(%])(?=[^\\\\s\"\\'`,;&|]{0,512}[0-9])(?=[^\\\\s\"\\'`,;&|]{0,512}[A-Za-z])(?<secret>[^\\\\s\"\\'`,;&|]{12,512})',\n 'i',\n)\n\nconst QUOTED_CREDENTIAL_FIELD =\n /[\"'][A-Za-z0-9_.-]{0,40}?(?:api[_-]?key|apikey|access[_-]?key|secret[_-]?key|private[_-]?key|client[_-]?secret|secret|password|passwd|passphrase|credentials?|(?:access|refresh|id|auth|session|bearer|api|github|gh|slack|npm)[_-]?token)[\"'][ \\t]*:[ \\t]*/\n\n/**\n * High-confidence credential shapes. A hit replaces the whole string. Each\n * pattern is written without the `g` flag so `test` stays stateless.\n *\n * The provider-branded prefixes below (`sk-ant-`, `AIza`, `ghp_`, `xoxb-`,\n * `AKIA`, `hubcap_`, `eyJ`…) have no leading `\\b`. A `\\b` word-boundary\n * assertion does not fire between two word characters, so it silently passed\n * a real token when something else glued a word character directly in front\n * of it — a compound identifier like `env.GITHUB_TOKEN_ghp_<token>` (a `_`\n * before `ghp_`) or `BACKUP_AKIA<key>` (a `_` before `AKIA`). These prefixes\n * are distinctive enough on their own, so scanning without that boundary\n * catches the same real credential wherever it is glued, at the cost of no\n * meaningful new false positives (`scripts/redaction-corpus.json` covers\n * both).\n */\nexport const CREDENTIAL_DETECTORS: readonly ValueDetector[] = [\n {\n id: 'private-key',\n pattern: /-----BEGIN ([A-Z0-9 ]*PRIVATE KEY)-----[^\"'`]*?(?:-----END \\1-----|(?=[\"'`]|$))/,\n },\n { id: 'jwt', pattern: /eyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}/ },\n { id: 'bearer', pattern: /\\bbearer\\s+[A-Za-z0-9._~+/=-]{12,}/i },\n {\n id: 'authorization-header',\n pattern: /^\\s*(?:basic|digest|apikey)\\s+[A-Za-z0-9._~+/=:-]{8,}\\s*$/i,\n },\n { id: 'anthropic-key', pattern: /sk-ant-[A-Za-z0-9_-]{8,}/ },\n { id: 'tangle-key', pattern: /sk-tan-[A-Za-z0-9_-]{8,}/ },\n { id: 'gtm-operator-key', pattern: /gak_[A-Za-z0-9_-]{8,}/ },\n { id: 'agent-app-key', pattern: /lak_[A-Za-z0-9_-]{8,}/ },\n { id: 'platform-labs-key', pattern: /plabs_[A-Za-z0-9_-]{8,}/ },\n { id: 'stripe-webhook-secret', pattern: /whsec_[A-Za-z0-9]{8,}/ },\n { id: 'provider-key', pattern: /sk-(?:proj-|tan-)?[A-Za-z0-9_-]{16,}/ },\n { id: 'stripe-key', pattern: /(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9_]{8,}/ },\n { id: 'google-api-key', pattern: /AIza[0-9A-Za-z_-]{20,}/ },\n { id: 'github-token', pattern: /(?:gh[pousr]_[A-Za-z0-9_]{16,}|github_pat_[A-Za-z0-9_]{16,})/ },\n { id: 'slack-token', pattern: /xox[abeoprs]-[A-Za-z0-9-]{10,}/ },\n { id: 'aws-access-key', pattern: /(?:AKIA|ASIA)[A-Z0-9]{16}\\b/ },\n { id: 'tangle-capability', pattern: /(?:hubcap_|hct_)[A-Za-z0-9_=-]{8,}/ },\n {\n // Scheme, userinfo user and password each bounded (32/512/512 chars): the\n // unbounded `*`/`+` here made `detectCredential` catastrophically slow on\n // adversarial text with no `://` at all — 256 KiB of `\"a.\"` took ~59s,\n // measured before this fix (scratchpad/rv/before.ts). A real URL's scheme\n // and userinfo are always far under these bounds.\n id: 'url-credentials',\n pattern: /\\b[a-z][a-z0-9+.-]{0,31}:\\/\\/(?<secret>[^\\s/:@]{1,512}:[^\\s/@]{1,512})@/i,\n },\n {\n id: 'url-secret-param',\n pattern:\n /[?&](?:access_token|api_key|apikey|auth|token|secret|password|sig|signature|x-amz-signature|x-goog-signature)=(?<secret>[^&\\s\"'#)]{8,})/i,\n },\n {\n // `GH_TOKEN=…`, `--api-key=…`, `\"client_secret\": \"…\"`, `password: …` in free\n // text. The value must mix letters and digits and be at least 12\n // characters, so prose (`token: string`), variable references (`$TOKEN`)\n // and dotenvx ciphertext (`encrypted:…`) pass. The pattern starts at the\n // key word itself, with no identifier prefix, so it scans in linear time.\n // Detection and its mixed-content lookaheads are bounded to 512 chars:\n // unbounded, `'token='` repeated took ~20s at 256 KiB and\n // `'password:x'` repeated took ~12s at 256 KiB (measured before this fix,\n // scratchpad/rv/before.ts). Substring replacement consumes the complete\n // detected token so a long value cannot leave an unrecognized tail.\n id: 'secret-assignment',\n pattern: SECRET_ASSIGNMENT,\n // Only the consumed range is unbounded; detection lookaheads remain bounded.\n substringPattern: new RegExp(\n SECRET_ASSIGNMENT.source.replace('{12,512}', '{12,}'),\n SECRET_ASSIGNMENT.flags,\n ),\n },\n {\n // `{\"password\": \"hunter2\"}` or `'client_secret': '…'` inside serialized\n // JSON, YAML or a log line. A quoted credential field name followed by a\n // quoted value holds a secret whatever the value's shape or length. Bare\n // `\"token\"` is left out: model logprob output uses it for text tokens.\n // Placeholders (`[REDACTED…]`, `$VAR`, `{env:VAR}`, `***`, `<value>`) and\n // prose with two or more spaces (a field description) do not match.\n id: 'json-secret',\n pattern: new RegExp(\n String.raw`${QUOTED_CREDENTIAL_FIELD.source}[\"'](?!\\[REDACTED|[$*{<])(?![^\"'\\r\\n]* [^\"'\\r\\n]* )(?<secret>[^\"'\\r\\n]{3,})[\"']`,\n 'i',\n ),\n // Quoted fields and assignments cover spaces and escaped quotes in the whole value.\n substringPattern: new RegExp(\n String.raw`(?:${QUOTED_CREDENTIAL_FIELD.source}|${CREDENTIAL_ASSIGNMENT_KEY.source}[ \\t]*[:=][ \\t]*)(?<quote>[\"'])(?!\\[REDACTED|[$*{<])(?<secret>(?:\\\\.|(?!\\k<quote>)[^\\\\\\r\\n]){3,})\\k<quote>`,\n 'i',\n ),\n },\n {\n // `DB_PASSWORD=CorrectHorseBatteryStaple`, `PGPASSWORD=postgres`: unlike\n // `secret-assignment` above, the all-upper-case env-var name ending in a\n // credential word is itself the signal, so a letters-only or short real\n // password still matches (no digit-mixing or 12-char minimum). Requires\n // the name to be immediately followed by `=`, so `MAX_TOKENS=16` and\n // `TOKEN_EXPIRY=…` (the word isn't the end of the name) do not match.\n id: 'env-secret-assignment',\n pattern:\n /\\b[A-Z][A-Z0-9_]*?(?:PASSWORD|PASSWD|SECRET|PASSPHRASE|APIKEY|API_KEY|TOKEN|CREDENTIALS?)[ \\t]*=[ \\t]*(?!\\$|<|\\*|\\{|%|encrypted:)(?<secret>[^\\s\"'`,;&|]{4,})/,\n },\n // Bare-key shapes not covered above. Each requires a distinctive prefix so\n // it does not fire on ordinary identifiers — same reasoning as the\n // provider-branded block above, and the same leading-`\\b` bug: a token\n // glued to preceding text by a digit or underscore (`1ghp_…`, `_sk_live_…`)\n // is invisible to an anchored detector.\n { id: 'huggingface-token', pattern: /hf_[A-Za-z0-9]{20,}/ },\n { id: 'npm-token', pattern: /npm_[A-Za-z0-9]{20,}/ },\n { id: 'gitlab-token', pattern: /glpat-[A-Za-z0-9_-]{16,}/ },\n { id: 'groq-key', pattern: /gsk_[A-Za-z0-9]{20,}/ },\n { id: 'xai-key', pattern: /xai-[A-Za-z0-9]{16,}/ },\n // ElevenLabs and similar bare `sk_<hex>` shapes — underscore, unlike the\n // hyphenated `sk-…` `provider-key` pattern above, so the two never overlap.\n { id: 'bare-sk-key', pattern: /sk_[A-Za-z0-9]{32,}\\b/ },\n {\n // `Cookie: sessionid=…; csrftoken=…` in free text or a captured header.\n id: 'cookie-header',\n pattern: /\\bcookie\\s*:\\s*[A-Za-z0-9_-]+=[^;\\r\\n]{3,}(?:;\\s*[A-Za-z0-9_-]+=[^;\\r\\n]{3,})*/i,\n substringPattern:\n /\\bcookie\\s*:\\s*(?<secret>[A-Za-z0-9_-]+=(?:(?<quote>\\\\?\")[^\\r\\n]*?\\k<quote>|[^;\\s\"'\\r\\n]{3,})(?:;\\s*[A-Za-z0-9_-]+=(?:(?<quote2>\\\\?\")[^\\r\\n]*?\\k<quote2>|[^;\\s\"'\\r\\n]{3,}))*)/i,\n },\n]\n\nconst CARD_NUMBER =\n /(?<![\\w-])(?:\\d{13,19}|\\d{4}([ -])\\d{4}\\1\\d{4}\\1\\d{4}(?:\\1\\d{3})?|\\d{4}([ -])\\d{6}\\2\\d{5})(?![\\w-])/g\nconst PHONE_NUMBER = /(?:\\+1[-.\\s]?)?(?:\\(\\d{3}\\)\\s?|\\b\\d{3}[-.\\s])\\d{3}[-.\\s]\\d{4}\\b/g\n\n// Whole UUIDs and decimals are exemptions, not prefixes of a neighboring value.\n// Match independent values before the fallback for other grouped contact formats.\nconst NUMERIC_PRIVACY = new RegExp(\n String.raw`(?<![A-Za-z0-9_])[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(?![A-Za-z0-9_])|(?<![A-Za-z0-9_.-])\\d+\\.\\d+(?![\\w.])|${CARD_NUMBER.source}|${PHONE_NUMBER.source}|(?<![A-Za-z0-9_-])\\+?\\d{1,3}[ \\t.-](?:\\(\\d{1,4}\\)|\\d{1,4})[ \\t.-](?:\\d{3,4}[ \\t.-]\\d{3,4}|\\d{5,8})(?![\\w-])|(?<![A-Za-z0-9_-])\\+?\\d[\\d().-]{8,}\\d(?![A-Za-z0-9_])|(?<![A-Za-z0-9_-])\\+?\\d[\\d\\s().-]{8,}\\d(?![A-Za-z0-9_])`,\n 'gi',\n)\n\nfunction numericPrivacyKind(\n value: string,\n options: ValueDetectorOptions = {},\n): 'card-number' | 'phone' | undefined {\n if (\n /^[0-9a-f]{8}-[0-9a-f-]{27}$/i.test(value) ||\n /^\\d*\\.\\d+$/.test(value) ||\n /\\d\\.\\d{5,}/.test(value)\n )\n return\n const digits = value.replace(/\\D/g, '')\n const conservative = options.numericPolicy === 'conservative'\n if (\n digits.length >= 13 &&\n digits.length <= 19 &&\n (conservative || CARD_PREFIX.test(digits)) &&\n luhnValid(digits, conservative)\n )\n return 'card-number'\n if (digits.length >= 10 && digits.length <= 15) return 'phone'\n}\n\n/** Ordered rules. Conservative numeric scanning is explicit; core patterns keep their existing defaults. */\nexport const PERSONAL_DATA_DETECTORS: readonly ValueDetector[] = [\n {\n id: 'email',\n requires: '@',\n pattern: /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b/g,\n accept: isEmailAddress,\n },\n {\n id: 'card-number',\n pattern: CARD_NUMBER,\n conservativePattern: NUMERIC_PRIVACY,\n accept: (value, options) => numericPrivacyKind(value, options) === 'card-number',\n },\n { id: 'ssn', pattern: /\\b\\d{3}-\\d{2}-\\d{4}\\b/g },\n {\n id: 'phone',\n pattern: PHONE_NUMBER,\n conservativePattern: NUMERIC_PRIVACY,\n accept: (value, options) => numericPrivacyKind(value, options) === 'phone',\n },\n]\n\nconst CARD_PREFIX = /^(?:4|5[1-5]|2[2-7]|3[04-9]|6(?:011|4[4-9]|5|2))/\n\n/**\n * Top-level domains that are file extensions: `icon@2x.png`, `worker@3.service`\n * and `notes@AGENTS.md` are not addresses.\n */\nconst NON_EMAIL_TLDS: ReadonlySet<string> = new Set([\n 'md',\n 'mdx',\n 'txt',\n 'json',\n 'jsonl',\n 'yaml',\n 'yml',\n 'toml',\n 'lock',\n 'ts',\n 'tsx',\n 'js',\n 'jsx',\n 'mjs',\n 'cjs',\n 'py',\n 'rs',\n 'go',\n 'sh',\n 'css',\n 'html',\n 'svg',\n 'png',\n 'jpg',\n 'jpeg',\n 'gif',\n 'webp',\n 'service',\n 'socket',\n 'timer',\n 'mount',\n 'target',\n])\n\nfunction isEmailAddress(match: string): boolean {\n // `git@github.com:org/repo` is an SSH remote, not a person.\n if (match.toLowerCase().startsWith('git@')) return false\n const tld = match.slice(match.lastIndexOf('.') + 1).toLowerCase()\n return !NON_EMAIL_TLDS.has(tld)\n}\n\nfunction luhnValid(digits: string, allowRepeated = false): boolean {\n if (!allowRepeated && /^(\\d)\\1+$/.test(digits)) return false\n let sum = 0\n let double = false\n for (let index = digits.length - 1; index >= 0; index -= 1) {\n let digit = digits.charCodeAt(index) - 48\n if (double) {\n digit *= 2\n if (digit > 9) digit -= 9\n }\n sum += digit\n double = !double\n }\n return sum % 10 === 0\n}\n\n/** The first credential detector that matches, or undefined. */\nexport function detectCredential(text: string): string | undefined {\n for (const detector of CREDENTIAL_DETECTORS) {\n if (detector.pattern.test(text)) return detector.id\n }\n return undefined\n}\n\n/** Personal-data detector ids that match somewhere in `text`. */\nexport function detectPersonalData(text: string): string[] {\n return PERSONAL_DATA_DETECTORS.filter(\n (detector) => !matchValueDetector(text, detector).next().done,\n ).map((detector) => detector.id)\n}\n\n/**\n * Every form in which a known secret can appear in a trace: as written,\n * base64, base64url and URL-encoded. Values shorter than 4 characters are\n * ignored; they would match ordinary text.\n */\nexport function knownSecretForms(values: readonly string[] | undefined): string[] {\n const forms = new Set<string>()\n for (const value of values ?? []) {\n if (value.length < 4) continue\n const bytes = Buffer.from(value, 'utf8')\n forms.add(value)\n forms.add(bytes.toString('base64'))\n forms.add(bytes.toString('base64url'))\n forms.add(encodeURIComponent(value))\n }\n // Longest first, so a secret that contains another is reported as itself.\n return [...forms].sort((left, right) => right.length - left.length)\n}\n\nconst BASE64_TEXT = /^[A-Za-z0-9+/_-]+={0,2}$/\n\n// A base64 blob embedded in larger text — `Authorization: Basic <base64>` is\n// the common case — can hold a known secret without the WHOLE string being\n// base64. Bounded to 4096 chars per candidate: this scans in linear time (the\n// sum of candidate lengths is at most `text.length`), so no ReDoS risk.\nconst EMBEDDED_BASE64 = /[A-Za-z0-9+/]{16,4096}={0,2}/g\n\nfunction containsKnownSecret(text: string, forms: readonly string[]): boolean {\n if (forms.length === 0) return false\n if (forms.some((form) => text.includes(form))) return true\n // A whole-string base64 payload can hold a secret at any byte offset.\n if (text.length >= 8 && BASE64_TEXT.test(text)) {\n const decoded = Buffer.from(\n text,\n text.includes('-') || text.includes('_') ? 'base64url' : 'base64',\n ).toString('utf8')\n if (forms.some((form) => decoded.includes(form))) return true\n }\n // `Basic <base64(user:key)>` jointly encodes the userinfo, so the secret's\n // OWN base64 form (added to `forms` above) is generally not a substring of\n // it — 3-byte base64 group alignment shifts with whatever precedes the\n // secret in the original bytes. Decode any embedded base64-looking run and\n // check its plaintext directly instead of relying on aligned forms.\n for (const match of text.matchAll(EMBEDDED_BASE64)) {\n if (match[0] === text) continue // already checked above\n try {\n const decoded = Buffer.from(match[0], 'base64').toString('utf8')\n if (forms.some((form) => decoded.includes(form))) return true\n } catch {\n // Not valid base64 (e.g. wrong padding) — not a candidate.\n }\n }\n return false\n}\n\n/** The detector that marks `text` as a credential: a known secret first, then the value shapes. */\nexport function credentialIn(text: string, knownSecrets: readonly string[]): string | undefined {\n return containsKnownSecret(text, knownSecrets) ? 'known-secret' : detectCredential(text)\n}\n","/**\n * The redaction core: the one place that decides what must not leave a\n * process or a machine. Every trace writer, exporter, uploader and share path\n * calls it.\n *\n * Three profiles, each a superset of the one before:\n * - `default` removes credentials, found by key name and by value shape, and\n * personal data (email addresses, card numbers, SSNs, phone numbers).\n * Content is kept. Strings are capped at 1 MiB.\n * - `share` also removes phone, IP and postal-address fields, replaces\n * account, user, tenant, session and request identifiers with pseudonyms\n * that stay consistent within one call, and caps strings at 64 KiB.\n * - `strict` also removes prompt, completion, message, tool payload and other\n * raw-content fields and embedded media, and caps strings at 4 KiB.\n *\n * A string that holds a credential is replaced whole with\n * `[REDACTED:<detector>]`. Replacing only the matched span can leave part of a\n * secret behind when a pattern's boundary is wrong. Personal data inside prose\n * is replaced in place, so the rest of the text stays readable.\n *\n * `assessShareSafety` reads a value without changing it and returns SAFE,\n * SAFE_WITH_WARNINGS, UNSAFE or UNKNOWN. UNKNOWN means the scanner could not\n * read part of the value (a cycle, binary data, nesting past the depth limit);\n * it is never reported as safe. `redactForShare` redacts and then assesses the\n * redacted output, so a detector gap shows up as UNSAFE instead of a leak.\n *\n * Reports and findings carry paths, categories and detector ids, never the\n * values they matched.\n *\n * The key classifier and the credential detector list are adapted from\n * agent-inspect (MIT, commit 3c3cbeda). `scripts/redaction-corpus.json` holds\n * the must-flag and must-not-flag cases, including the copied agent-inspect\n * safety corpus with its MIT notice; `pnpm redaction:corpus` runs this module\n * over every case.\n */\n\nimport { createHmac, randomBytes } from 'node:crypto'\nimport {\n classifyKey,\n classifyKeyName,\n credentialIn,\n detectPersonalData,\n knownSecretForms,\n PERSONAL_DATA_DETECTORS,\n} from './redaction/detectors'\n\nexport {\n CREDENTIAL_DETECTORS,\n matchValueDetector,\n PERSONAL_DATA_DETECTORS,\n type ValueDetector,\n type ValueDetectorOptions,\n} from './redaction/detectors'\n\nexport type RedactionProfile = 'default' | 'share' | 'strict'\n\nexport const REDACTION_PROFILES: readonly RedactionProfile[] = ['default', 'share', 'strict']\n\n/** What a finding is about. `media` is embedded binary content (a `data:` URI) no text detector can read. */\nexport type SafetyCategory = 'credential' | 'personal-data' | 'identifier' | 'raw-content' | 'media'\n\n/**\n * Version of the detector set and profile rules. Stored work that depends on\n * redaction behavior (saved optimizer inputs, per-span redaction stamps) keys\n * on it, so bump it whenever a detector, key list, cap or marker changes.\n */\nexport const REDACTION_VERSION = '2.5.0'\n\nexport interface RedactionFinding {\n /** JSON Pointer (RFC 6901) to the value or key that was changed. */\n path: string\n category: SafetyCategory\n detector: string\n action: 'redacted' | 'pseudonymized' | 'truncated'\n}\n\nexport interface RedactionReport {\n version: string\n profile: RedactionProfile\n /** Values and keys replaced, pseudonymized or truncated. */\n redactionCount: number\n byDetector: Record<string, number>\n truncatedCount: number\n findings: RedactionFinding[]\n}\n\nexport interface RedactOptions {\n /** Default `default`. */\n profile?: RedactionProfile\n /** Lower the profile's per-string cap. A value above the profile cap is ignored. */\n maxStringBytes?: number\n /**\n * Exact values the caller knows are secret (an API key the run was given, a\n * password from the environment), whatever shape they have. Each occurrence\n * in a string, as written or base64, base64url or URL-encoded, becomes\n * `[REDACTED:known-secret]` and the text around it is kept. A key that\n * contains one, and a whole-string base64 payload that holds one at any byte\n * offset, is replaced whole.\n */\n knownSecrets?: readonly string[]\n /** Add this call's findings to an existing report instead of a new one. */\n report?: RedactionReport\n}\n\nexport interface AssessOptions {\n /** Default `default`. */\n profile?: RedactionProfile\n /** As in `RedactOptions`: any surviving occurrence makes the verdict UNSAFE. */\n knownSecrets?: readonly string[]\n}\n\nexport type ShareSafetyStatus = 'SAFE' | 'SAFE_WITH_WARNINGS' | 'UNSAFE' | 'UNKNOWN'\n\nexport interface ShareSafetyFinding {\n category: SafetyCategory\n detector: string\n severity: 'error' | 'warning'\n count: number\n /** Up to five JSON Pointers where the detector fired. */\n paths: string[]\n}\n\nexport interface ShareSafetyVerdict {\n status: ShareSafetyStatus\n profile: RedactionProfile\n findings: ShareSafetyFinding[]\n /** Parts the scanner could not read, as `<path>: <reason>`. Any entry makes the status UNKNOWN. */\n unreadable: string[]\n}\n\n// ── Profiles ─────────────────────────────────────────────────────────────\n\ninterface ProfileRules {\n maxStringBytes: number\n /** Key categories whose values are removed or pseudonymized. */\n redactKeys: ReadonlySet<'share-personal' | 'identifier' | 'raw-content'>\n redactMedia: boolean\n severity: Record<SafetyCategory, 'error' | 'warning' | undefined>\n}\n\nconst KIB = 1024\n\nconst PROFILE_RULES: Record<RedactionProfile, ProfileRules> = {\n default: {\n maxStringBytes: 1024 * KIB,\n redactKeys: new Set(),\n redactMedia: false,\n severity: {\n credential: 'error',\n 'personal-data': 'warning',\n identifier: undefined,\n 'raw-content': 'warning',\n media: 'warning',\n },\n },\n share: {\n maxStringBytes: 64 * KIB,\n redactKeys: new Set(['share-personal', 'identifier']),\n redactMedia: false,\n severity: {\n credential: 'error',\n 'personal-data': 'error',\n identifier: 'warning',\n 'raw-content': 'warning',\n media: 'warning',\n },\n },\n strict: {\n maxStringBytes: 4 * KIB,\n redactKeys: new Set(['share-personal', 'identifier', 'raw-content']),\n redactMedia: true,\n severity: {\n credential: 'error',\n 'personal-data': 'error',\n identifier: 'warning',\n 'raw-content': 'error',\n media: 'error',\n },\n },\n}\n\nconst MARKER_PREFIX = '[REDACTED:'\n\nfunction marker(detector: string): string {\n return `${MARKER_PREFIX}${detector}]`\n}\n\n/**\n * Placeholders other tools write for a removed value. A credential field that\n * holds one of these is already redacted and is not flagged again.\n */\nconst REDACTED_PLACEHOLDER =\n /^(?:\\[(?:REDACTED|redacted)(?::[^\\]]*)?\\]|\\[ID:[0-9a-f]{12}\\]|\\*{3,}|<redacted>|«redacted»|\\[HASH:[0-9a-f]{8,}\\])$/\n\nfunction isPlaceholder(value: string): boolean {\n return value === '' || REDACTED_PLACEHOLDER.test(value)\n}\n\n// The whole string must be the data URI — `$` at the end, not just a `^`\n// prefix check. A prefix-only check let `data:text/plain;base64,…\\n` PLUS\n// arbitrary trailing text through as unread \"media\", when the trailing text\n// (or, for text/json mimes, the payload itself once decoded) is exactly the\n// kind of prose a credential or personal-data detector should see.\nconst DATA_URI = /^data:([\\w.+-]+\\/[\\w.+-]+)(?:;[\\w.+-]+=[\\w.+-]+)*;base64,([A-Za-z0-9+/=\\s]*)$/i\n\n/** A data: URI's mime type and base64 payload, only when the whole string is the URI. */\nfunction matchDataUri(text: string): { mime: string; payload: string } | undefined {\n const m = DATA_URI.exec(text)\n if (!m) return undefined\n return { mime: (m[1] ?? '').toLowerCase(), payload: m[2] ?? '' }\n}\n\n/** Decodes a data: URI's base64 payload to text, or undefined if it is not valid base64. */\nfunction decodeDataUriPayload(payload: string): string | undefined {\n const cleaned = payload.replace(/\\s+/g, '')\n if (cleaned.length === 0) return ''\n if (!/^[A-Za-z0-9+/]*={0,2}$/.test(cleaned) || cleaned.length % 4 !== 0) return undefined\n try {\n return Buffer.from(cleaned, 'base64').toString('utf8')\n } catch {\n return undefined\n }\n}\n\nconst READABLE_IMAGE_MIME = /^image\\//\n\n/** Mimes whose payload is text a detector can read once decoded. */\nconst DECODABLE_TEXT_MIME = /^text\\/|^application\\/json$/\n\n/** Whether a decoded data: URI payload holds a credential or personal data,\n * by key name (for application/json) or by value shape (for any text). */\nfunction decodedPayloadIsUnsafe(\n decoded: string,\n mime: string,\n knownSecrets: readonly string[],\n): boolean {\n if (mime === 'application/json') {\n try {\n return jsonValueIsUnsafe(JSON.parse(decoded), knownSecrets)\n } catch {\n // Not actually valid JSON despite the mime type — fall through to plain text.\n }\n }\n if (credentialIn(decoded, knownSecrets)) return true\n return detectPersonalData(decoded).length > 0\n}\n\nfunction jsonValueIsUnsafe(value: unknown, knownSecrets: readonly string[]): boolean {\n if (value === null || value === undefined) return false\n if (typeof value === 'string')\n return credentialIn(value, knownSecrets) !== undefined || detectPersonalData(value).length > 0\n if (typeof value !== 'object') return false\n if (Array.isArray(value)) return value.some((item) => jsonValueIsUnsafe(item, knownSecrets))\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n const category = classifyKey(key)\n if (category === 'credential') return true\n if (category === 'personal-data' && (typeof item === 'string' || typeof item === 'number'))\n return true\n if (jsonValueIsUnsafe(item, knownSecrets)) return true\n }\n return false\n}\n\n// ── Redaction ────────────────────────────────────────────────────────────\n\nconst MAX_DEPTH = 64\n\ninterface WalkState {\n rules: ProfileRules\n maxStringBytes: number\n knownSecrets: string[]\n report: RedactionReport\n /** Created on first use: most calls pseudonymize nothing. */\n pseudonymKey?: Buffer\n seen: WeakSet<object>\n}\n\nfunction record(\n state: WalkState,\n path: string,\n category: SafetyCategory,\n detector: string,\n action: RedactionFinding['action'],\n): void {\n const report = state.report\n if (action === 'truncated') report.truncatedCount += 1\n report.redactionCount += 1\n report.byDetector[detector] = (report.byDetector[detector] ?? 0) + 1\n report.findings.push({ path, category, detector, action })\n}\n\nfunction pointer(parent: string, key: string | number): string {\n return `${parent}/${String(key).replace(/~/g, '~0').replace(/\\//g, '~1')}`\n}\n\nfunction truncateUtf8(text: string, maxBytes: number): string | undefined {\n if (text.length <= maxBytes / 4) return undefined\n const bytes = Buffer.from(text, 'utf8')\n if (bytes.length <= maxBytes) return undefined\n // Step back to the first byte of a UTF-8 sequence so no character is split.\n let cut = maxBytes\n while (cut > 0 && ((bytes[cut] ?? 0) & 0xc0) === 0x80) cut -= 1\n return `${bytes.subarray(0, cut).toString('utf8')}…[truncated ${bytes.length - cut} bytes]`\n}\n\nfunction redactStringAt(text: string, path: string, state: WalkState): string {\n if (isPlaceholder(text)) return text\n // A known secret is an exact value, so it is cut out where it stands and the\n // text around it survives: an error message keeps its diagnosis.\n let output = text\n for (const form of state.knownSecrets) {\n if (!output.includes(form)) continue\n output = output.split(form).join(marker('known-secret'))\n record(state, path, 'credential', 'known-secret', 'redacted')\n }\n const dataUri = matchDataUri(output)\n if (dataUri) {\n if (DECODABLE_TEXT_MIME.test(dataUri.mime)) {\n const decoded = decodeDataUriPayload(dataUri.payload)\n if (decoded === undefined) {\n // Can't verify what an undecodable payload holds — fail closed rather\n // than pass it through as if it were opaque, harmless media.\n record(state, path, 'credential', 'data-uri-payload', 'redacted')\n return marker('data-uri-payload')\n }\n if (decodedPayloadIsUnsafe(decoded, dataUri.mime, state.knownSecrets)) {\n record(state, path, 'credential', 'data-uri-payload', 'redacted')\n return marker('data-uri-payload')\n }\n // Decoded clean: still opaque bytes to a downstream reader once\n // embedded, so it's subject to the ordinary media rule below, same as\n // any other data URI.\n }\n if (!state.rules.redactMedia) return output\n record(state, path, 'media', 'media', 'redacted')\n return marker('media')\n }\n // A value shape, or a whole-string base64 payload that holds a known secret\n // at any byte offset, replaces the whole string. The detectors themselves\n // only ever see a bounded prefix (`boundForScan`): a credential that lives\n // entirely beyond `maxStringBytes` would be truncated out of the output\n // below anyway, so scanning past the bound costs time without changing\n // what can leak. The untouched tail is reattached after the personal-data\n // pass so later truncation still sees (and cuts) the full length.\n const boundLen = Math.min(output.length, state.maxStringBytes)\n let scanTarget = output.slice(0, boundLen)\n const tail = output.slice(boundLen)\n const credential = credentialIn(scanTarget, state.knownSecrets)\n if (credential) {\n record(state, path, 'credential', credential, 'redacted')\n return marker(credential)\n }\n for (const detector of PERSONAL_DATA_DETECTORS) {\n if (detector.requires && !scanTarget.includes(detector.requires)) continue\n scanTarget = scanTarget.replace(detector.pattern, (match) => {\n if (detector.accept && !detector.accept(match)) return match\n record(state, path, 'personal-data', detector.id, 'redacted')\n return marker(detector.id)\n })\n }\n output = scanTarget + tail\n const truncated = truncateUtf8(output, state.maxStringBytes)\n if (truncated === undefined) return output\n record(state, path, 'raw-content', 'size-cap', 'truncated')\n return truncated\n}\n\nfunction pseudonym(value: string | number, state: WalkState): string {\n state.pseudonymKey ??= randomBytes(32)\n const digest = createHmac('sha256', state.pseudonymKey).update(String(value)).digest('hex')\n return `[ID:${digest.slice(0, 12)}]`\n}\n\nfunction redactKeyed(\n key: string,\n value: unknown,\n path: string,\n depth: number,\n state: WalkState,\n): unknown {\n const kind = classifyKeyName(key)\n if (value === null || value === undefined || typeof value === 'boolean') {\n return value\n }\n if (typeof value === 'string' && isPlaceholder(value)) return value\n // Numbers under a credential name are limits and counts (`password_max_age`), not secrets.\n if (kind === 'credential' && typeof value !== 'number') {\n record(state, path, 'credential', 'credential-key', 'redacted')\n return marker('credential-key')\n }\n if (\n kind === 'email' ||\n (kind === 'share-personal' && state.rules.redactKeys.has('share-personal'))\n ) {\n if (typeof value === 'string' || typeof value === 'number') {\n record(state, path, 'personal-data', 'personal-data-key', 'redacted')\n return marker('personal-data-key')\n }\n }\n if (kind === 'identifier' && state.rules.redactKeys.has('identifier')) {\n if (typeof value === 'string' || typeof value === 'number') {\n record(state, path, 'identifier', 'identifier-key', 'pseudonymized')\n return pseudonym(value, state)\n }\n }\n if (\n kind === 'raw-content' &&\n state.rules.redactKeys.has('raw-content') &&\n typeof value !== 'number'\n ) {\n record(state, path, 'raw-content', 'raw-content-key', 'redacted')\n return marker('raw-content-key')\n }\n return walk(value, path, depth + 1, state)\n}\n\nfunction walk(value: unknown, path: string, depth: number, state: WalkState): unknown {\n if (typeof value === 'string') return redactStringAt(value, path, state)\n if (value === null || typeof value !== 'object') return value\n if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {\n record(state, path, 'media', 'binary', 'redacted')\n return marker('binary')\n }\n if (value instanceof Date) return value\n if (depth > MAX_DEPTH) {\n record(state, path, 'raw-content', 'depth-limit', 'truncated')\n return marker('depth-limit')\n }\n if (state.seen.has(value)) {\n record(state, path, 'raw-content', 'circular', 'redacted')\n return marker('circular')\n }\n state.seen.add(value)\n try {\n if (Array.isArray(value)) {\n return value.map((item, index) => walk(item, pointer(path, index), depth + 1, state))\n }\n const out: Record<string, unknown> = {}\n let renamed = 0\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n let outKey = key\n const keyCredential = credentialIn(key, state.knownSecrets)\n // A personal-data value used AS a key (an email or card number mapping\n // to something) is just as reachable as one in a value — walk() only\n // ever inspects keys for a credential shape, so `{'alice@x.com': 3}`\n // passed through unchanged with verdict SAFE.\n const keyPersonalData = keyCredential ? undefined : detectPersonalData(key)[0]\n if (keyCredential) {\n renamed += 1\n outKey = `${marker(keyCredential)}#${renamed}`\n record(state, pointer(path, outKey), 'credential', keyCredential, 'redacted')\n } else if (keyPersonalData) {\n renamed += 1\n outKey = `${marker(keyPersonalData)}#${renamed}`\n record(state, pointer(path, outKey), 'personal-data', keyPersonalData, 'redacted')\n }\n out[outKey] = redactKeyed(key, item, pointer(path, outKey), depth, state)\n }\n return out\n } finally {\n state.seen.delete(value)\n }\n}\n\n/** An empty report to accumulate `redactText` calls into. */\nexport function emptyRedactionReport(profile: RedactionProfile = 'default'): RedactionReport {\n return {\n version: REDACTION_VERSION,\n profile,\n redactionCount: 0,\n byDetector: {},\n truncatedCount: 0,\n findings: [],\n }\n}\n\nfunction newState(options: RedactOptions, report?: RedactionReport): WalkState {\n const profile = options.profile ?? 'default'\n const rules = PROFILE_RULES[profile]\n if (!rules) throw new Error(`unknown redaction profile: ${String(profile)}`)\n const requested = options.maxStringBytes\n const maxStringBytes =\n typeof requested === 'number' && Number.isFinite(requested) && requested >= 0\n ? Math.min(Math.floor(requested), rules.maxStringBytes)\n : rules.maxStringBytes\n return {\n rules,\n maxStringBytes,\n knownSecrets: knownSecretForms(options.knownSecrets),\n report: report ?? emptyRedactionReport(profile),\n seen: new WeakSet(),\n }\n}\n\n/**\n * Return a redacted deep copy of `value` and a report of what changed. Pure:\n * the input is not mutated. Never throws on the value's shape; cycles, binary\n * data and nesting past 64 levels are replaced with markers.\n */\nexport function redact<T>(\n value: T,\n options: RedactOptions = {},\n): { value: T; report: RedactionReport } {\n const state = newState(options, options.report)\n const out = walk(value, '', 0, state) as T\n return { value: out, report: state.report }\n}\n\n/**\n * Redact one free-text string with the value detectors (no field name is\n * known). Pass `report` to accumulate counts across calls.\n */\nexport function redactText(text: string, options: RedactOptions = {}): string {\n const state = newState(options, options.report)\n return redactStringAt(text, '', state)\n}\n\n// ── Share-safety assessment ──────────────────────────────────────────────\n\ninterface ScanState {\n profile: RedactionProfile\n rules: ProfileRules\n knownSecrets: string[]\n findings: Map<string, ShareSafetyFinding>\n unreadable: string[]\n seen: WeakSet<object>\n}\n\nfunction flag(state: ScanState, path: string, category: SafetyCategory, detector: string): void {\n const severity = state.rules.severity[category]\n if (!severity) return\n const id = `${category}\\u0000${detector}`\n const existing = state.findings.get(id)\n if (existing) {\n existing.count += 1\n if (existing.paths.length < 5) existing.paths.push(path)\n return\n }\n state.findings.set(id, { category, detector, severity, count: 1, paths: [path] })\n}\n\nfunction scanString(text: string, path: string, state: ScanState): void {\n if (isPlaceholder(text)) return\n const dataUri = matchDataUri(text)\n if (dataUri) {\n scanDataUri(dataUri, path, state)\n return\n }\n const credential = credentialIn(text, state.knownSecrets)\n if (credential) {\n flag(state, path, 'credential', credential)\n return\n }\n for (const detector of detectPersonalData(text)) flag(state, path, 'personal-data', detector)\n}\n\nfunction scanDataUri(\n dataUri: { mime: string; payload: string },\n path: string,\n state: ScanState,\n): void {\n if (READABLE_IMAGE_MIME.test(dataUri.mime)) {\n flag(state, path, 'media', 'media')\n return\n }\n if (DECODABLE_TEXT_MIME.test(dataUri.mime)) {\n const decoded = decodeDataUriPayload(dataUri.payload)\n if (decoded === undefined) {\n state.unreadable.push(`${path || '/'}: data URI payload is not valid base64`)\n return\n }\n if (dataUri.mime === 'application/json') {\n try {\n scan(JSON.parse(decoded), path, 0, state)\n return\n } catch {\n // Not actually valid JSON despite the mime type — fall through to plain text.\n }\n }\n scanString(decoded, path, state)\n return\n }\n // audio/video/octet-stream/etc: bytes no text detector can read. A warning\n // under `default` (matches the existing image rule); under `share` and\n // `strict` — the profiles that actually gate whether something may be sent\n // off the machine — treat it as unreadable so the verdict is UNKNOWN\n // instead of silently allowing it through.\n if (state.profile === 'default') {\n flag(state, path, 'media', 'media')\n } else {\n state.unreadable.push(`${path || '/'}: ${dataUri.mime} data URI cannot be read`)\n }\n}\n\nfunction scanKeyed(\n key: string,\n value: unknown,\n path: string,\n depth: number,\n state: ScanState,\n): void {\n if (value === null || value === undefined || typeof value === 'boolean') return\n if (typeof value === 'string' && isPlaceholder(value)) return\n const category = classifyKey(key)\n if (category === 'credential' && typeof value !== 'number') {\n flag(state, path, 'credential', 'credential-key')\n return\n }\n const scalar = typeof value === 'string' || typeof value === 'number'\n if (category === 'personal-data' && scalar) {\n const kind = classifyKeyName(key)\n // Phone, IP and address fields are flagged from the share profile up; email always.\n if (kind === 'email' || state.profile !== 'default') {\n flag(state, path, 'personal-data', 'personal-data-key')\n return\n }\n }\n if (category === 'identifier' && scalar) flag(state, path, 'identifier', 'identifier-key')\n if (category === 'raw-content' && typeof value !== 'number')\n flag(state, path, 'raw-content', 'raw-content-key')\n scan(value, path, depth + 1, state)\n}\n\nfunction scan(value: unknown, path: string, depth: number, state: ScanState): void {\n if (typeof value === 'string') {\n scanString(value, path, state)\n return\n }\n if (value === null || typeof value !== 'object') return\n if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {\n state.unreadable.push(`${path || '/'}: binary data`)\n return\n }\n if (value instanceof Date) return\n if (depth > MAX_DEPTH) {\n state.unreadable.push(`${path || '/'}: nested deeper than ${MAX_DEPTH} levels`)\n return\n }\n if (state.seen.has(value)) {\n state.unreadable.push(`${path || '/'}: circular reference`)\n return\n }\n state.seen.add(value)\n try {\n if (Array.isArray(value)) {\n for (const [index, item] of value.entries())\n scan(item, pointer(path, index), depth + 1, state)\n return\n }\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n // A credential or personal-data value used as a key must not reach the\n // finding paths.\n const keyCredential = credentialIn(key, state.knownSecrets)\n const keyPersonalData = keyCredential ? undefined : detectPersonalData(key)[0]\n const keyDetector = keyCredential ?? keyPersonalData\n const segment = keyDetector ? marker(keyDetector) : key\n if (keyCredential) flag(state, pointer(path, segment), 'credential', keyCredential)\n else if (keyPersonalData)\n flag(state, pointer(path, segment), 'personal-data', keyPersonalData)\n scanKeyed(key, item, pointer(path, segment), depth, state)\n }\n } finally {\n state.seen.delete(value)\n }\n}\n\n/**\n * Read `value` without changing it and say whether it is safe to share under\n * `profile`. UNKNOWN when any part could not be read; UNSAFE when any\n * error-severity finding remains; SAFE_WITH_WARNINGS when only warnings\n * remain (raw content, embedded media, identifiers under `share`).\n */\nexport function assessShareSafety(value: unknown, options: AssessOptions = {}): ShareSafetyVerdict {\n const profile = options.profile ?? 'default'\n const rules = PROFILE_RULES[profile]\n if (!rules) throw new Error(`unknown redaction profile: ${String(profile)}`)\n const state: ScanState = {\n profile,\n rules,\n knownSecrets: knownSecretForms(options.knownSecrets),\n findings: new Map(),\n unreadable: [],\n seen: new WeakSet(),\n }\n scan(value, '', 0, state)\n return verdictFrom(profile, [...state.findings.values()], state.unreadable)\n}\n\n/**\n * One verdict over several parts (files in a directory, spans in a bundle).\n * Callers prefix each part's paths with its source before combining.\n */\nexport function combineVerdicts(\n profile: RedactionProfile,\n verdicts: readonly ShareSafetyVerdict[],\n unreadable: readonly string[] = [],\n): ShareSafetyVerdict {\n const findings = new Map<string, ShareSafetyFinding>()\n for (const verdict of verdicts) {\n for (const finding of verdict.findings) {\n const id = `${finding.category}\\u0000${finding.detector}`\n const existing = findings.get(id)\n if (!existing) {\n findings.set(id, { ...finding, paths: [...finding.paths] })\n continue\n }\n existing.count += finding.count\n for (const path of finding.paths) if (existing.paths.length < 5) existing.paths.push(path)\n }\n }\n return verdictFrom(\n profile,\n [...findings.values()],\n [...verdicts.flatMap((verdict) => verdict.unreadable), ...unreadable],\n )\n}\n\nfunction verdictFrom(\n profile: RedactionProfile,\n findings: readonly ShareSafetyFinding[],\n unreadable: readonly string[],\n): ShareSafetyVerdict {\n const status: ShareSafetyStatus =\n unreadable.length > 0\n ? 'UNKNOWN'\n : findings.some((finding) => finding.severity === 'error')\n ? 'UNSAFE'\n : findings.length > 0\n ? 'SAFE_WITH_WARNINGS'\n : 'SAFE'\n return { status, profile, findings: [...findings], unreadable: [...unreadable] }\n}\n\n/** Whether a verdict allows sharing: SAFE or SAFE_WITH_WARNINGS. UNSAFE and UNKNOWN refuse. */\nexport function shareAllowed(verdict: ShareSafetyVerdict): boolean {\n return verdict.status === 'SAFE' || verdict.status === 'SAFE_WITH_WARNINGS'\n}\n\n/**\n * Redact `value` under `profile`, then assess the redacted output. The\n * verdict describes what would actually be shared: a detector that failed to\n * remove something shows up as UNSAFE here.\n */\nexport function redactForShare<T>(\n value: T,\n options: RedactOptions = {},\n): { value: T; report: RedactionReport; verdict: ShareSafetyVerdict } {\n const redacted = redact(value, options)\n const verdict = assessShareSafety(redacted.value, {\n profile: options.profile,\n knownSecrets: options.knownSecrets,\n })\n return { value: redacted.value, report: redacted.report, verdict }\n}\n"],"mappings":";;;;;;;AASA,SAAgB,aAAa,KAAqB;CAChD,OAAO,IACJ,QAAQ,sBAAsB,OAAO,CAAC,CACtC,YAAY,CAAC,CACb,QAAQ,eAAe,GAAG,CAAC,CAC3B,QAAQ,YAAY,EAAE;AAC3B;;AAGA,MAAM,4CAAiD,IAAI,IAAI;CAC7D;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,kBAAkB;CACtB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,MAAM,aAAa,CAAC,SAAS,eAAe;;AAG5C,MAAM,sBAAsB;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,MAAM,kBAAkB;CACtB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,MAAM,mBAAmB;CACvB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;;;;AAUA,SAAS,eAAe,YAAoB,MAAkC;CAC5E,KAAK,MAAM,OAAO,MAChB,IAAI,eAAe,OAAO,WAAW,SAAS,IAAI,KAAK,GAAG,OAAO;CAEnE,OAAO;AACT;AAEA,SAAS,qBAAqB,YAA6B;CACzD,IAAI,0BAA0B,IAAI,UAAU,GAAG,OAAO;CACtD,IAAI,eAAe,SAAS,OAAO;CAEnC,IAAI,WAAW,SAAS,QAAQ,GAAG,OAAO;CAC1C,OAAO,WAAW,SA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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { S as ValueDetectorOptions, T as matchValueDetector, _ as redactText, a as RedactionFinding, b as PERSONAL_DATA_DETECTORS, c as SafetyCategory, d as ShareSafetyVerdict, f as assessShareSafety, g as redactForShare, h as redact, i as RedactOptions, l as ShareSafetyFinding, m as emptyRedactionReport, n as REDACTION_PROFILES, o as RedactionProfile, p as combineVerdicts, r as REDACTION_VERSION, s as RedactionReport, t as AssessOptions, u as ShareSafetyStatus, v as shareAllowed, x as ValueDetector, y as CREDENTIAL_DETECTORS } from "./redact-jrT0APTU.js";
|
|
2
|
+
export { AssessOptions, CREDENTIAL_DETECTORS, PERSONAL_DATA_DETECTORS, REDACTION_PROFILES, REDACTION_VERSION, RedactOptions, RedactionFinding, RedactionProfile, RedactionReport, SafetyCategory, ShareSafetyFinding, ShareSafetyStatus, ShareSafetyVerdict, type ValueDetector, type ValueDetectorOptions, assessShareSafety, combineVerdicts, emptyRedactionReport, matchValueDetector, redact, redactForShare, redactText, shareAllowed };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { u as CREDENTIAL_DETECTORS, d as PERSONAL_DATA_DETECTORS, t as REDACTION_PROFILES, n as REDACTION_VERSION, r as assessShareSafety, i as combineVerdicts, a as emptyRedactionReport, h as matchValueDetector, o as redact, s as redactForShare, c as redactText, l as shareAllowed } from "./redact-zp_ILC4l.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { o as CostLedgerHandle } from "./cost-ledger-Czro9wmo.js";
|
|
2
2
|
import { c as AnalystRunEvent, d as AnalystRunSummary, i as AnalystFinding, l as AnalystRunInputs, n as AnalystContext, t as Analyst, u as AnalystRunResult } from "./types-DzCO-S1m.js";
|
|
3
3
|
import { x as ChatClient } from "./types-0KglnQ9o.js";
|
|
4
|
-
import { i as ExactAnalystRunEvent, o as ExactAnalystRunResult, u as ExactExecutionComponentIdentity } from "./exact-types-
|
|
4
|
+
import { i as ExactAnalystRunEvent, o as ExactAnalystRunResult, u as ExactExecutionComponentIdentity } from "./exact-types-CIViGj98.js";
|
|
5
5
|
interface AnalystHooks {
|
|
6
6
|
/** Legacy runs may mutate ctx; exact runs provide a frozen observational context. */
|
|
7
7
|
onBeforeAnalyze?(args: {
|
|
@@ -165,4 +165,4 @@ declare class AnalystRegistry {
|
|
|
165
165
|
runStream(runId: string, inputs: AnalystRunInputs, runOpts?: RegistryRunOpts): AsyncGenerator<AnalystRunEvent, void, void>;
|
|
166
166
|
}
|
|
167
167
|
export { BudgetPolicy as a, RegistryRunOpts as c, AnalystRegistryOptions as i, ExactAnalystRunExecutionError as n, ExactAnalystBudgetPolicy as o, AnalystHooks as r, ExactRegistryRunOpts as s, AnalystRegistry as t };
|
|
168
|
-
//# sourceMappingURL=registry-
|
|
168
|
+
//# sourceMappingURL=registry-CMtGAxOw.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-
|
|
1
|
+
{"version":3,"file":"registry-CMtGAxOw.d.ts","names":[],"sources":["../src/analyst/registry-plan.ts","../src/analyst/registry-execution.ts","../src/analyst/registry.ts"],"mappings":";;;;UAiBiB;;EAEf,iBAAiB;IACf,SAAS;IACT,KAAK;IACL;aACS;;EAEX,gBAAgB;IACd,SAAS;IACT,SAAS;IACT,UAAU;IACV;aACS;;;;;;EAMX,SAAS;IACP,SAAS;IACT,OAAO;IACP;MACE,+BAA+B,QAAQ;;EAE3C,YAAY;IAAQ,QAAQ;aAA4B;;UAGzC;;EAEf;;EAEA,UAAU;;;;;;;EAOV,YAAY;IACV,SAAS;IACT;IACA;IACA;;;UAIa;;EAEf,OAAO;;EAEP,OAAO,aAAa,SAAS;;EAE7B,QAAQ;;EAER,gBAAgB;;EAEhB,gBAAgB;;EAEhB,eAAe;;UAGA;;EAEf;;EAEA;;EAEA,SAAS;;EAET;;EAEA,SAAS;;EAET,aAAa;;EAEb;;EAEA,OAAO;;;;;;;;;EASP,gBAAgB,cAAc,kBAAkB,eAAe,cAAc;;;;;;EAM7E;;;KAIU;WAEG;WACA;;WAGA;WACA;;WAEA,SAAS,SAAS;;;;;;;;;;UAWhB;WACN;WACA,QAAQ;WACR;WACA,QAAQ;WACR,YAAY;WACZ,oBAAoB;WACpB;WACA,MAAM,SAAS;WACf,eACL,cAAc,kBACd,SAAS,eAAe,cAAc;WAEjC;WACA;WACA;WACA;;;cChHE,sCAAsC;WACxC;WACA,QAAQ;EAEL,YAAA,iBAAiB,QAAQ,uBAAuB,UAAU;;cCN3D;mBACM;mBACA;EAEL,YAAA,UAAS;EAIrB,SAAS,SAAS;EAsBlB,QAAQ;IACN;IACA;IACA;IACA,MAAM;;EAUF,IACJ,eACA,QAAQ,kBACR,UAAS,kBACR,QAAQ;;EAUL,SACJ,eACA,QAAQ,kBACR,SAAS,uBACR,QAAQ;;EAQJ,eACL,eACA,QAAQ,kBACR,SAAS,uBACR,eAAe;;;;;;;;;;;;EAmBX,UACL,eACA,QAAQ,kBACR,UAAS,kBACR,eAAe"}
|
|
@@ -3,7 +3,7 @@ import { r as observedSplitScore, t as isRealnessGated } from "./reward-P0VD_Aft
|
|
|
3
3
|
import { t as FAILURE_CLASSES } from "./schema-D-xu3MU_.js";
|
|
4
4
|
import { c as validateRunRecord } from "./run-record-DEjx43cI.js";
|
|
5
5
|
import { t as mulberry32 } from "./random-DrzcgC7F.js";
|
|
6
|
-
import {
|
|
6
|
+
import { c as summarizeNumberSeries } from "./descriptive-BTzLL-aj.js";
|
|
7
7
|
// src/promotion-gate.ts
|
|
8
8
|
/**
|
|
9
9
|
* Bootstrap-CI promotion gate.
|
|
@@ -513,4 +513,4 @@ function fmt(x) {
|
|
|
513
513
|
}
|
|
514
514
|
export { bootstrapCi as n, judgeReplayGate as r, evaluateReleaseConfidence as t };
|
|
515
515
|
|
|
516
|
-
//# sourceMappingURL=release-confidence-
|
|
516
|
+
//# sourceMappingURL=release-confidence--1iP-d3x.js.map
|