@sanctuary-framework/mcp-server 1.2.9 → 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/index.d.cts CHANGED
@@ -7129,6 +7129,72 @@ declare class ApprovalAggregator {
7129
7129
  private hydrate;
7130
7130
  }
7131
7131
 
7132
+ /**
7133
+ * Sanctuary v1.3 WP-V1.3-1 Sentinel Finding Store.
7134
+ *
7135
+ * Encrypted at-rest persistence for sentinel findings. Sibling to the
7136
+ * Upsilon-3 aggregator-store: same fortress-master-key-derived HKDF
7137
+ * subkey shape, AAD-bound to the finding_id, retention-aware.
7138
+ *
7139
+ * Storage layout:
7140
+ * namespace: `_sentinel_findings`
7141
+ * key: `finding.{finding_id}` (one record per finding)
7142
+ * payload: AES-256-GCM ciphertext of the JSON-serialized record.
7143
+ * key: `l2-sentinel-finding-v1` HKDF subkey of fortress master.
7144
+ * AAD: UTF-8 bytes of `finding_id`.
7145
+ *
7146
+ * Multi-fortress isolation: HKDF subkey derives from the fortress
7147
+ * master key. Two fortresses never produce identical encryption keys
7148
+ * for identical finding_ids.
7149
+ *
7150
+ * Retention: 30 days default, mirroring the audit-log envelope and the
7151
+ * aggregator payload store.
7152
+ */
7153
+
7154
+ interface SentinelFindingStoreOptions {
7155
+ storage: StorageBackend;
7156
+ masterKey: Uint8Array;
7157
+ fortressId: string;
7158
+ /** Operator-tunable retention window. Default 30 days. */
7159
+ retentionDays?: number;
7160
+ /** Wall-clock provider for deterministic tests. */
7161
+ now?: () => Date;
7162
+ }
7163
+ declare class SentinelFindingStore {
7164
+ private readonly storage;
7165
+ private readonly encryptionKey;
7166
+ private readonly fortressId;
7167
+ private readonly retentionDays;
7168
+ private readonly now;
7169
+ constructor(opts: SentinelFindingStoreOptions);
7170
+ /**
7171
+ * Persist a finding. Truncates the operator-visible summary to
7172
+ * SENTINEL_SUMMARY_MAX_CHARS so the dashboard render stays bounded.
7173
+ * Returns the retention deadline so callers can audit it.
7174
+ */
7175
+ saveFinding(finding: SentinelFinding): Promise<string>;
7176
+ /** Load a single finding by id, or null when absent / corrupted. */
7177
+ loadFinding(findingId: string): Promise<SentinelFinding | null>;
7178
+ /**
7179
+ * List findings, newest first. Optional filters: since (ISO 8601),
7180
+ * severity, sentinel_id, agent_id, limit. Default limit 100.
7181
+ */
7182
+ listFindings(opts?: {
7183
+ since?: string;
7184
+ severity?: SentinelSeverity;
7185
+ sentinelId?: string;
7186
+ agentId?: string;
7187
+ limit?: number;
7188
+ }): Promise<SentinelFinding[]>;
7189
+ /**
7190
+ * Drop expired findings. Returns the count removed.
7191
+ */
7192
+ pruneExpired(now?: Date): Promise<{
7193
+ pruned: number;
7194
+ }>;
7195
+ private decode;
7196
+ }
7197
+
7132
7198
  /**
7133
7199
  * Sanctuary v1.3 WP-V1.3-1 Sentinel Baseline Pack (Castle Layer 2 anchor)
7134
7200
  *
@@ -7166,6 +7232,22 @@ interface SentinelContext {
7166
7232
  substrateSelector?: SubstrateSelector;
7167
7233
  /** Wall-clock provider. Tests inject a deterministic clock. */
7168
7234
  now: () => Date;
