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