@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.cjs
CHANGED
|
@@ -4443,13 +4443,23 @@ function parseScalar(value) {
|
|
|
4443
4443
|
return value.replace(/^["']|["']$/g, "");
|
|
4444
4444
|
}
|
|
4445
4445
|
function validatePolicy(raw) {
|
|
4446
|
+
if (!("tier1_always_approve" in raw)) {
|
|
4447
|
+
throw new Error(
|
|
4448
|
+
"Policy file must include 'tier1_always_approve' as an explicit list (use [] for empty). Remove specific entries instead of removing the whole key."
|
|
4449
|
+
);
|
|
4450
|
+
}
|
|
4451
|
+
if (!("approval_channel" in raw)) {
|
|
4452
|
+
throw new Error(
|
|
4453
|
+
"Policy file must include 'approval_channel' as an explicit object (use {} for defaults). Remove specific entries instead of removing the whole key."
|
|
4454
|
+
);
|
|
4455
|
+
}
|
|
4446
4456
|
const userTier3 = raw.tier3_always_allow ?? [];
|
|
4447
4457
|
const mergedTier3 = [
|
|
4448
4458
|
.../* @__PURE__ */ new Set([...userTier3, ...DEFAULT_POLICY.tier3_always_allow])
|
|
4449
4459
|
];
|
|
4450
4460
|
return {
|
|
4451
4461
|
version: raw.version ?? 1,
|
|
4452
|
-
tier1_always_approve: raw.tier1_always_approve
|
|
4462
|
+
tier1_always_approve: raw.tier1_always_approve,
|
|
4453
4463
|
tier2_anomaly: {
|
|
4454
4464
|
...DEFAULT_TIER2,
|
|
4455
4465
|
...raw.tier2_anomaly ?? {}
|
|
@@ -4470,6 +4480,11 @@ function generateDefaultPolicyYaml() {
|
|
|
4470
4480
|
# This file controls what your agent can do without asking.
|
|
4471
4481
|
# Edit this file directly. Your agent cannot modify it.
|
|
4472
4482
|
# Changes take effect on server restart.
|
|
4483
|
+
#
|
|
4484
|
+
# Required keys (must be present; use [] or {} for empty):
|
|
4485
|
+
# tier1_always_approve, approval_channel
|
|
4486
|
+
# Optional keys (omit to use defaults; new defaults merge automatically):
|
|
4487
|
+
# tier2_anomaly, tier3_always_allow
|
|
4473
4488
|
|
|
4474
4489
|
version: 1
|
|
4475
4490
|
|
|
@@ -11120,10 +11135,11 @@ function initTemplate(params) {
|
|
|
11120
11135
|
var DEFAULT_STORAGE_DIR = ".sanctuary";
|
|
11121
11136
|
var KEYCHAIN_SERVICE_DEFAULT = "sanctuary-passphrase";
|
|
11122
11137
|
function keychainServiceFor(storagePath, home = os.homedir()) {
|
|
11123
|
-
const defaultPath = path.join(home, DEFAULT_STORAGE_DIR);
|
|
11124
|
-
|
|
11125
|
-
|
|
11126
|
-
const
|
|
11138
|
+
const defaultPath = path.resolve(path.join(home, DEFAULT_STORAGE_DIR));
|
|
11139
|
+
const canonicalStorage = path.resolve(storagePath);
|
|
11140
|
+
if (canonicalStorage === defaultPath) return KEYCHAIN_SERVICE_DEFAULT;
|
|
11141
|
+
const digest = sha256.sha256(Buffer.from(canonicalStorage, "utf-8"));
|
|
11142
|
+
const suffix = Buffer.from(digest).toString("hex").slice(0, 16);
|
|
11127
11143
|
return `${KEYCHAIN_SERVICE_DEFAULT}-${suffix}`;
|
|
11128
11144
|
}
|
|
11129
11145
|
var RUNTIME_FILE_NAME = "runtime.json";
|
|
@@ -11264,7 +11280,7 @@ async function discoverTenants(options = {}) {
|
|
|
11264
11280
|
for (const child of children) {
|
|
11265
11281
|
const childPath = path.join(root, child);
|
|
11266
11282
|
if (child.startsWith(".")) continue;
|
|
11267
|
-
if (child === "state" || child === "backup" || child === "config") continue;
|
|
11283
|
+
if (child === "state" || child === "backup" || child === "config" || child === "default") continue;
|
|
11268
11284
|
const s = await promises.stat(childPath).catch(() => null);
|
|
11269
11285
|
if (!s || !s.isDirectory()) continue;
|
|
11270
11286
|
const desc = await describeTenant(child, childPath, home);
|
|
@@ -11276,6 +11292,17 @@ async function discoverTenants(options = {}) {
|
|
|
11276
11292
|
const desc = await describeTenant(path.basename(extra), extra, home);
|
|
11277
11293
|
if (desc) tenants.push(desc);
|
|
11278
11294
|
}
|
|
11295
|
+
const seen = /* @__PURE__ */ new Map();
|
|
11296
|
+
for (const t of tenants) {
|
|
11297
|
+
seen.set(t.name, (seen.get(t.name) ?? 0) + 1);
|
|
11298
|
+
}
|
|
11299
|
+
for (const [name, count] of seen) {
|
|
11300
|
+
if (count > 1) {
|
|
11301
|
+
console.error(
|
|
11302
|
+
`[sanctuary] warning: ${count} tenants share the name "${name}". Use --tenant with a unique name or storage path to disambiguate.`
|
|
11303
|
+
);
|
|
11304
|
+
}
|
|
11305
|
+
}
|
|
11279
11306
|
tenants.sort((a, b) => {
|
|
11280
11307
|
if (a.name === "default") return -1;
|
|
11281
11308
|
if (b.name === "default") return 1;
|
|
@@ -15644,6 +15671,8 @@ var IntelligenceRouterError = class extends Error {
|
|
|
15644
15671
|
this.code = code;
|
|
15645
15672
|
this.name = "IntelligenceRouterError";
|
|
15646
15673
|
}
|
|
15674
|
+
statusCode;
|
|
15675
|
+
code;
|
|
15647
15676
|
};
|
|
15648
15677
|
function writeJSON3(res, status, payload) {
|
|
15649
15678
|
res.writeHead(status, {
|
|
@@ -16227,7 +16256,7 @@ var DashboardApprovalChannel = class {
|
|
|
16227
16256
|
server = http.createServer(handler);
|
|
16228
16257
|
}
|
|
16229
16258
|
this.httpServer = server;
|
|
16230
|
-
return new Promise((
|
|
16259
|
+
return new Promise((resolve6, reject) => {
|
|
16231
16260
|
const protocol = this.useTLS ? "https" : "http";
|
|
16232
16261
|
const baseUrl = `${protocol}://${this.config.host}:${this.config.port}`;
|
|
16233
16262
|
server.listen(this.config.port, this.config.host, () => {
|
|
@@ -16252,7 +16281,7 @@ var DashboardApprovalChannel = class {
|
|
|
16252
16281
|
if (shouldAutoOpen) {
|
|
16253
16282
|
this.openInBrowser(sessionUrl);
|
|
16254
16283
|
}
|
|
16255
|
-
|
|
16284
|
+
resolve6();
|
|
16256
16285
|
});
|
|
16257
16286
|
server.on("error", (err) => {
|
|
16258
16287
|
if (err.code === "EADDRINUSE") {
|
|
@@ -16298,8 +16327,8 @@ var DashboardApprovalChannel = class {
|
|
|
16298
16327
|
}
|
|
16299
16328
|
this.rateLimits.clear();
|
|
16300
16329
|
if (this.httpServer) {
|
|
16301
|
-
return new Promise((
|
|
16302
|
-
this.httpServer.close(() =>
|
|
16330
|
+
return new Promise((resolve6) => {
|
|
16331
|
+
this.httpServer.close(() => resolve6());
|
|
16303
16332
|
});
|
|
16304
16333
|
}
|
|
16305
16334
|
}
|
|
@@ -16313,7 +16342,7 @@ var DashboardApprovalChannel = class {
|
|
|
16313
16342
|
`[Sanctuary] Approval required: ${request.operation} (Tier ${request.tier}) \u2014 open dashboard to respond
|
|
16314
16343
|
`
|
|
16315
16344
|
);
|
|
16316
|
-
return new Promise((
|
|
16345
|
+
return new Promise((resolve6) => {
|
|
16317
16346
|
const timer = setTimeout(() => {
|
|
16318
16347
|
this.pending.delete(id);
|
|
16319
16348
|
const response = {
|
|
@@ -16327,12 +16356,12 @@ var DashboardApprovalChannel = class {
|
|
|
16327
16356
|
decision: response.decision,
|
|
16328
16357
|
decided_by: "timeout"
|
|
16329
16358
|
});
|
|
16330
|
-
|
|
16359
|
+
resolve6(response);
|
|
16331
16360
|
}, this.config.timeout_seconds * 1e3);
|
|
16332
16361
|
const pending = {
|
|
16333
16362
|
id,
|
|
16334
16363
|
request,
|
|
16335
|
-
resolve:
|
|
16364
|
+
resolve: resolve6,
|
|
16336
16365
|
timer,
|
|
16337
16366
|
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
16338
16367
|
};
|
|
@@ -17193,7 +17222,7 @@ var WebhookApprovalChannel = class {
|
|
|
17193
17222
|
* Start the callback listener server.
|
|
17194
17223
|
*/
|
|
17195
17224
|
async start() {
|
|
17196
|
-
return new Promise((
|
|
17225
|
+
return new Promise((resolve6, reject) => {
|
|
17197
17226
|
this.callbackServer = http.createServer(
|
|
17198
17227
|
(req, res) => this.handleCallback(req, res)
|
|
17199
17228
|
);
|
|
@@ -17208,7 +17237,7 @@ var WebhookApprovalChannel = class {
|
|
|
17208
17237
|
|
|
17209
17238
|
`
|
|
17210
17239
|
);
|
|
17211
|
-
|
|
17240
|
+
resolve6();
|
|
17212
17241
|
}
|
|
17213
17242
|
);
|
|
17214
17243
|
this.callbackServer.on("error", reject);
|
|
@@ -17228,8 +17257,8 @@ var WebhookApprovalChannel = class {
|
|
|
17228
17257
|
}
|
|
17229
17258
|
this.pending.clear();
|
|
17230
17259
|
if (this.callbackServer) {
|
|
17231
|
-
return new Promise((
|
|
17232
|
-
this.callbackServer.close(() =>
|
|
17260
|
+
return new Promise((resolve6) => {
|
|
17261
|
+
this.callbackServer.close(() => resolve6());
|
|
17233
17262
|
});
|
|
17234
17263
|
}
|
|
17235
17264
|
}
|
|
@@ -17242,7 +17271,7 @@ var WebhookApprovalChannel = class {
|
|
|
17242
17271
|
`[Sanctuary] Webhook approval sent: ${request.operation} (Tier ${request.tier}) \u2014 awaiting callback
|
|
17243
17272
|
`
|
|
17244
17273
|
);
|
|
17245
|
-
return new Promise((
|
|
17274
|
+
return new Promise((resolve6) => {
|
|
17246
17275
|
const timer = setTimeout(() => {
|
|
17247
17276
|
this.pending.delete(id);
|
|
17248
17277
|
const response = {
|
|
@@ -17251,12 +17280,12 @@ var WebhookApprovalChannel = class {
|
|
|
17251
17280
|
decided_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17252
17281
|
decided_by: "timeout"
|
|
17253
17282
|
};
|
|
17254
|
-
|
|
17283
|
+
resolve6(response);
|
|
17255
17284
|
}, this.config.timeout_seconds * 1e3);
|
|
17256
17285
|
const pending = {
|
|
17257
17286
|
id,
|
|
17258
17287
|
request,
|
|
17259
|
-
resolve:
|
|
17288
|
+
resolve: resolve6,
|
|
17260
17289
|
timer,
|
|
17261
17290
|
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
17262
17291
|
};
|
|
@@ -18542,6 +18571,11 @@ var InjectionDetector = class {
|
|
|
18542
18571
|
}
|
|
18543
18572
|
};
|
|
18544
18573
|
|
|
18574
|
+
// src/principal-policy/deny-vocabulary.ts
|
|
18575
|
+
var AGENT_VISIBLE_DENY_REASONS = {
|
|
18576
|
+
REQUIRES_APPROVAL: "operation requires operator approval",
|
|
18577
|
+
NOT_PERMITTED: "operation not permitted"};
|
|
18578
|
+
|
|
18545
18579
|
// src/principal-policy/gate.ts
|
|
18546
18580
|
var ApprovalGate = class {
|
|
18547
18581
|
policy;
|
|
@@ -18594,10 +18628,16 @@ var ApprovalGate = class {
|
|
|
18594
18628
|
});
|
|
18595
18629
|
}
|
|
18596
18630
|
if (injectionResult.recommendation === "block") {
|
|
18631
|
+
this.auditLog.append("l2", `gate_injection_block:${operation}`, "system", {
|
|
18632
|
+
tier: 1,
|
|
18633
|
+
operation,
|
|
18634
|
+
injection_confidence: injectionResult.confidence,
|
|
18635
|
+
signal_count: injectionResult.signals.length
|
|
18636
|
+
});
|
|
18597
18637
|
return {
|
|
18598
18638
|
allowed: false,
|
|
18599
18639
|
tier: 1,
|
|
18600
|
-
reason:
|
|
18640
|
+
reason: AGENT_VISIBLE_DENY_REASONS.NOT_PERMITTED,
|
|
18601
18641
|
approval_required: false
|
|
18602
18642
|
};
|
|
18603
18643
|
}
|
|
@@ -18674,7 +18714,7 @@ var ApprovalGate = class {
|
|
|
18674
18714
|
this.auditLog.append("l2", `gate_unclassified:${operation}`, "system", {
|
|
18675
18715
|
tier: 1,
|
|
18676
18716
|
operation,
|
|
18677
|
-
warning: "Operation is not classified in any policy tier
|
|
18717
|
+
warning: "Operation is not classified in any policy tier, defaulting to Tier 1 (require approval)"
|
|
18678
18718
|
});
|
|
18679
18719
|
return this.requestApproval(
|
|
18680
18720
|
operation,
|
|
@@ -18803,7 +18843,7 @@ var ApprovalGate = class {
|
|
|
18803
18843
|
return {
|
|
18804
18844
|
allowed: response.decision === "approve",
|
|
18805
18845
|
tier,
|
|
18806
|
-
reason: response.decision === "approve" ? `Approved by ${response.decided_by}` :
|
|
18846
|
+
reason: response.decision === "approve" ? `Approved by ${response.decided_by}` : AGENT_VISIBLE_DENY_REASONS.REQUIRES_APPROVAL,
|
|
18807
18847
|
approval_required: true,
|
|
18808
18848
|
approval_response: response
|
|
18809
18849
|
};
|
|
@@ -19373,7 +19413,11 @@ init_identity();
|
|
|
19373
19413
|
init_encoding();
|
|
19374
19414
|
init_random();
|
|
19375
19415
|
function generateNonce() {
|
|
19376
|
-
|
|
19416
|
+
const nonce = randomBytes(32);
|
|
19417
|
+
if (!nonce || nonce.length !== 32) {
|
|
19418
|
+
throw new Error("Nonce generation failed: randomBytes returned unexpected length");
|
|
19419
|
+
}
|
|
19420
|
+
return toBase64url(nonce);
|
|
19377
19421
|
}
|
|
19378
19422
|
function initiateHandshake(ourSHR) {
|
|
19379
19423
|
const nonce = generateNonce();
|
|
@@ -19484,6 +19528,18 @@ function completeHandshake(response, session, identityManager, masterKey, identi
|
|
|
19484
19528
|
return { completion, result };
|
|
19485
19529
|
}
|
|
19486
19530
|
function verifyCompletion(completion, session) {
|
|
19531
|
+
if (completion.protocol_version !== "1.0") {
|
|
19532
|
+
return {
|
|
19533
|
+
counterparty_id: "unknown",
|
|
19534
|
+
counterparty_shr: session.our_shr,
|
|
19535
|
+
verified: false,
|
|
19536
|
+
sovereignty_level: "unverified",
|
|
19537
|
+
trust_tier: "unverified",
|
|
19538
|
+
completed_at: completion.completed_at,
|
|
19539
|
+
expires_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19540
|
+
errors: [`Unsupported protocol version: ${completion.protocol_version}`]
|
|
19541
|
+
};
|
|
19542
|
+
}
|
|
19487
19543
|
const errors = [];
|
|
19488
19544
|
if (!session.their_shr) {
|
|
19489
19545
|
return {
|
|
@@ -21585,6 +21641,9 @@ Inspect the file and either correct the JSON or delete it manually before re-run
|
|
|
21585
21641
|
this.cause = cause;
|
|
21586
21642
|
this.name = "ResetHistoryMalformedError";
|
|
21587
21643
|
}
|
|
21644
|
+
markerPath;
|
|
21645
|
+
lineNumber;
|
|
21646
|
+
cause;
|
|
21588
21647
|
};
|
|
21589
21648
|
function parseResetHistory(content, markerPath) {
|
|
21590
21649
|
const markerHash = hashToString(stringToBytes(content));
|
|
@@ -23826,7 +23885,7 @@ async function runOpenAIPrivacyFilter(text, config) {
|
|
|
23826
23885
|
return parsed;
|
|
23827
23886
|
}
|
|
23828
23887
|
function runCommand(command, input, timeoutMs) {
|
|
23829
|
-
return new Promise((
|
|
23888
|
+
return new Promise((resolve6, reject) => {
|
|
23830
23889
|
const child = child_process.spawn(command, [], {
|
|
23831
23890
|
stdio: ["pipe", "pipe", "pipe"],
|
|
23832
23891
|
shell: false
|
|
@@ -23857,7 +23916,7 @@ function runCommand(command, input, timeoutMs) {
|
|
|
23857
23916
|
));
|
|
23858
23917
|
return;
|
|
23859
23918
|
}
|
|
23860
|
-
|
|
23919
|
+
resolve6(stdout);
|
|
23861
23920
|
});
|
|
23862
23921
|
child.stdin.end(input);
|
|
23863
23922
|
});
|
|
@@ -25678,13 +25737,13 @@ var ProxyRouter = class {
|
|
|
25678
25737
|
* Call an upstream tool with a timeout.
|
|
25679
25738
|
*/
|
|
25680
25739
|
async callWithTimeout(serverName, toolName, args, timeoutMs) {
|
|
25681
|
-
return new Promise((
|
|
25740
|
+
return new Promise((resolve6, reject) => {
|
|
25682
25741
|
const timer = setTimeout(() => {
|
|
25683
25742
|
reject(new Error(`Upstream tool call timed out after ${timeoutMs}ms`));
|
|
25684
25743
|
}, timeoutMs);
|
|
25685
25744
|
this.clientManager.callTool(serverName, toolName, args).then((result) => {
|
|
25686
25745
|
clearTimeout(timer);
|
|
25687
|
-
|
|
25746
|
+
resolve6(result);
|
|
25688
25747
|
}).catch((err) => {
|
|
25689
25748
|
clearTimeout(timer);
|
|
25690
25749
|
reject(err);
|
|
@@ -30731,6 +30790,33 @@ var CONCIERGE_THREAD_KEY = "_fortress";
|
|
|
30731
30790
|
|
|
30732
30791
|
// src/chat/operator-chat-service.ts
|
|
30733
30792
|
var DEFAULT_CONCIERGE_MAX_TOKENS = 512;
|
|
30793
|
+
var SANCTUARY_DOMAIN_REFERENCE = `Castle Architecture (four enforcement layers):
|
|
30794
|
+
1. Castle Wall: OS-boundary egress filter enforced at the kernel level. Blocks unauthorized outbound calls even from prompt-injected agents.
|
|
30795
|
+
2. Sentinels: internal observation via process introspection. Surfaces anomalies to the operator; does not enforce.
|
|
30796
|
+
3. Charter (Cooperative MCP): the sovereignty surface for compliant agents. Policy gates, approval tiers, audit logging, and encrypted state all live here.
|
|
30797
|
+
4. Heralds: Concordia receipts and Verascore reputation. Cross-fortress accountability after an action completes.
|
|
30798
|
+
|
|
30799
|
+
Five channel templates (canonical names):
|
|
30800
|
+
- request-approve-act: agent proposes an action, operator approves or denies before execution.
|
|
30801
|
+
- read-then-report: agent reads outputs from a data source and reports summaries to the operator.
|
|
30802
|
+
- scheduled-digest: agent runs on a schedule and delivers a periodic digest.
|
|
30803
|
+
- plan-draft-only: agent drafts plans; operator reviews before any execution step.
|
|
30804
|
+
- fortress-relay: agent relays messages between fortresses under operator-scoped policy.
|
|
30805
|
+
|
|
30806
|
+
Four canonical policy slots:
|
|
30807
|
+
- memory: governs what the agent may persist and retrieve from encrypted state.
|
|
30808
|
+
- credentials: governs access to secrets, API keys, and tokens held in the broker.
|
|
30809
|
+
- plans: governs the agent's ability to create, modify, or execute plans.
|
|
30810
|
+
- outputs: governs what the agent may emit to external surfaces (files, APIs, messages).
|
|
30811
|
+
|
|
30812
|
+
Key concepts:
|
|
30813
|
+
- Fortress: the operator-owned sovereignty harness. All state is encrypted at rest under the cocoon.
|
|
30814
|
+
- Cocoon: master-key-wrapped storage derived from the operator's passphrase via Argon2id.
|
|
30815
|
+
- Identity: Ed25519 keypair with a DID, owned by the operator. Private keys never leave the cocoon.
|
|
30816
|
+
- Audit log: append-only encrypted blobs, sequential, recording every gate decision and tool call.
|
|
30817
|
+
- Wrapped agent: any agent runtime that connects to Sanctuary as an MCP client. Tier A (native), Tier B (adapter-wrapped), Tier C (escape hatch).
|
|
30818
|
+
|
|
30819
|
+
Note: this is a static reference block (v1.2.x). Dynamic context injection (live template list, policy schema) ships in v1.3.`;
|
|
30734
30820
|
var OperatorChatService = class {
|
|
30735
30821
|
store;
|
|
30736
30822
|
auditLog;
|
|
@@ -30875,6 +30961,9 @@ var OperatorChatService = class {
|
|
|
30875
30961
|
* than nested structures. Format:
|
|
30876
30962
|
*
|
|
30877
30963
|
* ```
|
|
30964
|
+
* ## Sanctuary reference
|
|
30965
|
+
* <static domain reference block>
|
|
30966
|
+
*
|
|
30878
30967
|
* ## Recent activity
|
|
30879
30968
|
* <recentActivity output>
|
|
30880
30969
|
*
|
|
@@ -30886,15 +30975,28 @@ var OperatorChatService = class {
|
|
|
30886
30975
|
* ```
|
|
30887
30976
|
*/
|
|
30888
30977
|
async assembleConciergeContext() {
|
|
30978
|
+
const ref = `## Sanctuary reference
|
|
30979
|
+
${SANCTUARY_DOMAIN_REFERENCE}`;
|
|
30889
30980
|
if (!this.contextProviders) {
|
|
30890
|
-
return
|
|
30981
|
+
return `${ref}
|
|
30982
|
+
|
|
30983
|
+
## Recent activity
|
|
30984
|
+
(no providers wired)
|
|
30985
|
+
|
|
30986
|
+
## Wrapped agents
|
|
30987
|
+
(no providers wired)
|
|
30988
|
+
|
|
30989
|
+
## Open inbox
|
|
30990
|
+
(no providers wired)`;
|
|
30891
30991
|
}
|
|
30892
30992
|
const [activity, agents, inbox] = await Promise.all([
|
|
30893
30993
|
this.contextProviders.recentActivity(),
|
|
30894
30994
|
this.contextProviders.agentInventory(),
|
|
30895
30995
|
this.contextProviders.openInbox()
|
|
30896
30996
|
]);
|
|
30897
|
-
return
|
|
30997
|
+
return `${ref}
|
|
30998
|
+
|
|
30999
|
+
## Recent activity
|
|
30898
31000
|
${activity}
|
|
30899
31001
|
|
|
30900
31002
|
## Wrapped agents
|
|
@@ -33999,6 +34101,9 @@ async function importExitBundle(opts) {
|
|
|
33999
34101
|
reputationArtifact?.json ?? null,
|
|
34000
34102
|
manifest
|
|
34001
34103
|
);
|
|
34104
|
+
if (!conflicts.public_identity_exists && identityArtifact?.json && opts.identityManager.getPrimaryIdentityId() !== null && opts.identityManager.getPrimaryIdentityId() !== identityArtifact.json.bundle.identity_id) {
|
|
34105
|
+
conflicts.public_identity_exists = true;
|
|
34106
|
+
}
|
|
34002
34107
|
if (!opts.activate) {
|
|
34003
34108
|
return {
|
|
34004
34109
|
verified: true,
|
|
@@ -34025,7 +34130,7 @@ async function importExitBundle(opts) {
|
|
|
34025
34130
|
if (conflicts.public_identity_exists && !opts.forceRebind) {
|
|
34026
34131
|
throw new ExitBundleImportError(
|
|
34027
34132
|
"IDENTITY_OVERWRITE_REFUSED",
|
|
34028
|
-
"Importing this bundle would overwrite an existing fortress public identity. Pass forceRebind: true (CLI: --force-rebind) to confirm explicit replacement."
|
|
34133
|
+
"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."
|
|
34029
34134
|
);
|
|
34030
34135
|
}
|
|
34031
34136
|
if (conflicts.public_identity_exists && opts.forceRebind && identityArtifact) {
|
|
@@ -34383,6 +34488,26 @@ async function runExitCommand(args) {
|
|
|
34383
34488
|
write(err, "Usage: sanctuary exit import <dir> [--activate]\n");
|
|
34384
34489
|
return 2;
|
|
34385
34490
|
}
|
|
34491
|
+
const bundleRoot = path.resolve(dir);
|
|
34492
|
+
try {
|
|
34493
|
+
await promises.access(bundleRoot);
|
|
34494
|
+
} catch {
|
|
34495
|
+
write(err, `Error: bundle directory not found: ${bundleRoot}
|
|
34496
|
+
`);
|
|
34497
|
+
return 1;
|
|
34498
|
+
}
|
|
34499
|
+
const manifestPath = path.join(bundleRoot, "manifest.json");
|
|
34500
|
+
try {
|
|
34501
|
+
const raw = await promises.readFile(manifestPath, "utf8");
|
|
34502
|
+
JSON.parse(raw);
|
|
34503
|
+
} catch {
|
|
34504
|
+
write(
|
|
34505
|
+
err,
|
|
34506
|
+
`Error: bundle manifest missing or malformed at ${manifestPath}
|
|
34507
|
+
`
|
|
34508
|
+
);
|
|
34509
|
+
return 1;
|
|
34510
|
+
}
|
|
34386
34511
|
const activate = hasFlag(argv, "--activate");
|
|
34387
34512
|
const forceRebind = hasFlag(argv, "--force-rebind");
|
|
34388
34513
|
const acceptUnverifiableAttestations = hasFlag(
|
|
@@ -34523,11 +34648,11 @@ async function startDashboardServer(options) {
|
|
|
34523
34648
|
}
|
|
34524
34649
|
}
|
|
34525
34650
|
});
|
|
34526
|
-
await new Promise((
|
|
34651
|
+
await new Promise((resolve6, reject) => {
|
|
34527
34652
|
server.once("error", reject);
|
|
34528
34653
|
server.listen(port, host, () => {
|
|
34529
34654
|
server.off("error", reject);
|
|
34530
|
-
|
|
34655
|
+
resolve6();
|
|
34531
34656
|
});
|
|
34532
34657
|
});
|
|
34533
34658
|
const actualPort = (() => {
|
|
@@ -34540,8 +34665,8 @@ async function startDashboardServer(options) {
|
|
|
34540
34665
|
url,
|
|
34541
34666
|
port: actualPort,
|
|
34542
34667
|
host,
|
|
34543
|
-
stop: () => new Promise((
|
|
34544
|
-
server.close((err) => err ? reject(err) :
|
|
34668
|
+
stop: () => new Promise((resolve6, reject) => {
|
|
34669
|
+
server.close((err) => err ? reject(err) : resolve6());
|
|
34545
34670
|
}),
|
|
34546
34671
|
publish,
|
|
34547
34672
|
publishActivity: (entry) => publish({ type: "activity", data: entry }),
|
|
@@ -35199,7 +35324,7 @@ Refusing to start the cocoon while the reset-history marker is unreadable.`
|
|
|
35199
35324
|
clientManager.configure(enabledServers).catch((err) => {
|
|
35200
35325
|
console.error(`[Sanctuary] Failed to configure upstream servers: ${err instanceof Error ? err.message : "unknown error"}`);
|
|
35201
35326
|
});
|
|
35202
|
-
await new Promise((
|
|
35327
|
+
await new Promise((resolve6) => setTimeout(resolve6, 2e3));
|
|
35203
35328
|
const proxiedTools = proxyRouter.getProxiedTools();
|
|
35204
35329
|
if (proxiedTools.length > 0) {
|
|
35205
35330
|
allTools.push(...proxiedTools);
|