7235
+ /**
7236
+ * Optional read view of the per-fortress sentinel finding store
7237
+ * (Phi-1 surface). First-order sentinels (Phi-1/2/3/4) do not need
7238
+ * this; the Phi-5 meta-sentinel reads it to detect patterns ACROSS
7239
+ * other sentinels' findings (compound finding, fortress-wide count
7240
+ * spikes, novel sentinel-ID combinations). The dispatcher attaches
7241
+ * the store automatically on `subscribeSentinel`; tests can omit it
7242
+ * when constructing a context literal for a first-order watcher.
7243
+ *
7244
+ * Multi-fortress isolation rides on the store's existing key shape:
7245
+ * the store is constructed per-fortress from the fortress master
7246
+ * key, so two fortresses' stores produce distinct ciphertext for
7247
+ * identical finding-ids and one fortress's read cannot decode
7248
+ * another fortress's findings.
7249
+ */
7250
+ findingStore?: SentinelFindingStore;
7169
7251
  }
7170
7252
  /**
7171
7253
  * One observation a sentinel produced. Persisted under the sentinel
@@ -7331,72 +7413,6 @@ declare class SentinelRegistry {
7331
7413
  unsubscribeAll(): Promise<void>;
7332
7414
  }
7333
7415
 
7334
- /**
7335
- * Sanctuary v1.3 WP-V1.3-1 Sentinel Finding Store.
7336
- *
7337
- * Encrypted at-rest persistence for sentinel findings. Sibling to the
7338
- * Upsilon-3 aggregator-store: same fortress-master-key-derived HKDF
7339
- * subkey shape, AAD-bound to the finding_id, retention-aware.
7340
- *
7341
- * Storage layout:
7342
- * namespace: `_sentinel_findings`
7343
- * key: `finding.{finding_id}` (one record per finding)
7344
- * payload: AES-256-GCM ciphertext of the JSON-serialized record.
7345
- * key: `l2-sentinel-finding-v1` HKDF subkey of fortress master.
7346
- * AAD: UTF-8 bytes of `finding_id`.
7347
- *
7348
- * Multi-fortress isolation: HKDF subkey derives from the fortress
7349
- * master key. Two fortresses never produce identical encryption keys
7350
- * for identical finding_ids.
7351
- *
7352
- * Retention: 30 days default, mirroring the audit-log envelope and the
7353
- * aggregator payload store.
7354
- */
7355
-
7356
- interface SentinelFindingStoreOptions {
7357
- storage: StorageBackend;
7358
- masterKey: Uint8Array;
7359
- fortressId: string;
7360
- /** Operator-tunable retention window. Default 30 days. */
7361
- retentionDays?: number;
7362
- /** Wall-clock provider for deterministic tests. */
7363
- now?: () => Date;
7364
- }
7365
- declare class SentinelFindingStore {
7366
- private readonly storage;
7367
- private readonly encryptionKey;
7368
- private readonly fortressId;
7369
- private readonly retentionDays;
7370
- private readonly now;
7371
- constructor(opts: SentinelFindingStoreOptions);
7372
- /**
7373
- * Persist a finding. Truncates the operator-visible summary to
7374
- * SENTINEL_SUMMARY_MAX_CHARS so the dashboard render stays bounded.
7375
- * Returns the retention deadline so callers can audit it.
7376
- */
7377
- saveFinding(finding: SentinelFinding): Promise<string>;
7378
- /** Load a single finding by id, or null when absent / corrupted. */
7379
- loadFinding(findingId: string): Promise<SentinelFinding | null>;
7380
- /**
7381
- * List findings, newest first. Optional filters: since (ISO 8601),
7382
- * severity, sentinel_id, agent_id, limit. Default limit 100.
7383
- */
7384
- listFindings(opts?: {
7385
- since?: string;
7386
- severity?: SentinelSeverity;
7387
- sentinelId?: string;
7388
- agentId?: string;
7389
- limit?: number;
7390
- }): Promise<SentinelFinding[]>;
7391
- /**
7392
- * Drop expired findings. Returns the count removed.
7393
- */
7394
- pruneExpired(now?: Date): Promise<{
7395
- pruned: number;
7396
- }>;
7397
- private decode;
7398
- }
7399
-
7400
7416
  /**
7401
7417
  * Sanctuary v1.3 WP-V1.3-1 Sentinel Dispatcher.
7402
7418
  *
@@ -7509,25 +7525,142 @@ declare class SentinelDispatcher {
7509
7525
  }
7510
7526
 
7511
7527
  /**
7512
- * Sanctuary MCP Server Principal Dashboard
7528
+ * Sanctuary v1.3 WP-V1.3-3 Omega-1 Coordination Handoff Log.
7513
7529
  *
7514
- * HTTP-based approval channel that serves a real-time web dashboard
7515
- * for human principals to approve/deny agent operations.
7530
+ * OPENS WP-V1.3-3 Coordination Handoff Visualization. Read-only
7531
+ * server-side data API: queries the existing audit log for the
7532
+ * handoff-shape event classes, normalizes them into a uniform
7533
+ * HandoffEntry, and exposes query + per-entry detail.
7516
7534
  *
7517
- * Architecture:
7518
- * - Node.js built-in `http`/`https` modules (no Express or external deps)
7519
- * - SSE (Server-Sent Events) for real-time push to browser
7520
- * - Pending approval requests block the MCP tool call via Promise
7521
- * - Human clicks approve/deny in browser POST /api/approve/:id → Promise resolves
7522
- * - Timeout fallback: auto-deny (or auto-approve) if no response
7535
+ * Why this matters: operators running multiple wrapped agents need
7536
+ * to SEE what their agents are doing together. Handoffs between
7537
+ * agents are the most important state transitions: who passed work
7538
+ * to whom, what got transferred, what got withheld. Without
7539
+ * visibility, operators can't audit the multi-agent workflow OR
7540
+ * diagnose where work stalled.
7523
7541
  *
7524
- * Security invariants:
7525
- * - Binds to 127.0.0.1 by default (localhost only)
7526
- * - Optional bearer token authentication for non-localhost deployments
7527
- * - Optional TLS (HTTPS) via cert/key paths
7528
- * - All decisions are audit-logged
7529
- * - Agent cannot access the dashboard (it runs outside MCP stdin/stdout)
7542
+ * Audit event sources unioned by this module:
7543
+ * - `v1.1_local_handoff` (Tau-3 in-process coordination): canonical
7544
+ * explicit-pair signal. Details carry sender_agent_id +
7545
+ * recipient_agent_id.
7546
+ * - `cross_harness_approval_aggregated` (Upsilon-1 cross-harness
7547
+ * aggregator): wrapped-agent -> operator handoff. Details carry
7548
+ * source_harness; recipient is the synthetic `operator` node.
7549
+ *
7550
+ * NOT included at v1.3 Omega-1 (deviation, documented in PR body):
7551
+ * - `composition_completed` events do not exist as audit-log
7552
+ * operations in current source; composition events are mesh-only
7553
+ * signed envelopes (`composition_receipt_*` / `composition_*` are
7554
+ * in COMPOSITION_EVENT_TYPES but never flow through
7555
+ * auditLog.append). When composition wires audit emissions, the
7556
+ * union extends here. Same posture as Phi-3 cross-agent-chatter
7557
+ * watcher.
7558
+ *
7559
+ * Castle-walking discipline:
7560
+ * - No outbound surface. Reads server-local audit log only.
7561
+ * - No LLM call (purely operator-eyes view; no inference).
7562
+ * - No new operator attack surface (read-only against existing audit
7563
+ * log; new audit events are operator-action observability only).
7564
+ *
7565
+ * Multi-fortress isolation: HandoffLog is scoped to ONE AuditLog
7566
+ * instance per fortress; the audit log itself enforces fortress
7567
+ * boundary at the encryption layer.
7568
+ */
7569
+
7570
+ /** Operator-facing per-handoff record. */
7571
+ interface HandoffEntry {
7572
+ /** Stable per-fortress entry id (32 hex chars; SHA-256 of audit_event_id). */
7573
+ entry_id: string;
7574
+ /** Pointer back to the source audit-event. */
7575
+ audit_event_id: string;
7576
+ source_agent_id: string;
7577
+ /** `operator` for cross-harness flows; `unknown` when the entry shape lacks a recipient. */
7578
+ target_agent_id: string;
7579
+ /** ISO 8601 timestamp from the underlying audit entry. */
7580
+ observed_at: string;
7581
+ /** The original audit operation (`v1.1_local_handoff`, `cross_harness_approval_aggregated`). */
7582
+ event_class: string;
7583
+ /** Operator-friendly one-liner. */
7584
+ context_transfer_summary: string;
7585
+ /** Multi-step workflow grouping key (Omega-3); v1.3 Omega-1 returns null. */
7586
+ workflow_link: string | null;
7587
+ }
7588
+ interface HandoffEntryDetail {
7589
+ entry: HandoffEntry;
7590
+ /** Source audit entry, decrypted under operator auth. */
7591
+ source_audit_entry: AuditEntry;
7592
+ }
7593
+ interface HandoffLogQueryOptions {
7594
+ /** Filter to entries with observed_at >= ISO 8601. */
7595
+ since?: string;
7596
+ /** Filter to entries with observed_at <= ISO 8601. */
7597
+ until?: string;
7598
+ /** Filter to entries where the agent participates as sender or recipient. */
7599
+ agent_id?: string;
7600
+ /** Result cap. Default 50; max 500. */
7601
+ limit?: number;
7602
+ }
7603
+ interface HandoffLogOptions {
7604
+ auditLog: AuditLog;
7605
+ fortressId: string;
7606
+ }
7607
+ declare class HandoffLog {
7608
+ private readonly auditLog;
7609
+ private readonly fortressId;
7610
+ constructor(opts: HandoffLogOptions);
7611
+ /** Stable fortress id this HandoffLog reads. */
7612
+ getFortressId(): string;
7613
+ /**
7614
+ * Query handoffs in chronological-newest-first order. Filters
7615
+ * applied after normalization so the per-event-class shape
7616
+ * differences (sender field name, recipient inference) are handled
7617
+ * once.
7618
+ */
7619
+ query(opts: HandoffLogQueryOptions): Promise<HandoffEntry[]>;
7620
+ /**
7621
+ * Look up a single entry by id. Returns the normalized entry +
7622
+ * the source audit payload for operator-facing detail rendering.
7623
+ * Returns null when no audit entry maps to the given id.
7624
+ */
7625
+ getEntry(entryId: string): Promise<HandoffEntryDetail | null>;
7626
+ private normalize;
7627
+ }
7628
+
7629
+ /**
7630
+ * Sanctuary v1.3 WP-V1.3-3 Omega-1 Coordination handoff HTTP routes.
7631
+ *
7632
+ * Mounted under `/api/coordination/*`. Mirrors the Phi-1 sentinel
7633
+ * route module shape (Standing CTO call: follow Phi-1 sibling-view
7634
+ * pattern; spawn-prompt's `dashboard-handoff-view.ts` filename did
7635
+ * not exist on main, so the routes live under the
7636
+ * `coordination/` subsystem with the rest of the handoff machinery).
7637
+ *
7638
+ * Routes:
7639
+ * GET /api/coordination/handoffs (chronological list, filtered)
7640
+ * GET /api/coordination/handoffs/stream (SSE stream of new entries)
7641
+ * GET /api/coordination/handoffs/:entry_id (full detail incl. source audit entry)
7642
+ *
7643
+ * Auth-gated via existing operator middleware. Multi-fortress
7644
+ * isolation enforced at the audit-log encryption boundary the
7645
+ * underlying HandoffLog reads through.
7646
+ *
7647
+ * Two new operator-action audit events fire on these routes:
7648
+ * - `operator_coordination_view_opened` on the list route.
7649
+ * - `operator_handoff_entry_drilled` on the detail route.
7650
+ */
7651
+
7652
+ /**
7653
+ * In-process bridge that lets the dispatcher (or any other in-process
7654
+ * source) push handoff events to live SSE subscribers without
7655
+ * coupling the HandoffLog to a transport. The list route reads
7656
+ * historical state via HandoffLog.query(); the stream route subscribes
7657
+ * here for new entries.
7530
7658
  */
