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