@sanctuary-framework/mcp-server 1.1.4 → 1.1.6
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 +206 -4
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +207 -5
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +34 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -5
- package/dist/index.d.ts +21 -5
- package/dist/index.js +35 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -28139,6 +28139,13 @@ var init_hub_service = __esm({
|
|
|
28139
28139
|
nowIso() {
|
|
28140
28140
|
return this.now().toISOString();
|
|
28141
28141
|
}
|
|
28142
|
+
refreshPersistedLocalAgents() {
|
|
28143
|
+
const readPersistedLocalAgents2 = this.deps.readPersistedLocalAgents;
|
|
28144
|
+
if (!readPersistedLocalAgents2) return;
|
|
28145
|
+
for (const record of readPersistedLocalAgents2()) {
|
|
28146
|
+
this.deps.agentRegistry.put(record);
|
|
28147
|
+
}
|
|
28148
|
+
}
|
|
28142
28149
|
// ── Inbox ───────────────────────────────────────────────────────────
|
|
28143
28150
|
listInbox() {
|
|
28144
28151
|
const items = aggregateInbox(this.deps.inboxSources, this.inboxStore);
|
|
@@ -28150,6 +28157,7 @@ var init_hub_service = __esm({
|
|
|
28150
28157
|
}
|
|
28151
28158
|
// ── Agents ──────────────────────────────────────────────────────────
|
|
28152
28159
|
listAgents(filter) {
|
|
28160
|
+
this.refreshPersistedLocalAgents();
|
|
28153
28161
|
const safeFilter = {
|
|
28154
28162
|
...filter ?? {},
|
|
28155
28163
|
identity_id: this.deps.identityId
|
|
@@ -28583,12 +28591,76 @@ var init_hub = __esm({
|
|
|
28583
28591
|
init_api_router();
|
|
28584
28592
|
}
|
|
28585
28593
|
});
|
|
28594
|
+
function localAgentsFilePath(storagePath) {
|
|
28595
|
+
return path.join(storagePath, "state", "_hub", "local-agents.json");
|
|
28596
|
+
}
|
|
28597
|
+
function readPersistedLocalAgents(storagePath) {
|
|
28598
|
+
const filePath = localAgentsFilePath(storagePath);
|
|
28599
|
+
if (!fs.existsSync(filePath)) return [];
|
|
28600
|
+
try {
|
|
28601
|
+
const raw = fs.readFileSync(filePath, "utf8");
|
|
28602
|
+
const parsed = JSON.parse(raw);
|
|
28603
|
+
if (!parsed || !Array.isArray(parsed.agents)) return [];
|
|
28604
|
+
return parsed.agents;
|
|
28605
|
+
} catch {
|
|
28606
|
+
return [];
|
|
28607
|
+
}
|
|
28608
|
+
}
|
|
28609
|
+
function writePersistedLocalAgents(storagePath, agents) {
|
|
28610
|
+
const filePath = localAgentsFilePath(storagePath);
|
|
28611
|
+
const dir = path.dirname(filePath);
|
|
28612
|
+
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
28613
|
+
const payload = {
|
|
28614
|
+
version: PERSISTED_VERSION,
|
|
28615
|
+
agents
|
|
28616
|
+
};
|
|
28617
|
+
const tmpPath = `${filePath}.tmp`;
|
|
28618
|
+
fs.writeFileSync(tmpPath, `${JSON.stringify(payload, null, 2)}
|
|
28619
|
+
`, {
|
|
28620
|
+
mode: 384
|
|
28621
|
+
});
|
|
28622
|
+
fs.renameSync(tmpPath, filePath);
|
|
28623
|
+
fs.chmodSync(filePath, 384);
|
|
28624
|
+
}
|
|
28625
|
+
function upsertPersistedLocalAgent(storagePath, record) {
|
|
28626
|
+
const existing = readPersistedLocalAgents(storagePath);
|
|
28627
|
+
const idx = existing.findIndex((r) => r.agent_id === record.agent_id);
|
|
28628
|
+
let next;
|
|
28629
|
+
if (idx >= 0) {
|
|
28630
|
+
const prior = existing[idx];
|
|
28631
|
+
if (prior === void 0) {
|
|
28632
|
+
next = [...existing, record];
|
|
28633
|
+
} else {
|
|
28634
|
+
const updated = {
|
|
28635
|
+
...record,
|
|
28636
|
+
wrapped_at: prior.wrapped_at,
|
|
28637
|
+
last_activity_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
28638
|
+
};
|
|
28639
|
+
next = [...existing];
|
|
28640
|
+
next[idx] = updated;
|
|
28641
|
+
}
|
|
28642
|
+
} else {
|
|
28643
|
+
next = [...existing, record];
|
|
28644
|
+
}
|
|
28645
|
+
writePersistedLocalAgents(storagePath, next);
|
|
28646
|
+
return next;
|
|
28647
|
+
}
|
|
28648
|
+
var PERSISTED_VERSION;
|
|
28649
|
+
var init_agent_registry_persistence = __esm({
|
|
28650
|
+
"src/hub/agent-registry-persistence.ts"() {
|
|
28651
|
+
PERSISTED_VERSION = "1.1";
|
|
28652
|
+
}
|
|
28653
|
+
});
|
|
28586
28654
|
function buildV11Bindings(inputs) {
|
|
28587
|
-
const
|
|
28655
|
+
const seed = inputs.storagePath !== void 0 ? readPersistedLocalAgents(inputs.storagePath) : [];
|
|
28656
|
+
const registry = new InMemoryLocalAgentRegistry(seed);
|
|
28657
|
+
const storagePath = inputs.storagePath;
|
|
28658
|
+
const readPersisted = storagePath !== void 0 ? () => readPersistedLocalAgents(storagePath) : void 0;
|
|
28588
28659
|
const hubService = new HubService({
|
|
28589
28660
|
identityId: inputs.identityId,
|
|
28590
28661
|
fortressId: inputs.fortressId,
|
|
28591
28662
|
agentRegistry: registry,
|
|
28663
|
+
...readPersisted ? { readPersistedLocalAgents: readPersisted } : {},
|
|
28592
28664
|
inboxSources: {
|
|
28593
28665
|
listPendingApprovals: () => [],
|
|
28594
28666
|
listRecentBlockedEgress: () => [],
|
|
@@ -28622,6 +28694,7 @@ var init_wiring = __esm({
|
|
|
28622
28694
|
"src/dashboard/v1_1/wiring.ts"() {
|
|
28623
28695
|
init_hub();
|
|
28624
28696
|
init_errors4();
|
|
28697
|
+
init_agent_registry_persistence();
|
|
28625
28698
|
CapabilityErrorAgentController = class {
|
|
28626
28699
|
fail(action) {
|
|
28627
28700
|
throw new HubCapabilityError(
|
|
@@ -30654,7 +30727,12 @@ Refusing to start the cocoon while the reset-history marker is unreadable.`
|
|
|
30654
30727
|
buildV11Bindings({
|
|
30655
30728
|
identityId: embeddedHubIdentityId,
|
|
30656
30729
|
fortressId: fortressIdFromStoragePath(config.storage_path),
|
|
30657
|
-
auditLog
|
|
30730
|
+
auditLog,
|
|
30731
|
+
// v1.1.5 (Finding Z): rehydrate the hub agent registry from
|
|
30732
|
+
// `<storagePath>/state/_hub/local-agents.json` so the embedded
|
|
30733
|
+
// dashboard surfaces wraps performed by prior `sanctuary wrap`
|
|
30734
|
+
// invocations against this same fortress.
|
|
30735
|
+
storagePath: config.storage_path
|
|
30658
30736
|
})
|
|
30659
30737
|
);
|
|
30660
30738
|
await dashboard.start();
|
|
@@ -31297,6 +31375,7 @@ __export(cli_exports, {
|
|
|
31297
31375
|
PORT_FALLBACK_ATTEMPTS: () => PORT_FALLBACK_ATTEMPTS,
|
|
31298
31376
|
formatMcpServerCount: () => formatMcpServerCount,
|
|
31299
31377
|
formatWrapSuccess: () => formatWrapSuccess,
|
|
31378
|
+
formatWrapSuccessNoDashboard: () => formatWrapSuccessNoDashboard,
|
|
31300
31379
|
parseCocoonArgs: () => parseCocoonArgs,
|
|
31301
31380
|
parseWrapArgs: () => parseWrapArgs,
|
|
31302
31381
|
promoteFortressToStoragePath: () => promoteFortressToStoragePath,
|
|
@@ -31569,6 +31648,28 @@ async function runWrap(options, deps = {}) {
|
|
|
31569
31648
|
backupPath
|
|
31570
31649
|
);
|
|
31571
31650
|
if (!verifyOk) process.exit(1);
|
|
31651
|
+
try {
|
|
31652
|
+
upsertPersistedLocalAgent(
|
|
31653
|
+
storagePath,
|
|
31654
|
+
buildLocalAgentRecord({
|
|
31655
|
+
storagePath,
|
|
31656
|
+
platform: agentConfig.platform
|
|
31657
|
+
})
|
|
31658
|
+
);
|
|
31659
|
+
} catch (err) {
|
|
31660
|
+
console.error(
|
|
31661
|
+
` Note: v1.1 hub agent record not persisted (${err.message}). Re-run \`sanctuary wrap\` to retry, or check storage permissions on ${storagePath}.`
|
|
31662
|
+
);
|
|
31663
|
+
}
|
|
31664
|
+
if (options.noDashboard) {
|
|
31665
|
+
const toolName2 = toolNameFor(agentConfig.platform, agentConfig.servers);
|
|
31666
|
+
printWrapSuccessNoDashboard({
|
|
31667
|
+
toolName: toolName2,
|
|
31668
|
+
version: readPackageVersion(),
|
|
31669
|
+
toolCount: countUpstreamTools(upstreamServers),
|
|
31670
|
+
serverCount: upstreamServers.length});
|
|
31671
|
+
return;
|
|
31672
|
+
}
|
|
31572
31673
|
const authToken = generateAuthToken();
|
|
31573
31674
|
const startFn = deps.startDashboard ?? ((opts) => startDashboard({
|
|
31574
31675
|
port: opts.port,
|
|
@@ -31608,7 +31709,12 @@ async function runWrap(options, deps = {}) {
|
|
|
31608
31709
|
buildV11Bindings({
|
|
31609
31710
|
identityId: `fortress:${storagePath}`,
|
|
31610
31711
|
fortressId: fortressIdFromStoragePath(storagePath),
|
|
31611
|
-
auditLog: wrapAuditLog
|
|
31712
|
+
auditLog: wrapAuditLog,
|
|
31713
|
+
// v1.1.5 (Finding Z): rehydrate from the file the upsert
|
|
31714
|
+
// above just wrote, so the registry the wrap-auto dashboard
|
|
31715
|
+
// serves contains this wrap plus any prior wraps against the
|
|
31716
|
+
// same fortress.
|
|
31717
|
+
storagePath
|
|
31612
31718
|
})
|
|
31613
31719
|
);
|
|
31614
31720
|
dashboard.setV11LoopbackAutoAuth(true);
|
|
@@ -31748,6 +31854,32 @@ function formatWrapSuccess(info) {
|
|
|
31748
31854
|
function printWrapSuccess(info) {
|
|
31749
31855
|
console.error(formatWrapSuccess(info));
|
|
31750
31856
|
}
|
|
31857
|
+
function formatWrapSuccessNoDashboard(info) {
|
|
31858
|
+
const g = (s) => `\x1B[32m${s}\x1B[0m`;
|
|
31859
|
+
const d = (s) => `\x1B[2m${s}\x1B[0m`;
|
|
31860
|
+
const b = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
31861
|
+
const check = "\u2713";
|
|
31862
|
+
const lines = [];
|
|
31863
|
+
lines.push("");
|
|
31864
|
+
lines.push(
|
|
31865
|
+
` ${g(check)} Wrapped ${b(info.toolName)} with Sanctuary v${info.version}`
|
|
31866
|
+
);
|
|
31867
|
+
lines.push(
|
|
31868
|
+
` ${g(check)} ${info.toolCount} tools registered across ${info.serverCount} upstream server${info.serverCount !== 1 ? "s" : ""}`
|
|
31869
|
+
);
|
|
31870
|
+
lines.push(
|
|
31871
|
+
` ${d("Dashboard spawn skipped per --no-dashboard. Run `sanctuary dashboard` separately for a persistent dashboard.")}`
|
|
31872
|
+
);
|
|
31873
|
+
lines.push("");
|
|
31874
|
+
lines.push(
|
|
31875
|
+
` ${b("Your agent is protected.")} L1 Full / L2 Degraded (no TEE) / L3 Full / L4 Full.`
|
|
31876
|
+
);
|
|
31877
|
+
lines.push("");
|
|
31878
|
+
return lines.join("\n");
|
|
31879
|
+
}
|
|
31880
|
+
function printWrapSuccessNoDashboard(info) {
|
|
31881
|
+
console.error(formatWrapSuccessNoDashboard(info));
|
|
31882
|
+
}
|
|
31751
31883
|
async function verifyRewrittenConfig(configPath, backupPath) {
|
|
31752
31884
|
try {
|
|
31753
31885
|
const raw = await promises.readFile(configPath, "utf-8");
|
|
@@ -31864,6 +31996,57 @@ function toolNameFor(platform4, _servers) {
|
|
|
31864
31996
|
return "your agent";
|
|
31865
31997
|
}
|
|
31866
31998
|
}
|
|
31999
|
+
function harnessKindForPlatform(platform4) {
|
|
32000
|
+
switch (platform4) {
|
|
32001
|
+
case "openclaw":
|
|
32002
|
+
return "openclaw";
|
|
32003
|
+
case "hermes":
|
|
32004
|
+
return "hermes";
|
|
32005
|
+
case "claude-code":
|
|
32006
|
+
return "claude_code";
|
|
32007
|
+
case "cursor":
|
|
32008
|
+
return "cursor";
|
|
32009
|
+
case "cline":
|
|
32010
|
+
return "cline";
|
|
32011
|
+
case "generic":
|
|
32012
|
+
return "generic_mcp";
|
|
32013
|
+
default: {
|
|
32014
|
+
return "other";
|
|
32015
|
+
}
|
|
32016
|
+
}
|
|
32017
|
+
}
|
|
32018
|
+
function buildLocalAgentRecord(input) {
|
|
32019
|
+
const harness = harnessKindForPlatform(input.platform);
|
|
32020
|
+
const fortressId = fortressIdFromStoragePath(input.storagePath);
|
|
32021
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
32022
|
+
return {
|
|
32023
|
+
version: "1.1",
|
|
32024
|
+
agent_id: `agent:${harness}:${fortressId}`,
|
|
32025
|
+
identity_id: `fortress:${input.storagePath}`,
|
|
32026
|
+
harness,
|
|
32027
|
+
model_provider: {
|
|
32028
|
+
vendor: "unknown",
|
|
32029
|
+
model_id: "unknown",
|
|
32030
|
+
runs_locally: false
|
|
32031
|
+
},
|
|
32032
|
+
policy_id: "unbound",
|
|
32033
|
+
status: "active",
|
|
32034
|
+
budget_summary: {
|
|
32035
|
+
last_refreshed_at: nowIso
|
|
32036
|
+
},
|
|
32037
|
+
last_activity_at: nowIso,
|
|
32038
|
+
wrapped_at: nowIso,
|
|
32039
|
+
capabilities: {
|
|
32040
|
+
can_pause: false,
|
|
32041
|
+
can_resume: false,
|
|
32042
|
+
can_restart: false,
|
|
32043
|
+
can_unwrap: true,
|
|
32044
|
+
can_lockdown: false,
|
|
32045
|
+
can_chat: false,
|
|
32046
|
+
can_change_template: false
|
|
32047
|
+
}
|
|
32048
|
+
};
|
|
32049
|
+
}
|
|
31867
32050
|
function countUpstreamTools(servers) {
|
|
31868
32051
|
return servers.length === 0 ? 0 : servers.length;
|
|
31869
32052
|
}
|
|
@@ -31924,6 +32107,9 @@ function parseWrapArgs(argv) {
|
|
|
31924
32107
|
case "--no-open":
|
|
31925
32108
|
options.noOpen = true;
|
|
31926
32109
|
break;
|
|
32110
|
+
case "--no-dashboard":
|
|
32111
|
+
options.noDashboard = true;
|
|
32112
|
+
break;
|
|
31927
32113
|
case "--fortress":
|
|
31928
32114
|
options.fortress = argv[++i];
|
|
31929
32115
|
break;
|
|
@@ -31964,6 +32150,11 @@ function printWrapHelp() {
|
|
|
31964
32150
|
--port <port> Preferred dashboard port (default: 3501)
|
|
31965
32151
|
--dry-run Show what would happen without making changes
|
|
31966
32152
|
--no-open Do not auto-open the dashboard in a browser
|
|
32153
|
+
--no-dashboard Do not spawn a per-call dashboard server. Wrap still
|
|
32154
|
+
persists the agent record so a separately-running
|
|
32155
|
+
\`sanctuary dashboard\` (or a later wrap) sees the
|
|
32156
|
+
harness. Use this for the clean operator setup
|
|
32157
|
+
(one persistent dashboard + many wraps).
|
|
31967
32158
|
--help, -h Show this help
|
|
31968
32159
|
|
|
31969
32160
|
What happens:
|
|
@@ -31981,6 +32172,7 @@ var init_cli2 = __esm({
|
|
|
31981
32172
|
init_passphrase();
|
|
31982
32173
|
init_dashboard2();
|
|
31983
32174
|
init_wiring();
|
|
32175
|
+
init_agent_registry_persistence();
|
|
31984
32176
|
init_filesystem();
|
|
31985
32177
|
init_key_derivation();
|
|
31986
32178
|
init_encoding();
|
|
@@ -35618,7 +35810,12 @@ Refusing to start the dashboard while the reset-history marker is unreadable.`
|
|
|
35618
35810
|
buildV11Bindings({
|
|
35619
35811
|
identityId: hubIdentityId,
|
|
35620
35812
|
fortressId: fortressIdFromStoragePath(config.storage_path),
|
|
35621
|
-
auditLog
|
|
35813
|
+
auditLog,
|
|
35814
|
+
// v1.1.5 (Finding Z): rehydrate the hub agent registry from
|
|
35815
|
+
// `<storagePath>/state/_hub/local-agents.json` so the standalone
|
|
35816
|
+
// dashboard surfaces wraps performed by prior `sanctuary wrap`
|
|
35817
|
+
// invocations against this same fortress.
|
|
35818
|
+
storagePath: config.storage_path
|
|
35622
35819
|
})
|
|
35623
35820
|
);
|
|
35624
35821
|
const hostIsLoopback = dashboardHost === "127.0.0.1" || dashboardHost === "::1" || dashboardHost === "localhost";
|
|
@@ -35648,6 +35845,10 @@ Refusing to start the dashboard while the reset-history marker is unreadable.`
|
|
|
35648
35845
|
console.error(`Sanctuary Dashboard v${SANCTUARY_VERSION} (standalone mode)`);
|
|
35649
35846
|
console.error(`Storage: ${config.storage_path}`);
|
|
35650
35847
|
console.error(`Identities loaded: ${loadResult.loaded}`);
|
|
35848
|
+
const persistedAgentsCount = readPersistedLocalAgents(
|
|
35849
|
+
config.storage_path
|
|
35850
|
+
).length;
|
|
35851
|
+
console.error(`Local agents loaded: ${persistedAgentsCount}`);
|
|
35651
35852
|
console.error(`Listening: http://${dashboardHost}:${dashboardPort}`);
|
|
35652
35853
|
if (loadResult.total > 0 && loadResult.loaded === 0) {
|
|
35653
35854
|
const service = keychainServiceFor(config.storage_path, os.homedir());
|
|
@@ -35706,6 +35907,7 @@ var init_dashboard_standalone = __esm({
|
|
|
35706
35907
|
init_recovery_key_disclosure();
|
|
35707
35908
|
init_discovery();
|
|
35708
35909
|
init_wiring();
|
|
35910
|
+
init_agent_registry_persistence();
|
|
35709
35911
|
}
|
|
35710
35912
|
});
|
|
35711
35913
|
|