@sanctuary-framework/mcp-server 1.2.2 → 1.2.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 +444 -89
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +444 -89
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +161 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +162 -37
- package/dist/index.js.map +1 -1
- package/package.json +17 -16
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { gcm } from '@noble/ciphers/aes.js';
|
|
|
3
3
|
import { sha256 } from '@noble/hashes/sha256';
|
|
4
4
|
import { hmac } from '@noble/hashes/hmac';
|
|
5
5
|
import { RistrettoPoint, ed25519 } from '@noble/curves/ed25519';
|
|
6
|
-
import { readFile, mkdir, writeFile, stat, unlink, readdir, chmod, lstat, realpath, rm,
|
|
6
|
+
import { readFile, mkdir, writeFile, stat, unlink, readdir, chmod, lstat, access, realpath, rm, constants } from 'fs/promises';
|
|
7
7
|
import { join, resolve, dirname, sep, basename } from 'path';
|
|
8
8
|
import os, { platform, homedir } from 'os';
|
|
9
9
|
import { createRequire } from 'module';
|
|
@@ -4436,13 +4436,23 @@ function parseScalar(value) {
|
|
|
4436
4436
|
return value.replace(/^["']|["']$/g, "");
|
|
4437
4437
|
}
|
|
4438
4438
|
function validatePolicy(raw) {
|
|
4439
|
+
if (!("tier1_always_approve" in raw)) {
|
|
4440
|
+
throw new Error(
|
|
4441
|
+
"Policy file must include 'tier1_always_approve' as an explicit list (use [] for empty). Remove specific entries instead of removing the whole key."
|
|
4442
|
+
);
|
|
4443
|
+
}
|
|
4444
|
+
if (!("approval_channel" in raw)) {
|
|
4445
|
+
throw new Error(
|
|
4446
|
+
"Policy file must include 'approval_channel' as an explicit object (use {} for defaults). Remove specific entries instead of removing the whole key."
|
|
4447
|
+
);
|
|
4448
|
+
}
|
|
4439
4449
|
const userTier3 = raw.tier3_always_allow ?? [];
|
|
4440
4450
|
const mergedTier3 = [
|
|
4441
4451
|
.../* @__PURE__ */ new Set([...userTier3, ...DEFAULT_POLICY.tier3_always_allow])
|
|
4442
4452
|
];
|
|
4443
4453
|
return {
|
|
4444
4454
|
version: raw.version ?? 1,
|
|
4445
|
-
tier1_always_approve: raw.tier1_always_approve
|
|
4455
|
+
tier1_always_approve: raw.tier1_always_approve,
|
|
4446
4456
|
tier2_anomaly: {
|
|
4447
4457
|
...DEFAULT_TIER2,
|
|
4448
4458
|
...raw.tier2_anomaly ?? {}
|
|
@@ -4463,6 +4473,11 @@ function generateDefaultPolicyYaml() {
|
|
|
4463
4473
|
# This file controls what your agent can do without asking.
|
|
4464
4474
|
# Edit this file directly. Your agent cannot modify it.
|
|
4465
4475
|
# Changes take effect on server restart.
|
|
4476
|
+
#
|
|
4477
|
+
# Required keys (must be present; use [] or {} for empty):
|
|
4478
|
+
# tier1_always_approve, approval_channel
|
|
4479
|
+
# Optional keys (omit to use defaults; new defaults merge automatically):
|
|
4480
|
+
# tier2_anomaly, tier3_always_allow
|
|
4466
4481
|
|
|
4467
4482
|
version: 1
|
|
4468
4483
|
|
|
@@ -11113,10 +11128,11 @@ function initTemplate(params) {
|
|
|
11113
11128
|
var DEFAULT_STORAGE_DIR = ".sanctuary";
|
|
11114
11129
|
var KEYCHAIN_SERVICE_DEFAULT = "sanctuary-passphrase";
|
|
11115
11130
|
function keychainServiceFor(storagePath, home = homedir()) {
|
|
11116
|
-
const defaultPath = join(home, DEFAULT_STORAGE_DIR);
|
|
11117
|
-
|
|
11118
|
-
|
|
11119
|
-
const
|
|
11131
|
+
const defaultPath = resolve(join(home, DEFAULT_STORAGE_DIR));
|
|
11132
|
+
const canonicalStorage = resolve(storagePath);
|
|
11133
|
+
if (canonicalStorage === defaultPath) return KEYCHAIN_SERVICE_DEFAULT;
|
|
11134
|
+
const digest = sha256(Buffer.from(canonicalStorage, "utf-8"));
|
|
11135
|
+
const suffix = Buffer.from(digest).toString("hex").slice(0, 16);
|
|
11120
11136
|
return `${KEYCHAIN_SERVICE_DEFAULT}-${suffix}`;
|
|
11121
11137
|
}
|
|
11122
11138
|
var RUNTIME_FILE_NAME = "runtime.json";
|
|
@@ -11257,7 +11273,7 @@ async function discoverTenants(options = {}) {
|
|
|
11257
11273
|
for (const child of children) {
|
|
11258
11274
|
const childPath = join(root, child);
|
|
11259
11275
|
if (child.startsWith(".")) continue;
|
|
11260
|
-
if (child === "state" || child === "backup" || child === "config") continue;
|
|
11276
|
+
if (child === "state" || child === "backup" || child === "config" || child === "default") continue;
|
|
11261
11277
|
const s = await stat(childPath).catch(() => null);
|
|
11262
11278
|
if (!s || !s.isDirectory()) continue;
|
|
11263
11279
|
const desc = await describeTenant(child, childPath, home);
|
|
@@ -11269,6 +11285,17 @@ async function discoverTenants(options = {}) {
|
|
|
11269
11285
|
const desc = await describeTenant(basename(extra), extra, home);
|
|
11270
11286
|
if (desc) tenants.push(desc);
|
|
11271
11287
|
}
|
|
11288
|
+
const seen = /* @__PURE__ */ new Map();
|
|
11289
|
+
for (const t of tenants) {
|
|
11290
|
+
seen.set(t.name, (seen.get(t.name) ?? 0) + 1);
|
|
11291
|
+
}
|
|
11292
|
+
for (const [name, count] of seen) {
|
|
11293
|
+
if (count > 1) {
|
|
11294
|
+
console.error(
|
|
11295
|
+
`[sanctuary] warning: ${count} tenants share the name "${name}". Use --tenant with a unique name or storage path to disambiguate.`
|
|
11296
|
+
);
|
|
11297
|
+
}
|
|
11298
|
+
}
|
|
11272
11299
|
tenants.sort((a, b) => {
|
|
11273
11300
|
if (a.name === "default") return -1;
|
|
11274
11301
|
if (b.name === "default") return 1;
|
|
@@ -15637,6 +15664,8 @@ var IntelligenceRouterError = class extends Error {
|
|
|
15637
15664
|
this.code = code;
|
|
15638
15665
|
this.name = "IntelligenceRouterError";
|
|
15639
15666
|
}
|
|
15667
|
+
statusCode;
|
|
15668
|
+
code;
|
|
15640
15669
|
};
|
|
15641
15670
|
function writeJSON3(res, status, payload) {
|
|
15642
15671
|
res.writeHead(status, {
|
|
@@ -16220,7 +16249,7 @@ var DashboardApprovalChannel = class {
|
|
|
16220
16249
|
server = createServer$2(handler);
|
|
16221
16250
|
}
|
|
16222
16251
|
this.httpServer = server;
|
|
16223
|
-
return new Promise((
|
|
16252
|
+
return new Promise((resolve6, reject) => {
|
|
16224
16253
|
const protocol = this.useTLS ? "https" : "http";
|
|
16225
16254
|
const baseUrl = `${protocol}://${this.config.host}:${this.config.port}`;
|
|
16226
16255
|
server.listen(this.config.port, this.config.host, () => {
|
|
@@ -16245,7 +16274,7 @@ var DashboardApprovalChannel = class {
|
|
|
16245
16274
|
if (shouldAutoOpen) {
|
|
16246
16275
|
this.openInBrowser(sessionUrl);
|
|
16247
16276
|
}
|
|
16248
|
-
|
|
16277
|
+
resolve6();
|
|
16249
16278
|
});
|
|
16250
16279
|
server.on("error", (err) => {
|
|
16251
16280
|
if (err.code === "EADDRINUSE") {
|
|
@@ -16291,8 +16320,8 @@ var DashboardApprovalChannel = class {
|
|
|
16291
16320
|
}
|
|
16292
16321
|
this.rateLimits.clear();
|
|
16293
16322
|
if (this.httpServer) {
|
|
16294
|
-
return new Promise((
|
|
16295
|
-
this.httpServer.close(() =>
|
|
16323
|
+
return new Promise((resolve6) => {
|
|
16324
|
+
this.httpServer.close(() => resolve6());
|
|
16296
16325
|
});
|
|
16297
16326
|
}
|
|
16298
16327
|
}
|
|
@@ -16306,7 +16335,7 @@ var DashboardApprovalChannel = class {
|
|
|
16306
16335
|
`[Sanctuary] Approval required: ${request.operation} (Tier ${request.tier}) \u2014 open dashboard to respond
|
|
16307
16336
|
`
|
|
16308
16337
|
);
|
|
16309
|
-
return new Promise((
|
|
16338
|
+
return new Promise((resolve6) => {
|
|
16310
16339
|
const timer = setTimeout(() => {
|
|
16311
16340
|
this.pending.delete(id);
|
|
16312
16341
|
const response = {
|
|
@@ -16320,12 +16349,12 @@ var DashboardApprovalChannel = class {
|
|
|
16320
16349
|
decision: response.decision,
|
|
16321
16350
|
decided_by: "timeout"
|
|
16322
16351
|
});
|
|
16323
|
-
|
|
16352
|
+
resolve6(response);
|
|
16324
16353
|
}, this.config.timeout_seconds * 1e3);
|
|
16325
16354
|
const pending = {
|
|
16326
16355
|
id,
|
|
16327
16356
|
request,
|
|
16328
|
-
resolve:
|
|
16357
|
+
resolve: resolve6,
|
|
16329
16358
|
timer,
|
|
16330
16359
|
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
16331
16360
|
};
|
|
@@ -17186,7 +17215,7 @@ var WebhookApprovalChannel = class {
|
|
|
17186
17215
|
* Start the callback listener server.
|
|
17187
17216
|
*/
|
|
17188
17217
|
async start() {
|
|
17189
|
-
return new Promise((
|
|
17218
|
+
return new Promise((resolve6, reject) => {
|
|
17190
17219
|
this.callbackServer = createServer$2(
|
|
17191
17220
|
(req, res) => this.handleCallback(req, res)
|
|
17192
17221
|
);
|
|
@@ -17201,7 +17230,7 @@ var WebhookApprovalChannel = class {
|
|
|
17201
17230
|
|
|
17202
17231
|
`
|
|
17203
17232
|
);
|
|
17204
|
-
|
|
17233
|
+
resolve6();
|
|
17205
17234
|
}
|
|
17206
17235
|
);
|
|
17207
17236
|
this.callbackServer.on("error", reject);
|
|
@@ -17221,8 +17250,8 @@ var WebhookApprovalChannel = class {
|
|
|
17221
17250
|
}
|
|
17222
17251
|
this.pending.clear();
|
|
17223
17252
|
if (this.callbackServer) {
|
|
17224
|
-
return new Promise((
|
|
17225
|
-
this.callbackServer.close(() =>
|
|
17253
|
+
return new Promise((resolve6) => {
|
|
17254
|
+
this.callbackServer.close(() => resolve6());
|
|
17226
17255
|
});
|
|
17227
17256
|
}
|
|
17228
17257
|
}
|
|
@@ -17235,7 +17264,7 @@ var WebhookApprovalChannel = class {
|
|
|
17235
17264
|
`[Sanctuary] Webhook approval sent: ${request.operation} (Tier ${request.tier}) \u2014 awaiting callback
|
|
17236
17265
|
`
|
|
17237
17266
|
);
|
|
17238
|
-
return new Promise((
|
|
17267
|
+
return new Promise((resolve6) => {
|
|
17239
17268
|
const timer = setTimeout(() => {
|
|
17240
17269
|
this.pending.delete(id);
|
|
17241
17270
|
const response = {
|
|
@@ -17244,12 +17273,12 @@ var WebhookApprovalChannel = class {
|
|
|
17244
17273
|
decided_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17245
17274
|
decided_by: "timeout"
|
|
17246
17275
|
};
|
|
17247
|
-
|
|
17276
|
+
resolve6(response);
|
|
17248
17277
|
}, this.config.timeout_seconds * 1e3);
|
|
17249
17278
|
const pending = {
|
|
17250
17279
|
id,
|
|
17251
17280
|
request,
|
|
17252
|
-
resolve:
|
|
17281
|
+
resolve: resolve6,
|
|
17253
17282
|
timer,
|
|
17254
17283
|
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
17255
17284
|
};
|
|
@@ -18535,6 +18564,11 @@ var InjectionDetector = class {
|
|
|
18535
18564
|
}
|
|
18536
18565
|
};
|
|
18537
18566
|
|
|
18567
|
+
// src/principal-policy/deny-vocabulary.ts
|
|
18568
|
+
var AGENT_VISIBLE_DENY_REASONS = {
|
|
18569
|
+
REQUIRES_APPROVAL: "operation requires operator approval",
|
|
18570
|
+
NOT_PERMITTED: "operation not permitted"};
|
|
18571
|
+
|
|
18538
18572
|
// src/principal-policy/gate.ts
|
|
18539
18573
|
var ApprovalGate = class {
|
|
18540
18574
|
policy;
|
|
@@ -18587,10 +18621,16 @@ var ApprovalGate = class {
|
|
|
18587
18621
|
});
|
|
18588
18622
|
}
|
|
18589
18623
|
if (injectionResult.recommendation === "block") {
|
|
18624
|
+
this.auditLog.append("l2", `gate_injection_block:${operation}`, "system", {
|
|
18625
|
+
tier: 1,
|
|
18626
|
+
operation,
|
|
18627
|
+
injection_confidence: injectionResult.confidence,
|
|
18628
|
+
signal_count: injectionResult.signals.length
|
|
18629
|
+
});
|
|
18590
18630
|
return {
|
|
18591
18631
|
allowed: false,
|
|
18592
18632
|
tier: 1,
|
|
18593
|
-
reason:
|
|
18633
|
+
reason: AGENT_VISIBLE_DENY_REASONS.NOT_PERMITTED,
|
|
18594
18634
|
approval_required: false
|
|
18595
18635
|
};
|
|
18596
18636
|
}
|
|
@@ -18667,7 +18707,7 @@ var ApprovalGate = class {
|
|
|
18667
18707
|
this.auditLog.append("l2", `gate_unclassified:${operation}`, "system", {
|
|
18668
18708
|
tier: 1,
|
|
18669
18709
|
operation,
|
|
18670
|
-
warning: "Operation is not classified in any policy tier
|
|
18710
|
+
warning: "Operation is not classified in any policy tier, defaulting to Tier 1 (require approval)"
|
|
18671
18711
|
});
|
|
18672
18712
|
return this.requestApproval(
|
|
18673
18713
|
operation,
|
|
@@ -18796,7 +18836,7 @@ var ApprovalGate = class {
|
|
|
18796
18836
|
return {
|
|
18797
18837
|
allowed: response.decision === "approve",
|
|
18798
18838
|
tier,
|
|
18799
|
-
reason: response.decision === "approve" ? `Approved by ${response.decided_by}` :
|
|
18839
|
+
reason: response.decision === "approve" ? `Approved by ${response.decided_by}` : AGENT_VISIBLE_DENY_REASONS.REQUIRES_APPROVAL,
|
|
18800
18840
|
approval_required: true,
|
|
18801
18841
|
approval_response: response
|
|
18802
18842
|
};
|
|
@@ -19366,7 +19406,11 @@ init_identity();
|
|
|
19366
19406
|
init_encoding();
|
|
19367
19407
|
init_random();
|
|
19368
19408
|
function generateNonce() {
|
|
19369
|
-
|
|
19409
|
+
const nonce = randomBytes(32);
|
|
19410
|
+
if (!nonce || nonce.length !== 32) {
|
|
19411
|
+
throw new Error("Nonce generation failed: randomBytes returned unexpected length");
|
|
19412
|
+
}
|
|
19413
|
+
return toBase64url(nonce);
|
|
19370
19414
|
}
|
|
19371
19415
|
function initiateHandshake(ourSHR) {
|
|
19372
19416
|
const nonce = generateNonce();
|
|
@@ -19477,6 +19521,18 @@ function completeHandshake(response, session, identityManager, masterKey, identi
|
|
|
19477
19521
|
return { completion, result };
|
|
19478
19522
|
}
|
|
19479
19523
|
function verifyCompletion(completion, session) {
|
|
19524
|
+
if (completion.protocol_version !== "1.0") {
|
|
19525
|
+
return {
|
|
19526
|
+
counterparty_id: "unknown",
|
|
19527
|
+
counterparty_shr: session.our_shr,
|
|
19528
|
+
verified: false,
|
|
19529
|
+
sovereignty_level: "unverified",
|
|
19530
|
+
trust_tier: "unverified",
|
|
19531
|
+
completed_at: completion.completed_at,
|
|
19532
|
+
expires_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19533
|
+
errors: [`Unsupported protocol version: ${completion.protocol_version}`]
|
|
19534
|
+
};
|
|
19535
|
+
}
|
|
19480
19536
|
const errors = [];
|
|
19481
19537
|
if (!session.their_shr) {
|
|
19482
19538
|
return {
|
|
@@ -21578,6 +21634,9 @@ Inspect the file and either correct the JSON or delete it manually before re-run
|
|
|
21578
21634
|
this.cause = cause;
|
|
21579
21635
|
this.name = "ResetHistoryMalformedError";
|
|
21580
21636
|
}
|
|
21637
|
+
markerPath;
|
|
21638
|
+
lineNumber;
|
|
21639
|
+
cause;
|
|
21581
21640
|
};
|
|
21582
21641
|
function parseResetHistory(content, markerPath) {
|
|
21583
21642
|
const markerHash = hashToString(stringToBytes(content));
|
|
@@ -23819,7 +23878,7 @@ async function runOpenAIPrivacyFilter(text, config) {
|
|
|
23819
23878
|
return parsed;
|
|
23820
23879
|
}
|
|
23821
23880
|
function runCommand(command, input, timeoutMs) {
|
|
23822
|
-
return new Promise((
|
|
23881
|
+
return new Promise((resolve6, reject) => {
|
|
23823
23882
|
const child = spawn(command, [], {
|
|
23824
23883
|
stdio: ["pipe", "pipe", "pipe"],
|
|
23825
23884
|
shell: false
|
|
@@ -23850,7 +23909,7 @@ function runCommand(command, input, timeoutMs) {
|
|
|
23850
23909
|
));
|
|
23851
23910
|
return;
|
|
23852
23911
|
}
|
|
23853
|
-
|
|
23912
|
+
resolve6(stdout);
|
|
23854
23913
|
});
|
|
23855
23914
|
child.stdin.end(input);
|
|
23856
23915
|
});
|
|
@@ -25671,13 +25730,13 @@ var ProxyRouter = class {
|
|
|
25671
25730
|
* Call an upstream tool with a timeout.
|
|
25672
25731
|
*/
|
|
25673
25732
|
async callWithTimeout(serverName, toolName, args, timeoutMs) {
|
|
25674
|
-
return new Promise((
|
|
25733
|
+
return new Promise((resolve6, reject) => {
|
|
25675
25734
|
const timer = setTimeout(() => {
|
|
25676
25735
|
reject(new Error(`Upstream tool call timed out after ${timeoutMs}ms`));
|
|
25677
25736
|
}, timeoutMs);
|
|
25678
25737
|
this.clientManager.callTool(serverName, toolName, args).then((result) => {
|
|
25679
25738
|
clearTimeout(timer);
|
|
25680
|
-
|
|
25739
|
+
resolve6(result);
|
|
25681
25740
|
}).catch((err) => {
|
|
25682
25741
|
clearTimeout(timer);
|
|
25683
25742
|
reject(err);
|
|
@@ -30724,6 +30783,33 @@ var CONCIERGE_THREAD_KEY = "_fortress";
|
|
|
30724
30783
|
|
|
30725
30784
|
// src/chat/operator-chat-service.ts
|
|
30726
30785
|
var DEFAULT_CONCIERGE_MAX_TOKENS = 512;
|
|
30786
|
+
var SANCTUARY_DOMAIN_REFERENCE = `Castle Architecture (four enforcement layers):
|
|
30787
|
+
1. Castle Wall: OS-boundary egress filter enforced at the kernel level. Blocks unauthorized outbound calls even from prompt-injected agents.
|
|
30788
|
+
2. Sentinels: internal observation via process introspection. Surfaces anomalies to the operator; does not enforce.
|
|
30789
|
+
3. Charter (Cooperative MCP): the sovereignty surface for compliant agents. Policy gates, approval tiers, audit logging, and encrypted state all live here.
|
|
30790
|
+
4. Heralds: Concordia receipts and Verascore reputation. Cross-fortress accountability after an action completes.
|
|
30791
|
+
|
|
30792
|
+
Five channel templates (canonical names):
|
|
30793
|
+
- request-approve-act: agent proposes an action, operator approves or denies before execution.
|
|
30794
|
+
- read-then-report: agent reads outputs from a data source and reports summaries to the operator.
|
|
30795
|
+
- scheduled-digest: agent runs on a schedule and delivers a periodic digest.
|
|
30796
|
+
- plan-draft-only: agent drafts plans; operator reviews before any execution step.
|
|
30797
|
+
- fortress-relay: agent relays messages between fortresses under operator-scoped policy.
|
|
30798
|
+
|
|
30799
|
+
Four canonical policy slots:
|
|
30800
|
+
- memory: governs what the agent may persist and retrieve from encrypted state.
|
|
30801
|
+
- credentials: governs access to secrets, API keys, and tokens held in the broker.
|
|
30802
|
+
- plans: governs the agent's ability to create, modify, or execute plans.
|
|
30803
|
+
- outputs: governs what the agent may emit to external surfaces (files, APIs, messages).
|
|
30804
|
+
|
|
30805
|
+
Key concepts:
|
|
30806
|
+
- Fortress: the operator-owned sovereignty harness. All state is encrypted at rest under the cocoon.
|
|
30807
|
+
- Cocoon: master-key-wrapped storage derived from the operator's passphrase via Argon2id.
|
|
30808
|
+
- Identity: Ed25519 keypair with a DID, owned by the operator. Private keys never leave the cocoon.
|
|
30809
|
+
- Audit log: append-only encrypted blobs, sequential, recording every gate decision and tool call.
|
|
30810
|
+
- Wrapped agent: any agent runtime that connects to Sanctuary as an MCP client. Tier A (native), Tier B (adapter-wrapped), Tier C (escape hatch).
|
|
30811
|
+
|
|
30812
|
+
Note: this is a static reference block (v1.2.x). Dynamic context injection (live template list, policy schema) ships in v1.3.`;
|
|
30727
30813
|
var OperatorChatService = class {
|
|
30728
30814
|
store;
|
|
30729
30815
|
auditLog;
|
|
@@ -30868,6 +30954,9 @@ var OperatorChatService = class {
|
|
|
30868
30954
|
* than nested structures. Format:
|
|
30869
30955
|
*
|
|
30870
30956
|
* ```
|
|
30957
|
+
* ## Sanctuary reference
|
|
30958
|
+
* <static domain reference block>
|
|
30959
|
+
*
|
|
30871
30960
|
* ## Recent activity
|
|
30872
30961
|
* <recentActivity output>
|
|
30873
30962
|
*
|
|
@@ -30879,15 +30968,28 @@ var OperatorChatService = class {
|
|
|
30879
30968
|
* ```
|
|
30880
30969
|
*/
|
|
30881
30970
|
async assembleConciergeContext() {
|
|
30971
|
+
const ref = `## Sanctuary reference
|
|
30972
|
+
${SANCTUARY_DOMAIN_REFERENCE}`;
|
|
30882
30973
|
if (!this.contextProviders) {
|
|
30883
|
-
return
|
|
30974
|
+
return `${ref}
|
|
30975
|
+
|
|
30976
|
+
## Recent activity
|
|
30977
|
+
(no providers wired)
|
|
30978
|
+
|
|
30979
|
+
## Wrapped agents
|
|
30980
|
+
(no providers wired)
|
|
30981
|
+
|
|
30982
|
+
## Open inbox
|
|
30983
|
+
(no providers wired)`;
|
|
30884
30984
|
}
|
|
30885
30985
|
const [activity, agents, inbox] = await Promise.all([
|
|
30886
30986
|
this.contextProviders.recentActivity(),
|
|
30887
30987
|
this.contextProviders.agentInventory(),
|
|
30888
30988
|
this.contextProviders.openInbox()
|
|
30889
30989
|
]);
|
|
30890
|
-
return
|
|
30990
|
+
return `${ref}
|
|
30991
|
+
|
|
30992
|
+
## Recent activity
|
|
30891
30993
|
${activity}
|
|
30892
30994
|
|
|
30893
30995
|
## Wrapped agents
|
|
@@ -33992,6 +34094,9 @@ async function importExitBundle(opts) {
|
|
|
33992
34094
|
reputationArtifact?.json ?? null,
|
|
33993
34095
|
manifest
|
|
33994
34096
|
);
|
|
34097
|
+
if (!conflicts.public_identity_exists && identityArtifact?.json && opts.identityManager.getPrimaryIdentityId() !== null && opts.identityManager.getPrimaryIdentityId() !== identityArtifact.json.bundle.identity_id) {
|
|
34098
|
+
conflicts.public_identity_exists = true;
|
|
34099
|
+
}
|
|
33995
34100
|
if (!opts.activate) {
|
|
33996
34101
|
return {
|
|
33997
34102
|
verified: true,
|
|
@@ -34018,7 +34123,7 @@ async function importExitBundle(opts) {
|
|
|
34018
34123
|
if (conflicts.public_identity_exists && !opts.forceRebind) {
|
|
34019
34124
|
throw new ExitBundleImportError(
|
|
34020
34125
|
"IDENTITY_OVERWRITE_REFUSED",
|
|
34021
|
-
"Importing this bundle would overwrite an existing fortress public identity. Pass forceRebind: true (CLI: --force-rebind) to confirm explicit replacement."
|
|
34126
|
+
"Importing this exit bundle would overwrite an existing fortress public identity (either the same identity already imported, or a different identity is currently active). Pass forceRebind: true (CLI: --force-rebind) to confirm explicit replacement."
|
|
34022
34127
|
);
|
|
34023
34128
|
}
|
|
34024
34129
|
if (conflicts.public_identity_exists && opts.forceRebind && identityArtifact) {
|
|
@@ -34376,6 +34481,26 @@ async function runExitCommand(args) {
|
|
|
34376
34481
|
write(err, "Usage: sanctuary exit import <dir> [--activate]\n");
|
|
34377
34482
|
return 2;
|
|
34378
34483
|
}
|
|
34484
|
+
const bundleRoot = resolve(dir);
|
|
34485
|
+
try {
|
|
34486
|
+
await access(bundleRoot);
|
|
34487
|
+
} catch {
|
|
34488
|
+
write(err, `Error: bundle directory not found: ${bundleRoot}
|
|
34489
|
+
`);
|
|
34490
|
+
return 1;
|
|
34491
|
+
}
|
|
34492
|
+
const manifestPath = join(bundleRoot, "manifest.json");
|
|
34493
|
+
try {
|
|
34494
|
+
const raw = await readFile(manifestPath, "utf8");
|
|
34495
|
+
JSON.parse(raw);
|
|
34496
|
+
} catch {
|
|
34497
|
+
write(
|
|
34498
|
+
err,
|
|
34499
|
+
`Error: bundle manifest missing or malformed at ${manifestPath}
|
|
34500
|
+
`
|
|
34501
|
+
);
|
|
34502
|
+
return 1;
|
|
34503
|
+
}
|
|
34379
34504
|
const activate = hasFlag(argv, "--activate");
|
|
34380
34505
|
const forceRebind = hasFlag(argv, "--force-rebind");
|
|
34381
34506
|
const acceptUnverifiableAttestations = hasFlag(
|
|
@@ -34516,11 +34641,11 @@ async function startDashboardServer(options) {
|
|
|
34516
34641
|
}
|
|
34517
34642
|
}
|
|
34518
34643
|
});
|
|
34519
|
-
await new Promise((
|
|
34644
|
+
await new Promise((resolve6, reject) => {
|
|
34520
34645
|
server.once("error", reject);
|
|
34521
34646
|
server.listen(port, host, () => {
|
|
34522
34647
|
server.off("error", reject);
|
|
34523
|
-
|
|
34648
|
+
resolve6();
|
|
34524
34649
|
});
|
|
34525
34650
|
});
|
|
34526
34651
|
const actualPort = (() => {
|
|
@@ -34533,8 +34658,8 @@ async function startDashboardServer(options) {
|
|
|
34533
34658
|
url,
|
|
34534
34659
|
port: actualPort,
|
|
34535
34660
|
host,
|
|
34536
|
-
stop: () => new Promise((
|
|
34537
|
-
server.close((err) => err ? reject(err) :
|
|
34661
|
+
stop: () => new Promise((resolve6, reject) => {
|
|
34662
|
+
server.close((err) => err ? reject(err) : resolve6());
|
|
34538
34663
|
}),
|
|
34539
34664
|
publish,
|
|
34540
34665
|
publishActivity: (entry) => publish({ type: "activity", data: entry }),
|
|
@@ -35192,7 +35317,7 @@ Refusing to start the cocoon while the reset-history marker is unreadable.`
|
|
|
35192
35317
|
clientManager.configure(enabledServers).catch((err) => {
|
|
35193
35318
|
console.error(`[Sanctuary] Failed to configure upstream servers: ${err instanceof Error ? err.message : "unknown error"}`);
|
|
35194
35319
|
});
|
|
35195
|
-
await new Promise((
|
|
35320
|
+
await new Promise((resolve6) => setTimeout(resolve6, 2e3));
|
|
35196
35321
|
const proxiedTools = proxyRouter.getProxiedTools();
|
|
35197
35322
|
if (proxiedTools.length > 0) {
|
|
35198
35323
|
allTools.push(...proxiedTools);
|