@sanctuary-framework/mcp-server 0.5.10 → 0.5.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
@@ -1358,9 +1358,13 @@ var init_tools = __esm({
1358
1358
  get encryptionKey() {
1359
1359
  return derivePurposeKey(this.masterKey, "identity-encryption");
1360
1360
  }
1361
- /** Load identities from storage on startup */
1361
+ /** Load identities from storage on startup.
1362
+ * Returns { total: number of encrypted files found, loaded: number successfully decrypted }.
1363
+ * A mismatch (total > 0, loaded === 0) indicates a wrong master key / missing passphrase.
1364
+ */
1362
1365
  async load() {
1363
1366
  const entries = await this.storage.list("_identities");
1367
+ let failed = 0;
1364
1368
  for (const entry of entries) {
1365
1369
  const raw = await this.storage.read("_identities", entry.key);
1366
1370
  if (!raw) continue;
@@ -1373,8 +1377,10 @@ var init_tools = __esm({
1373
1377
  this.primaryIdentityId = identity.identity_id;
1374
1378
  }
1375
1379
  } catch {
1380
+ failed++;
1376
1381
  }
1377
1382
  }
1383
+ return { total: entries.length, loaded: this.identities.size, failed };
1378
1384
  }
1379
1385
  /** Save an identity to storage */
1380
1386
  async save(identity) {
@@ -4921,7 +4927,7 @@ async function startStandaloneDashboard(options = {}) {
4921
4927
  // Default to auto-open in standalone mode
4922
4928
  });
4923
4929
  const identityManager = new IdentityManager(storage, masterKey);
4924
- await identityManager.load();
4930
+ const loadResult = await identityManager.load();
4925
4931
  const shrOpts = { config, identityManager, masterKey };
4926
4932
  const handshakeResults = /* @__PURE__ */ new Map();
4927
4933
  dashboard.setDependencies({
@@ -4937,9 +4943,31 @@ async function startStandaloneDashboard(options = {}) {
4937
4943
  await dashboard.start();
4938
4944
  console.error(`Sanctuary Dashboard v${SANCTUARY_VERSION} (standalone mode)`);
4939
4945
  console.error(`Storage: ${config.storage_path}`);
4940
- const identityCount = identityManager.list().length;
4941
- console.error(`Identities loaded: ${identityCount}`);
4946
+ console.error(`Identities loaded: ${loadResult.loaded}`);
4942
4947
  console.error(`Listening: http://${dashboardHost}:${dashboardPort}`);
4948
+ if (loadResult.total > 0 && loadResult.loaded === 0) {
4949
+ console.error(
4950
+ `
4951
+ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
4952
+ \u2551 \u26A0 WARNING: Encrypted identities found but NONE loaded \u2551
4953
+ \u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563
4954
+ \u2551 ${loadResult.total} encrypted identity file(s) found on disk \u2551
4955
+ \u2551 0 could be decrypted with the current master key \u2551
4956
+ \u2551 \u2551
4957
+ \u2551 This usually means SANCTUARY_PASSPHRASE is missing or \u2551
4958
+ \u2551 incorrect. The dashboard will show empty panels. \u2551
4959
+ \u2551 \u2551
4960
+ \u2551 To fix: restart with the correct SANCTUARY_PASSPHRASE: \u2551
4961
+ \u2551 SANCTUARY_PASSPHRASE=<your-passphrase> npx \\ \u2551
4962
+ \u2551 @sanctuary-framework/mcp-server dashboard \u2551
4963
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
4964
+ `
4965
+ );
4966
+ } else if (loadResult.failed > 0) {
4967
+ console.error(
4968
+ `Warning: ${loadResult.failed} of ${loadResult.total} identity files could not be decrypted (possibly corrupted).`
4969
+ );
4970
+ }
4943
4971
  const saveBaseline = () => {
4944
4972
  baseline.save().catch(() => {
4945
4973
  });
@@ -11371,11 +11399,57 @@ var TOOL_API_SCOPED = {
11371
11399
  ],
11372
11400
  default_action: "redact"
11373
11401
  };
11402
+ var REMOTE_INFERENCE_SANITIZE = {
11403
+ id: "remote-inference-sanitize",
11404
+ name: "Remote Inference Sanitization",
11405
+ description: "Maximum privacy for remote/cloud LLM calls. Strips all identity, financial, location, and personal data before passing queries to external models. Inspired by Vitalik Buterin's 2-of-2 sovereignty model.",
11406
+ use_when: "Your local agent needs to call a remote LLM for tasks beyond local model capability (complex coding, deep research) and you want to minimize data leakage to the remote provider. The remote model gets only the task, query, format requirements, and stripped code context.",
11407
+ rules: [
11408
+ {
11409
+ provider: "inference",
11410
+ allow: [
11411
+ "task",
11412
+ "task_description",
11413
+ "current_query",
11414
+ "query",
11415
+ "prompt",
11416
+ "question",
11417
+ "instruction",
11418
+ "output_format",
11419
+ "format",
11420
+ "language",
11421
+ "code_context",
11422
+ // Stripped code snippets for coding tasks
11423
+ "error_message"
11424
+ // For debugging help
11425
+ ],
11426
+ redact: [
11427
+ ...ALWAYS_REDACT_SECRETS,
11428
+ ...PII_PATTERNS,
11429
+ ...INTERNAL_STATE_PATTERNS,
11430
+ ...HISTORY_PATTERNS,
11431
+ "tool_results",
11432
+ "previous_results",
11433
+ // Additional redactions for remote inference
11434
+ "model_data",
11435
+ "agent_state",
11436
+ "runtime_config",
11437
+ "capabilities",
11438
+ "tool_list"
11439
+ ],
11440
+ // Deny patterns — these must NEVER reach the remote model, not even redacted
11441
+ hash: [],
11442
+ summarize: []
11443
+ }
11444
+ ],
11445
+ default_action: "deny"
11446
+ };
11374
11447
  var TEMPLATES = {
11375
11448
  "inference-minimal": INFERENCE_MINIMAL,
11376
11449
  "inference-standard": INFERENCE_STANDARD,
11377
11450
  "logging-strict": LOGGING_STRICT,
11378
- "tool-api-scoped": TOOL_API_SCOPED
11451
+ "tool-api-scoped": TOOL_API_SCOPED,
11452
+ "remote-inference-sanitize": REMOTE_INFERENCE_SANITIZE
11379
11453
  };
11380
11454
  function listTemplateIds() {
11381
11455
  return Object.keys(TEMPLATES);
@@ -12970,7 +13044,29 @@ async function createSanctuaryServer(options) {
12970
13044
  keyProtection,
12971
13045
  auditLog
12972
13046
  );
12973
- await identityManager.load();
13047
+ const loadResult = await identityManager.load();
13048
+ if (loadResult.total > 0 && loadResult.loaded === 0) {
13049
+ console.error(
13050
+ `
13051
+ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
13052
+ \u2551 \u26A0 WARNING: Encrypted identities found but NONE loaded \u2551
13053
+ \u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563
13054
+ \u2551 ${loadResult.total} encrypted identity file(s) found on disk \u2551
13055
+ \u2551 0 could be decrypted with the current master key \u2551
13056
+ \u2551 \u2551
13057
+ \u2551 This usually means SANCTUARY_PASSPHRASE is missing or \u2551
13058
+ \u2551 incorrect. The server will start but with NO identity data. \u2551
13059
+ \u2551 \u2551
13060
+ \u2551 To fix: set SANCTUARY_PASSPHRASE to the passphrase used \u2551
13061
+ \u2551 when this Sanctuary instance was first configured. \u2551
13062
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
13063
+ `
13064
+ );
13065
+ } else if (loadResult.failed > 0) {
13066
+ console.error(
13067
+ `Warning: ${loadResult.failed} of ${loadResult.total} identity files could not be decrypted (possibly corrupted).`
13068
+ );
13069
+ }
12974
13070
  const l2Tools = [
12975
13071
  {
12976
13072
  name: "sanctuary/exec_attest",