@sanctuary-framework/mcp-server 0.5.13 → 0.5.14

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/index.js CHANGED
@@ -745,7 +745,9 @@ var RESERVED_NAMESPACE_PREFIXES = [
745
745
  "_bridge",
746
746
  "_federation",
747
747
  "_handshake",
748
- "_shr"
748
+ "_shr",
749
+ "_sovereignty_profile",
750
+ "_context_gate_policies"
749
751
  ];
750
752
  var StateStore = class {
751
753
  storage;
@@ -1286,7 +1288,9 @@ var RESERVED_NAMESPACE_PREFIXES2 = [
1286
1288
  "_bridge",
1287
1289
  "_federation",
1288
1290
  "_handshake",
1289
- "_shr"
1291
+ "_shr",
1292
+ "_sovereignty_profile",
1293
+ "_context_gate_policies"
1290
1294
  ];
1291
1295
  function getReservedNamespaceViolation(namespace) {
1292
1296
  for (const prefix of RESERVED_NAMESPACE_PREFIXES2) {
@@ -3810,8 +3814,10 @@ var DEFAULT_POLICY = {
3810
3814
  "reputation_export",
3811
3815
  "bootstrap_provide_guarantee",
3812
3816
  "decommission_certificate",
3813
- "reputation_publish"
3817
+ "reputation_publish",
3814
3818
  // SEC-039: Explicit Tier 1 — sends data to external API
3819
+ "sovereignty_profile_update"
3820
+ // Changes enforcement behavior — always requires approval
3815
3821
  ],
3816
3822
  tier2_anomaly: DEFAULT_TIER2,
3817
3823
  tier3_always_allow: [
@@ -3864,8 +3870,10 @@ var DEFAULT_POLICY = {
3864
3870
  "bridge_commit",
3865
3871
  "bridge_verify",
3866
3872
  "bridge_attest",
3867
- "dashboard_open"
3873
+ "dashboard_open",
3868
3874
  // SEC-039: Explicit Tier 3 — only generates a URL
3875
+ "sovereignty_profile_get",
3876
+ "sovereignty_profile_generate_prompt"
3869
3877
  ],
3870
3878
  approval_channel: DEFAULT_CHANNEL
3871
3879
  };
@@ -3974,6 +3982,7 @@ tier1_always_approve:
3974
3982
  - reputation_export
3975
3983
  - bootstrap_provide_guarantee
3976
3984
  - reputation_publish
3985
+ - sovereignty_profile_update
3977
3986
 
3978
3987
  # \u2500\u2500\u2500 Tier 2: Behavioral Anomaly Detection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
3979
3988
  # Triggers approval when agent behavior deviates from its baseline.
@@ -4037,6 +4046,8 @@ tier3_always_allow:
4037
4046
  - bridge_verify
4038
4047
  - bridge_attest
4039
4048
  - dashboard_open
4049
+ - sovereignty_profile_get
4050
+ - sovereignty_profile_generate_prompt
4040
4051
 
4041
4052
  # \u2500\u2500\u2500 Approval Channel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
4042
4053
  # How Sanctuary reaches you when approval is needed.
@@ -5312,6 +5323,133 @@ function generateDashboardHTML(options) {
5312
5323
  background-color: #e03c3c;
5313
5324
  }
5314
5325
 
5326
+ /* Sovereignty Profile Panel */
5327
+ .profile-panel {
5328
+ background-color: var(--surface);
5329
+ border: 1px solid var(--border);
5330
+ border-radius: 8px;
5331
+ padding: 20px;
5332
+ }
5333
+
5334
+ .profile-panel .panel-header {
5335
+ display: flex;
5336
+ justify-content: space-between;
5337
+ align-items: center;
5338
+ margin-bottom: 16px;
5339
+ }
5340
+
5341
+ .profile-panel .panel-title {
5342
+ font-size: 14px;
5343
+ font-weight: 600;
5344
+ color: var(--text-primary);
5345
+ }
5346
+
5347
+ .profile-cards {
5348
+ display: grid;
5349
+ grid-template-columns: repeat(5, 1fr);
5350
+ gap: 12px;
5351
+ margin-bottom: 16px;
5352
+ }
5353
+
5354
+ .profile-card {
5355
+ background-color: var(--bg);
5356
+ border: 1px solid var(--border);
5357
+ border-radius: 6px;
5358
+ padding: 14px;
5359
+ display: flex;
5360
+ flex-direction: column;
5361
+ gap: 8px;
5362
+ }
5363
+
5364
+ .profile-card-name {
5365
+ font-size: 12px;
5366
+ font-weight: 600;
5367
+ color: var(--text-primary);
5368
+ }
5369
+
5370
+ .profile-card-desc {
5371
+ font-size: 11px;
5372
+ color: var(--text-secondary);
5373
+ line-height: 1.4;
5374
+ }
5375
+
5376
+ .profile-badge {
5377
+ display: inline-flex;
5378
+ align-items: center;
5379
+ gap: 4px;
5380
+ padding: 2px 8px;
5381
+ border-radius: 4px;
5382
+ font-size: 10px;
5383
+ font-weight: 600;
5384
+ width: fit-content;
5385
+ }
5386
+
5387
+ .profile-badge.enabled {
5388
+ background-color: rgba(63, 185, 80, 0.15);
5389
+ color: var(--green);
5390
+ }
5391
+
5392
+ .profile-badge.disabled {
5393
+ background-color: rgba(139, 148, 158, 0.15);
5394
+ color: var(--text-secondary);
5395
+ }
5396
+
5397
+ .prompt-section {
5398
+ margin-top: 12px;
5399
+ }
5400
+
5401
+ .prompt-textarea {
5402
+ width: 100%;
5403
+ min-height: 120px;
5404
+ background-color: var(--bg);
5405
+ border: 1px solid var(--border);
5406
+ border-radius: 6px;
5407
+ color: var(--text-primary);
5408
+ font-family: 'JetBrains Mono', monospace;
5409
+ font-size: 12px;
5410
+ padding: 12px;
5411
+ resize: vertical;
5412
+ margin-top: 8px;
5413
+ }
5414
+
5415
+ .prompt-actions {
5416
+ display: flex;
5417
+ gap: 8px;
5418
+ margin-top: 8px;
5419
+ }
5420
+
5421
+ .prompt-btn {
5422
+ padding: 6px 12px;
5423
+ border: 1px solid var(--border);
5424
+ border-radius: 4px;
5425
+ background-color: var(--surface);
5426
+ color: var(--text-primary);
5427
+ font-size: 12px;
5428
+ cursor: pointer;
5429
+ }
5430
+
5431
+ .prompt-btn:hover {
5432
+ background-color: var(--muted);
5433
+ }
5434
+
5435
+ .prompt-btn.primary {
5436
+ background-color: var(--blue);
5437
+ color: var(--bg);
5438
+ border-color: var(--blue);
5439
+ }
5440
+
5441
+ @media (max-width: 900px) {
5442
+ .profile-cards {
5443
+ grid-template-columns: repeat(2, 1fr);
5444
+ }
5445
+ }
5446
+
5447
+ @media (max-width: 500px) {
5448
+ .profile-cards {
5449
+ grid-template-columns: 1fr;
5450
+ }
5451
+ }
5452
+
5315
5453
  /* Threat Panel */
5316
5454
  .threat-panel {
5317
5455
  background-color: var(--surface);
@@ -5650,6 +5788,48 @@ function generateDashboardHTML(options) {
5650
5788
  </div>
5651
5789
  </div>
5652
5790
 
5791
+ <!-- Sovereignty Profile Panel -->
5792
+ <div class="profile-panel" id="sovereignty-profile-panel">
5793
+ <div class="panel-header">
5794
+ <div class="panel-title">Sovereignty Profile</div>
5795
+ <span class="card-value" id="profile-updated-at" style="font-size: 11px; color: var(--text-secondary);">\u2014</span>
5796
+ </div>
5797
+ <div class="profile-cards" id="profile-cards">
5798
+ <div class="profile-card" data-feature="audit_logging">
5799
+ <div class="profile-card-name">Audit Logging</div>
5800
+ <div class="profile-badge disabled" id="badge-audit_logging">OFF</div>
5801
+ <div class="profile-card-desc">Encrypted audit trail of all tool calls</div>
5802
+ </div>
5803
+ <div class="profile-card" data-feature="injection_detection">
5804
+ <div class="profile-card-name">Injection Detection</div>
5805
+ <div class="profile-badge disabled" id="badge-injection_detection">OFF</div>
5806
+ <div class="profile-card-desc">Scans tool arguments for prompt injection</div>
5807
+ </div>
5808
+ <div class="profile-card" data-feature="context_gating">
5809
+ <div class="profile-card-name">Context Gating</div>
5810
+ <div class="profile-badge disabled" id="badge-context_gating">OFF</div>
5811
+ <div class="profile-card-desc">Controls context flow to remote providers</div>
5812
+ </div>
5813
+ <div class="profile-card" data-feature="approval_gate">
5814
+ <div class="profile-card-name">Approval Gates</div>
5815
+ <div class="profile-badge disabled" id="badge-approval_gate">OFF</div>
5816
+ <div class="profile-card-desc">Human approval for high-risk operations</div>
5817
+ </div>
5818
+ <div class="profile-card" data-feature="zk_proofs">
5819
+ <div class="profile-card-name">ZK Proofs</div>
5820
+ <div class="profile-badge disabled" id="badge-zk_proofs">OFF</div>
5821
+ <div class="profile-card-desc">Prove claims without revealing data</div>
5822
+ </div>
5823
+ </div>
5824
+ <div class="prompt-section">
5825
+ <div class="prompt-actions">
5826
+ <button class="prompt-btn primary" id="generate-prompt-btn">Generate System Prompt</button>
5827
+ <button class="prompt-btn" id="copy-prompt-btn" style="display:none;">Copy</button>
5828
+ </div>
5829
+ <textarea class="prompt-textarea" id="system-prompt-output" readonly style="display:none;" placeholder="Click 'Generate System Prompt' to create an agent instruction snippet..."></textarea>
5830
+ </div>
5831
+ </div>
5832
+
5653
5833
  <!-- Threat Panel -->
5654
5834
  <div class="threat-panel collapsed">
5655
5835
  <div class="threat-header">
@@ -5684,6 +5864,7 @@ function generateDashboardHTML(options) {
5684
5864
  handshakes: [],
5685
5865
  shr: null,
5686
5866
  status: null,
5867
+ systemPrompt: null,
5687
5868
  };
5688
5869
 
5689
5870
  let pendingRequests = new Map();
@@ -6136,6 +6317,10 @@ function generateDashboardHTML(options) {
6136
6317
  removePendingRequest(data.requestId);
6137
6318
  });
6138
6319
 
6320
+ eventSource.addEventListener('sovereignty-profile-update', () => {
6321
+ updateSovereigntyProfile();
6322
+ });
6323
+
6139
6324
  eventSource.onerror = () => {
6140
6325
  console.error('SSE error');
6141
6326
  setTimeout(setupSSE, 5000);
@@ -6292,6 +6477,58 @@ function generateDashboardHTML(options) {
6292
6477
  document.getElementById('pending-overlay').classList.toggle('show');
6293
6478
  });
6294
6479
 
6480
+ // Sovereignty Profile
6481
+ async function updateSovereigntyProfile() {
6482
+ try {
6483
+ const data = await fetchAPI('/api/sovereignty-profile');
6484
+ if (data && data.profile) {
6485
+ const features = data.profile.features;
6486
+ for (const [key, value] of Object.entries(features)) {
6487
+ const badge = document.getElementById('badge-' + key);
6488
+ if (badge) {
6489
+ const enabled = value && value.enabled;
6490
+ badge.textContent = enabled ? 'ON' : 'OFF';
6491
+ badge.className = 'profile-badge ' + (enabled ? 'enabled' : 'disabled');
6492
+ }
6493
+ }
6494
+ const updatedEl = document.getElementById('profile-updated-at');
6495
+ if (updatedEl && data.profile.updated_at) {
6496
+ updatedEl.textContent = 'Updated: ' + new Date(data.profile.updated_at).toLocaleString();
6497
+ }
6498
+ // Cache the prompt
6499
+ if (data.system_prompt) {
6500
+ apiState.systemPrompt = data.system_prompt;
6501
+ }
6502
+ }
6503
+ } catch (e) {
6504
+ // Profile not available
6505
+ }
6506
+ }
6507
+
6508
+ document.getElementById('generate-prompt-btn').addEventListener('click', async () => {
6509
+ const data = await fetchAPI('/api/sovereignty-profile');
6510
+ if (data && data.system_prompt) {
6511
+ const textarea = document.getElementById('system-prompt-output');
6512
+ const copyBtn = document.getElementById('copy-prompt-btn');
6513
+ textarea.value = data.system_prompt;
6514
+ textarea.style.display = 'block';
6515
+ copyBtn.style.display = 'inline-flex';
6516
+ }
6517
+ });
6518
+
6519
+ document.getElementById('copy-prompt-btn').addEventListener('click', async () => {
6520
+ const textarea = document.getElementById('system-prompt-output');
6521
+ try {
6522
+ await navigator.clipboard.writeText(textarea.value);
6523
+ const btn = document.getElementById('copy-prompt-btn');
6524
+ const original = btn.textContent;
6525
+ btn.textContent = 'Copied!';
6526
+ setTimeout(() => { btn.textContent = original; }, 2000);
6527
+ } catch (err) {
6528
+ console.error('Copy failed:', err);
6529
+ }
6530
+ });
6531
+
6295
6532
  // Initialize
6296
6533
  async function initialize() {
6297
6534
  if (!AUTH_TOKEN) {
@@ -6306,6 +6543,7 @@ function generateDashboardHTML(options) {
6306
6543
  updateHandshakes(),
6307
6544
  updateSHR(),
6308
6545
  updateStatus(),
6546
+ updateSovereigntyProfile(),
6309
6547
  ]);
6310
6548
 
6311
6549
  // Setup SSE for real-time updates
@@ -6322,6 +6560,80 @@ function generateDashboardHTML(options) {
6322
6560
  </html>`;
6323
6561
  }
6324
6562
 
6563
+ // src/system-prompt-generator.ts
6564
+ var FEATURE_INFO = {
6565
+ audit_logging: {
6566
+ name: "Audit Logging",
6567
+ activeDescription: "All your tool calls are logged to an encrypted audit trail. No action needed \u2014 this is automatic.",
6568
+ disabledDescription: "audit logging (sanctuary/monitor_audit_log)"
6569
+ },
6570
+ injection_detection: {
6571
+ name: "Injection Detection",
6572
+ activeDescription: "Your tool call arguments are scanned for prompt injection attempts. No action needed \u2014 this is automatic.",
6573
+ disabledDescription: "injection detection"
6574
+ },
6575
+ context_gating: {
6576
+ name: "Context Gating",
6577
+ activeDescription: "Before making outbound calls to remote providers, filter your context through sanctuary/context_gate_filter to ensure minimum-necessary disclosure.",
6578
+ toolNames: ["sanctuary/context_gate_filter", "sanctuary/context_gate_set_policy"],
6579
+ disabledDescription: "context gating (sanctuary/context_gate_filter)"
6580
+ },
6581
+ approval_gate: {
6582
+ name: "Approval Gates",
6583
+ activeDescription: "High-risk operations require human approval before execution. Tier 1 operations always require approval; Tier 2 operations trigger approval on anomaly detection.",
6584
+ disabledDescription: "approval gates"
6585
+ },
6586
+ zk_proofs: {
6587
+ name: "Zero-Knowledge Proofs",
6588
+ activeDescription: "You can prove claims about your data without revealing the underlying values. Use sanctuary/zk_commit to create commitments, sanctuary/zk_prove for proofs of knowledge, and sanctuary/zk_range_prove for range proofs.",
6589
+ toolNames: ["sanctuary/zk_commit", "sanctuary/zk_prove", "sanctuary/zk_range_prove"],
6590
+ disabledDescription: "zero-knowledge proofs (sanctuary/zk_commit, sanctuary/zk_prove)"
6591
+ }
6592
+ };
6593
+ function generateSystemPrompt(profile) {
6594
+ const activeFeatures = [];
6595
+ const inactiveFeatures = [];
6596
+ const featureKeys = [
6597
+ "audit_logging",
6598
+ "injection_detection",
6599
+ "context_gating",
6600
+ "approval_gate",
6601
+ "zk_proofs"
6602
+ ];
6603
+ for (const key of featureKeys) {
6604
+ const featureConfig = profile.features[key];
6605
+ const info = FEATURE_INFO[key];
6606
+ if (featureConfig.enabled) {
6607
+ let desc = `- ${info.name}: ${info.activeDescription}`;
6608
+ if (key === "injection_detection" && "sensitivity" in featureConfig && featureConfig.sensitivity) {
6609
+ desc += ` Sensitivity: ${featureConfig.sensitivity}.`;
6610
+ }
6611
+ if (key === "context_gating" && "policy_id" in featureConfig && featureConfig.policy_id) {
6612
+ desc += ` Active policy: ${featureConfig.policy_id}.`;
6613
+ }
6614
+ activeFeatures.push(desc);
6615
+ } else {
6616
+ inactiveFeatures.push(info.disabledDescription);
6617
+ }
6618
+ }
6619
+ const lines = [
6620
+ "You are protected by Sanctuary sovereignty infrastructure. The following protections are active:",
6621
+ ""
6622
+ ];
6623
+ if (activeFeatures.length > 0) {
6624
+ lines.push(...activeFeatures);
6625
+ } else {
6626
+ lines.push("- No features are currently enabled. Contact your operator to configure protections.");
6627
+ }
6628
+ if (inactiveFeatures.length > 0) {
6629
+ lines.push("");
6630
+ lines.push(
6631
+ `Optional tools available but not currently enabled: ${inactiveFeatures.join(", ")}.`
6632
+ );
6633
+ }
6634
+ return lines.join("\n");
6635
+ }
6636
+
6325
6637
  // src/principal-policy/dashboard.ts
6326
6638
  var SESSION_TTL_REMOTE_MS = 5 * 60 * 1e3;
6327
6639
  var SESSION_TTL_LOCAL_MS = 24 * 60 * 60 * 1e3;
@@ -6342,6 +6654,7 @@ var DashboardApprovalChannel = class {
6342
6654
  handshakeResults = null;
6343
6655
  shrOpts = null;
6344
6656
  _sanctuaryConfig = null;
6657
+ profileStore = null;
6345
6658
  dashboardHTML;
6346
6659
  loginHTML;
6347
6660
  authToken;
@@ -6381,6 +6694,7 @@ var DashboardApprovalChannel = class {
6381
6694
  if (deps.handshakeResults) this.handshakeResults = deps.handshakeResults;
6382
6695
  if (deps.shrOpts) this.shrOpts = deps.shrOpts;
6383
6696
  if (deps.sanctuaryConfig) this._sanctuaryConfig = deps.sanctuaryConfig;
6697
+ if (deps.profileStore) this.profileStore = deps.profileStore;
6384
6698
  }
6385
6699
  /**
6386
6700
  * Mark this dashboard as running in standalone mode.
@@ -6728,6 +7042,10 @@ var DashboardApprovalChannel = class {
6728
7042
  this.handleHandshakes(res);
6729
7043
  } else if (method === "GET" && url.pathname === "/api/shr") {
6730
7044
  this.handleSHR(res);
7045
+ } else if (method === "GET" && url.pathname === "/api/sovereignty-profile") {
7046
+ this.handleSovereigntyProfileGet(res);
7047
+ } else if (method === "POST" && url.pathname === "/api/sovereignty-profile") {
7048
+ this.handleSovereigntyProfileUpdate(req, res);
6731
7049
  } else if (method === "POST" && url.pathname.startsWith("/api/approve/")) {
6732
7050
  if (!this.checkRateLimit(req, res, "decisions")) return;
6733
7051
  const id = url.pathname.slice("/api/approve/".length);
@@ -7019,6 +7337,61 @@ data: ${JSON.stringify(initData)}
7019
7337
  res.writeHead(200, { "Content-Type": "application/json" });
7020
7338
  res.end(JSON.stringify(shr));
7021
7339
  }
7340
+ // ── Sovereignty Profile API ─────────────────────────────────────────
7341
+ handleSovereigntyProfileGet(res) {
7342
+ if (!this.profileStore) {
7343
+ res.writeHead(200, { "Content-Type": "application/json" });
7344
+ res.end(JSON.stringify({ error: "Sovereignty Profile not available" }));
7345
+ return;
7346
+ }
7347
+ try {
7348
+ const profile = this.profileStore.get();
7349
+ const prompt = generateSystemPrompt(profile);
7350
+ res.writeHead(200, { "Content-Type": "application/json" });
7351
+ res.end(JSON.stringify({ profile, system_prompt: prompt }));
7352
+ } catch {
7353
+ res.writeHead(500, { "Content-Type": "application/json" });
7354
+ res.end(JSON.stringify({ error: "Failed to read sovereignty profile" }));
7355
+ }
7356
+ }
7357
+ handleSovereigntyProfileUpdate(req, res) {
7358
+ if (!this.profileStore) {
7359
+ res.writeHead(400, { "Content-Type": "application/json" });
7360
+ res.end(JSON.stringify({ error: "Sovereignty Profile not available" }));
7361
+ return;
7362
+ }
7363
+ let body = "";
7364
+ let destroyed = false;
7365
+ req.on("data", (chunk) => {
7366
+ body += chunk.toString();
7367
+ if (body.length > 16384) {
7368
+ destroyed = true;
7369
+ res.writeHead(413, { "Content-Type": "application/json" });
7370
+ res.end(JSON.stringify({ error: "Request body too large" }));
7371
+ req.destroy();
7372
+ }
7373
+ });
7374
+ req.on("end", async () => {
7375
+ if (destroyed) return;
7376
+ try {
7377
+ const updates = JSON.parse(body);
7378
+ const updated = await this.profileStore.update(updates);
7379
+ const prompt = generateSystemPrompt(updated);
7380
+ if (this.auditLog) {
7381
+ this.auditLog.append("l2", "sovereignty_profile_update_dashboard", "dashboard", {
7382
+ changes: updates,
7383
+ features_enabled: Object.entries(updated.features).filter(([, v]) => v.enabled).map(([k]) => k)
7384
+ });
7385
+ }
7386
+ this.broadcastSSE("sovereignty-profile-update", { profile: updated, system_prompt: prompt });
7387
+ res.writeHead(200, { "Content-Type": "application/json" });
7388
+ res.end(JSON.stringify({ profile: updated, system_prompt: prompt }));
7389
+ } catch {
7390
+ res.writeHead(400, { "Content-Type": "application/json" });
7391
+ res.end(JSON.stringify({ error: "Invalid JSON body" }));
7392
+ }
7393
+ });
7394
+ }
7022
7395
  // ── SSE Broadcasting ────────────────────────────────────────────────
7023
7396
  broadcastSSE(event, data) {
7024
7397
  const message = `event: ${event}
@@ -12701,6 +13074,270 @@ function createL2HardeningTools(storagePath, auditLog) {
12701
13074
  ];
12702
13075
  }
12703
13076
 
13077
+ // src/sovereignty-profile.ts
13078
+ init_encryption();
13079
+ init_encoding();
13080
+ var NAMESPACE = "_sovereignty_profile";
13081
+ var PROFILE_KEY = "active";
13082
+ var HKDF_DOMAIN = "sovereignty-profile";
13083
+ function createDefaultProfile() {
13084
+ return {
13085
+ version: 1,
13086
+ features: {
13087
+ audit_logging: { enabled: true },
13088
+ injection_detection: { enabled: true },
13089
+ context_gating: { enabled: false },
13090
+ approval_gate: { enabled: false },
13091
+ zk_proofs: { enabled: false }
13092
+ },
13093
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
13094
+ };
13095
+ }
13096
+ var SovereigntyProfileStore = class {
13097
+ storage;
13098
+ encryptionKey;
13099
+ profile = null;
13100
+ constructor(storage, masterKey) {
13101
+ this.storage = storage;
13102
+ this.encryptionKey = derivePurposeKey(masterKey, HKDF_DOMAIN);
13103
+ }
13104
+ /**
13105
+ * Load the active sovereignty profile from encrypted storage.
13106
+ * Creates the default profile on first run.
13107
+ */
13108
+ async load() {
13109
+ if (this.profile) return this.profile;
13110
+ const raw = await this.storage.read(NAMESPACE, PROFILE_KEY);
13111
+ if (raw) {
13112
+ try {
13113
+ const encrypted = JSON.parse(bytesToString(raw));
13114
+ const decrypted = decrypt(encrypted, this.encryptionKey);
13115
+ this.profile = JSON.parse(bytesToString(decrypted));
13116
+ return this.profile;
13117
+ } catch {
13118
+ }
13119
+ }
13120
+ this.profile = createDefaultProfile();
13121
+ await this.persist();
13122
+ return this.profile;
13123
+ }
13124
+ /**
13125
+ * Get the current profile. Must call load() first.
13126
+ */
13127
+ get() {
13128
+ if (!this.profile) {
13129
+ throw new Error("SovereigntyProfileStore: call load() before get()");
13130
+ }
13131
+ return this.profile;
13132
+ }
13133
+ /**
13134
+ * Apply a partial update to the profile.
13135
+ * Returns the updated profile.
13136
+ */
13137
+ async update(updates) {
13138
+ if (!this.profile) {
13139
+ await this.load();
13140
+ }
13141
+ const features = this.profile.features;
13142
+ if (updates.audit_logging !== void 0) {
13143
+ if (updates.audit_logging.enabled !== void 0) {
13144
+ if (typeof updates.audit_logging.enabled !== "boolean") {
13145
+ throw new Error("audit_logging.enabled must be a boolean");
13146
+ }
13147
+ features.audit_logging.enabled = updates.audit_logging.enabled;
13148
+ }
13149
+ }
13150
+ if (updates.injection_detection !== void 0) {
13151
+ if (updates.injection_detection.enabled !== void 0) {
13152
+ if (typeof updates.injection_detection.enabled !== "boolean") {
13153
+ throw new Error("injection_detection.enabled must be a boolean");
13154
+ }
13155
+ features.injection_detection.enabled = updates.injection_detection.enabled;
13156
+ }
13157
+ if (updates.injection_detection.sensitivity !== void 0) {
13158
+ const valid = ["low", "medium", "high"];
13159
+ if (!valid.includes(updates.injection_detection.sensitivity)) {
13160
+ throw new Error("injection_detection.sensitivity must be low, medium, or high");
13161
+ }
13162
+ features.injection_detection.sensitivity = updates.injection_detection.sensitivity;
13163
+ }
13164
+ }
13165
+ if (updates.context_gating !== void 0) {
13166
+ if (updates.context_gating.enabled !== void 0) {
13167
+ if (typeof updates.context_gating.enabled !== "boolean") {
13168
+ throw new Error("context_gating.enabled must be a boolean");
13169
+ }
13170
+ features.context_gating.enabled = updates.context_gating.enabled;
13171
+ }
13172
+ if (updates.context_gating.policy_id !== void 0) {
13173
+ if (typeof updates.context_gating.policy_id !== "string" || updates.context_gating.policy_id.length > 256) {
13174
+ throw new Error("context_gating.policy_id must be a string of 256 characters or fewer");
13175
+ }
13176
+ features.context_gating.policy_id = updates.context_gating.policy_id;
13177
+ }
13178
+ }
13179
+ if (updates.approval_gate !== void 0) {
13180
+ if (updates.approval_gate.enabled !== void 0) {
13181
+ if (typeof updates.approval_gate.enabled !== "boolean") {
13182
+ throw new Error("approval_gate.enabled must be a boolean");
13183
+ }
13184
+ features.approval_gate.enabled = updates.approval_gate.enabled;
13185
+ }
13186
+ }
13187
+ if (updates.zk_proofs !== void 0) {
13188
+ if (updates.zk_proofs.enabled !== void 0) {
13189
+ if (typeof updates.zk_proofs.enabled !== "boolean") {
13190
+ throw new Error("zk_proofs.enabled must be a boolean");
13191
+ }
13192
+ features.zk_proofs.enabled = updates.zk_proofs.enabled;
13193
+ }
13194
+ }
13195
+ this.profile.updated_at = (/* @__PURE__ */ new Date()).toISOString();
13196
+ await this.persist();
13197
+ return this.profile;
13198
+ }
13199
+ /**
13200
+ * Persist the current profile to encrypted storage.
13201
+ */
13202
+ async persist() {
13203
+ const serialized = stringToBytes(JSON.stringify(this.profile));
13204
+ const encrypted = encrypt(serialized, this.encryptionKey);
13205
+ await this.storage.write(
13206
+ NAMESPACE,
13207
+ PROFILE_KEY,
13208
+ stringToBytes(JSON.stringify(encrypted))
13209
+ );
13210
+ }
13211
+ };
13212
+
13213
+ // src/sovereignty-profile-tools.ts
13214
+ function createSovereigntyProfileTools(profileStore, auditLog) {
13215
+ const tools = [
13216
+ // ── Get Profile ──────────────────────────────────────────────────
13217
+ {
13218
+ name: "sanctuary/sovereignty_profile_get",
13219
+ description: "Get the current Sovereignty Profile \u2014 shows which Sanctuary features are active (audit logging, injection detection, context gating, approval gates, ZK proofs) and their configuration.",
13220
+ inputSchema: {
13221
+ type: "object",
13222
+ properties: {}
13223
+ },
13224
+ handler: async () => {
13225
+ const profile = profileStore.get();
13226
+ auditLog.append("l2", "sovereignty_profile_get", "system", {
13227
+ features_enabled: Object.entries(profile.features).filter(([, v]) => v.enabled).map(([k]) => k)
13228
+ });
13229
+ return toolResult({
13230
+ profile,
13231
+ message: "Current Sovereignty Profile. Use sovereignty_profile_update to change settings."
13232
+ });
13233
+ }
13234
+ },
13235
+ // ── Update Profile ───────────────────────────────────────────────
13236
+ {
13237
+ name: "sanctuary/sovereignty_profile_update",
13238
+ description: "Update the Sovereignty Profile feature toggles. This changes which Sanctuary protections are active. Requires human approval (Tier 1) because it modifies enforcement behavior. Pass only the features you want to change \u2014 unspecified features remain unchanged.",
13239
+ inputSchema: {
13240
+ type: "object",
13241
+ properties: {
13242
+ audit_logging: {
13243
+ type: "object",
13244
+ properties: {
13245
+ enabled: { type: "boolean" }
13246
+ },
13247
+ description: "Toggle audit logging on/off"
13248
+ },
13249
+ injection_detection: {
13250
+ type: "object",
13251
+ properties: {
13252
+ enabled: { type: "boolean" },
13253
+ sensitivity: {
13254
+ type: "string",
13255
+ enum: ["low", "medium", "high"],
13256
+ description: "Detection sensitivity threshold"
13257
+ }
13258
+ },
13259
+ description: "Toggle injection detection and set sensitivity"
13260
+ },
13261
+ context_gating: {
13262
+ type: "object",
13263
+ properties: {
13264
+ enabled: { type: "boolean" },
13265
+ policy_id: {
13266
+ type: "string",
13267
+ description: "ID of the context-gating policy to use"
13268
+ }
13269
+ },
13270
+ description: "Toggle context gating and set active policy"
13271
+ },
13272
+ approval_gate: {
13273
+ type: "object",
13274
+ properties: {
13275
+ enabled: { type: "boolean" }
13276
+ },
13277
+ description: "Toggle approval gates on/off"
13278
+ },
13279
+ zk_proofs: {
13280
+ type: "object",
13281
+ properties: {
13282
+ enabled: { type: "boolean" }
13283
+ },
13284
+ description: "Toggle zero-knowledge proofs on/off"
13285
+ }
13286
+ }
13287
+ },
13288
+ handler: async (args) => {
13289
+ const updates = {};
13290
+ if (args.audit_logging !== void 0) {
13291
+ updates.audit_logging = args.audit_logging;
13292
+ }
13293
+ if (args.injection_detection !== void 0) {
13294
+ updates.injection_detection = args.injection_detection;
13295
+ }
13296
+ if (args.context_gating !== void 0) {
13297
+ updates.context_gating = args.context_gating;
13298
+ }
13299
+ if (args.approval_gate !== void 0) {
13300
+ updates.approval_gate = args.approval_gate;
13301
+ }
13302
+ if (args.zk_proofs !== void 0) {
13303
+ updates.zk_proofs = args.zk_proofs;
13304
+ }
13305
+ const updated = await profileStore.update(updates);
13306
+ auditLog.append("l2", "sovereignty_profile_update", "system", {
13307
+ changes: updates,
13308
+ features_enabled: Object.entries(updated.features).filter(([, v]) => v.enabled).map(([k]) => k)
13309
+ });
13310
+ return toolResult({
13311
+ profile: updated,
13312
+ message: "Sovereignty Profile updated. Changes take effect immediately."
13313
+ });
13314
+ }
13315
+ },
13316
+ // ── Generate System Prompt ───────────────────────────────────────
13317
+ {
13318
+ name: "sanctuary/sovereignty_profile_generate_prompt",
13319
+ description: "Generate a system prompt snippet based on the active Sovereignty Profile. The snippet instructs an agent on which Sanctuary features are active and how to use them. Copy and paste this into your agent's system configuration.",
13320
+ inputSchema: {
13321
+ type: "object",
13322
+ properties: {}
13323
+ },
13324
+ handler: async () => {
13325
+ const profile = profileStore.get();
13326
+ const prompt = generateSystemPrompt(profile);
13327
+ auditLog.append("l2", "sovereignty_profile_generate_prompt", "system", {
13328
+ features_enabled: Object.entries(profile.features).filter(([, v]) => v.enabled).map(([k]) => k)
13329
+ });
13330
+ return toolResult({
13331
+ system_prompt: prompt,
13332
+ token_estimate: Math.ceil(prompt.length / 4),
13333
+ message: "Copy the system_prompt text above and paste it into your agent's system configuration. It will update dynamically as you toggle features."
13334
+ });
13335
+ }
13336
+ }
13337
+ ];
13338
+ return { tools };
13339
+ }
13340
+
12704
13341
  // src/index.ts
12705
13342
  init_random();
12706
13343
  init_encoding();
@@ -13209,6 +13846,9 @@ async function createSanctuaryServer(options) {
13209
13846
  const { tools: auditTools } = createAuditTools(config);
13210
13847
  const { tools: contextGateTools, enforcer: contextGateEnforcer } = createContextGateTools(storage, masterKey, auditLog);
13211
13848
  const hardeningTools = createL2HardeningTools(config.storage_path, auditLog);
13849
+ const profileStore = new SovereigntyProfileStore(storage, masterKey);
13850
+ await profileStore.load();
13851
+ const { tools: profileTools } = createSovereigntyProfileTools(profileStore, auditLog);
13212
13852
  const policy = await loadPrincipalPolicy(config.storage_path);
13213
13853
  const baseline = new BaselineTracker(storage, masterKey);
13214
13854
  await baseline.load();
@@ -13236,7 +13876,8 @@ async function createSanctuaryServer(options) {
13236
13876
  identityManager,
13237
13877
  handshakeResults,
13238
13878
  shrOpts: { config, identityManager, masterKey },
13239
- sanctuaryConfig: config
13879
+ sanctuaryConfig: config,
13880
+ profileStore
13240
13881
  });
13241
13882
  await dashboard.start();
13242
13883
  approvalChannel = dashboard;
@@ -13313,6 +13954,7 @@ async function createSanctuaryServer(options) {
13313
13954
  ...auditTools,
13314
13955
  ...contextGateTools,
13315
13956
  ...hardeningTools,
13957
+ ...profileTools,
13316
13958
  ...dashboardTools,
13317
13959
  manifestTool
13318
13960
  ];
@@ -13343,6 +13985,6 @@ async function createSanctuaryServer(options) {
13343
13985
  return { server, config };
13344
13986
  }
13345
13987
 
13346
- export { ATTESTATION_VERSION, ApprovalGate, AuditLog, AutoApproveChannel, BaselineTracker, TEMPLATES as CONTEXT_GATE_TEMPLATES, CallbackApprovalChannel, CommitmentStore, ContextGateEnforcer, ContextGatePolicyStore, DashboardApprovalChannel, FederationRegistry, FilesystemStorage, InMemoryModelProvenanceStore, InjectionDetector, MODEL_PRESETS, MemoryStorage, PolicyStore, ReputationStore, StateStore, StderrApprovalChannel, TIER_WEIGHTS, WebhookApprovalChannel, canonicalize, classifyField, completeHandshake, computeWeightedScore, createBridgeCommitment, createPedersenCommitment, createProofOfKnowledge, createRangeProof, createSanctuaryServer, evaluateField, filterContext, generateAttestation, generateSHR, getTemplate, initiateHandshake, listTemplateIds, loadConfig, loadPrincipalPolicy, recommendPolicy, resolveTier, respondToHandshake, signPayload, tierDistribution, verifyAttestation, verifyBridgeCommitment, verifyCompletion, verifyPedersenCommitment, verifyProofOfKnowledge, verifyRangeProof, verifySHR, verifySignature };
13988
+ export { ATTESTATION_VERSION, ApprovalGate, AuditLog, AutoApproveChannel, BaselineTracker, TEMPLATES as CONTEXT_GATE_TEMPLATES, CallbackApprovalChannel, CommitmentStore, ContextGateEnforcer, ContextGatePolicyStore, DashboardApprovalChannel, FederationRegistry, FilesystemStorage, InMemoryModelProvenanceStore, InjectionDetector, MODEL_PRESETS, MemoryStorage, PolicyStore, ReputationStore, SovereigntyProfileStore, StateStore, StderrApprovalChannel, TIER_WEIGHTS, WebhookApprovalChannel, canonicalize, classifyField, completeHandshake, computeWeightedScore, createBridgeCommitment, createDefaultProfile, createPedersenCommitment, createProofOfKnowledge, createRangeProof, createSanctuaryServer, evaluateField, filterContext, generateAttestation, generateSHR, generateSystemPrompt, getTemplate, initiateHandshake, listTemplateIds, loadConfig, loadPrincipalPolicy, recommendPolicy, resolveTier, respondToHandshake, signPayload, tierDistribution, verifyAttestation, verifyBridgeCommitment, verifyCompletion, verifyPedersenCommitment, verifyProofOfKnowledge, verifyRangeProof, verifySHR, verifySignature };
13347
13989
  //# sourceMappingURL=index.js.map
13348
13990
  //# sourceMappingURL=index.js.map