@sanctuary-framework/mcp-server 1.2.10 → 1.2.11
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 +766 -15
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +766 -15
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +374 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +161 -15
- package/dist/index.d.ts +161 -15
- package/dist/index.js +374 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -17473,6 +17473,318 @@ var init_sentinel_routes = __esm({
|
|
|
17473
17473
|
FINDINGS_MAX_LIMIT = 500;
|
|
17474
17474
|
}
|
|
17475
17475
|
});
|
|
17476
|
+
function makeEntryId(auditEventId) {
|
|
17477
|
+
return createHash("sha256").update(auditEventId).digest("hex").slice(0, 32);
|
|
17478
|
+
}
|
|
17479
|
+
function optString(details, key) {
|
|
17480
|
+
if (!details) return null;
|
|
17481
|
+
const value = details[key];
|
|
17482
|
+
if (typeof value !== "string" || value.length === 0) return null;
|
|
17483
|
+
return value;
|
|
17484
|
+
}
|
|
17485
|
+
function auditEventIdFallback(audit) {
|
|
17486
|
+
return `${audit.timestamp}:${audit.operation}`;
|
|
17487
|
+
}
|
|
17488
|
+
function localHandoffSummary(details, sender, recipient) {
|
|
17489
|
+
const taskScope = optString(details, "task_scope");
|
|
17490
|
+
const reasonClass = optString(details, "reason_class");
|
|
17491
|
+
if (taskScope) {
|
|
17492
|
+
return `${sender} -> ${recipient} handoff: ${taskScope}`;
|
|
17493
|
+
}
|
|
17494
|
+
if (reasonClass) {
|
|
17495
|
+
return `${sender} -> ${recipient} handoff (${reasonClass})`;
|
|
17496
|
+
}
|
|
17497
|
+
return `${sender} -> ${recipient} handoff`;
|
|
17498
|
+
}
|
|
17499
|
+
function crossHarnessSummary(details, sender) {
|
|
17500
|
+
const policyRule = optString(details, "policy_rule_id");
|
|
17501
|
+
if (policyRule) {
|
|
17502
|
+
return `${sender} -> operator approval (${policyRule})`;
|
|
17503
|
+
}
|
|
17504
|
+
return `${sender} -> operator approval`;
|
|
17505
|
+
}
|
|
17506
|
+
var HANDOFF_LOG_OBSERVED_OPS, OBSERVED_OP_LIST, OPERATOR_PSEUDO_AGENT, DEFAULT_LIMIT, MAX_LIMIT, AUDIT_QUERY_LIMIT, HandoffLog, COORDINATION_VIEW_AUDIT_OPS;
|
|
17507
|
+
var init_handoff_log = __esm({
|
|
17508
|
+
"src/coordination/handoff-log.ts"() {
|
|
17509
|
+
HANDOFF_LOG_OBSERVED_OPS = {
|
|
17510
|
+
/** Tau-3 in-process coordination handoff. */
|
|
17511
|
+
LOCAL_HANDOFF: "v1.1_local_handoff",
|
|
17512
|
+
/** Upsilon-1 cross-harness approval (wrapped-agent -> operator). */
|
|
17513
|
+
CROSS_HARNESS_APPROVAL: "cross_harness_approval_aggregated"
|
|
17514
|
+
};
|
|
17515
|
+
OBSERVED_OP_LIST = [
|
|
17516
|
+
HANDOFF_LOG_OBSERVED_OPS.LOCAL_HANDOFF,
|
|
17517
|
+
HANDOFF_LOG_OBSERVED_OPS.CROSS_HARNESS_APPROVAL
|
|
17518
|
+
];
|
|
17519
|
+
OPERATOR_PSEUDO_AGENT = "operator";
|
|
17520
|
+
DEFAULT_LIMIT = 50;
|
|
17521
|
+
MAX_LIMIT = 500;
|
|
17522
|
+
AUDIT_QUERY_LIMIT = 1e4;
|
|
17523
|
+
HandoffLog = class {
|
|
17524
|
+
auditLog;
|
|
17525
|
+
fortressId;
|
|
17526
|
+
constructor(opts) {
|
|
17527
|
+
this.auditLog = opts.auditLog;
|
|
17528
|
+
this.fortressId = opts.fortressId;
|
|
17529
|
+
}
|
|
17530
|
+
/** Stable fortress id this HandoffLog reads. */
|
|
17531
|
+
getFortressId() {
|
|
17532
|
+
return this.fortressId;
|
|
17533
|
+
}
|
|
17534
|
+
/**
|
|
17535
|
+
* Query handoffs in chronological-newest-first order. Filters
|
|
17536
|
+
* applied after normalization so the per-event-class shape
|
|
17537
|
+
* differences (sender field name, recipient inference) are handled
|
|
17538
|
+
* once.
|
|
17539
|
+
*/
|
|
17540
|
+
async query(opts) {
|
|
17541
|
+
const limit = Math.min(opts.limit ?? DEFAULT_LIMIT, MAX_LIMIT);
|
|
17542
|
+
const queryResult = await this.auditLog.query({
|
|
17543
|
+
...opts.since !== void 0 ? { since: opts.since } : {},
|
|
17544
|
+
layer: "l2",
|
|
17545
|
+
limit: AUDIT_QUERY_LIMIT
|
|
17546
|
+
});
|
|
17547
|
+
const normalized = [];
|
|
17548
|
+
for (const entry of queryResult.entries) {
|
|
17549
|
+
if (!OBSERVED_OP_LIST.includes(entry.operation)) continue;
|
|
17550
|
+
const handoff = this.normalize(entry);
|
|
17551
|
+
if (!handoff) continue;
|
|
17552
|
+
if (opts.until && handoff.observed_at > opts.until) continue;
|
|
17553
|
+
if (opts.since && handoff.observed_at < opts.since) continue;
|
|
17554
|
+
if (opts.agent_id) {
|
|
17555
|
+
if (handoff.source_agent_id !== opts.agent_id && handoff.target_agent_id !== opts.agent_id) {
|
|
17556
|
+
continue;
|
|
17557
|
+
}
|
|
17558
|
+
}
|
|
17559
|
+
normalized.push(handoff);
|
|
17560
|
+
}
|
|
17561
|
+
normalized.sort((a, b) => a.observed_at < b.observed_at ? 1 : -1);
|
|
17562
|
+
return normalized.slice(0, limit);
|
|
17563
|
+
}
|
|
17564
|
+
/**
|
|
17565
|
+
* Look up a single entry by id. Returns the normalized entry +
|
|
17566
|
+
* the source audit payload for operator-facing detail rendering.
|
|
17567
|
+
* Returns null when no audit entry maps to the given id.
|
|
17568
|
+
*/
|
|
17569
|
+
async getEntry(entryId) {
|
|
17570
|
+
const queryResult = await this.auditLog.query({
|
|
17571
|
+
layer: "l2",
|
|
17572
|
+
limit: AUDIT_QUERY_LIMIT
|
|
17573
|
+
});
|
|
17574
|
+
for (const audit of queryResult.entries) {
|
|
17575
|
+
if (!OBSERVED_OP_LIST.includes(audit.operation)) continue;
|
|
17576
|
+
const handoff = this.normalize(audit);
|
|
17577
|
+
if (!handoff) continue;
|
|
17578
|
+
if (handoff.entry_id === entryId) {
|
|
17579
|
+
return { entry: handoff, source_audit_entry: audit };
|
|
17580
|
+
}
|
|
17581
|
+
}
|
|
17582
|
+
return null;
|
|
17583
|
+
}
|
|
17584
|
+
normalize(audit) {
|
|
17585
|
+
const details = audit.details;
|
|
17586
|
+
if (audit.operation === HANDOFF_LOG_OBSERVED_OPS.LOCAL_HANDOFF) {
|
|
17587
|
+
const sender = optString(details, "sender_agent_id");
|
|
17588
|
+
const recipient = optString(details, "recipient_agent_id");
|
|
17589
|
+
if (!sender || !recipient || sender === recipient) return null;
|
|
17590
|
+
const auditEventId = optString(details, "event_id") ?? auditEventIdFallback(audit);
|
|
17591
|
+
return {
|
|
17592
|
+
entry_id: makeEntryId(auditEventId),
|
|
17593
|
+
audit_event_id: auditEventId,
|
|
17594
|
+
source_agent_id: sender,
|
|
17595
|
+
target_agent_id: recipient,
|
|
17596
|
+
observed_at: audit.timestamp,
|
|
17597
|
+
event_class: audit.operation,
|
|
17598
|
+
context_transfer_summary: localHandoffSummary(details, sender, recipient),
|
|
17599
|
+
workflow_link: null
|
|
17600
|
+
};
|
|
17601
|
+
}
|
|
17602
|
+
if (audit.operation === HANDOFF_LOG_OBSERVED_OPS.CROSS_HARNESS_APPROVAL) {
|
|
17603
|
+
const sender = optString(details, "source_harness") ?? optString(details, "source_agent_id");
|
|
17604
|
+
if (!sender) return null;
|
|
17605
|
+
const auditEventId = optString(details, "aggregator_id") ?? auditEventIdFallback(audit);
|
|
17606
|
+
return {
|
|
17607
|
+
entry_id: makeEntryId(auditEventId),
|
|
17608
|
+
audit_event_id: auditEventId,
|
|
17609
|
+
source_agent_id: sender,
|
|
17610
|
+
target_agent_id: OPERATOR_PSEUDO_AGENT,
|
|
17611
|
+
observed_at: audit.timestamp,
|
|
17612
|
+
event_class: audit.operation,
|
|
17613
|
+
context_transfer_summary: crossHarnessSummary(details, sender),
|
|
17614
|
+
workflow_link: null
|
|
17615
|
+
};
|
|
17616
|
+
}
|
|
17617
|
+
return null;
|
|
17618
|
+
}
|
|
17619
|
+
};
|
|
17620
|
+
COORDINATION_VIEW_AUDIT_OPS = {
|
|
17621
|
+
VIEW_OPENED: "operator_coordination_view_opened",
|
|
17622
|
+
ENTRY_DRILLED: "operator_handoff_entry_drilled"
|
|
17623
|
+
};
|
|
17624
|
+
}
|
|
17625
|
+
});
|
|
17626
|
+
|
|
17627
|
+
// src/coordination/handoff-routes.ts
|
|
17628
|
+
function writeJSON6(res, status, payload) {
|
|
17629
|
+
res.writeHead(status, {
|
|
17630
|
+
"Content-Type": "application/json",
|
|
17631
|
+
"Cache-Control": "no-store"
|
|
17632
|
+
});
|
|
17633
|
+
res.end(JSON.stringify(payload));
|
|
17634
|
+
}
|
|
17635
|
+
function parseLimit4(raw, defaultValue, max) {
|
|
17636
|
+
if (raw === null || raw === "") return defaultValue;
|
|
17637
|
+
const parsed = Number.parseInt(raw, 10);
|
|
17638
|
+
if (Number.isNaN(parsed) || parsed < 0) return defaultValue;
|
|
17639
|
+
return Math.min(parsed, max);
|
|
17640
|
+
}
|
|
17641
|
+
function matchEntryRoute2(path) {
|
|
17642
|
+
const prefix = `${COORDINATION_HANDOFFS_PREFIX}/`;
|
|
17643
|
+
if (!path.startsWith(prefix)) return null;
|
|
17644
|
+
const rest = path.slice(prefix.length);
|
|
17645
|
+
if (rest.length === 0 || rest === "stream") return null;
|
|
17646
|
+
if (rest.includes("/")) return null;
|
|
17647
|
+
return { entryId: decodeURIComponent(rest) };
|
|
17648
|
+
}
|
|
17649
|
+
async function handleStream3(deps, res) {
|
|
17650
|
+
res.writeHead(200, {
|
|
17651
|
+
"Content-Type": "text/event-stream",
|
|
17652
|
+
"Cache-Control": "no-cache, no-transform",
|
|
17653
|
+
Connection: "keep-alive",
|
|
17654
|
+
"X-Accel-Buffering": "no"
|
|
17655
|
+
});
|
|
17656
|
+
const snapshot = await deps.handoffLog.query({ limit: 50 });
|
|
17657
|
+
res.write(
|
|
17658
|
+
`event: handoff_snapshot
|
|
17659
|
+
data: ${JSON.stringify({ entries: snapshot })}
|
|
17660
|
+
|
|
17661
|
+
`
|
|
17662
|
+
);
|
|
17663
|
+
const unsubscribe = deps.events.subscribe((entry) => {
|
|
17664
|
+
try {
|
|
17665
|
+
res.write(
|
|
17666
|
+
`event: handoff_added
|
|
17667
|
+
data: ${JSON.stringify(entry)}
|
|
17668
|
+
|
|
17669
|
+
`
|
|
17670
|
+
);
|
|
17671
|
+
} catch {
|
|
17672
|
+
}
|
|
17673
|
+
});
|
|
17674
|
+
const keepAlive = setInterval(() => {
|
|
17675
|
+
try {
|
|
17676
|
+
res.write(": keepalive\n\n");
|
|
17677
|
+
} catch {
|
|
17678
|
+
}
|
|
17679
|
+
}, 25e3);
|
|
17680
|
+
const cleanup = () => {
|
|
17681
|
+
clearInterval(keepAlive);
|
|
17682
|
+
unsubscribe();
|
|
17683
|
+
};
|
|
17684
|
+
res.on("close", cleanup);
|
|
17685
|
+
res.on("error", cleanup);
|
|
17686
|
+
}
|
|
17687
|
+
async function handleCoordinationRoute(deps, req, res) {
|
|
17688
|
+
const host = req.headers.host || "localhost";
|
|
17689
|
+
const url = new URL(req.url ?? "/", `http://${host}`);
|
|
17690
|
+
const method = (req.method ?? "GET").toUpperCase();
|
|
17691
|
+
const path = url.pathname;
|
|
17692
|
+
if (path !== COORDINATION_API_PREFIX && !path.startsWith(`${COORDINATION_API_PREFIX}/`)) {
|
|
17693
|
+
return false;
|
|
17694
|
+
}
|
|
17695
|
+
const checkAuth = authMiddleware(deps.authConfig);
|
|
17696
|
+
if (!checkAuth(req, res, url)) return true;
|
|
17697
|
+
try {
|
|
17698
|
+
if (method === "GET" && path === `${COORDINATION_HANDOFFS_PREFIX}/stream`) {
|
|
17699
|
+
await handleStream3(deps, res);
|
|
17700
|
+
return true;
|
|
17701
|
+
}
|
|
17702
|
+
if (method === "GET" && path === COORDINATION_HANDOFFS_PREFIX) {
|
|
17703
|
+
const limit = parseLimit4(
|
|
17704
|
+
url.searchParams.get("limit"),
|
|
17705
|
+
COORDINATION_LIST_DEFAULT_LIMIT,
|
|
17706
|
+
COORDINATION_LIST_MAX_LIMIT
|
|
17707
|
+
);
|
|
17708
|
+
const since = url.searchParams.get("since") ?? void 0;
|
|
17709
|
+
const until = url.searchParams.get("until") ?? void 0;
|
|
17710
|
+
const agentId = url.searchParams.get("agent_id") ?? void 0;
|
|
17711
|
+
const entries = await deps.handoffLog.query({
|
|
17712
|
+
limit,
|
|
17713
|
+
...since !== void 0 ? { since } : {},
|
|
17714
|
+
...until !== void 0 ? { until } : {},
|
|
17715
|
+
...agentId !== void 0 ? { agent_id: agentId } : {}
|
|
17716
|
+
});
|
|
17717
|
+
deps.auditLog.append(
|
|
17718
|
+
"l2",
|
|
17719
|
+
COORDINATION_VIEW_AUDIT_OPS.VIEW_OPENED,
|
|
17720
|
+
deps.operatorId,
|
|
17721
|
+
{
|
|
17722
|
+
fortress_id: deps.handoffLog.getFortressId(),
|
|
17723
|
+
result_count: entries.length,
|
|
17724
|
+
...since !== void 0 ? { since } : {},
|
|
17725
|
+
...until !== void 0 ? { until } : {},
|
|
17726
|
+
...agentId !== void 0 ? { agent_id: agentId } : {}
|
|
17727
|
+
}
|
|
17728
|
+
);
|
|
17729
|
+
writeJSON6(res, 200, { ok: true, data: { entries } });
|
|
17730
|
+
return true;
|
|
17731
|
+
}
|
|
17732
|
+
const entryMatch = matchEntryRoute2(path);
|
|
17733
|
+
if (method === "GET" && entryMatch) {
|
|
17734
|
+
const detail = await deps.handoffLog.getEntry(entryMatch.entryId);
|
|
17735
|
+
if (!detail) {
|
|
17736
|
+
writeJSON6(res, 404, { ok: false, error: "not_found" });
|
|
17737
|
+
return true;
|
|
17738
|
+
}
|
|
17739
|
+
deps.auditLog.append(
|
|
17740
|
+
"l2",
|
|
17741
|
+
COORDINATION_VIEW_AUDIT_OPS.ENTRY_DRILLED,
|
|
17742
|
+
deps.operatorId,
|
|
17743
|
+
{
|
|
17744
|
+
fortress_id: deps.handoffLog.getFortressId(),
|
|
17745
|
+
entry_id: detail.entry.entry_id,
|
|
17746
|
+
event_class: detail.entry.event_class,
|
|
17747
|
+
source_agent_id: detail.entry.source_agent_id,
|
|
17748
|
+
target_agent_id: detail.entry.target_agent_id
|
|
17749
|
+
}
|
|
17750
|
+
);
|
|
17751
|
+
writeJSON6(res, 200, { ok: true, data: detail });
|
|
17752
|
+
return true;
|
|
17753
|
+
}
|
|
17754
|
+
writeJSON6(res, 404, { ok: false, error: "not_found", path });
|
|
17755
|
+
return true;
|
|
17756
|
+
} catch (err) {
|
|
17757
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
17758
|
+
writeJSON6(res, 500, { ok: false, error: "internal", detail: msg });
|
|
17759
|
+
return true;
|
|
17760
|
+
}
|
|
17761
|
+
}
|
|
17762
|
+
var COORDINATION_API_PREFIX, COORDINATION_HANDOFFS_PREFIX, COORDINATION_LIST_DEFAULT_LIMIT, COORDINATION_LIST_MAX_LIMIT, HandoffEventBridge;
|
|
17763
|
+
var init_handoff_routes = __esm({
|
|
17764
|
+
"src/coordination/handoff-routes.ts"() {
|
|
17765
|
+
init_auth_middleware();
|
|
17766
|
+
init_handoff_log();
|
|
17767
|
+
COORDINATION_API_PREFIX = "/api/coordination";
|
|
17768
|
+
COORDINATION_HANDOFFS_PREFIX = "/api/coordination/handoffs";
|
|
17769
|
+
COORDINATION_LIST_DEFAULT_LIMIT = 50;
|
|
17770
|
+
COORDINATION_LIST_MAX_LIMIT = 500;
|
|
17771
|
+
HandoffEventBridge = class {
|
|
17772
|
+
listeners = /* @__PURE__ */ new Set();
|
|
17773
|
+
subscribe(listener) {
|
|
17774
|
+
this.listeners.add(listener);
|
|
17775
|
+
return () => this.listeners.delete(listener);
|
|
17776
|
+
}
|
|
17777
|
+
emit(entry) {
|
|
17778
|
+
for (const listener of this.listeners) {
|
|
17779
|
+
try {
|
|
17780
|
+
listener(entry);
|
|
17781
|
+
} catch {
|
|
17782
|
+
}
|
|
17783
|
+
}
|
|
17784
|
+
}
|
|
17785
|
+
};
|
|
17786
|
+
}
|
|
17787
|
+
});
|
|
17476
17788
|
function isDashboardViewRoute(method, path) {
|
|
17477
17789
|
if (method !== "GET") return false;
|
|
17478
17790
|
return path === "/" || path === "/dashboard" || path === "/v1.0" || path === "/fortress" || path === "/events";
|
|
@@ -17488,6 +17800,7 @@ var init_dashboard = __esm({
|
|
|
17488
17800
|
init_dispatch();
|
|
17489
17801
|
init_approval_aggregator_routes();
|
|
17490
17802
|
init_sentinel_routes();
|
|
17803
|
+
init_handoff_routes();
|
|
17491
17804
|
SESSION_TTL_REMOTE_MS = 5 * 60 * 1e3;
|
|
17492
17805
|
SESSION_TTL_LOCAL_MS = 24 * 60 * 60 * 1e3;
|
|
17493
17806
|
MAX_SESSIONS = 1e3;
|
|
@@ -17562,6 +17875,17 @@ var init_dashboard = __esm({
|
|
|
17562
17875
|
* dispatcher's audited paths.
|
|
17563
17876
|
*/
|
|
17564
17877
|
sentinelDispatcher = null;
|
|
17878
|
+
/**
|
|
17879
|
+
* v1.3 WP-V1.3-3 Omega-1 Coordination Handoff Visualization.
|
|
17880
|
+
* Mounted additively at `/api/coordination/*` when set. Read-only
|
|
17881
|
+
* against the audit log; the only writes are operator-action audit
|
|
17882
|
+
* events (operator_coordination_view_opened,
|
|
17883
|
+
* operator_handoff_entry_drilled).
|
|
17884
|
+
*/
|
|
17885
|
+
handoffLog = null;
|
|
17886
|
+
handoffEventBridge = null;
|
|
17887
|
+
handoffAuditLog = null;
|
|
17888
|
+
handoffOperatorId = null;
|
|
17565
17889
|
constructor(config) {
|
|
17566
17890
|
this.config = config;
|
|
17567
17891
|
this.authToken = config.auth_token;
|
|
@@ -17629,6 +17953,18 @@ var init_dashboard = __esm({
|
|
|
17629
17953
|
setSentinelDispatcher(dispatcher) {
|
|
17630
17954
|
this.sentinelDispatcher = dispatcher;
|
|
17631
17955
|
}
|
|
17956
|
+
/**
|
|
17957
|
+
* v1.3 WP-V1.3-3 Omega-1: bind the Coordination handoff log +
|
|
17958
|
+
* event bridge + audit log + operator id. Once set, requests to
|
|
17959
|
+
* `/api/coordination/*` route through `handleCoordinationRoute`.
|
|
17960
|
+
* Pass `null` for any field to detach.
|
|
17961
|
+
*/
|
|
17962
|
+
setHandoffLog(opts) {
|
|
17963
|
+
this.handoffLog = opts.handoffLog;
|
|
17964
|
+
this.handoffEventBridge = opts.eventBridge ?? null;
|
|
17965
|
+
this.handoffAuditLog = opts.auditLog ?? null;
|
|
17966
|
+
this.handoffOperatorId = opts.operatorId ?? null;
|
|
17967
|
+
}
|
|
17632
17968
|
/**
|
|
17633
17969
|
* v1.3 WP-V1.3-10 dispatch entry point. Called from `handleRequest`
|
|
17634
17970
|
* before the legacy approval route table. Returns true when served.
|
|
@@ -17667,6 +18003,30 @@ var init_dashboard = __esm({
|
|
|
17667
18003
|
res
|
|
17668
18004
|
);
|
|
17669
18005
|
}
|
|
18006
|
+
/**
|
|
18007
|
+
* v1.3 WP-V1.3-3 Omega-1 dispatch entry point. Routes
|
|
18008
|
+
* `/api/coordination/*` requests through the coordination router
|
|
18009
|
+
* when a HandoffLog has been bound. Returns true when served.
|
|
18010
|
+
*/
|
|
18011
|
+
async dispatchCoordination(req, res) {
|
|
18012
|
+
if (!this.handoffLog || !this.handoffEventBridge || !this.handoffAuditLog) {
|
|
18013
|
+
return false;
|
|
18014
|
+
}
|
|
18015
|
+
return handleCoordinationRoute(
|
|
18016
|
+
{
|
|
18017
|
+
authConfig: {
|
|
18018
|
+
loopbackAutoAuth: this._autoAuthLocalhost,
|
|
18019
|
+
...this.authToken !== void 0 ? { authToken: this.authToken } : {}
|
|
18020
|
+
},
|
|
18021
|
+
handoffLog: this.handoffLog,
|
|
18022
|
+
auditLog: this.handoffAuditLog,
|
|
18023
|
+
operatorId: this.handoffOperatorId ?? this.identityManager?.getPrimaryIdentityId() ?? "operator_dashboard",
|
|
18024
|
+
events: this.handoffEventBridge
|
|
18025
|
+
},
|
|
18026
|
+
req,
|
|
18027
|
+
res
|
|
18028
|
+
);
|
|
18029
|
+
}
|
|
17670
18030
|
/**
|
|
17671
18031
|
* v1.1 dispatch entry point. Called from `handleRequest` before the
|
|
17672
18032
|
* legacy route table. Returns true when the request was served by v1.1
|
|
@@ -18066,6 +18426,18 @@ var init_dashboard = __esm({
|
|
|
18066
18426
|
});
|
|
18067
18427
|
return;
|
|
18068
18428
|
}
|
|
18429
|
+
if (this.handoffLog && url.pathname.startsWith(COORDINATION_API_PREFIX)) {
|
|
18430
|
+
this.dispatchCoordination(req, res).then((handled) => {
|
|
18431
|
+
if (handled) return;
|
|
18432
|
+
this.handleLegacyRequest(req, res, url, method);
|
|
18433
|
+
}).catch(() => {
|
|
18434
|
+
if (!res.headersSent) {
|
|
18435
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
18436
|
+
res.end(JSON.stringify({ error: "Internal server error" }));
|
|
18437
|
+
}
|
|
18438
|
+
});
|
|
18439
|
+
return;
|
|
18440
|
+
}
|
|
18069
18441
|
if (this.v11Bindings) {
|
|
18070
18442
|
this.dispatchV11(req, res, url, method).then((handled) => {
|
|
18071
18443
|
if (handled) return;
|
|
@@ -22421,7 +22793,7 @@ function extractInterAgentEvents(entries) {
|
|
|
22421
22793
|
if (!sender) continue;
|
|
22422
22794
|
out.push({
|
|
22423
22795
|
sender,
|
|
22424
|
-
recipient:
|
|
22796
|
+
recipient: OPERATOR_PSEUDO_AGENT2,
|
|
22425
22797
|
timestampMs: Date.parse(entry.timestamp),
|
|
22426
22798
|
auditId: `${entry.timestamp}:${entry.operation}`
|
|
22427
22799
|
});
|
|
@@ -22435,7 +22807,7 @@ function optionalString(details, key) {
|
|
|
22435
22807
|
if (typeof value !== "string" || value.length === 0) return null;
|
|
22436
22808
|
return value;
|
|
22437
22809
|
}
|
|
22438
|
-
var CROSS_AGENT_CHATTER_SENTINEL_ID, WARN_SIGMA2, ALERT_SIGMA2, BASELINE_WINDOWS2, QUERY_LIMIT2, MULTI_NEW_PARTNER_ALERT_THRESHOLD,
|
|
22810
|
+
var CROSS_AGENT_CHATTER_SENTINEL_ID, WARN_SIGMA2, ALERT_SIGMA2, BASELINE_WINDOWS2, QUERY_LIMIT2, MULTI_NEW_PARTNER_ALERT_THRESHOLD, OPERATOR_PSEUDO_AGENT2, HANDOFF_OP, CROSS_HARNESS_OPS, CrossAgentChatterWatcher;
|
|
22439
22811
|
var init_cross_agent_chatter_watcher = __esm({
|
|
22440
22812
|
"src/sentinel/sentinels/cross-agent-chatter-watcher.ts"() {
|
|
22441
22813
|
init_sentinel();
|
|
@@ -22445,7 +22817,7 @@ var init_cross_agent_chatter_watcher = __esm({
|
|
|
22445
22817
|
BASELINE_WINDOWS2 = 7;
|
|
22446
22818
|
QUERY_LIMIT2 = 1e4;
|
|
22447
22819
|
MULTI_NEW_PARTNER_ALERT_THRESHOLD = 3;
|
|
22448
|
-
|
|
22820
|
+
OPERATOR_PSEUDO_AGENT2 = "operator";
|
|
22449
22821
|
HANDOFF_OP = "v1.1_local_handoff";
|
|
22450
22822
|
CROSS_HARNESS_OPS = /* @__PURE__ */ new Set([
|
|
22451
22823
|
"cross_harness_approval_aggregated",
|
|
@@ -25507,7 +25879,7 @@ function createBridgeCommitment(outcome, identity, identityEncryptionKey, includ
|
|
|
25507
25879
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
25508
25880
|
const canonicalBytes = canonicalize2(outcome);
|
|
25509
25881
|
const canonicalString = new TextDecoder().decode(canonicalBytes);
|
|
25510
|
-
const
|
|
25882
|
+
const sha25612 = createCommitment(canonicalString);
|
|
25511
25883
|
let pedersenData;
|
|
25512
25884
|
if (includePedersen && Number.isInteger(outcome.rounds) && outcome.rounds >= 0) {
|
|
25513
25885
|
const pedersen = createPedersenCommitment(outcome.rounds);
|
|
@@ -25519,7 +25891,7 @@ function createBridgeCommitment(outcome, identity, identityEncryptionKey, includ
|
|
|
25519
25891
|
const commitmentPayload = {
|
|
25520
25892
|
bridge_commitment_id: commitmentId,
|
|
25521
25893
|
session_id: outcome.session_id,
|
|
25522
|
-
sha256_commitment:
|
|
25894
|
+
sha256_commitment: sha25612.commitment,
|
|
25523
25895
|
terms_hash: outcome.terms_hash,
|
|
25524
25896
|
committer_did: identity.did,
|
|
25525
25897
|
committed_at: now,
|
|
@@ -25530,8 +25902,8 @@ function createBridgeCommitment(outcome, identity, identityEncryptionKey, includ
|
|
|
25530
25902
|
return {
|
|
25531
25903
|
bridge_commitment_id: commitmentId,
|
|
25532
25904
|
session_id: outcome.session_id,
|
|
25533
|
-
sha256_commitment:
|
|
25534
|
-
blinding_factor:
|
|
25905
|
+
sha256_commitment: sha25612.commitment,
|
|
25906
|
+
blinding_factor: sha25612.blinding_factor,
|
|
25535
25907
|
committer_did: identity.did,
|
|
25536
25908
|
signature: toBase64url(signature),
|
|
25537
25909
|
pedersen_commitment: pedersenData,
|
|
@@ -42653,6 +43025,19 @@ ${err.message}
|
|
|
42653
43025
|
identityId: aggregatorIdentityId
|
|
42654
43026
|
});
|
|
42655
43027
|
anomalyDispatcher.start();
|
|
43028
|
+
const handoffLog = new HandoffLog({
|
|
43029
|
+
auditLog,
|
|
43030
|
+
fortressId: fortressIdForAggregator
|
|
43031
|
+
});
|
|
43032
|
+
const handoffEventBridge = new HandoffEventBridge();
|
|
43033
|
+
if (dashboard) {
|
|
43034
|
+
dashboard.setHandoffLog({
|
|
43035
|
+
handoffLog,
|
|
43036
|
+
eventBridge: handoffEventBridge,
|
|
43037
|
+
auditLog,
|
|
43038
|
+
operatorId: aggregatorIdentityId
|
|
43039
|
+
});
|
|
43040
|
+
}
|
|
42656
43041
|
const policyTools = createPrincipalPolicyTools(policy, baseline, auditLog);
|
|
42657
43042
|
const { tools: sanctuaryMetaTools } = createSanctuaryTools({
|
|
42658
43043
|
config,
|
|
@@ -42850,6 +43235,8 @@ var init_src = __esm({
|
|
|
42850
43235
|
init_sentinel_registry();
|
|
42851
43236
|
init_sentinel_dispatcher();
|
|
42852
43237
|
init_anomaly_pipeline();
|
|
43238
|
+
init_handoff_log();
|
|
43239
|
+
init_handoff_routes();
|
|
42853
43240
|
init_sentinels();
|
|
42854
43241
|
init_subscription_store();
|
|
42855
43242
|
init_tools4();
|
|
@@ -44950,32 +45337,32 @@ endstream`;
|
|
|
44950
45337
|
const offsets = new Array(totalObjects + 1).fill(0);
|
|
44951
45338
|
const chunks = [];
|
|
44952
45339
|
let bytePos = 0;
|
|
44953
|
-
const
|
|
45340
|
+
const write4 = (s) => {
|
|
44954
45341
|
const buf = Buffer.from(s, "latin1");
|
|
44955
45342
|
chunks.push(buf);
|
|
44956
45343
|
bytePos += buf.length;
|
|
44957
45344
|
};
|
|
44958
|
-
|
|
45345
|
+
write4("%PDF-1.4\n%\xE2\xE3\xCF\xD3\n");
|
|
44959
45346
|
for (let i = 1; i <= totalObjects; i++) {
|
|
44960
45347
|
offsets[i] = bytePos;
|
|
44961
|
-
|
|
45348
|
+
write4(`${i} 0 obj
|
|
44962
45349
|
${objectBodies[i]}
|
|
44963
45350
|
endobj
|
|
44964
45351
|
`);
|
|
44965
45352
|
}
|
|
44966
45353
|
const xrefPos = bytePos;
|
|
44967
|
-
|
|
45354
|
+
write4(`xref
|
|
44968
45355
|
0 ${totalObjects + 1}
|
|
44969
45356
|
`);
|
|
44970
|
-
|
|
45357
|
+
write4("0000000000 65535 f \n");
|
|
44971
45358
|
for (let i = 1; i <= totalObjects; i++) {
|
|
44972
|
-
|
|
45359
|
+
write4(`${offsets[i].toString().padStart(10, "0")} 00000 n
|
|
44973
45360
|
`);
|
|
44974
45361
|
}
|
|
44975
|
-
|
|
45362
|
+
write4(`trailer
|
|
44976
45363
|
<< /Size ${totalObjects + 1} /Root 1 0 R >>
|
|
44977
45364
|
`);
|
|
44978
|
-
|
|
45365
|
+
write4(`startxref
|
|
44979
45366
|
${xrefPos}
|
|
44980
45367
|
%%EOF
|
|
44981
45368
|
`);
|
|
@@ -48246,6 +48633,365 @@ var init_sentinel2 = __esm({
|
|
|
48246
48633
|
init_sentinels();
|
|
48247
48634
|
}
|
|
48248
48635
|
});
|
|
48636
|
+
async function issueDidWeb(opts) {
|
|
48637
|
+
if (!opts.authority_host || !HOST_RE.test(opts.authority_host)) {
|
|
48638
|
+
throw new Error(
|
|
48639
|
+
`did-web: authority_host '${opts.authority_host}' is not a valid DNS host`
|
|
48640
|
+
);
|
|
48641
|
+
}
|
|
48642
|
+
if (!FORTRESS_LABEL_RE.test(opts.fortress_id)) {
|
|
48643
|
+
throw new Error(
|
|
48644
|
+
`did-web: fortress_id '${opts.fortress_id}' is not a valid label`
|
|
48645
|
+
);
|
|
48646
|
+
}
|
|
48647
|
+
if (opts.agent_label !== void 0 && !AGENT_LABEL_RE.test(opts.agent_label)) {
|
|
48648
|
+
throw new Error(
|
|
48649
|
+
`did-web: agent_label '${opts.agent_label}' is not a valid label`
|
|
48650
|
+
);
|
|
48651
|
+
}
|
|
48652
|
+
if (opts.public_key.length !== 32) {
|
|
48653
|
+
throw new Error(
|
|
48654
|
+
`did-web: public_key must be exactly 32 bytes (Ed25519), got ${opts.public_key.length}`
|
|
48655
|
+
);
|
|
48656
|
+
}
|
|
48657
|
+
const did = buildDid(opts);
|
|
48658
|
+
const verificationMethodId = `${did}#key-1`;
|
|
48659
|
+
const verificationMethod = {
|
|
48660
|
+
id: verificationMethodId,
|
|
48661
|
+
type: "JsonWebKey2020",
|
|
48662
|
+
controller: did,
|
|
48663
|
+
publicKeyJwk: {
|
|
48664
|
+
kty: "OKP",
|
|
48665
|
+
crv: "Ed25519",
|
|
48666
|
+
x: toBase64url(opts.public_key)
|
|
48667
|
+
}
|
|
48668
|
+
};
|
|
48669
|
+
const didDocument = {
|
|
48670
|
+
"@context": [...DID_CONTEXT],
|
|
48671
|
+
id: did,
|
|
48672
|
+
verificationMethod: [verificationMethod],
|
|
48673
|
+
authentication: [verificationMethodId],
|
|
48674
|
+
assertionMethod: [verificationMethodId]
|
|
48675
|
+
};
|
|
48676
|
+
const now = (opts.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
48677
|
+
return {
|
|
48678
|
+
did,
|
|
48679
|
+
did_document: didDocument,
|
|
48680
|
+
public_key: opts.public_key,
|
|
48681
|
+
created_at: now.toISOString(),
|
|
48682
|
+
authority_host: opts.authority_host,
|
|
48683
|
+
fortress_id: opts.fortress_id,
|
|
48684
|
+
...opts.agent_label !== void 0 ? { agent_label: opts.agent_label } : {}
|
|
48685
|
+
};
|
|
48686
|
+
}
|
|
48687
|
+
function publishDidWebDocument(identifier, opts = {}) {
|
|
48688
|
+
const path = opts.publish_path ?? canonicalPublishPath(identifier);
|
|
48689
|
+
const artifact = canonicalSerializeDidDocument(identifier.did_document);
|
|
48690
|
+
const digest = sha256(stringToBytes(artifact));
|
|
48691
|
+
const url = `https://${identifier.authority_host}${path}`;
|
|
48692
|
+
return {
|
|
48693
|
+
url,
|
|
48694
|
+
publish_path: path,
|
|
48695
|
+
artifact,
|
|
48696
|
+
sha256: hashToString(digest)
|
|
48697
|
+
};
|
|
48698
|
+
}
|
|
48699
|
+
function buildDid(opts) {
|
|
48700
|
+
if (opts.agent_label === void 0) {
|
|
48701
|
+
return `did:web:${opts.authority_host}`;
|
|
48702
|
+
}
|
|
48703
|
+
return `did:web:${opts.authority_host}:fortress:${opts.fortress_id}:agent:${opts.agent_label}`;
|
|
48704
|
+
}
|
|
48705
|
+
function canonicalPublishPath(identifier) {
|
|
48706
|
+
if (identifier.agent_label === void 0) {
|
|
48707
|
+
return "/.well-known/did.json";
|
|
48708
|
+
}
|
|
48709
|
+
return `/fortress/${identifier.fortress_id}/agent/${identifier.agent_label}/did.json`;
|
|
48710
|
+
}
|
|
48711
|
+
function canonicalSerializeDidDocument(doc) {
|
|
48712
|
+
return JSON.stringify(
|
|
48713
|
+
{
|
|
48714
|
+
"@context": doc["@context"],
|
|
48715
|
+
id: doc.id,
|
|
48716
|
+
verificationMethod: doc.verificationMethod,
|
|
48717
|
+
authentication: doc.authentication,
|
|
48718
|
+
assertionMethod: doc.assertionMethod
|
|
48719
|
+
},
|
|
48720
|
+
null,
|
|
48721
|
+
2
|
|
48722
|
+
);
|
|
48723
|
+
}
|
|
48724
|
+
var DID_CONTEXT, HOST_RE, FORTRESS_LABEL_RE, AGENT_LABEL_RE;
|
|
48725
|
+
var init_did_web = __esm({
|
|
48726
|
+
"src/recognition/did-web.ts"() {
|
|
48727
|
+
init_encoding();
|
|
48728
|
+
init_hashing();
|
|
48729
|
+
DID_CONTEXT = [
|
|
48730
|
+
"https://www.w3.org/ns/did/v1",
|
|
48731
|
+
"https://w3id.org/security/suites/jws-2020/v1"
|
|
48732
|
+
];
|
|
48733
|
+
HOST_RE = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)+$/i;
|
|
48734
|
+
FORTRESS_LABEL_RE = /^[a-zA-Z0-9_-]{1,64}$/;
|
|
48735
|
+
AGENT_LABEL_RE = /^[a-zA-Z0-9_-]{1,64}$/;
|
|
48736
|
+
}
|
|
48737
|
+
});
|
|
48738
|
+
|
|
48739
|
+
// src/cli/did-web.ts
|
|
48740
|
+
var did_web_exports = {};
|
|
48741
|
+
__export(did_web_exports, {
|
|
48742
|
+
runDidWebCommand: () => runDidWebCommand
|
|
48743
|
+
});
|
|
48744
|
+
function write3(stream, text) {
|
|
48745
|
+
stream.write(text);
|
|
48746
|
+
}
|
|
48747
|
+
function flagValue3(argv, name) {
|
|
48748
|
+
const i = argv.indexOf(name);
|
|
48749
|
+
if (i === -1) return void 0;
|
|
48750
|
+
return argv[i + 1];
|
|
48751
|
+
}
|
|
48752
|
+
function hasFlag3(argv, name) {
|
|
48753
|
+
return argv.includes(name);
|
|
48754
|
+
}
|
|
48755
|
+
function printUsage7(out) {
|
|
48756
|
+
write3(
|
|
48757
|
+
out,
|
|
48758
|
+
`Usage: sanctuary did-web <command> [options]
|
|
48759
|
+
|
|
48760
|
+
Commands:
|
|
48761
|
+
issue --authority-host <host> [--agent-label <label>] [--json]
|
|
48762
|
+
Generate a did:web identifier bound to the operator's
|
|
48763
|
+
fortress Ed25519 public key. Writes the DID Document
|
|
48764
|
+
artifact to <storage>/recognition/did-web.json and
|
|
48765
|
+
prints publication instructions for the operator's
|
|
48766
|
+
HTTPS server.
|
|
48767
|
+
|
|
48768
|
+
show [--json] Display the previously issued did:web identifier.
|
|
48769
|
+
Exits non-zero if none issued.
|
|
48770
|
+
|
|
48771
|
+
Options:
|
|
48772
|
+
--authority-host <host> HTTPS host the operator controls and will
|
|
48773
|
+
serve /.well-known/did.json from.
|
|
48774
|
+
--agent-label <label> Optional agent-scoped identifier (label-safe;
|
|
48775
|
+
alphanumeric + dash + underscore, 1-64 chars).
|
|
48776
|
+
--fortress <path> Override the storage path.
|
|
48777
|
+
--passphrase <val> Passphrase for master-key derivation.
|
|
48778
|
+
--json Output as JSON.
|
|
48779
|
+
--help, -h Show this help.
|
|
48780
|
+
|
|
48781
|
+
Castle-walking note: did:web resolution is outbound HTTPS by design.
|
|
48782
|
+
This CLI never opens an outbound socket. The opt-in surface is your
|
|
48783
|
+
choice to run "did-web issue" with --authority-host; the resulting
|
|
48784
|
+
artifact is yours to publish on your own infrastructure. Sanctuary
|
|
48785
|
+
does not phone home.
|
|
48786
|
+
`
|
|
48787
|
+
);
|
|
48788
|
+
}
|
|
48789
|
+
async function runDidWebCommand(args) {
|
|
48790
|
+
const argv = args.argv;
|
|
48791
|
+
const out = args.out ?? process.stdout;
|
|
48792
|
+
const err = args.err ?? process.stderr;
|
|
48793
|
+
const env = args.env ?? process.env;
|
|
48794
|
+
if (argv.length === 0 || hasFlag3(argv, "--help") || hasFlag3(argv, "-h")) {
|
|
48795
|
+
printUsage7(out);
|
|
48796
|
+
return 0;
|
|
48797
|
+
}
|
|
48798
|
+
const command = argv[0];
|
|
48799
|
+
if (command === "issue") {
|
|
48800
|
+
return await cmdIssue(argv.slice(1), out, err, env);
|
|
48801
|
+
}
|
|
48802
|
+
if (command === "show") {
|
|
48803
|
+
return await cmdShow3(argv.slice(1), out, err);
|
|
48804
|
+
}
|
|
48805
|
+
write3(err, `Unknown did-web command: ${command}
|
|
48806
|
+
`);
|
|
48807
|
+
write3(err, `Run "sanctuary did-web --help" for usage.
|
|
48808
|
+
`);
|
|
48809
|
+
return 2;
|
|
48810
|
+
}
|
|
48811
|
+
async function loadFortressIdentity(argv, env, err) {
|
|
48812
|
+
const fortressFlag = flagValue3(argv, "--fortress");
|
|
48813
|
+
if (fortressFlag) {
|
|
48814
|
+
process.env.SANCTUARY_STORAGE_PATH = fortressFlag;
|
|
48815
|
+
}
|
|
48816
|
+
const passphrase = flagValue3(argv, "--passphrase") ?? env.SANCTUARY_PASSPHRASE;
|
|
48817
|
+
const recoveryKey = env.SANCTUARY_RECOVERY_KEY;
|
|
48818
|
+
if (!passphrase && !recoveryKey) {
|
|
48819
|
+
write3(
|
|
48820
|
+
err,
|
|
48821
|
+
"Error: sanctuary did-web requires SANCTUARY_PASSPHRASE, --passphrase, or SANCTUARY_RECOVERY_KEY.\n"
|
|
48822
|
+
);
|
|
48823
|
+
return null;
|
|
48824
|
+
}
|
|
48825
|
+
const config = await loadConfig();
|
|
48826
|
+
await mkdir(config.storage_path, { recursive: true, mode: 448 });
|
|
48827
|
+
const stateStoragePath = join(config.storage_path, "state");
|
|
48828
|
+
const storage = new FilesystemStorage(stateStoragePath);
|
|
48829
|
+
let masterKey;
|
|
48830
|
+
if (passphrase) {
|
|
48831
|
+
let existingParams;
|
|
48832
|
+
const raw = await storage.read("_meta", "key-params");
|
|
48833
|
+
if (raw) {
|
|
48834
|
+
existingParams = JSON.parse(bytesToString(raw));
|
|
48835
|
+
}
|
|
48836
|
+
const derivation = await deriveMasterKey(passphrase, existingParams);
|
|
48837
|
+
masterKey = derivation.key;
|
|
48838
|
+
} else if (recoveryKey) {
|
|
48839
|
+
masterKey = fromBase64url(recoveryKey);
|
|
48840
|
+
} else {
|
|
48841
|
+
return null;
|
|
48842
|
+
}
|
|
48843
|
+
const identityManager = new IdentityManager(storage, masterKey);
|
|
48844
|
+
const loadResult = await identityManager.load();
|
|
48845
|
+
if (loadResult.loaded === 0) {
|
|
48846
|
+
write3(
|
|
48847
|
+
err,
|
|
48848
|
+
loadResult.total > 0 ? "Error: identity files found but none could be decrypted. Wrong passphrase?\n" : "Error: no identities on this fortress yet. Run sanctuary wrap first.\n"
|
|
48849
|
+
);
|
|
48850
|
+
return null;
|
|
48851
|
+
}
|
|
48852
|
+
const primary = identityManager.getDefault();
|
|
48853
|
+
if (!primary) {
|
|
48854
|
+
write3(err, "Error: no primary identity on this fortress yet. Run sanctuary wrap first.\n");
|
|
48855
|
+
return null;
|
|
48856
|
+
}
|
|
48857
|
+
return {
|
|
48858
|
+
publicKey: fromBase64url(primary.public_key),
|
|
48859
|
+
identityId: primary.identity_id,
|
|
48860
|
+
storagePath: config.storage_path
|
|
48861
|
+
};
|
|
48862
|
+
}
|
|
48863
|
+
async function cmdIssue(argv, out, err, env) {
|
|
48864
|
+
const authorityHost = flagValue3(argv, "--authority-host");
|
|
48865
|
+
const agentLabel = flagValue3(argv, "--agent-label");
|
|
48866
|
+
const json = hasFlag3(argv, "--json");
|
|
48867
|
+
if (!authorityHost) {
|
|
48868
|
+
write3(err, "Error: --authority-host is required.\n");
|
|
48869
|
+
write3(err, "Example: sanctuary did-web issue --authority-host alice.example.com\n");
|
|
48870
|
+
return 1;
|
|
48871
|
+
}
|
|
48872
|
+
const snapshot = await loadFortressIdentity(argv, env, err);
|
|
48873
|
+
if (!snapshot) return 1;
|
|
48874
|
+
let identifier;
|
|
48875
|
+
try {
|
|
48876
|
+
identifier = await issueDidWeb({
|
|
48877
|
+
fortress_id: snapshot.identityId,
|
|
48878
|
+
authority_host: authorityHost,
|
|
48879
|
+
public_key: snapshot.publicKey,
|
|
48880
|
+
...agentLabel !== void 0 ? { agent_label: agentLabel } : {}
|
|
48881
|
+
});
|
|
48882
|
+
} catch (e) {
|
|
48883
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
48884
|
+
write3(err, `Error: ${message}
|
|
48885
|
+
`);
|
|
48886
|
+
return 1;
|
|
48887
|
+
}
|
|
48888
|
+
const artifact = publishDidWebDocument(identifier);
|
|
48889
|
+
const persistDir = join(snapshot.storagePath, "recognition");
|
|
48890
|
+
await mkdir(persistDir, { recursive: true, mode: 448 });
|
|
48891
|
+
const persistPath = join(persistDir, "did-web.json");
|
|
48892
|
+
const record = {
|
|
48893
|
+
version: 1,
|
|
48894
|
+
identifier: {
|
|
48895
|
+
did: identifier.did,
|
|
48896
|
+
created_at: identifier.created_at,
|
|
48897
|
+
authority_host: identifier.authority_host,
|
|
48898
|
+
fortress_id: identifier.fortress_id,
|
|
48899
|
+
...identifier.agent_label !== void 0 ? { agent_label: identifier.agent_label } : {},
|
|
48900
|
+
did_document: identifier.did_document
|
|
48901
|
+
},
|
|
48902
|
+
artifact: {
|
|
48903
|
+
url: artifact.url,
|
|
48904
|
+
publish_path: artifact.publish_path,
|
|
48905
|
+
sha256: artifact.sha256
|
|
48906
|
+
}
|
|
48907
|
+
};
|
|
48908
|
+
await writeFile(persistPath, JSON.stringify(record, null, 2), {
|
|
48909
|
+
mode: 384
|
|
48910
|
+
});
|
|
48911
|
+
if (json) {
|
|
48912
|
+
write3(out, JSON.stringify(record, null, 2) + "\n");
|
|
48913
|
+
return 0;
|
|
48914
|
+
}
|
|
48915
|
+
write3(out, `did:web identifier issued.
|
|
48916
|
+
`);
|
|
48917
|
+
write3(out, ` DID: ${identifier.did}
|
|
48918
|
+
`);
|
|
48919
|
+
write3(out, ` Authority host: ${identifier.authority_host}
|
|
48920
|
+
`);
|
|
48921
|
+
write3(out, ` Created at: ${identifier.created_at}
|
|
48922
|
+
`);
|
|
48923
|
+
write3(out, ` Persisted: ${persistPath}
|
|
48924
|
+
`);
|
|
48925
|
+
write3(out, `
|
|
48926
|
+
Next step: publish the DID Document to your HTTPS host.
|
|
48927
|
+
`);
|
|
48928
|
+
write3(out, ` Target URL: ${artifact.url}
|
|
48929
|
+
`);
|
|
48930
|
+
write3(out, ` SHA-256: ${artifact.sha256}
|
|
48931
|
+
`);
|
|
48932
|
+
write3(out, ` Artifact: ${join(persistDir, "did.json")}
|
|
48933
|
+
`);
|
|
48934
|
+
const artifactPath = join(persistDir, "did.json");
|
|
48935
|
+
await writeFile(artifactPath, artifact.artifact, { mode: 420 });
|
|
48936
|
+
write3(out, `
|
|
48937
|
+
Castle-walking note: this CLI never opens an outbound socket.
|
|
48938
|
+
`);
|
|
48939
|
+
write3(out, `Publishing the DID Document is your operation; serve the artifact
|
|
48940
|
+
`);
|
|
48941
|
+
write3(out, `at the URL above from infrastructure you control.
|
|
48942
|
+
`);
|
|
48943
|
+
return 0;
|
|
48944
|
+
}
|
|
48945
|
+
async function cmdShow3(argv, out, err, _env) {
|
|
48946
|
+
const json = hasFlag3(argv, "--json");
|
|
48947
|
+
const fortressFlag = flagValue3(argv, "--fortress");
|
|
48948
|
+
if (fortressFlag) {
|
|
48949
|
+
process.env.SANCTUARY_STORAGE_PATH = fortressFlag;
|
|
48950
|
+
}
|
|
48951
|
+
const config = await loadConfig();
|
|
48952
|
+
const persistPath = join(config.storage_path, "recognition", "did-web.json");
|
|
48953
|
+
let bytes;
|
|
48954
|
+
try {
|
|
48955
|
+
bytes = await readFile(persistPath);
|
|
48956
|
+
} catch {
|
|
48957
|
+
write3(
|
|
48958
|
+
err,
|
|
48959
|
+
`No did:web identifier configured on this fortress.
|
|
48960
|
+
Run "sanctuary did-web issue --authority-host <host>" to issue one.
|
|
48961
|
+
`
|
|
48962
|
+
);
|
|
48963
|
+
return 1;
|
|
48964
|
+
}
|
|
48965
|
+
if (json) {
|
|
48966
|
+
write3(out, bytes.toString("utf-8"));
|
|
48967
|
+
if (!bytes.toString("utf-8").endsWith("\n")) write3(out, "\n");
|
|
48968
|
+
return 0;
|
|
48969
|
+
}
|
|
48970
|
+
const parsed = JSON.parse(bytes.toString("utf-8"));
|
|
48971
|
+
write3(out, `did:web identifier on this fortress:
|
|
48972
|
+
`);
|
|
48973
|
+
write3(out, ` DID: ${parsed.identifier.did}
|
|
48974
|
+
`);
|
|
48975
|
+
write3(out, ` Authority host: ${parsed.identifier.authority_host}
|
|
48976
|
+
`);
|
|
48977
|
+
write3(out, ` Created at: ${parsed.identifier.created_at}
|
|
48978
|
+
`);
|
|
48979
|
+
write3(out, ` Publish URL: ${parsed.artifact.url}
|
|
48980
|
+
`);
|
|
48981
|
+
write3(out, ` SHA-256: ${parsed.artifact.sha256}
|
|
48982
|
+
`);
|
|
48983
|
+
return 0;
|
|
48984
|
+
}
|
|
48985
|
+
var init_did_web2 = __esm({
|
|
48986
|
+
"src/cli/did-web.ts"() {
|
|
48987
|
+
init_filesystem();
|
|
48988
|
+
init_tools();
|
|
48989
|
+
init_key_derivation();
|
|
48990
|
+
init_encoding();
|
|
48991
|
+
init_config();
|
|
48992
|
+
init_did_web();
|
|
48993
|
+
}
|
|
48994
|
+
});
|
|
48249
48995
|
|
|
48250
48996
|
// src/mcp/broker-server.ts
|
|
48251
48997
|
var broker_server_exports = {};
|
|
@@ -49111,6 +49857,11 @@ async function main() {
|
|
|
49111
49857
|
const code = await runSentinelCommand2({ argv: args.slice(1) });
|
|
49112
49858
|
process.exit(code);
|
|
49113
49859
|
}
|
|
49860
|
+
if (args[0] === "did-web") {
|
|
49861
|
+
const { runDidWebCommand: runDidWebCommand2 } = await Promise.resolve().then(() => (init_did_web2(), did_web_exports));
|
|
49862
|
+
const code = await runDidWebCommand2({ argv: args.slice(1) });
|
|
49863
|
+
process.exit(code);
|
|
49864
|
+
}
|
|
49114
49865
|
if (args[0] === "broker-server") {
|
|
49115
49866
|
const { openBroker: openBroker2 } = await Promise.resolve().then(() => (init_open(), open_exports));
|
|
49116
49867
|
const { createBrokerMcpServer: createBrokerMcpServer2 } = await Promise.resolve().then(() => (init_broker_server(), broker_server_exports));
|