@sanctuary-framework/mcp-server 0.5.6 → 0.5.7

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
@@ -7,6 +7,7 @@ import { randomBytes as randomBytes$1, createHmac } from 'crypto';
7
7
  import { gcm } from '@noble/ciphers/aes.js';
8
8
  import { sha256 } from '@noble/hashes/sha256';
9
9
  import { hmac } from '@noble/hashes/hmac';
10
+ import { RistrettoPoint, ed25519 } from '@noble/curves/ed25519';
10
11
  import { argon2id } from 'hash-wasm';
11
12
  import { hkdf } from '@noble/hashes/hkdf';
12
13
  import { createServer as createServer$1 } from 'http';
@@ -14,7 +15,6 @@ import { get, createServer as createServer$2 } from 'https';
14
15
  import { statSync, readFileSync } from 'fs';
15
16
  import { execSync, exec } from 'child_process';
16
17
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
17
- import { RistrettoPoint, ed25519 } from '@noble/curves/ed25519';
18
18
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
19
19
  import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
20
20
 
@@ -557,6 +557,111 @@ var init_hashing = __esm({
557
557
  init_encoding();
558
558
  }
559
559
  });
560
+ function generateKeypair() {
561
+ const privateKey = randomBytes(32);
562
+ const publicKey = ed25519.getPublicKey(privateKey);
563
+ return { publicKey, privateKey };
564
+ }
565
+ function publicKeyToDid(publicKey) {
566
+ const multicodec = new Uint8Array([237, 1, ...publicKey]);
567
+ return `did:key:z${toBase64url(multicodec)}`;
568
+ }
569
+ function generateIdentityId(publicKey) {
570
+ const keyHash = hash(publicKey);
571
+ return Array.from(keyHash.slice(0, 16)).map((b) => b.toString(16).padStart(2, "0")).join("");
572
+ }
573
+ function createIdentity(label, encryptionKey, keyProtection) {
574
+ const { publicKey, privateKey } = generateKeypair();
575
+ const identityId = generateIdentityId(publicKey);
576
+ const did = publicKeyToDid(publicKey);
577
+ const now = (/* @__PURE__ */ new Date()).toISOString();
578
+ const encryptedPrivateKey = encrypt(privateKey, encryptionKey);
579
+ privateKey.fill(0);
580
+ const publicIdentity = {
581
+ identity_id: identityId,
582
+ label,
583
+ public_key: toBase64url(publicKey),
584
+ did,
585
+ created_at: now,
586
+ key_type: "ed25519",
587
+ key_protection: keyProtection
588
+ };
589
+ const storedIdentity = {
590
+ ...publicIdentity,
591
+ encrypted_private_key: encryptedPrivateKey,
592
+ rotation_history: []
593
+ };
594
+ return { publicIdentity, storedIdentity };
595
+ }
596
+ function sign(payload, encryptedPrivateKey, encryptionKey) {
597
+ const privateKey = decrypt(encryptedPrivateKey, encryptionKey);
598
+ try {
599
+ return ed25519.sign(payload, privateKey);
600
+ } finally {
601
+ privateKey.fill(0);
602
+ }
603
+ }
604
+ function verify(payload, signature, publicKey) {
605
+ try {
606
+ return ed25519.verify(signature, payload, publicKey);
607
+ } catch {
608
+ return false;
609
+ }
610
+ }
611
+ function rotateKeys(storedIdentity, encryptionKey, reason) {
612
+ const { publicKey: newPublicKey, privateKey: newPrivateKey } = generateKeypair();
613
+ const newIdentityDid = publicKeyToDid(newPublicKey);
614
+ const now = (/* @__PURE__ */ new Date()).toISOString();
615
+ const eventData = JSON.stringify({
616
+ old_public_key: storedIdentity.public_key,
617
+ new_public_key: toBase64url(newPublicKey),
618
+ identity_id: storedIdentity.identity_id,
619
+ reason,
620
+ rotated_at: now
621
+ });
622
+ const eventBytes = new TextEncoder().encode(eventData);
623
+ const signature = sign(
624
+ eventBytes,
625
+ storedIdentity.encrypted_private_key,
626
+ encryptionKey
627
+ );
628
+ const rotationEvent = {
629
+ old_public_key: storedIdentity.public_key,
630
+ new_public_key: toBase64url(newPublicKey),
631
+ identity_id: storedIdentity.identity_id,
632
+ reason,
633
+ rotated_at: now,
634
+ signature: toBase64url(signature)
635
+ };
636
+ const encryptedNewPrivateKey = encrypt(newPrivateKey, encryptionKey);
637
+ newPrivateKey.fill(0);
638
+ const updatedIdentity = {
639
+ ...storedIdentity,
640
+ public_key: toBase64url(newPublicKey),
641
+ did: newIdentityDid,
642
+ encrypted_private_key: encryptedNewPrivateKey,
643
+ rotation_history: [
644
+ ...storedIdentity.rotation_history,
645
+ {
646
+ old_public_key: storedIdentity.public_key,
647
+ new_public_key: toBase64url(newPublicKey),
648
+ rotation_event: toBase64url(
649
+ new TextEncoder().encode(JSON.stringify(rotationEvent))
650
+ ),
651
+ rotated_at: now
652
+ }
653
+ ]
654
+ };
655
+ return { updatedIdentity, rotationEvent };
656
+ }
657
+ var init_identity = __esm({
658
+ "src/core/identity.ts"() {
659
+ init_encoding();
660
+ init_encryption();
661
+ init_hashing();
662
+ init_random();
663
+ }
664
+ });
560
665
  async function deriveMasterKey(passphrase, existingParams) {
561
666
  const salt = existingParams ? fromBase64url(existingParams.salt) : generateSalt();
562
667
  const params = existingParams ?? {
@@ -1161,6 +1266,120 @@ var init_baseline = __esm({
1161
1266
  }
1162
1267
  });
1163
1268
 
1269
+ // src/shr/types.ts
1270
+ function deepSortKeys(obj) {
1271
+ if (obj === null || typeof obj !== "object") return obj;
1272
+ if (Array.isArray(obj)) return obj.map(deepSortKeys);
1273
+ const sorted = {};
1274
+ for (const key of Object.keys(obj).sort()) {
1275
+ sorted[key] = deepSortKeys(obj[key]);
1276
+ }
1277
+ return sorted;
1278
+ }
1279
+ function canonicalizeForSigning(body) {
1280
+ return JSON.stringify(deepSortKeys(body));
1281
+ }
1282
+ var init_types = __esm({
1283
+ "src/shr/types.ts"() {
1284
+ }
1285
+ });
1286
+
1287
+ // src/shr/generator.ts
1288
+ function generateSHR(identityId, opts) {
1289
+ const { config, identityManager, masterKey, validityMs } = opts;
1290
+ const identity = identityId ? identityManager.get(identityId) : identityManager.getDefault();
1291
+ if (!identity) {
1292
+ return "No identity available for signing. Create an identity first.";
1293
+ }
1294
+ const now = /* @__PURE__ */ new Date();
1295
+ const expiresAt = new Date(now.getTime() + (validityMs ?? DEFAULT_VALIDITY_MS));
1296
+ const degradations = [];
1297
+ if (config.execution.environment === "local-process") {
1298
+ degradations.push({
1299
+ layer: "l2",
1300
+ code: "PROCESS_ISOLATION_ONLY",
1301
+ severity: "warning",
1302
+ description: "Process-level isolation only (no TEE)",
1303
+ mitigation: "TEE support planned for a future release"
1304
+ });
1305
+ degradations.push({
1306
+ layer: "l2",
1307
+ code: "SELF_REPORTED_ATTESTATION",
1308
+ severity: "warning",
1309
+ description: "Attestation is self-reported (no hardware root of trust)",
1310
+ mitigation: "TEE attestation planned for a future release"
1311
+ });
1312
+ }
1313
+ const body = {
1314
+ shr_version: "1.0",
1315
+ implementation: {
1316
+ sanctuary_version: config.version,
1317
+ node_version: process.versions.node,
1318
+ generated_by: "sanctuary-mcp-server"
1319
+ },
1320
+ instance_id: identity.identity_id,
1321
+ generated_at: now.toISOString(),
1322
+ expires_at: expiresAt.toISOString(),
1323
+ layers: {
1324
+ l1: {
1325
+ status: "active",
1326
+ encryption: config.state.encryption,
1327
+ key_custody: "self",
1328
+ integrity: config.state.integrity,
1329
+ identity_type: config.state.identity_provider,
1330
+ state_portable: true
1331
+ },
1332
+ l2: {
1333
+ status: config.execution.environment === "local-process" ? "degraded" : "active",
1334
+ isolation_type: config.execution.environment,
1335
+ attestation_available: config.execution.attestation
1336
+ },
1337
+ l3: {
1338
+ status: "active",
1339
+ proof_system: config.disclosure.proof_system,
1340
+ selective_disclosure: true
1341
+ },
1342
+ l4: {
1343
+ status: "active",
1344
+ reputation_mode: config.reputation.mode,
1345
+ attestation_format: config.reputation.attestation_format,
1346
+ reputation_portable: true
1347
+ }
1348
+ },
1349
+ capabilities: {
1350
+ handshake: true,
1351
+ shr_exchange: true,
1352
+ reputation_verify: true,
1353
+ encrypted_channel: false
1354
+ // Not yet implemented
1355
+ },
1356
+ degradations
1357
+ };
1358
+ const canonical = canonicalizeForSigning(body);
1359
+ const payload = stringToBytes(canonical);
1360
+ const encryptionKey = derivePurposeKey(masterKey, "identity-encryption");
1361
+ const signatureBytes = sign(
1362
+ payload,
1363
+ identity.encrypted_private_key,
1364
+ encryptionKey
1365
+ );
1366
+ return {
1367
+ body,
1368
+ signed_by: identity.public_key,
1369
+ signature: toBase64url(signatureBytes)
1370
+ };
1371
+ }
1372
+ var DEFAULT_VALIDITY_MS;
1373
+ var init_generator = __esm({
1374
+ "src/shr/generator.ts"() {
1375
+ init_types();
1376
+ init_identity();
1377
+ init_encoding();
1378
+ init_key_derivation();
1379
+ DEFAULT_VALIDITY_MS = 60 * 60 * 1e3;
1380
+ }
1381
+ });
1382
+
1164
1383
  // src/principal-policy/dashboard-html.ts
1165
1384
  function generateLoginHTML(options) {
1166
1385
  return `<!DOCTYPE html>
@@ -1168,7 +1387,7 @@ function generateLoginHTML(options) {
1168
1387
  <head>
1169
1388
  <meta charset="UTF-8">
1170
1389
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
1171
- <title>Sanctuary Dashboard</title>
1390
+ <title>Sanctuary \u2014 Principal Dashboard</title>
1172
1391
  <style>
1173
1392
  :root {
1174
1393
  --bg: #0d1117;
@@ -1339,7 +1558,7 @@ function generateLoginHTML(options) {
1339
1558
 
1340
1559
  <form id="login-form">
1341
1560
  <div class="form-group">
1342
- <label for="auth-token">Bearer Token</label>
1561
+ <label for="auth-token">Auth Token</label>
1343
1562
  <input
1344
1563
  type="text"
1345
1564
  id="auth-token"
@@ -1424,7 +1643,7 @@ function generateDashboardHTML(options) {
1424
1643
  <head>
1425
1644
  <meta charset="UTF-8">
1426
1645
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
1427
- <title>Sanctuary Dashboard</title>
1646
+ <title>Sanctuary \u2014 Principal Dashboard</title>
1428
1647
  <style>
1429
1648
  :root {
1430
1649
  --bg: #0d1117;
@@ -3075,6 +3294,7 @@ var SESSION_TTL_REMOTE_MS, SESSION_TTL_LOCAL_MS, MAX_SESSIONS, RATE_LIMIT_WINDOW
3075
3294
  var init_dashboard = __esm({
3076
3295
  "src/principal-policy/dashboard.ts"() {
3077
3296
  init_config();
3297
+ init_generator();
3078
3298
  init_dashboard_html();
3079
3299
  SESSION_TTL_REMOTE_MS = 5 * 60 * 1e3;
3080
3300
  SESSION_TTL_LOCAL_MS = 24 * 60 * 60 * 1e3;
@@ -3091,6 +3311,10 @@ var init_dashboard = __esm({
3091
3311
  policy = null;
3092
3312
  baseline = null;
3093
3313
  auditLog = null;
3314
+ identityManager = null;
3315
+ handshakeResults = null;
3316
+ shrOpts = null;
3317
+ _sanctuaryConfig = null;
3094
3318
  dashboardHTML;
3095
3319
  loginHTML;
3096
3320
  authToken;
@@ -3124,6 +3348,10 @@ var init_dashboard = __esm({
3124
3348
  this.policy = deps.policy;
3125
3349
  this.baseline = deps.baseline;
3126
3350
  this.auditLog = deps.auditLog;
3351
+ if (deps.identityManager) this.identityManager = deps.identityManager;
3352
+ if (deps.handshakeResults) this.handshakeResults = deps.handshakeResults;
3353
+ if (deps.shrOpts) this.shrOpts = deps.shrOpts;
3354
+ if (deps.sanctuaryConfig) this._sanctuaryConfig = deps.sanctuaryConfig;
3127
3355
  }
3128
3356
  /**
3129
3357
  * Start the HTTP(S) server for the dashboard.
@@ -3456,6 +3684,14 @@ var init_dashboard = __esm({
3456
3684
  this.handlePendingList(res);
3457
3685
  } else if (method === "GET" && url.pathname === "/api/audit-log") {
3458
3686
  this.handleAuditLog(url, res);
3687
+ } else if (method === "GET" && url.pathname === "/api/sovereignty") {
3688
+ this.handleSovereignty(res);
3689
+ } else if (method === "GET" && url.pathname === "/api/identity") {
3690
+ this.handleIdentity(res);
3691
+ } else if (method === "GET" && url.pathname === "/api/handshakes") {
3692
+ this.handleHandshakes(res);
3693
+ } else if (method === "GET" && url.pathname === "/api/shr") {
3694
+ this.handleSHR(res);
3459
3695
  } else if (method === "POST" && url.pathname.startsWith("/api/approve/")) {
3460
3696
  if (!this.checkRateLimit(req, res, "decisions")) return;
3461
3697
  const id = url.pathname.slice("/api/approve/".length);
@@ -3645,6 +3881,107 @@ data: ${JSON.stringify(initData)}
3645
3881
  res.writeHead(200, { "Content-Type": "application/json" });
3646
3882
  res.end(JSON.stringify({ success: true, decision }));
3647
3883
  }
3884
+ // ── Sovereignty Data Routes ─────────────────────────────────────────
3885
+ handleSovereignty(res) {
3886
+ if (!this.shrOpts) {
3887
+ res.writeHead(200, { "Content-Type": "application/json" });
3888
+ res.end(JSON.stringify({ error: "SHR generator not available" }));
3889
+ return;
3890
+ }
3891
+ const shr = generateSHR(void 0, this.shrOpts);
3892
+ if (typeof shr === "string") {
3893
+ res.writeHead(200, { "Content-Type": "application/json" });
3894
+ res.end(JSON.stringify({ error: shr }));
3895
+ return;
3896
+ }
3897
+ const layers = shr.body.layers;
3898
+ let score = 0;
3899
+ for (const layer of [layers.l1, layers.l2, layers.l3, layers.l4]) {
3900
+ if (layer.status === "active") score += 25;
3901
+ else if (layer.status === "degraded") score += 15;
3902
+ }
3903
+ const overallLevel = score === 100 ? "full" : score >= 65 ? "degraded" : score >= 25 ? "minimal" : "unverified";
3904
+ res.writeHead(200, { "Content-Type": "application/json" });
3905
+ res.end(JSON.stringify({
3906
+ score,
3907
+ overall_level: overallLevel,
3908
+ layers: {
3909
+ l1: { status: layers.l1.status, detail: layers.l1.encryption, key_custody: layers.l1.key_custody },
3910
+ l2: { status: layers.l2.status, detail: layers.l2.isolation_type, attestation: layers.l2.attestation_available },
3911
+ l3: { status: layers.l3.status, detail: layers.l3.proof_system, selective_disclosure: layers.l3.selective_disclosure },
3912
+ l4: { status: layers.l4.status, detail: layers.l4.attestation_format, reputation_portable: layers.l4.reputation_portable }
3913
+ },
3914
+ degradations: shr.body.degradations,
3915
+ capabilities: shr.body.capabilities,
3916
+ config_loaded: this._sanctuaryConfig != null
3917
+ }));
3918
+ }
3919
+ handleIdentity(res) {
3920
+ if (!this.identityManager) {
3921
+ res.writeHead(200, { "Content-Type": "application/json" });
3922
+ res.end(JSON.stringify({ identities: [], count: 0 }));
3923
+ return;
3924
+ }
3925
+ const identities = this.identityManager.list().map((id) => ({
3926
+ identity_id: id.identity_id,
3927
+ label: id.label,
3928
+ public_key: id.public_key,
3929
+ did: id.did,
3930
+ created_at: id.created_at,
3931
+ key_type: id.key_type,
3932
+ key_protection: id.key_protection,
3933
+ rotation_count: id.rotation_history?.length ?? 0
3934
+ }));
3935
+ const primary = this.identityManager.getDefault();
3936
+ res.writeHead(200, { "Content-Type": "application/json" });
3937
+ res.end(JSON.stringify({
3938
+ identities,
3939
+ count: identities.length,
3940
+ primary_id: primary?.identity_id ?? null
3941
+ }));
3942
+ }
3943
+ handleHandshakes(res) {
3944
+ if (!this.handshakeResults) {
3945
+ res.writeHead(200, { "Content-Type": "application/json" });
3946
+ res.end(JSON.stringify({ handshakes: [], count: 0 }));
3947
+ return;
3948
+ }
3949
+ const handshakes = Array.from(this.handshakeResults.values()).map((h) => ({
3950
+ counterparty_id: h.counterparty_id,
3951
+ verified: h.verified,
3952
+ sovereignty_level: h.sovereignty_level,
3953
+ trust_tier: h.trust_tier,
3954
+ completed_at: h.completed_at,
3955
+ expires_at: h.expires_at,
3956
+ errors: h.errors
3957
+ }));
3958
+ handshakes.sort((a, b) => new Date(b.completed_at).getTime() - new Date(a.completed_at).getTime());
3959
+ res.writeHead(200, { "Content-Type": "application/json" });
3960
+ res.end(JSON.stringify({
3961
+ handshakes,
3962
+ count: handshakes.length,
3963
+ tier_distribution: {
3964
+ verified_sovereign: handshakes.filter((h) => h.trust_tier === "verified-sovereign").length,
3965
+ verified_degraded: handshakes.filter((h) => h.trust_tier === "verified-degraded").length,
3966
+ unverified: handshakes.filter((h) => h.trust_tier === "unverified").length
3967
+ }
3968
+ }));
3969
+ }
3970
+ handleSHR(res) {
3971
+ if (!this.shrOpts) {
3972
+ res.writeHead(200, { "Content-Type": "application/json" });
3973
+ res.end(JSON.stringify({ error: "SHR generator not available" }));
3974
+ return;
3975
+ }
3976
+ const shr = generateSHR(void 0, this.shrOpts);
3977
+ if (typeof shr === "string") {
3978
+ res.writeHead(200, { "Content-Type": "application/json" });
3979
+ res.end(JSON.stringify({ error: shr }));
3980
+ return;
3981
+ }
3982
+ res.writeHead(200, { "Content-Type": "application/json" });
3983
+ res.end(JSON.stringify(shr));
3984
+ }
3648
3985
  // ── SSE Broadcasting ────────────────────────────────────────────────
3649
3986
  broadcastSSE(event, data) {
3650
3987
  const message = `event: ${event}
@@ -3886,111 +4223,7 @@ init_filesystem();
3886
4223
  // src/l1-cognitive/state-store.ts
3887
4224
  init_encryption();
3888
4225
  init_hashing();
3889
-
3890
- // src/core/identity.ts
3891
- init_encoding();
3892
- init_encryption();
3893
- init_hashing();
3894
- init_random();
3895
- function generateKeypair() {
3896
- const privateKey = randomBytes(32);
3897
- const publicKey = ed25519.getPublicKey(privateKey);
3898
- return { publicKey, privateKey };
3899
- }
3900
- function publicKeyToDid(publicKey) {
3901
- const multicodec = new Uint8Array([237, 1, ...publicKey]);
3902
- return `did:key:z${toBase64url(multicodec)}`;
3903
- }
3904
- function generateIdentityId(publicKey) {
3905
- const keyHash = hash(publicKey);
3906
- return Array.from(keyHash.slice(0, 16)).map((b) => b.toString(16).padStart(2, "0")).join("");
3907
- }
3908
- function createIdentity(label, encryptionKey, keyProtection) {
3909
- const { publicKey, privateKey } = generateKeypair();
3910
- const identityId = generateIdentityId(publicKey);
3911
- const did = publicKeyToDid(publicKey);
3912
- const now = (/* @__PURE__ */ new Date()).toISOString();
3913
- const encryptedPrivateKey = encrypt(privateKey, encryptionKey);
3914
- privateKey.fill(0);
3915
- const publicIdentity = {
3916
- identity_id: identityId,
3917
- label,
3918
- public_key: toBase64url(publicKey),
3919
- did,
3920
- created_at: now,
3921
- key_type: "ed25519",
3922
- key_protection: keyProtection
3923
- };
3924
- const storedIdentity = {
3925
- ...publicIdentity,
3926
- encrypted_private_key: encryptedPrivateKey,
3927
- rotation_history: []
3928
- };
3929
- return { publicIdentity, storedIdentity };
3930
- }
3931
- function sign(payload, encryptedPrivateKey, encryptionKey) {
3932
- const privateKey = decrypt(encryptedPrivateKey, encryptionKey);
3933
- try {
3934
- return ed25519.sign(payload, privateKey);
3935
- } finally {
3936
- privateKey.fill(0);
3937
- }
3938
- }
3939
- function verify(payload, signature, publicKey) {
3940
- try {
3941
- return ed25519.verify(signature, payload, publicKey);
3942
- } catch {
3943
- return false;
3944
- }
3945
- }
3946
- function rotateKeys(storedIdentity, encryptionKey, reason) {
3947
- const { publicKey: newPublicKey, privateKey: newPrivateKey } = generateKeypair();
3948
- const newIdentityDid = publicKeyToDid(newPublicKey);
3949
- const now = (/* @__PURE__ */ new Date()).toISOString();
3950
- const eventData = JSON.stringify({
3951
- old_public_key: storedIdentity.public_key,
3952
- new_public_key: toBase64url(newPublicKey),
3953
- identity_id: storedIdentity.identity_id,
3954
- reason,
3955
- rotated_at: now
3956
- });
3957
- const eventBytes = new TextEncoder().encode(eventData);
3958
- const signature = sign(
3959
- eventBytes,
3960
- storedIdentity.encrypted_private_key,
3961
- encryptionKey
3962
- );
3963
- const rotationEvent = {
3964
- old_public_key: storedIdentity.public_key,
3965
- new_public_key: toBase64url(newPublicKey),
3966
- identity_id: storedIdentity.identity_id,
3967
- reason,
3968
- rotated_at: now,
3969
- signature: toBase64url(signature)
3970
- };
3971
- const encryptedNewPrivateKey = encrypt(newPrivateKey, encryptionKey);
3972
- newPrivateKey.fill(0);
3973
- const updatedIdentity = {
3974
- ...storedIdentity,
3975
- public_key: toBase64url(newPublicKey),
3976
- did: newIdentityDid,
3977
- encrypted_private_key: encryptedNewPrivateKey,
3978
- rotation_history: [
3979
- ...storedIdentity.rotation_history,
3980
- {
3981
- old_public_key: storedIdentity.public_key,
3982
- new_public_key: toBase64url(newPublicKey),
3983
- rotation_event: toBase64url(
3984
- new TextEncoder().encode(JSON.stringify(rotationEvent))
3985
- ),
3986
- rotated_at: now
3987
- }
3988
- ]
3989
- };
3990
- return { updatedIdentity, rotationEvent };
3991
- }
3992
-
3993
- // src/l1-cognitive/state-store.ts
4226
+ init_identity();
3994
4227
  init_key_derivation();
3995
4228
  init_encoding();
3996
4229
  var RESERVED_NAMESPACE_PREFIXES = [
@@ -4530,6 +4763,7 @@ function toolResult(data) {
4530
4763
  }
4531
4764
 
4532
4765
  // src/l1-cognitive/tools.ts
4766
+ init_identity();
4533
4767
  init_key_derivation();
4534
4768
  init_encoding();
4535
4769
  init_encryption();
@@ -5939,6 +6173,7 @@ init_encryption();
5939
6173
  init_key_derivation();
5940
6174
  init_encoding();
5941
6175
  init_random();
6176
+ init_identity();
5942
6177
  function computeMedian(values) {
5943
6178
  if (values.length === 0) return 0;
5944
6179
  const sorted = [...values].sort((a, b) => a - b);
@@ -7911,110 +8146,12 @@ function createPrincipalPolicyTools(policy, baseline, auditLog) {
7911
8146
  ];
7912
8147
  }
7913
8148
 
7914
- // src/shr/types.ts
7915
- function deepSortKeys(obj) {
7916
- if (obj === null || typeof obj !== "object") return obj;
7917
- if (Array.isArray(obj)) return obj.map(deepSortKeys);
7918
- const sorted = {};
7919
- for (const key of Object.keys(obj).sort()) {
7920
- sorted[key] = deepSortKeys(obj[key]);
7921
- }
7922
- return sorted;
7923
- }
7924
- function canonicalizeForSigning(body) {
7925
- return JSON.stringify(deepSortKeys(body));
7926
- }
7927
-
7928
- // src/shr/generator.ts
7929
- init_encoding();
7930
- init_key_derivation();
7931
- var DEFAULT_VALIDITY_MS = 60 * 60 * 1e3;
7932
- function generateSHR(identityId, opts) {
7933
- const { config, identityManager, masterKey, validityMs } = opts;
7934
- const identity = identityId ? identityManager.get(identityId) : identityManager.getDefault();
7935
- if (!identity) {
7936
- return "No identity available for signing. Create an identity first.";
7937
- }
7938
- const now = /* @__PURE__ */ new Date();
7939
- const expiresAt = new Date(now.getTime() + (validityMs ?? DEFAULT_VALIDITY_MS));
7940
- const degradations = [];
7941
- if (config.execution.environment === "local-process") {
7942
- degradations.push({
7943
- layer: "l2",
7944
- code: "PROCESS_ISOLATION_ONLY",
7945
- severity: "warning",
7946
- description: "Process-level isolation only (no TEE)",
7947
- mitigation: "TEE support planned for a future release"
7948
- });
7949
- degradations.push({
7950
- layer: "l2",
7951
- code: "SELF_REPORTED_ATTESTATION",
7952
- severity: "warning",
7953
- description: "Attestation is self-reported (no hardware root of trust)",
7954
- mitigation: "TEE attestation planned for a future release"
7955
- });
7956
- }
7957
- const body = {
7958
- shr_version: "1.0",
7959
- implementation: {
7960
- sanctuary_version: config.version,
7961
- node_version: process.versions.node,
7962
- generated_by: "sanctuary-mcp-server"
7963
- },
7964
- instance_id: identity.identity_id,
7965
- generated_at: now.toISOString(),
7966
- expires_at: expiresAt.toISOString(),
7967
- layers: {
7968
- l1: {
7969
- status: "active",
7970
- encryption: config.state.encryption,
7971
- key_custody: "self",
7972
- integrity: config.state.integrity,
7973
- identity_type: config.state.identity_provider,
7974
- state_portable: true
7975
- },
7976
- l2: {
7977
- status: config.execution.environment === "local-process" ? "degraded" : "active",
7978
- isolation_type: config.execution.environment,
7979
- attestation_available: config.execution.attestation
7980
- },
7981
- l3: {
7982
- status: "active",
7983
- proof_system: config.disclosure.proof_system,
7984
- selective_disclosure: true
7985
- },
7986
- l4: {
7987
- status: "active",
7988
- reputation_mode: config.reputation.mode,
7989
- attestation_format: config.reputation.attestation_format,
7990
- reputation_portable: true
7991
- }
7992
- },
7993
- capabilities: {
7994
- handshake: true,
7995
- shr_exchange: true,
7996
- reputation_verify: true,
7997
- encrypted_channel: false
7998
- // Not yet implemented
7999
- },
8000
- degradations
8001
- };
8002
- const canonical = canonicalizeForSigning(body);
8003
- const payload = stringToBytes(canonical);
8004
- const encryptionKey = derivePurposeKey(masterKey, "identity-encryption");
8005
- const signatureBytes = sign(
8006
- payload,
8007
- identity.encrypted_private_key,
8008
- encryptionKey
8009
- );
8010
- return {
8011
- body,
8012
- signed_by: identity.public_key,
8013
- signature: toBase64url(signatureBytes)
8014
- };
8015
- }
8149
+ // src/shr/tools.ts
8150
+ init_generator();
8016
8151
 
8017
8152
  // src/shr/verifier.ts
8153
+ init_types();
8154
+ init_identity();
8018
8155
  init_encoding();
8019
8156
  function verifySHR(shr, now) {
8020
8157
  const errors = [];
@@ -8436,7 +8573,11 @@ function createSHRTools(config, identityManager, masterKey, auditLog) {
8436
8573
  return { tools };
8437
8574
  }
8438
8575
 
8576
+ // src/handshake/tools.ts
8577
+ init_generator();
8578
+
8439
8579
  // src/handshake/protocol.ts
8580
+ init_identity();
8440
8581
  init_encoding();
8441
8582
  init_random();
8442
8583
  init_key_derivation();
@@ -8606,8 +8747,11 @@ function deriveTrustTier(level) {
8606
8747
  }
8607
8748
 
8608
8749
  // src/handshake/attestation.ts
8750
+ init_types();
8751
+ init_identity();
8609
8752
  init_encoding();
8610
8753
  init_key_derivation();
8754
+ init_identity();
8611
8755
  init_encoding();
8612
8756
  var ATTESTATION_VERSION = "1.0";
8613
8757
  function deriveTrustTier2(level) {
@@ -9405,6 +9549,7 @@ init_encryption();
9405
9549
  init_encoding();
9406
9550
 
9407
9551
  // src/bridge/bridge.ts
9552
+ init_identity();
9408
9553
  init_encoding();
9409
9554
  init_random();
9410
9555
  init_hashing();
@@ -12493,6 +12638,7 @@ init_filesystem();
12493
12638
  init_baseline();
12494
12639
  init_loader();
12495
12640
  init_dashboard();
12641
+ init_generator();
12496
12642
  async function createSanctuaryServer(options) {
12497
12643
  const config = await loadConfig(options?.configPath);
12498
12644
  await mkdir(config.storage_path, { recursive: true, mode: 448 });
@@ -12846,7 +12992,15 @@ async function createSanctuaryServer(options) {
12846
12992
  tls: config.dashboard.tls,
12847
12993
  auto_open: config.dashboard.auto_open
12848
12994
  });
12849
- dashboard.setDependencies({ policy, baseline, auditLog });
12995
+ dashboard.setDependencies({
12996
+ policy,
12997
+ baseline,
12998
+ auditLog,
12999
+ identityManager,
13000
+ handshakeResults,
13001
+ shrOpts: { config, identityManager, masterKey },
13002
+ sanctuaryConfig: config
13003
+ });
12850
13004
  await dashboard.start();
12851
13005
  approvalChannel = dashboard;
12852
13006
  } else if (config.webhook.enabled && config.webhook.url && config.webhook.secret) {