@sanctuary-framework/mcp-server 1.1.2 → 1.1.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 +122 -36
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +127 -41
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +98 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +98 -33
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -21,7 +21,7 @@ var url = require('url');
|
|
|
21
21
|
var index_js = require('@modelcontextprotocol/sdk/client/index.js');
|
|
22
22
|
var stdio_js = require('@modelcontextprotocol/sdk/client/stdio.js');
|
|
23
23
|
var sse_js = require('@modelcontextprotocol/sdk/client/sse.js');
|
|
24
|
-
require('readline/promises');
|
|
24
|
+
var promises$1 = require('readline/promises');
|
|
25
25
|
|
|
26
26
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
27
27
|
var __defProp = Object.defineProperty;
|
|
@@ -12730,7 +12730,7 @@ function renderDashboardV11Html(options = {}) {
|
|
|
12730
12730
|
streamUrl,
|
|
12731
12731
|
identityId,
|
|
12732
12732
|
fortressId
|
|
12733
|
-
});
|
|
12733
|
+
}).replace(/</g, "\\u003c");
|
|
12734
12734
|
const clientBlock = embedClient ? `<script type="module">${getClientScript()}</script>` : `<!-- client script omitted by render option -->`;
|
|
12735
12735
|
return `<!doctype html>
|
|
12736
12736
|
<html lang="en">
|
|
@@ -12761,7 +12761,7 @@ function renderDashboardV11Html(options = {}) {
|
|
|
12761
12761
|
<aside class="fortress" id="fortress"><p class="muted">Loading fortress column.</p></aside>
|
|
12762
12762
|
</div>
|
|
12763
12763
|
<div id="toast-host" aria-live="polite"></div>
|
|
12764
|
-
<script id="dashboard-config" type="application/json">${
|
|
12764
|
+
<script id="dashboard-config" type="application/json">${config}</script>
|
|
12765
12765
|
${clientBlock}
|
|
12766
12766
|
</body>
|
|
12767
12767
|
</html>`;
|
|
@@ -26358,14 +26358,41 @@ function createComplianceTools(deps) {
|
|
|
26358
26358
|
init_random();
|
|
26359
26359
|
init_encoding();
|
|
26360
26360
|
var RECOVERY_KEY_FILENAME = "recovery-key.txt";
|
|
26361
|
-
|
|
26361
|
+
var RECOVERY_KEY_COPY = {
|
|
26362
|
+
fileName: RECOVERY_KEY_FILENAME,
|
|
26363
|
+
bannerHeader: "SANCTUARY: First Run, Recovery Key Generated",
|
|
26364
|
+
bannerSecretLabel: "Recovery Key",
|
|
26365
|
+
bannerSaveLine: "SAVE THIS KEY. It will not be shown again.",
|
|
26366
|
+
bannerLossLine: "Without it, your encrypted state is unrecoverable.",
|
|
26367
|
+
fileWarningHeader: "SANCTUARY RECOVERY KEY, DO NOT COMMIT, DO NOT EMAIL, MOVE OFF-HOST IMMEDIATELY.",
|
|
26368
|
+
fileSecretLabel: "Recovery key:",
|
|
26369
|
+
fileBody: "This file was created on first init. Sanctuary will NOT regenerate this file on\nsubsequent runs and will NOT display the key again. After moving this file off\nthe host (encrypted backup, password manager, paper safe), delete it from the\nfortress directory. Do NOT keep it in the fortress; the recovery key bypasses\nthe cocoon passphrase by design.\n",
|
|
26370
|
+
promptLabel: "recovery key"
|
|
26371
|
+
};
|
|
26372
|
+
var RecoveryKeyConfirmationDeclinedError = class extends Error {
|
|
26373
|
+
constructor() {
|
|
26374
|
+
super(
|
|
26375
|
+
"Recovery key confirmation declined. Save the recovery key (printed above and written to recovery-key.txt) before re-running init."
|
|
26376
|
+
);
|
|
26377
|
+
this.name = "RecoveryKeyConfirmationDeclinedError";
|
|
26378
|
+
}
|
|
26379
|
+
};
|
|
26380
|
+
var RecoveryKeyConfirmationNonInteractiveError = class extends Error {
|
|
26381
|
+
constructor() {
|
|
26382
|
+
super(
|
|
26383
|
+
"Recovery key confirmation requires an interactive terminal. Re-run with --no-confirm for CI/scripted use, or run from a TTY."
|
|
26384
|
+
);
|
|
26385
|
+
this.name = "RecoveryKeyConfirmationNonInteractiveError";
|
|
26386
|
+
}
|
|
26387
|
+
};
|
|
26388
|
+
function printSecretBanner(secret, filePath, copy, output = process.stderr) {
|
|
26362
26389
|
const lines = [
|
|
26363
|
-
|
|
26390
|
+
copy.bannerHeader,
|
|
26364
26391
|
"",
|
|
26365
|
-
|
|
26392
|
+
`${copy.bannerSecretLabel}: ${secret}`,
|
|
26366
26393
|
"",
|
|
26367
|
-
|
|
26368
|
-
|
|
26394
|
+
copy.bannerSaveLine,
|
|
26395
|
+
copy.bannerLossLine,
|
|
26369
26396
|
"",
|
|
26370
26397
|
"Plaintext copy written to:",
|
|
26371
26398
|
` ${filePath}`,
|
|
@@ -26384,8 +26411,8 @@ ${bottom}
|
|
|
26384
26411
|
|
|
26385
26412
|
`);
|
|
26386
26413
|
}
|
|
26387
|
-
async function
|
|
26388
|
-
const filePath = path.join(opts.storagePath,
|
|
26414
|
+
async function writeSecretFile(opts) {
|
|
26415
|
+
const filePath = path.join(opts.storagePath, opts.copy.fileName);
|
|
26389
26416
|
try {
|
|
26390
26417
|
await promises.access(filePath, promises.constants.F_OK);
|
|
26391
26418
|
return { filePath, written: false };
|
|
@@ -26395,40 +26422,76 @@ async function writeRecoveryKeyFile(opts) {
|
|
|
26395
26422
|
const now = (opts.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
|
|
26396
26423
|
const fortressLine = opts.fortressId ? `Fortress: ${opts.fortressId}
|
|
26397
26424
|
` : "";
|
|
26398
|
-
const content =
|
|
26425
|
+
const content = `${opts.copy.fileWarningHeader}
|
|
26399
26426
|
Generated: ${now}
|
|
26400
26427
|
` + fortressLine + `
|
|
26401
|
-
|
|
26402
|
-
${opts.
|
|
26403
|
-
|
|
26404
|
-
|
|
26405
|
-
subsequent runs and will NOT display the key again. After moving this file off
|
|
26406
|
-
the host (encrypted backup, password manager, paper safe), delete it from the
|
|
26407
|
-
fortress directory. Do NOT keep it in the fortress; the recovery key bypasses
|
|
26408
|
-
the cocoon passphrase by design.
|
|
26409
|
-
`;
|
|
26428
|
+
${opts.copy.fileSecretLabel}
|
|
26429
|
+
${opts.secret}
|
|
26430
|
+
|
|
26431
|
+
` + opts.copy.fileBody;
|
|
26410
26432
|
await promises.writeFile(filePath, content, { mode: 384 });
|
|
26411
26433
|
return { filePath, written: true };
|
|
26412
26434
|
}
|
|
26413
|
-
async function
|
|
26414
|
-
const
|
|
26435
|
+
async function confirmSecretSaved(copy, declinedError, nonInteractiveError, io) {
|
|
26436
|
+
const input = io?.input ?? process.stdin;
|
|
26437
|
+
const output = io?.output ?? process.stderr;
|
|
26438
|
+
const realStdin = !io && process.stdin.isTTY !== true;
|
|
26439
|
+
if (realStdin) {
|
|
26440
|
+
throw new nonInteractiveError();
|
|
26441
|
+
}
|
|
26442
|
+
const rl = promises$1.createInterface({ input, output });
|
|
26443
|
+
try {
|
|
26444
|
+
const answer = await rl.question(
|
|
26445
|
+
`Have you saved the ${copy.promptLabel}? [y/N] `
|
|
26446
|
+
);
|
|
26447
|
+
const normalized = answer.trim().toLowerCase();
|
|
26448
|
+
if (normalized !== "y" && normalized !== "yes") {
|
|
26449
|
+
throw new declinedError();
|
|
26450
|
+
}
|
|
26451
|
+
} finally {
|
|
26452
|
+
rl.close();
|
|
26453
|
+
}
|
|
26454
|
+
}
|
|
26455
|
+
async function discloseSecret(opts, copy, declinedError, nonInteractiveError) {
|
|
26456
|
+
const mode = opts.mode ?? "interactive";
|
|
26457
|
+
const writeOpts = {
|
|
26415
26458
|
storagePath: opts.storagePath,
|
|
26416
|
-
|
|
26417
|
-
|
|
26418
|
-
|
|
26419
|
-
|
|
26420
|
-
|
|
26421
|
-
|
|
26422
|
-
|
|
26423
|
-
|
|
26424
|
-
);
|
|
26425
|
-
{
|
|
26459
|
+
secret: opts.secret,
|
|
26460
|
+
copy
|
|
26461
|
+
};
|
|
26462
|
+
if (opts.fortressId !== void 0) writeOpts.fortressId = opts.fortressId;
|
|
26463
|
+
if (opts.now !== void 0) writeOpts.now = opts.now;
|
|
26464
|
+
const fileResult = await writeSecretFile(writeOpts);
|
|
26465
|
+
printSecretBanner(opts.secret, fileResult.filePath, copy, opts.io?.output);
|
|
26466
|
+
if (mode === "no-confirm" || mode === "stdio-server") {
|
|
26426
26467
|
return {
|
|
26427
26468
|
filePath: fileResult.filePath,
|
|
26428
26469
|
fileWritten: fileResult.written,
|
|
26429
26470
|
confirmed: false
|
|
26430
26471
|
};
|
|
26431
26472
|
}
|
|
26473
|
+
await confirmSecretSaved(copy, declinedError, nonInteractiveError, opts.io);
|
|
26474
|
+
return {
|
|
26475
|
+
filePath: fileResult.filePath,
|
|
26476
|
+
fileWritten: fileResult.written,
|
|
26477
|
+
confirmed: true
|
|
26478
|
+
};
|
|
26479
|
+
}
|
|
26480
|
+
async function discloseRecoveryKey(opts) {
|
|
26481
|
+
const internalOpts = {
|
|
26482
|
+
secret: opts.recoveryKey,
|
|
26483
|
+
storagePath: opts.storagePath
|
|
26484
|
+
};
|
|
26485
|
+
if (opts.fortressId !== void 0) internalOpts.fortressId = opts.fortressId;
|
|
26486
|
+
if (opts.mode !== void 0) internalOpts.mode = opts.mode;
|
|
26487
|
+
if (opts.now !== void 0) internalOpts.now = opts.now;
|
|
26488
|
+
if (opts.io !== void 0) internalOpts.io = opts.io;
|
|
26489
|
+
return discloseSecret(
|
|
26490
|
+
internalOpts,
|
|
26491
|
+
RECOVERY_KEY_COPY,
|
|
26492
|
+
RecoveryKeyConfirmationDeclinedError,
|
|
26493
|
+
RecoveryKeyConfirmationNonInteractiveError
|
|
26494
|
+
);
|
|
26432
26495
|
}
|
|
26433
26496
|
|
|
26434
26497
|
// src/hub/agent-registry.ts
|
|
@@ -29568,7 +29631,9 @@ Refusing to start the cocoon while the reset-history marker is unreadable.`
|
|
|
29568
29631
|
if (recoveryKey) {
|
|
29569
29632
|
await discloseRecoveryKey({
|
|
29570
29633
|
recoveryKey,
|
|
29571
|
-
storagePath: config.storage_path
|
|
29634
|
+
storagePath: config.storage_path,
|
|
29635
|
+
mode: "stdio-server"
|
|
29636
|
+
});
|
|
29572
29637
|
}
|
|
29573
29638
|
return {
|
|
29574
29639
|
server,
|