@sanctuary-framework/mcp-server 1.1.1 → 1.1.3
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 +266 -84
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +272 -90
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +179 -77
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +179 -77
- 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;
|
|
@@ -11141,6 +11141,20 @@ async function handleRequest(deps, req, res) {
|
|
|
11141
11141
|
const url = new URL(req.url ?? "/", `http://${host}`);
|
|
11142
11142
|
const method = (req.method ?? "GET").toUpperCase();
|
|
11143
11143
|
const path = url.pathname;
|
|
11144
|
+
if (deps.v11Bindings) {
|
|
11145
|
+
const handled = await dispatchV11Request(
|
|
11146
|
+
{
|
|
11147
|
+
bindings: deps.v11Bindings,
|
|
11148
|
+
...deps.authToken !== void 0 ? { authToken: deps.authToken } : {},
|
|
11149
|
+
loopbackAutoAuth: deps.loopbackAutoAuth ?? false
|
|
11150
|
+
},
|
|
11151
|
+
req,
|
|
11152
|
+
res,
|
|
11153
|
+
url,
|
|
11154
|
+
method
|
|
11155
|
+
);
|
|
11156
|
+
if (handled) return true;
|
|
11157
|
+
}
|
|
11144
11158
|
if (!isAuthorized(deps, req, url)) {
|
|
11145
11159
|
writeJSON(res, 401, { error: "unauthorized" });
|
|
11146
11160
|
return true;
|
|
@@ -12770,6 +12784,47 @@ function handleDashboardV11Route(deps, req, res) {
|
|
|
12770
12784
|
return true;
|
|
12771
12785
|
}
|
|
12772
12786
|
|
|
12787
|
+
// src/dashboard/v1_1/dispatch.ts
|
|
12788
|
+
async function dispatchV11Request(inputs, req, res, url, method) {
|
|
12789
|
+
const { bindings, authToken, loopbackAutoAuth } = inputs;
|
|
12790
|
+
if (method === "GET" && (url.pathname === "/v1.1" || url.pathname === "/v1.1/")) {
|
|
12791
|
+
return handleDashboardV11Route(
|
|
12792
|
+
{
|
|
12793
|
+
identityId: bindings.identityId,
|
|
12794
|
+
fortressId: bindings.fortressId,
|
|
12795
|
+
...authToken !== void 0 ? { authToken } : {}
|
|
12796
|
+
},
|
|
12797
|
+
req,
|
|
12798
|
+
res
|
|
12799
|
+
);
|
|
12800
|
+
}
|
|
12801
|
+
if (url.pathname.startsWith("/api/hub/")) {
|
|
12802
|
+
const authConfig = {
|
|
12803
|
+
loopbackAutoAuth,
|
|
12804
|
+
...authToken !== void 0 ? { authToken } : {}
|
|
12805
|
+
};
|
|
12806
|
+
return handleHubRoute(
|
|
12807
|
+
{ authConfig, service: bindings.hubService },
|
|
12808
|
+
req,
|
|
12809
|
+
res
|
|
12810
|
+
);
|
|
12811
|
+
}
|
|
12812
|
+
if (method === "GET" && url.pathname === "/api/identities") {
|
|
12813
|
+
const authConfig = {
|
|
12814
|
+
loopbackAutoAuth,
|
|
12815
|
+
...authToken !== void 0 ? { authToken } : {}
|
|
12816
|
+
};
|
|
12817
|
+
const aliasReq = Object.create(req);
|
|
12818
|
+
aliasReq.url = "/api/hub/agents" + url.search;
|
|
12819
|
+
return handleHubRoute(
|
|
12820
|
+
{ authConfig, service: bindings.hubService },
|
|
12821
|
+
aliasReq,
|
|
12822
|
+
res
|
|
12823
|
+
);
|
|
12824
|
+
}
|
|
12825
|
+
return false;
|
|
12826
|
+
}
|
|
12827
|
+
|
|
12773
12828
|
// src/principal-policy/dashboard.ts
|
|
12774
12829
|
var SESSION_TTL_REMOTE_MS = 5 * 60 * 1e3;
|
|
12775
12830
|
var SESSION_TTL_LOCAL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -12896,45 +12951,17 @@ var DashboardApprovalChannel = class {
|
|
|
12896
12951
|
*/
|
|
12897
12952
|
async dispatchV11(req, res, url, method) {
|
|
12898
12953
|
if (!this.v11Bindings) return false;
|
|
12899
|
-
|
|
12900
|
-
|
|
12901
|
-
|
|
12902
|
-
|
|
12903
|
-
|
|
12904
|
-
|
|
12905
|
-
|
|
12906
|
-
|
|
12907
|
-
|
|
12908
|
-
|
|
12909
|
-
|
|
12910
|
-
}
|
|
12911
|
-
if (url.pathname.startsWith("/api/hub/")) {
|
|
12912
|
-
const authConfig = {
|
|
12913
|
-
loopbackAutoAuth: this._autoAuthLocalhost,
|
|
12914
|
-
...this.authToken !== void 0 ? { authToken: this.authToken } : {}
|
|
12915
|
-
};
|
|
12916
|
-
const handled = await handleHubRoute(
|
|
12917
|
-
{ authConfig, service: this.v11Bindings.hubService },
|
|
12918
|
-
req,
|
|
12919
|
-
res
|
|
12920
|
-
);
|
|
12921
|
-
return handled;
|
|
12922
|
-
}
|
|
12923
|
-
if (method === "GET" && url.pathname === "/api/identities") {
|
|
12924
|
-
const authConfig = {
|
|
12925
|
-
loopbackAutoAuth: this._autoAuthLocalhost,
|
|
12926
|
-
...this.authToken !== void 0 ? { authToken: this.authToken } : {}
|
|
12927
|
-
};
|
|
12928
|
-
const aliasReq = Object.create(req);
|
|
12929
|
-
aliasReq.url = "/api/hub/agents" + url.search;
|
|
12930
|
-
const handled = await handleHubRoute(
|
|
12931
|
-
{ authConfig, service: this.v11Bindings.hubService },
|
|
12932
|
-
aliasReq,
|
|
12933
|
-
res
|
|
12934
|
-
);
|
|
12935
|
-
return handled;
|
|
12936
|
-
}
|
|
12937
|
-
return false;
|
|
12954
|
+
return dispatchV11Request(
|
|
12955
|
+
{
|
|
12956
|
+
bindings: this.v11Bindings,
|
|
12957
|
+
...this.authToken !== void 0 ? { authToken: this.authToken } : {},
|
|
12958
|
+
loopbackAutoAuth: this._autoAuthLocalhost
|
|
12959
|
+
},
|
|
12960
|
+
req,
|
|
12961
|
+
res,
|
|
12962
|
+
url,
|
|
12963
|
+
method
|
|
12964
|
+
);
|
|
12938
12965
|
}
|
|
12939
12966
|
/**
|
|
12940
12967
|
* v0.10.2: enable (or disable) the loopback auto-auth fast path. See
|
|
@@ -26331,14 +26358,41 @@ function createComplianceTools(deps) {
|
|
|
26331
26358
|
init_random();
|
|
26332
26359
|
init_encoding();
|
|
26333
26360
|
var RECOVERY_KEY_FILENAME = "recovery-key.txt";
|
|
26334
|
-
|
|
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) {
|
|
26335
26389
|
const lines = [
|
|
26336
|
-
|
|
26390
|
+
copy.bannerHeader,
|
|
26337
26391
|
"",
|
|
26338
|
-
|
|
26392
|
+
`${copy.bannerSecretLabel}: ${secret}`,
|
|
26339
26393
|
"",
|
|
26340
|
-
|
|
26341
|
-
|
|
26394
|
+
copy.bannerSaveLine,
|
|
26395
|
+
copy.bannerLossLine,
|
|
26342
26396
|
"",
|
|
26343
26397
|
"Plaintext copy written to:",
|
|
26344
26398
|
` ${filePath}`,
|
|
@@ -26357,8 +26411,8 @@ ${bottom}
|
|
|
26357
26411
|
|
|
26358
26412
|
`);
|
|
26359
26413
|
}
|
|
26360
|
-
async function
|
|
26361
|
-
const filePath = path.join(opts.storagePath,
|
|
26414
|
+
async function writeSecretFile(opts) {
|
|
26415
|
+
const filePath = path.join(opts.storagePath, opts.copy.fileName);
|
|
26362
26416
|
try {
|
|
26363
26417
|
await promises.access(filePath, promises.constants.F_OK);
|
|
26364
26418
|
return { filePath, written: false };
|
|
@@ -26368,40 +26422,76 @@ async function writeRecoveryKeyFile(opts) {
|
|
|
26368
26422
|
const now = (opts.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
|
|
26369
26423
|
const fortressLine = opts.fortressId ? `Fortress: ${opts.fortressId}
|
|
26370
26424
|
` : "";
|
|
26371
|
-
const content =
|
|
26425
|
+
const content = `${opts.copy.fileWarningHeader}
|
|
26372
26426
|
Generated: ${now}
|
|
26373
26427
|
` + fortressLine + `
|
|
26374
|
-
|
|
26375
|
-
${opts.
|
|
26376
|
-
|
|
26377
|
-
|
|
26378
|
-
subsequent runs and will NOT display the key again. After moving this file off
|
|
26379
|
-
the host (encrypted backup, password manager, paper safe), delete it from the
|
|
26380
|
-
fortress directory. Do NOT keep it in the fortress; the recovery key bypasses
|
|
26381
|
-
the cocoon passphrase by design.
|
|
26382
|
-
`;
|
|
26428
|
+
${opts.copy.fileSecretLabel}
|
|
26429
|
+
${opts.secret}
|
|
26430
|
+
|
|
26431
|
+
` + opts.copy.fileBody;
|
|
26383
26432
|
await promises.writeFile(filePath, content, { mode: 384 });
|
|
26384
26433
|
return { filePath, written: true };
|
|
26385
26434
|
}
|
|
26386
|
-
async function
|
|
26387
|
-
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 = {
|
|
26388
26458
|
storagePath: opts.storagePath,
|
|
26389
|
-
|
|
26390
|
-
|
|
26391
|
-
|
|
26392
|
-
|
|
26393
|
-
|
|
26394
|
-
|
|
26395
|
-
|
|
26396
|
-
|
|
26397
|
-
);
|
|
26398
|
-
{
|
|
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") {
|
|
26399
26467
|
return {
|
|
26400
26468
|
filePath: fileResult.filePath,
|
|
26401
26469
|
fileWritten: fileResult.written,
|
|
26402
26470
|
confirmed: false
|
|
26403
26471
|
};
|
|
26404
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
|
+
);
|
|
26405
26495
|
}
|
|
26406
26496
|
|
|
26407
26497
|
// src/hub/agent-registry.ts
|
|
@@ -28823,14 +28913,18 @@ async function startDashboardServer(options) {
|
|
|
28823
28913
|
}
|
|
28824
28914
|
}
|
|
28825
28915
|
};
|
|
28826
|
-
|
|
28827
|
-
|
|
28828
|
-
authToken: options.authToken,
|
|
28829
|
-
approvals: options.approvals,
|
|
28830
|
-
onEvent
|
|
28831
|
-
};
|
|
28916
|
+
let v11Bindings = null;
|
|
28917
|
+
let v11LoopbackAutoAuth = false;
|
|
28832
28918
|
const server = http.createServer(async (req, res) => {
|
|
28833
28919
|
try {
|
|
28920
|
+
const deps = {
|
|
28921
|
+
sources: options.sources,
|
|
28922
|
+
authToken: options.authToken,
|
|
28923
|
+
approvals: options.approvals,
|
|
28924
|
+
onEvent,
|
|
28925
|
+
v11Bindings,
|
|
28926
|
+
loopbackAutoAuth: v11LoopbackAutoAuth
|
|
28927
|
+
};
|
|
28834
28928
|
const served = await handleRequest(deps, req, res);
|
|
28835
28929
|
if (!served) {
|
|
28836
28930
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
@@ -28868,7 +28962,13 @@ async function startDashboardServer(options) {
|
|
|
28868
28962
|
publishActivity: (entry) => publish({ type: "activity", data: entry }),
|
|
28869
28963
|
publishApproval: (approval) => publish({ type: "approval", data: approval }),
|
|
28870
28964
|
publishInbox: (item) => publish({ type: "inbox", data: item }),
|
|
28871
|
-
publishAgentStatus: (snapshot) => publish({ type: "agent_status", data: snapshot })
|
|
28965
|
+
publishAgentStatus: (snapshot) => publish({ type: "agent_status", data: snapshot }),
|
|
28966
|
+
setV11Bindings: (bindings) => {
|
|
28967
|
+
v11Bindings = bindings;
|
|
28968
|
+
},
|
|
28969
|
+
setV11LoopbackAutoAuth: (enabled) => {
|
|
28970
|
+
v11LoopbackAutoAuth = enabled;
|
|
28971
|
+
}
|
|
28872
28972
|
};
|
|
28873
28973
|
}
|
|
28874
28974
|
|
|
@@ -29531,7 +29631,9 @@ Refusing to start the cocoon while the reset-history marker is unreadable.`
|
|
|
29531
29631
|
if (recoveryKey) {
|
|
29532
29632
|
await discloseRecoveryKey({
|
|
29533
29633
|
recoveryKey,
|
|
29534
|
-
storagePath: config.storage_path
|
|
29634
|
+
storagePath: config.storage_path,
|
|
29635
|
+
mode: "stdio-server"
|
|
29636
|
+
});
|
|
29535
29637
|
}
|
|
29536
29638
|
return {
|
|
29537
29639
|
server,
|