@sanctuary-framework/mcp-server 1.2.11 → 1.2.12

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/dist/cli.cjs CHANGED
@@ -17631,6 +17631,281 @@ var init_handoff_log = __esm({
17631
17631
  }
17632
17632
  });
17633
17633
 
17634
+ // src/coordination/context-transfer-extractor.ts
17635
+ async function extractContextTransferBreakdown(detail, deps = {}) {
17636
+ const pathA = tryStructuredPath(detail);
17637
+ if (pathA) return pathA;
17638
+ const pathB = tryCompositionPath(detail);
17639
+ if (pathB) return pathB;
17640
+ const pathC = tryHeuristicPath(detail);
17641
+ if (pathC.confidence >= 0.5 || !deps.substrateSelector) {
17642
+ return pathC;
17643
+ }
17644
+ const assist = await tryLlmAssistPath(detail, deps.substrateSelector);
17645
+ return assist ?? pathC;
17646
+ }
17647
+ function tryStructuredPath(detail) {
17648
+ const details = sourceDetails(detail.source_audit_entry);
17649
+ if (!details) return null;
17650
+ const transferredRaw = details["transferred"];
17651
+ const withheldRaw = details["withheld"];
17652
+ if (transferredRaw === void 0 && withheldRaw === void 0) return null;
17653
+ const transferred = parseExplicitContextItems(transferredRaw);
17654
+ const withheld = parseExplicitContextItems(withheldRaw);
17655
+ return {
17656
+ handoff_entry_id: detail.entry.entry_id,
17657
+ transferred,
17658
+ withheld,
17659
+ source: "structured",
17660
+ confidence: 1
17661
+ };
17662
+ }
17663
+ function tryCompositionPath(detail) {
17664
+ const op = detail.source_audit_entry.operation;
17665
+ if (!op.startsWith("composition_completed")) return null;
17666
+ const details = sourceDetails(detail.source_audit_entry);
17667
+ if (!details) return null;
17668
+ const receiptRaw = details["receipt"];
17669
+ const sourceStateRaw = details["source_state_snapshot"];
17670
+ if (receiptRaw === void 0) return null;
17671
+ const transferred = parseExplicitContextItems(receiptRaw);
17672
+ const withheld = [];
17673
+ if (Array.isArray(sourceStateRaw)) {
17674
+ const transferredKeys = new Set(
17675
+ transferred.map((t) => `${t.category}:${t.summary}`)
17676
+ );
17677
+ for (const item of parseExplicitContextItems(sourceStateRaw)) {
17678
+ const key = `${item.category}:${item.summary}`;
17679
+ if (!transferredKeys.has(key)) withheld.push(item);
17680
+ }
17681
+ }
17682
+ return {
17683
+ handoff_entry_id: detail.entry.entry_id,
17684
+ transferred,
17685
+ withheld,
17686
+ source: "composition",
17687
+ confidence: 0.9
17688
+ };
17689
+ }
17690
+ function tryHeuristicPath(detail) {
17691
+ const entry = detail.entry;
17692
+ const audit = detail.source_audit_entry;
17693
+ const details = sourceDetails(audit);
17694
+ if (audit.operation === "cross_harness_approval_aggregated") {
17695
+ const ruleId = optString2(details, "policy_rule_id");
17696
+ if (ruleId) {
17697
+ const category = categoryFromPolicyRuleId(ruleId);
17698
+ const summary = `${ruleId} (${entry.source_agent_id} -> operator)`;
17699
+ return {
17700
+ handoff_entry_id: entry.entry_id,
17701
+ transferred: [
17702
+ {
17703
+ category,
17704
+ summary: truncate(summary, SUMMARY_MAX_CHARS),
17705
+ size_hint: "minimal"
17706
+ }
17707
+ ],
17708
+ withheld: [],
17709
+ source: "heuristic",
17710
+ confidence: 0.5
17711
+ };
17712
+ }
17713
+ }
17714
+ if (audit.operation === "v1.1_local_handoff") {
17715
+ const reasonClass = optString2(details, "reason_class");
17716
+ const newStatus = optString2(details, "new_status");
17717
+ const previousStatus = optString2(details, "previous_status");
17718
+ const transferred = [];
17719
+ const withheld = [];
17720
+ if (newStatus === "denied" || newStatus === "failed") {
17721
+ withheld.push({
17722
+ category: "other",
17723
+ summary: truncate(
17724
+ `handoff ${newStatus}${reasonClass ? ` (${reasonClass})` : ""}: ${entry.source_agent_id} -> ${entry.target_agent_id}`,
17725
+ SUMMARY_MAX_CHARS
17726
+ ),
17727
+ size_hint: "minimal"
17728
+ });
17729
+ } else if (newStatus === "accepted" || newStatus === "completed") {
17730
+ transferred.push({
17731
+ category: "other",
17732
+ summary: truncate(
17733
+ `handoff ${newStatus}${previousStatus ? ` (from ${previousStatus})` : ""}: ${entry.source_agent_id} -> ${entry.target_agent_id}`,
17734
+ SUMMARY_MAX_CHARS
17735
+ ),
17736
+ size_hint: "small"
17737
+ });
17738
+ } else {
17739
+ transferred.push({
17740
+ category: "other",
17741
+ summary: truncate(
17742
+ `handoff ${entry.source_agent_id} -> ${entry.target_agent_id}${newStatus ? ` (${newStatus})` : ""}`,
17743
+ SUMMARY_MAX_CHARS
17744
+ ),
17745
+ size_hint: "minimal"
17746
+ });
17747
+ }
17748
+ return {
17749
+ handoff_entry_id: entry.entry_id,
17750
+ transferred,
17751
+ withheld,
17752
+ source: "heuristic",
17753
+ confidence: reasonClass || newStatus ? 0.5 : 0.3
17754
+ };
17755
+ }
17756
+ return {
17757
+ handoff_entry_id: entry.entry_id,
17758
+ transferred: [
17759
+ {
17760
+ category: "other",
17761
+ summary: truncate(
17762
+ `handoff ${entry.source_agent_id} -> ${entry.target_agent_id}`,
17763
+ SUMMARY_MAX_CHARS
17764
+ ),
17765
+ size_hint: "minimal"
17766
+ }
17767
+ ],
17768
+ withheld: [],
17769
+ source: "heuristic",
17770
+ confidence: 0.3
17771
+ };
17772
+ }
17773
+ async function tryLlmAssistPath(detail, selector) {
17774
+ const entry = detail.entry;
17775
+ const audit = detail.source_audit_entry;
17776
+ const probe = `event=${audit.operation} sender=${entry.source_agent_id} target=${entry.target_agent_id} summary=${entry.context_transfer_summary}`;
17777
+ try {
17778
+ const response = await selector.invokeClassify("sentinel-scoring", {
17779
+ kind: "classify",
17780
+ items: [probe],
17781
+ categories: [...CATEGORY_VALUES]
17782
+ });
17783
+ if (response.body.kind !== "classify") return null;
17784
+ const top = response.body.results[0];
17785
+ if (!top || !isCategory(top.category) || top.confidence < 0.4) {
17786
+ return null;
17787
+ }
17788
+ return {
17789
+ handoff_entry_id: entry.entry_id,
17790
+ transferred: [
17791
+ {
17792
+ category: top.category,
17793
+ summary: truncate(
17794
+ `LLM-classified handoff ${entry.source_agent_id} -> ${entry.target_agent_id}: ${top.category} (confidence ${top.confidence.toFixed(2)})`,
17795
+ SUMMARY_MAX_CHARS
17796
+ ),
17797
+ size_hint: "minimal"
17798
+ }
17799
+ ],
17800
+ withheld: [],
17801
+ source: "llm-assist",
17802
+ confidence: 0.6
17803
+ };
17804
+ } catch {
17805
+ return null;
17806
+ }
17807
+ }
17808
+ function sourceDetails(audit) {
17809
+ return audit.details;
17810
+ }
17811
+ function optString2(details, key) {
17812
+ if (!details) return null;
17813
+ const value = details[key];
17814
+ if (typeof value !== "string" || value.length === 0) return null;
17815
+ return value;
17816
+ }
17817
+ function isCategory(value) {
17818
+ return CATEGORY_VALUES.includes(value);
17819
+ }
17820
+ function truncate(s, cap) {
17821
+ return s.length <= cap ? s : `${s.slice(0, cap - 3)}...`;
17822
+ }
17823
+ function parseExplicitContextItems(raw) {
17824
+ if (raw === null || raw === void 0) return [];
17825
+ if (Array.isArray(raw)) {
17826
+ const out = [];
17827
+ for (const entry of raw) {
17828
+ if (typeof entry === "string") {
17829
+ out.push({
17830
+ category: "other",
17831
+ summary: truncate(entry, SUMMARY_MAX_CHARS),
17832
+ size_hint: "minimal"
17833
+ });
17834
+ continue;
17835
+ }
17836
+ if (entry && typeof entry === "object") {
17837
+ const obj = entry;
17838
+ const category = isCategoryValue(obj["category"]) ? obj["category"] : "other";
17839
+ const summary = typeof obj["summary"] === "string" ? truncate(obj["summary"], SUMMARY_MAX_CHARS) : "(unspecified)";
17840
+ const sizeHint = isSizeHintValue(obj["size_hint"]) ? obj["size_hint"] : "minimal";
17841
+ out.push({ category, summary, size_hint: sizeHint });
17842
+ }
17843
+ }
17844
+ return out;
17845
+ }
17846
+ if (typeof raw === "object" && raw !== null) {
17847
+ const out = [];
17848
+ for (const [k, v] of Object.entries(raw)) {
17849
+ const category = isCategoryValue(k) ? k : "other";
17850
+ if (Array.isArray(v)) {
17851
+ for (const item of v) {
17852
+ if (typeof item === "string") {
17853
+ out.push({
17854
+ category,
17855
+ summary: truncate(item, SUMMARY_MAX_CHARS),
17856
+ size_hint: "minimal"
17857
+ });
17858
+ }
17859
+ }
17860
+ }
17861
+ }
17862
+ return out;
17863
+ }
17864
+ return [];
17865
+ }
17866
+ function isCategoryValue(v) {
17867
+ return typeof v === "string" && CATEGORY_VALUES.includes(v);
17868
+ }
17869
+ function isSizeHintValue(v) {
17870
+ return typeof v === "string" && (v === "minimal" || v === "small" || v === "medium" || v === "large");
17871
+ }
17872
+ function categoryFromPolicyRuleId(ruleId) {
17873
+ const lower = ruleId.toLowerCase();
17874
+ if (lower.includes("credential") || lower.includes("broker_secret")) {
17875
+ return "credentials";
17876
+ }
17877
+ if (lower.includes("memory") || lower.includes("state_read")) {
17878
+ return "memory";
17879
+ }
17880
+ if (lower.includes("plan")) {
17881
+ return "plans";
17882
+ }
17883
+ if (lower.includes("export") || lower.includes("output")) {
17884
+ return "outputs";
17885
+ }
17886
+ if (lower.includes("audit")) {
17887
+ return "audit-refs";
17888
+ }
17889
+ return "other";
17890
+ }
17891
+ var SUMMARY_MAX_CHARS, CATEGORY_VALUES, CONTEXT_TRANSFER_AUDIT_OPS;
17892
+ var init_context_transfer_extractor = __esm({
17893
+ "src/coordination/context-transfer-extractor.ts"() {
17894
+ SUMMARY_MAX_CHARS = 240;
17895
+ CATEGORY_VALUES = [
17896
+ "memory",
17897
+ "credentials",
17898
+ "plans",
17899
+ "outputs",
17900
+ "audit-refs",
17901
+ "other"
17902
+ ];
17903
+ CONTEXT_TRANSFER_AUDIT_OPS = {
17904
+ DECODED: "operator_handoff_context_transfer_decoded"
17905
+ };
17906
+ }
17907
+ });
17908
+
17634
17909
  // src/coordination/handoff-routes.ts
