@sanctuary-framework/mcp-server 0.10.3 → 0.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +96 -18
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +96 -18
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -27420,10 +27420,64 @@ var init_multi_server = __esm({
|
|
|
27420
27420
|
// src/dashboard-standalone.ts
|
|
27421
27421
|
var dashboard_standalone_exports = {};
|
|
27422
27422
|
__export(dashboard_standalone_exports, {
|
|
27423
|
+
discoverableSubTenants: () => discoverableSubTenants,
|
|
27424
|
+
renderTenantDiscoveryHint: () => renderTenantDiscoveryHint,
|
|
27423
27425
|
startStandaloneDashboard: () => startStandaloneDashboard
|
|
27424
27426
|
});
|
|
27427
|
+
async function discoverableSubTenants(currentStoragePath) {
|
|
27428
|
+
let all;
|
|
27429
|
+
try {
|
|
27430
|
+
all = await discoverTenants();
|
|
27431
|
+
} catch {
|
|
27432
|
+
return [];
|
|
27433
|
+
}
|
|
27434
|
+
return all.filter((t) => t.storage_path !== currentStoragePath && t.initialized);
|
|
27435
|
+
}
|
|
27436
|
+
function renderTenantDiscoveryHint(tenants) {
|
|
27437
|
+
if (tenants.length === 0) {
|
|
27438
|
+
return `No wrapped tenants discovered on this host.
|
|
27439
|
+
Run \`sanctuary wrap\` to create one, or set SANCTUARY_STORAGE_PATH
|
|
27440
|
+
if your tenant lives outside ~/.sanctuary/.`;
|
|
27441
|
+
}
|
|
27442
|
+
const lines = tenants.map((t) => {
|
|
27443
|
+
const runtime = t.runtime ? ` (running on :${t.runtime.dashboard_port})` : "";
|
|
27444
|
+
return ` \u2022 ${t.name}${runtime}
|
|
27445
|
+
storage: ${t.storage_path}
|
|
27446
|
+
keychain: ${t.keychain_service}`;
|
|
27447
|
+
});
|
|
27448
|
+
if (tenants.length === 1) {
|
|
27449
|
+
return `Detected 1 wrapped tenant on this host:
|
|
27450
|
+
` + lines.join("\n") + `
|
|
27451
|
+
|
|
27452
|
+
Boot the dashboard against it with:
|
|
27453
|
+
sanctuary dashboard --tenant ${tenants[0].name}
|
|
27454
|
+
`;
|
|
27455
|
+
}
|
|
27456
|
+
return `Detected ${tenants.length} wrapped tenants on this host:
|
|
27457
|
+
` + lines.join("\n") + `
|
|
27458
|
+
|
|
27459
|
+
Pick one explicitly:
|
|
27460
|
+
sanctuary dashboard --tenant <name>
|
|
27461
|
+
|
|
27462
|
+
Or browse all of them in the multi-tenant overview (no decryption):
|
|
27463
|
+
sanctuary dashboard --multi
|
|
27464
|
+
`;
|
|
27465
|
+
}
|
|
27425
27466
|
async function startStandaloneDashboard(options = {}) {
|
|
27426
27467
|
process.env.SANCTUARY_DASHBOARD_ENABLED = "true";
|
|
27468
|
+
if (options.tenant !== void 0) {
|
|
27469
|
+
const match = await findTenant(options.tenant);
|
|
27470
|
+
if (!match) {
|
|
27471
|
+
const available = await discoverTenants();
|
|
27472
|
+
const names = available.map((t) => t.name).join(", ") || "(none \u2014 run `sanctuary wrap`)";
|
|
27473
|
+
throw new Error(
|
|
27474
|
+
`Sanctuary Dashboard: --tenant "${options.tenant}" did not match any wrapped tenant.
|
|
27475
|
+
Available tenants: ${names}
|
|
27476
|
+
List details with \`sanctuary agents\`.`
|
|
27477
|
+
);
|
|
27478
|
+
}
|
|
27479
|
+
process.env.SANCTUARY_STORAGE_PATH = match.storage_path;
|
|
27480
|
+
}
|
|
27427
27481
|
const config = await loadConfig(options.configPath);
|
|
27428
27482
|
await mkdir(config.storage_path, { recursive: true, mode: 448 });
|
|
27429
27483
|
const storage = new FilesystemStorage(`${config.storage_path}/state`);
|
|
@@ -27473,12 +27527,16 @@ async function startStandaloneDashboard(options = {}) {
|
|
|
27473
27527
|
} else {
|
|
27474
27528
|
const { hashToString: hashToString2 } = await Promise.resolve().then(() => (init_hashing(), hashing_exports));
|
|
27475
27529
|
const { stringToBytes: stringToBytes2, bytesToString: bytesToString2, fromBase64url: fromBase64url2, constantTimeEqual: constantTimeEqual2 } = await Promise.resolve().then(() => (init_encoding(), encoding_exports));
|
|
27530
|
+
const otherTenants = await discoverableSubTenants(config.storage_path);
|
|
27476
27531
|
const existingHash = await storage.read("_meta", "recovery-key-hash");
|
|
27477
27532
|
if (existingHash) {
|
|
27478
27533
|
const envRecoveryKey = process.env.SANCTUARY_RECOVERY_KEY;
|
|
27479
27534
|
if (!envRecoveryKey) {
|
|
27480
27535
|
throw new Error(
|
|
27481
|
-
|
|
27536
|
+
`Sanctuary Dashboard: Existing encrypted data found at ${config.storage_path} but no credentials provided.
|
|
27537
|
+
Provide SANCTUARY_PASSPHRASE or SANCTUARY_RECOVERY_KEY to start the dashboard against this storage path.
|
|
27538
|
+
|
|
27539
|
+
` + (otherTenants.length > 0 ? renderTenantDiscoveryHint(otherTenants) + "\n" : "") + `See server/docs/keychain-schema.md for the keychain layout.`
|
|
27482
27540
|
);
|
|
27483
27541
|
}
|
|
27484
27542
|
let recoveryKeyBytes;
|
|
@@ -27509,7 +27567,19 @@ async function startStandaloneDashboard(options = {}) {
|
|
|
27509
27567
|
const hasKeyParams = existingNamespaces.some((e) => e.key === "key-params");
|
|
27510
27568
|
if (hasKeyParams) {
|
|
27511
27569
|
throw new Error(
|
|
27512
|
-
|
|
27570
|
+
`Sanctuary Dashboard: Existing encrypted data found at ${config.storage_path} (passphrase-protected).
|
|
27571
|
+
No passphrase was supplied via --passphrase, SANCTUARY_PASSPHRASE,
|
|
27572
|
+
or the per-tenant Keychain item ${keychainServiceFor(config.storage_path, homedir())}.
|
|
27573
|
+
|
|
27574
|
+
` + (otherTenants.length > 0 ? renderTenantDiscoveryHint(otherTenants) + "\n" : "") + `See server/docs/keychain-schema.md for the keychain layout and recovery options.`
|
|
27575
|
+
);
|
|
27576
|
+
}
|
|
27577
|
+
if (otherTenants.length > 0) {
|
|
27578
|
+
throw new Error(
|
|
27579
|
+
`Sanctuary Dashboard: ${config.storage_path} has no Sanctuary state, but other wrapped tenants exist on this host.
|
|
27580
|
+
Refusing to generate a new recovery key over the default root \u2014 that would obscure the existing tenants.
|
|
27581
|
+
|
|
27582
|
+
` + renderTenantDiscoveryHint(otherTenants)
|
|
27513
27583
|
);
|
|
27514
27584
|
}
|
|
27515
27585
|
console.error(
|
|
@@ -27599,27 +27669,26 @@ async function startStandaloneDashboard(options = {}) {
|
|
|
27599
27669
|
if (loadResult.total > 0 && loadResult.loaded === 0) {
|
|
27600
27670
|
const service = keychainServiceFor(config.storage_path, homedir());
|
|
27601
27671
|
const sourceLabel = passphraseSource === "option" ? "--passphrase option" : passphraseSource === "env" ? "SANCTUARY_PASSPHRASE env var" : passphraseSource === "keychain" ? `macOS Keychain (service ${service})` : passphraseSource === "fallback-file" ? "encrypted fallback file" : "recovery key";
|
|
27672
|
+
const otherTenants = await discoverableSubTenants(config.storage_path);
|
|
27673
|
+
const hint = otherTenants.length > 0 ? `
|
|
27674
|
+
${renderTenantDiscoveryHint(otherTenants).split("\n").join("\n ")}
|
|
27675
|
+
` : "";
|
|
27602
27676
|
console.error(
|
|
27603
27677
|
`
|
|
27604
27678
|
\u26A0 WARNING: Encrypted identities found but NONE loaded
|
|
27605
27679
|
${loadResult.total} encrypted identity file(s) in ${config.storage_path}/state/_identities/
|
|
27606
27680
|
0 could be decrypted with the master key derived from the ${sourceLabel}.
|
|
27607
27681
|
|
|
27608
|
-
The dashboard will show empty panels.
|
|
27609
|
-
|
|
27610
|
-
service
|
|
27611
|
-
|
|
27612
|
-
|
|
27613
|
-
|
|
27614
|
-
|
|
27615
|
-
|
|
27616
|
-
|
|
27617
|
-
|
|
27618
|
-
|
|
27619
|
-
If this tenant's passphrase lives only in a different Keychain item
|
|
27620
|
-
or on another machine, restore it before this dashboard can read
|
|
27621
|
-
any state. Sanctuary will never auto-regenerate \u2014 that would
|
|
27622
|
-
permanently destroy the data encrypted under the prior key.
|
|
27682
|
+
The dashboard will show empty panels. Each wrapped tenant has its
|
|
27683
|
+
own passphrase under its own per-tenant Keychain service
|
|
27684
|
+
(this tenant's service: ${service}) \u2014 there is no global master
|
|
27685
|
+
credential. Setting SANCTUARY_PASSPHRASE here will not help unless
|
|
27686
|
+
that value is the passphrase that originally encrypted the
|
|
27687
|
+
identity files at this storage path.
|
|
27688
|
+
` + hint + `
|
|
27689
|
+
Diagnostic recipes: server/docs/keychain-schema.md
|
|
27690
|
+
Sanctuary will never auto-regenerate \u2014 that would permanently
|
|
27691
|
+
destroy the data encrypted under the prior key.
|
|
27623
27692
|
`
|
|
27624
27693
|
);
|
|
27625
27694
|
} else if (loadResult.failed > 0) {
|
|
@@ -27650,6 +27719,7 @@ var init_dashboard_standalone = __esm({
|
|
|
27650
27719
|
init_sovereignty_profile();
|
|
27651
27720
|
init_runtime();
|
|
27652
27721
|
init_passphrase();
|
|
27722
|
+
init_discovery();
|
|
27653
27723
|
}
|
|
27654
27724
|
});
|
|
27655
27725
|
|
|
@@ -27818,6 +27888,7 @@ async function runStandaloneDashboard(args) {
|
|
|
27818
27888
|
let port;
|
|
27819
27889
|
let host;
|
|
27820
27890
|
let multi = false;
|
|
27891
|
+
let tenant;
|
|
27821
27892
|
for (let i = 0; i < args.length; i++) {
|
|
27822
27893
|
if (args[i] === "--passphrase" && args[i + 1]) {
|
|
27823
27894
|
console.error(
|
|
@@ -27830,6 +27901,8 @@ async function runStandaloneDashboard(args) {
|
|
|
27830
27901
|
host = args[++i];
|
|
27831
27902
|
} else if (args[i] === "--multi") {
|
|
27832
27903
|
multi = true;
|
|
27904
|
+
} else if (args[i] === "--tenant" && args[i + 1]) {
|
|
27905
|
+
tenant = args[++i];
|
|
27833
27906
|
} else if (args[i] === "--help" || args[i] === "-h") {
|
|
27834
27907
|
printDashboardHelp();
|
|
27835
27908
|
process.exit(0);
|
|
@@ -27859,7 +27932,8 @@ async function runStandaloneDashboard(args) {
|
|
|
27859
27932
|
await startStandaloneDashboard2({
|
|
27860
27933
|
passphrase,
|
|
27861
27934
|
port,
|
|
27862
|
-
host
|
|
27935
|
+
host,
|
|
27936
|
+
...tenant !== void 0 ? { tenant } : {}
|
|
27863
27937
|
});
|
|
27864
27938
|
console.error(`
|
|
27865
27939
|
Sanctuary Dashboard running (standalone mode). Press Ctrl+C to stop.
|
|
@@ -27993,6 +28067,10 @@ Usage:
|
|
|
27993
28067
|
Options:
|
|
27994
28068
|
--port <port> Dashboard port (default: from config or 3501; 3500 for --multi)
|
|
27995
28069
|
--host <host> Bind address (default: 127.0.0.1)
|
|
28070
|
+
--tenant <name> Boot against a specific wrapped tenant by the name printed
|
|
28071
|
+
by \`sanctuary agents\`. Resolves the per-tenant storage
|
|
28072
|
+
path and Keychain entry automatically. Use this on multi-
|
|
28073
|
+
tenant hosts instead of guessing SANCTUARY_PASSPHRASE.
|
|
27996
28074
|
--multi Start the multi-agent overview instead of a single-tenant
|
|
27997
28075
|
dashboard. Does not decrypt any tenant state \u2014 scans every
|
|
27998
28076
|
tenant on the host and deep-links into per-tenant dashboards.
|