7659
+ declare class HandoffEventBridge {
7660
+ private readonly listeners;
7661
+ subscribe(listener: (entry: HandoffEntry) => void): () => void;
7662
+ emit(entry: HandoffEntry): void;
7663
+ }
7531
7664
 
7532
7665
  interface DashboardConfig {
7533
7666
  port: number;
@@ -7612,6 +7745,17 @@ declare class DashboardApprovalChannel implements ApprovalChannel {
7612
7745
  * dispatcher's audited paths.
7613
7746
  */
7614
7747
  private sentinelDispatcher;
7748
+ /**
7749
+ * v1.3 WP-V1.3-3 Omega-1 Coordination Handoff Visualization.
7750
+ * Mounted additively at `/api/coordination/*` when set. Read-only
7751
+ * against the audit log; the only writes are operator-action audit
7752
+ * events (operator_coordination_view_opened,
7753
+ * operator_handoff_entry_drilled).
7754
+ */
7755
+ private handoffLog;
7756
+ private handoffEventBridge;
7757
+ private handoffAuditLog;
7758
+ private handoffOperatorId;
7615
7759
  constructor(config: DashboardConfig);
7616
7760
  /**
7617
7761
  * Inject dependencies after construction.
@@ -7655,6 +7799,18 @@ declare class DashboardApprovalChannel implements ApprovalChannel {
7655
7799
  * Pass `null` to detach (used by tests + during shutdown).
7656
7800
  */
7657
7801
  setSentinelDispatcher(dispatcher: SentinelDispatcher | null): void;
7802
+ /**
7803
+ * v1.3 WP-V1.3-3 Omega-1: bind the Coordination handoff log +
7804
+ * event bridge + audit log + operator id. Once set, requests to
7805
+ * `/api/coordination/*` route through `handleCoordinationRoute`.
7806
+ * Pass `null` for any field to detach.
7807
+ */
7808
+ setHandoffLog(opts: {
7809
+ handoffLog: HandoffLog | null;
7810
+ eventBridge?: HandoffEventBridge | null;
7811
+ auditLog?: AuditLog | null;
7812
+ operatorId?: string | null;
7813
+ }): void;
7658
7814
  /**
7659
7815
  * v1.3 WP-V1.3-10 dispatch entry point. Called from `handleRequest`
7660
7816
  * before the legacy approval route table. Returns true when served.
@@ -7666,6 +7822,12 @@ declare class DashboardApprovalChannel implements ApprovalChannel {
7666
7822
  * bound. Returns true when served.
7667
7823
  */
7668
7824
  private dispatchSentinel;
7825
+ /**
7826
+ * v1.3 WP-V1.3-3 Omega-1 dispatch entry point. Routes
7827
+ * `/api/coordination/*` requests through the coordination router
7828
+ * when a HandoffLog has been bound. Returns true when served.
7829
+ */
7830
+ private dispatchCoordination;
7669
7831
  /**
7670
7832
  * v1.1 dispatch entry point. Called from `handleRequest` before the
7671
7833
  * legacy route table. Returns true when the request was served by v1.1