17635
17910
  function writeJSON6(res, status, payload) {
17636
17911
  res.writeHead(status, {
@@ -17755,7 +18030,29 @@ async function handleCoordinationRoute(deps, req, res) {
17755
18030
  target_agent_id: detail.entry.target_agent_id
17756
18031
  }
17757
18032
  );
17758
- writeJSON6(res, 200, { ok: true, data: detail });
18033
+ let breakdown = null;
18034
+ try {
18035
+ breakdown = await extractContextTransferBreakdown(
18036
+ detail,
18037
+ deps.contextTransfer ?? {}
18038
+ );
18039
+ deps.auditLog.append(
18040
+ "l2",
18041
+ CONTEXT_TRANSFER_AUDIT_OPS.DECODED,
18042
+ deps.operatorId,
18043
+ {
18044
+ fortress_id: deps.handoffLog.getFortressId(),
18045
+ entry_id: detail.entry.entry_id,
18046
+ extractor_path: breakdown.source,
18047
+ confidence: breakdown.confidence,
18048
+ transferred_count: breakdown.transferred.length,
18049
+ withheld_count: breakdown.withheld.length
18050
+ }
18051
+ );
18052
+ } catch {
18053
+ }
18054
+ const responseData = breakdown !== null ? { ...detail, context_transfer_breakdown: breakdown } : detail;
18055
+ writeJSON6(res, 200, { ok: true, data: responseData });
17759
18056
  return true;
17760
18057
  }
17761
18058
  writeJSON6(res, 404, { ok: false, error: "not_found", path });
@@ -17771,6 +18068,7 @@ var init_handoff_routes = __esm({
17771
18068
  "src/coordination/handoff-routes.ts"() {
17772
18069
  init_auth_middleware();
17773
18070
  init_handoff_log();
18071
+ init_context_transfer_extractor();
17774
18072
  COORDINATION_API_PREFIX = "/api/coordination";
17775
18073
  COORDINATION_HANDOFFS_PREFIX = "/api/coordination/handoffs";
17776
18074
  COORDINATION_LIST_DEFAULT_LIMIT = 50;
@@ -22311,15 +22609,52 @@ var init_sentinel_dispatcher = __esm({
22311
22609
  };
22312
22610
  }
22313
22611
  });
22612
+ var init_classifier_state_store = __esm({
22613
+ "src/anomaly-detection/classifier-state-store.ts"() {
22614
+ init_encryption();
22615
+ init_key_derivation();
22616
+ init_encoding();
22617
+ }
22618
+ });
22619
+
22620
+ // src/anomaly-detection/classifiers/cusum.ts
22621
+ var CUSUM_CLASSIFIER_ID;
22622
+ var init_cusum = __esm({
22623
+ "src/anomaly-detection/classifiers/cusum.ts"() {
22624
+ init_classifier_state_store();
22625
+ CUSUM_CLASSIFIER_ID = "cusum";
22626
+ }
22627
+ });
22628
+
22629
+ // src/anomaly-detection/classifiers/psi.ts
22630
+ var PSI_CLASSIFIER_ID;
22631
+ var init_psi = __esm({
22632
+ "src/anomaly-detection/classifiers/psi.ts"() {
22633
+ init_classifier_state_store();
22634
+ PSI_CLASSIFIER_ID = "psi";
22635
+ }
22636
+ });
22314
22637
 
22315
22638
  // src/anomaly-detection/types.ts
22316
22639
  var init_types4 = __esm({
22317
22640
  "src/anomaly-detection/types.ts"() {
22318
22641
  }
22319
22642
  });
22643
+ function classifierSpecificAuditOp(classifierId) {
22644
+ if (classifierId === null) return null;
22645
+ if (classifierId === CUSUM_CLASSIFIER_ID) {
22646
+ return ANOMALY_AUDIT_OPS.CUSUM_DRIFT_DETECTED;
22647
+ }
22648
+ if (classifierId === PSI_CLASSIFIER_ID) {
22649
+ return ANOMALY_AUDIT_OPS.PSI_DISTRIBUTION_SHIFT_DETECTED;
22650
+ }
22651
+ return null;
22652
+ }
22320
22653
  var ANOMALY_AUDIT_OPS, DEFAULT_TICK_INTERVAL_MS2, AnomalyPipelineDispatcher;
22321
22654
  var init_anomaly_pipeline = __esm({
22322
22655
  "src/anomaly-detection/anomaly-pipeline.ts"() {
22656
+ init_cusum();
22657
+ init_psi();
22323
22658
  init_types4();
22324
22659
  ANOMALY_AUDIT_OPS = {
22325
22660
  DETECTOR_REGISTERED: "anomaly_detector_registered",
@@ -22327,7 +22662,15 @@ var init_anomaly_pipeline = __esm({
22327
22662
  FINDING_EMITTED: "anomaly_finding_emitted",
22328
22663
  EVALUATION_FAILED: "anomaly_evaluation_failed",
22329
22664
  TRAINING_COMPLETED: "anomaly_training_completed",
22330
- TRAINING_FAILED: "anomaly_training_failed"
22665
+ TRAINING_FAILED: "anomaly_training_failed",
22666
+ /** Chi-2: a classifier was attached to an existing detector. */
22667
+ CLASSIFIER_SUBSCRIBED: "anomaly_classifier_subscribed",
22668
+ /** Chi-2: a classifier was detached from an existing detector. */
22669
+ CLASSIFIER_UNSUBSCRIBED: "anomaly_classifier_unsubscribed",
22670
+ /** Chi-2: CUSUM-flagged mean-shift drift on a per-agent feature. */
22671
+ CUSUM_DRIFT_DETECTED: "anomaly_cusum_drift_detected",
22672
+ /** Chi-2: PSI-flagged distribution shift on a per-agent feature. */
22673
+ PSI_DISTRIBUTION_SHIFT_DETECTED: "anomaly_psi_distribution_shift_detected"
22331
22674
  };
22332
22675
  DEFAULT_TICK_INTERVAL_MS2 = 6e4;
22333
22676
  AnomalyPipelineDispatcher = class {
@@ -22418,34 +22761,37 @@ var init_anomaly_pipeline = __esm({
22418
22761
  const stamped = await this.routeFinding(detectorId, raw);
22419
22762
  findings.push(stamped);
22420
22763
  }
22421
- try {
22422
- const trainingResult = await detector.classifier.train();
22423
- this.auditLog.append(
22424
- "l2",
22425
- ANOMALY_AUDIT_OPS.TRAINING_COMPLETED,
22426
- this.identityId,
22427
- {
22428
- detector_id: detectorId,
22429
- classifier_id: detector.classifier.classifierId,
22430
- trained_at: trainingResult.trained_at,
22431
- sample_count: trainingResult.sample_count,
22432
- agent_count: trainingResult.agent_count,
22433
- fortress_id: this.fortressId
22434
- }
22435
- );
22436
- } catch (trainErr) {
22437
- const message = trainErr instanceof Error ? trainErr.message : String(trainErr);
22438
- this.auditLog.append(
22439
- "l2",
22440
- ANOMALY_AUDIT_OPS.TRAINING_FAILED,
22441
- this.identityId,
22442
- {
22443
- detector_id: detectorId,
22444
- error_message: message,
22445
- fortress_id: this.fortressId
22446
- },
22447
- "failure"
22448
- );
22764
+ for (const classifier of detector.getAllClassifiers()) {
22765
+ try {
22766
+ const trainingResult = await classifier.train();
22767
+ this.auditLog.append(
22768
+ "l2",
22769
+ ANOMALY_AUDIT_OPS.TRAINING_COMPLETED,
22770
+ this.identityId,
22771
+ {
22772
+ detector_id: detectorId,
22773
+ classifier_id: classifier.classifierId,
22774
+ trained_at: trainingResult.trained_at,
22775
+ sample_count: trainingResult.sample_count,
22776
+ agent_count: trainingResult.agent_count,
22777
+ fortress_id: this.fortressId
22778
+ }
22779
+ );
22780
+ } catch (trainErr) {
22781
+ const message = trainErr instanceof Error ? trainErr.message : String(trainErr);
22782
+ this.auditLog.append(
22783
+ "l2",
22784
+ ANOMALY_AUDIT_OPS.TRAINING_FAILED,
22785
+ this.identityId,
22786
+ {
22787
+ detector_id: detectorId,
22788
+ classifier_id: classifier.classifierId,
22789
+ error_message: message,
22790
+ fortress_id: this.fortressId
22791
+ },
22792
+ "failure"
22793
+ );
22794
+ }
22449
22795
  }
22450
22796
  } catch (err) {
22451
22797
  const message = err instanceof Error ? err.message : String(err);
@@ -22508,6 +22854,7 @@ var init_anomaly_pipeline = __esm({
22508
22854
  observed_at: raw.observed_at || this.now().toISOString()
22509
22855
  };
22510
22856
  await this.findingStore.saveFinding(stamped);
22857
+ const classifierId = stamped.details["classifier_id"] ?? null;
22511
22858
  this.auditLog.append(
22512
22859
  "l2",
22513
22860
  ANOMALY_AUDIT_OPS.FINDING_EMITTED,
@@ -22517,13 +22864,79 @@ var init_anomaly_pipeline = __esm({
22517
22864
  finding_id: stamped.finding_id,
22518
22865
  severity: stamped.severity,
22519
22866
  anomaly_score: stamped.details["anomaly_score"] ?? null,
22867
+ ...classifierId !== null ? { classifier_id: classifierId } : {},
22520
22868
  ...stamped.agent_id !== void 0 ? { agent_id: stamped.agent_id } : {},
22521
22869
  fortress_id: this.fortressId
22522
22870
  }
22523
22871
  );
22872
+ const specificOp = classifierSpecificAuditOp(classifierId);
22873
+ if (specificOp !== null) {
22874
+ this.auditLog.append("l2", specificOp, this.identityId, {
22875
+ detector_id: detectorId,
22876
+ finding_id: stamped.finding_id,
22877
+ severity: stamped.severity,
22878
+ anomaly_score: stamped.details["anomaly_score"] ?? null,
22879
+ ...stamped.agent_id !== void 0 ? { agent_id: stamped.agent_id } : {},
22880
+ fortress_id: this.fortressId
22881
+ });
22882
+ }
22524
22883
  this.emit({ type: "finding", finding: stamped });
22525
22884
  return stamped;
22526
22885
  }
22886
+ /**
22887
+ * Chi-2: attach an additional classifier to an already-registered
22888
+ * detector. Emits ANOMALY_CLASSIFIER_SUBSCRIBED on success. The
22889
+ * factory is called with the fortress AnomalyContext so the
22890
+ * classifier can build its own state-store binding. Idempotent: a
22891
+ * second call with the same classifierId returns false.
22892
+ */
22893
+ async addClassifierToDetector(detectorId, factory) {
22894
+ const detector = this.detectors.get(detectorId);
22895
+ if (!detector) return false;
22896
+ const context = {
22897
+ fortressId: this.fortressId,
22898
+ auditLog: this.auditLog,
22899
+ storage: this.storage,
22900
+ masterKey: this.masterKey,
22901
+ now: this.now
22902
+ };
22903
+ const classifier = factory(context);
22904
+ const added = detector.addClassifier(classifier);
22905
+ if (!added) return false;
22906
+ this.auditLog.append(
22907
+ "l2",
22908
+ ANOMALY_AUDIT_OPS.CLASSIFIER_SUBSCRIBED,
22909
+ this.identityId,
22910
+ {
22911
+ detector_id: detectorId,
22912
+ classifier_id: classifier.classifierId,
22913
+ fortress_id: this.fortressId
22914
+ }
22915
+ );
22916
+ return true;
22917
+ }
22918
+ /**
22919
+ * Chi-2: detach an additional classifier from an already-registered
22920
+ * detector. Emits ANOMALY_CLASSIFIER_UNSUBSCRIBED on success. The
22921
+ * primary classifier cannot be detached (returns false).
22922
+ */
22923
+ async removeClassifierFromDetector(detectorId, classifierId) {
22924
+ const detector = this.detectors.get(detectorId);
22925
+ if (!detector) return false;
22926
+ const removed = detector.removeClassifier(classifierId);
22927
+ if (!removed) return false;
22928
+ this.auditLog.append(
22929
+ "l2",
22930
+ ANOMALY_AUDIT_OPS.CLASSIFIER_UNSUBSCRIBED,
22931
+ this.identityId,
22932
+ {
22933
+ detector_id: detectorId,
22934
+ classifier_id: classifierId,
22935
+ fortress_id: this.fortressId
22936
+ }
22937
+ );
22938
+ return true;
22939
+ }
22527
22940
  emit(event) {
22528
22941
  for (const listener of this.listeners) {
22529
22942
  try {
@@ -39833,6 +40246,141 @@ ${redactedItems.map((r) => `- ${r.redacted}`).join("\n")}`,
39833
40246
  }
39834
40247
  });
39835
40248
 
40249
+ // src/query-anonymity/header-strip.ts
40250
+ function stripHeaders(headers) {
40251
+ const stripped = {};
40252
+ const removed = [];
40253
+ for (const [name, value] of Object.entries(headers)) {
40254
+ const lower = name.toLowerCase();
40255
+ if (REQUIRED_HEADER_SET.has(lower)) {
40256
+ stripped[name] = value;
40257
+ continue;
40258
+ }
40259
+ const reason = STRIP_REASON_BY_NAME.get(lower);
40260
+ if (reason !== void 0) {
40261
+ removed.push({ name, reason });
40262
+ continue;
40263
+ }
40264
+ stripped[name] = value;
40265
+ }
40266
+ return { stripped, removed };
40267
+ }
40268
+ function defeatUndiciDefaultsInto(headers) {
40269
+ if (headers["user-agent"] === void 0 && headers["User-Agent"] === void 0) {
40270
+ headers["User-Agent"] = "";
40271
+ }
40272
+ if (headers["accept-language"] === void 0 && headers["Accept-Language"] === void 0) {
40273
+ headers["Accept-Language"] = "";
40274
+ }
40275
+ return headers;
40276
+ }
40277
+ function createAnonymizedFetch(baseFetch, onAudit) {
40278
+ const wrapped = async (input, init) => {
40279
+ const headers = normalizeHeadersInit(init?.headers);
40280
+ const result = stripHeaders(headers);
40281
+ defeatUndiciDefaultsInto(result.stripped);
40282
+ const preservedRequired = Object.keys(result.stripped).filter(
40283
+ (k) => REQUIRED_HEADER_SET.has(k.toLowerCase())
40284
+ );
40285
+ const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
40286
+ const method = init?.method ?? (input instanceof Request ? input.method : "GET");
40287
+ if (onAudit) {
40288
+ onAudit({
40289
+ url,
40290
+ method,
40291
+ stripped_count: result.removed.length,
40292
+ removed: result.removed,
40293
+ required_preserved: preservedRequired
40294
+ });
40295
+ }
40296
+ return baseFetch(input, { ...init, headers: result.stripped });
40297
+ };
40298
+ return wrapped;
40299
+ }
40300
+ function normalizeHeadersInit(raw) {
40301
+ if (raw === void 0) return {};
40302
+ if (typeof Headers !== "undefined" && raw instanceof Headers) {
40303
+ const out = {};
40304
+ raw.forEach((value, key) => {
40305
+ out[key] = value;
40306
+ });
40307
+ return out;
40308
+ }
40309
+ if (Array.isArray(raw)) {
40310
+ const out = {};
40311
+ for (const [k, v] of raw) {
40312
+ if (k !== void 0 && v !== void 0) out[k] = v;
40313
+ }
40314
+ return out;
40315
+ }
40316
+ return { ...raw };
40317
+ }
40318
+ var QUERY_ANONYMITY_AUDIT_OPS, CANONICAL_STRIP_LIST, REQUIRED_HEADERS, REQUIRED_HEADER_SET, STRIP_REASON_BY_NAME;
40319
+ var init_header_strip = __esm({
40320
+ "src/query-anonymity/header-strip.ts"() {
40321
+ QUERY_ANONYMITY_AUDIT_OPS = {
40322
+ HEADERS_STRIPPED: "query_anonymity_headers_stripped"
40323
+ };
40324
+ CANONICAL_STRIP_LIST = [
40325
+ // Browser / runtime fingerprinting.
40326
+ { name: "user-agent", reason: "user-agent" },
40327
+ { name: "sec-ch-ua", reason: "fingerprintable-extension" },
40328
+ { name: "sec-ch-ua-mobile", reason: "fingerprintable-extension" },
40329
+ { name: "sec-ch-ua-platform", reason: "fingerprintable-extension" },
40330
+ { name: "sec-ch-ua-platform-version", reason: "fingerprintable-extension" },
40331
+ { name: "sec-ch-ua-arch", reason: "fingerprintable-extension" },
40332
+ { name: "sec-ch-ua-bitness", reason: "fingerprintable-extension" },
40333
+ { name: "sec-ch-ua-model", reason: "fingerprintable-extension" },
40334
+ { name: "sec-ch-ua-full-version-list", reason: "fingerprintable-extension" },
40335
+ // Locale fingerprint.
40336
+ { name: "accept-language", reason: "locale-fingerprint" },
40337
+ // Request-origin leak.
40338
+ { name: "referer", reason: "leaking-network-info" },
40339
+ { name: "referrer-policy", reason: "leaking-network-info" },
40340
+ { name: "origin", reason: "leaking-network-info" },
40341
+ // Forwarded-by / IP-derived network info.
40342
+ { name: "via", reason: "leaking-network-info" },
40343
+ { name: "forwarded", reason: "leaking-network-info" },
40344
+ { name: "x-forwarded-for", reason: "leaking-network-info" },
40345
+ { name: "x-real-ip", reason: "leaking-network-info" },
40346
+ { name: "x-client-ip", reason: "leaking-network-info" },
40347
+ // DNT / GPC are technically anti-tracking signals but they
40348
+ // themselves form a fingerprint (operators who set DNT=1 are a
40349
+ // smaller subset). Strip to keep the substrate ignorant of
40350
+ // operator preferences.
40351
+ { name: "dnt", reason: "unnecessary-metadata" },
40352
+ { name: "sec-gpc", reason: "unnecessary-metadata" }
40353
+ ];
40354
+ REQUIRED_HEADERS = [
40355
+ "authorization",
40356
+ "content-type",
40357
+ "content-length",
40358
+ "host",
40359
+ "accept",
40360
+ "x-api-key",
40361
+ // Anthropic API auth
40362
+ "anthropic-version",
40363
+ // Anthropic API contract version
40364
+ "anthropic-beta",
40365
+ // optional Anthropic beta opt-in
40366
+ "openai-organization",
40367
+ // optional OpenAI org id
40368
+ "x-stainless-package-version",
40369
+ // allowed for Anthropic + OpenAI SDK contract compat
40370
+ "x-goog-api-key",
40371
+ // Google AI Studio
40372
+ "x-goog-user-project"
40373
+ // Google AI Studio
40374
+ ];
40375
+ REQUIRED_HEADER_SET = new Set(
40376
+ REQUIRED_HEADERS.map((h) => h.toLowerCase())
40377
+ );
40378
+ STRIP_REASON_BY_NAME = new Map(
40379
+ CANONICAL_STRIP_LIST.map((h) => [h.name.toLowerCase(), h.reason])
40380
+ );
40381
+ }
40382
+ });
40383
+
39836
40384
  // src/intelligence/substrates/hybrid/per-surface-router.ts
39837
40385
  function resolveHybridChoice(rules, surface) {
39838
40386
  if (!rules) return null;
@@ -39954,6 +40502,7 @@ var init_selector = __esm({
39954
40502
  init_local();
39955
40503
  init_venice();
39956
40504
  init_frontier();
40505
+ init_header_strip();
39957
40506
  init_per_surface_router();
39958
40507
  DISABLED_CAPABILITY = {
39959
40508
  summarize: false,
@@ -39988,7 +40537,21 @@ var init_selector = __esm({
39988
40537
  this.auditLog = cfg.auditLog;
39989
40538
  this.identityId = cfg.identityId;
39990
40539
  this.redactor = cfg.redactor ?? IDENTITY_REDACTOR;
39991
- this.fetchImpl = cfg.fetchImpl;
40540
+ const baseFetch = cfg.fetchImpl ?? globalThis.fetch;
40541
+ this.fetchImpl = createAnonymizedFetch(baseFetch, (event) => {
40542
+ this.auditLog.append(
40543
+ "l2",
40544
+ QUERY_ANONYMITY_AUDIT_OPS.HEADERS_STRIPPED,
40545
+ this.identityId,
40546
+ {
40547
+ url: event.url,
40548
+ method: event.method,
40549
+ stripped_count: event.stripped_count,
40550
+ removed: event.removed,
40551
+ required_preserved: event.required_preserved
40552
+ }
40553
+ );
40554
+ });
39992
40555
  this.config = buildDefaultConfig();
39993
40556
  }
39994
40557
  /**