@sanctuary-framework/mcp-server 1.2.11 → 1.2.13

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
@@ -3522,6 +3522,44 @@ interface ExitBundleArtifactEntry {
3522
3522
  */
3523
3523
  subkind?: string;
3524
3524
  }
3525
+ /**
3526
+ * did:web pointer embedded in the identity binding when the operator
3527
+ * has issued a did:web identifier for the source fortress and asked
3528
+ * the exit-bundle exporter to publish that pointer alongside the
3529
+ * manifest (Recognition-Layer Path C primary build 2).
3530
+ *
3531
+ * The bundle does NOT carry the did:web DID Document itself; the
3532
+ * receiving regime resolves the DID Document via standard DNS + TLS
3533
+ * against `authority_host`. That dependency is intentional: it is
3534
+ * the operator's HTTPS infrastructure that publishes the document,
3535
+ * not Sanctuary's, and it is the receiving regime's resolver that
3536
+ * verifies the document, not Sanctuary's. Recognition flows along
3537
+ * the web's existing trust chain without trusting Sanctuary as a
3538
+ * middleman.
3539
+ *
3540
+ * The signature scheme over the manifest body covers this field by
3541
+ * construction (it lives inside `ExitBundleManifestBody`), so an
3542
+ * attacker who substituted the did:web pointer without re-signing
3543
+ * the body would be rejected at the existing manifest-signature
3544
+ * gate.
3545
+ */
3546
+ interface ExitBundleDidWebBinding {
3547
+ /**
3548
+ * The did:web URI string the operator published, e.g.,
3549
+ * `did:web:alice.example.com:fortress:abc123`. The receiving
3550
+ * regime resolves this to fetch the DID Document.
3551
+ */
3552
+ identifier: string;
3553
+ /** Authority host the operator's DID Document is published on. */
3554
+ authority_host: string;
3555
+ /**
3556
+ * Optional ISO 8601 timestamp at which the operator confirmed
3557
+ * HTTPS publication. Surfaces to the verifier as evidence that
3558
+ * the operator believes the document is reachable; the verifier
3559
+ * still re-resolves to confirm.
3560
+ */
3561
+ published_at?: string;
3562
+ }
3525
3563
  /**
3526
3564
  * Identity binding embedded in the manifest. Carries only public material.
3527
3565
  */
@@ -3534,6 +3572,17 @@ interface ExitBundleIdentityBinding {
3534
3572
  fortress_master_pubkey: string;
3535
3573
  /** Optional DID, when one is bound to this identity. */
3536
3574
  did?: string;
3575
+ /**
3576
+ * Optional did:web pointer (Recognition-Layer Path C primary build 2).
3577
+ * Present only when the operator has issued a did:web identifier
3578
+ * for the source fortress AND has not explicitly opted out at
3579
+ * export time via `--include-did-web=false`. The receiving regime
3580
+ * resolves the pointer via DNS + TLS to verify the bundle's origin
3581
+ * without trusting Sanctuary as intermediary. Absent on bundles
3582
+ * exported before the recognition-layer integration shipped
3583
+ * (backward-compatible).
3584
+ */
3585
+ did_web?: ExitBundleDidWebBinding;
3537
3586
  }
3538
3587
  /**
3539
3588
  * v1 manifest body — what the operator's fortress-master signs.
@@ -3925,6 +3974,37 @@ declare class FilesystemStorage implements StorageBackend {
3925
3974
  totalSize(): Promise<number>;
3926
3975
  }
3927
3976
 
3977
+ interface ResolveDidWebOpts {
3978
+ /**
3979
+ * Hosts the operator has explicitly allowed for outbound did:web
3980
+ * resolution. Empty array means resolution is disabled and the
3981
+ * call returns synchronously with `host_not_allowed`. This is
3982
+ * the load-bearing opt-in surface for the no-outbound-by-default
3983
+ * rule; the kernel-level Castle Wall egress filter enforces the
3984
+ * same allowlist independently.
3985
+ */
3986
+ allowed_hosts: string[];
3987
+ /** Resolution timeout. Defaults to 5000ms. */
3988
+ timeout_ms?: number;
3989
+ /**
3990
+ * Optional fetcher override for tests. Defaults to globalThis.fetch.
3991
+ * Production callers should leave this undefined.
3992
+ */
3993
+ fetcher?: (url: string, init?: {
3994
+ signal?: AbortSignal;
3995
+ }) => Promise<{
3996
+ ok: boolean;
3997
+ status: number;
3998
+ json: () => Promise<unknown>;
3999
+ }>;
4000
+ /**
4001
+ * Optional expected Ed25519 public key. When set, the resolved
4002
+ * document's verificationMethod[0].publicKeyJwk.x must match
4003
+ * (base64url-encoded). Mismatch returns `signature_mismatch`.
4004
+ */
4005
+ expected_public_key?: Uint8Array;
4006
+ }
4007
+
3928
4008
  /**
3929
4009
  * Sanctuary MCP Server — Key Derivation
3930
4010
  *
@@ -4052,6 +4132,21 @@ interface ExportExitBundleOptions {
4052
4132
  * When omitted, the export self-generates an id.
4053
4133
  */
4054
4134
  exportApprovalAuditId?: string;
4135
+ /**
4136
+ * Recognition-Layer Path C primary build 2: optional did:web binding
4137
+ * to embed in the manifest's identity_binding. When provided, the
4138
+ * export validates that the binding's identifier resolves (per the
4139
+ * did:web spec) to a pointer over the same authority host as
4140
+ * `binding.authority_host`, and that the operator's fortress public
4141
+ * key matches the key the did:web identifier was issued against
4142
+ * (the export does NOT re-fetch the published DID Document; that
4143
+ * check is the receiving regime's job at import time).
4144
+ *
4145
+ * Omit to skip did:web embedding entirely. Receiving regimes that
4146
+ * import the bundle treat absence as backward-compatible (no
4147
+ * recognition-layer verification step).
4148
+ */
4149
+ didWeb?: ExitBundleDidWebBinding;
4055
4150
  }
4056
4151
  interface ExportExitBundleResult {
4057
4152
  bundle_dir: string;
@@ -4090,6 +4185,40 @@ interface ImportExitBundleOptions {
4090
4185
  * operator in to an explicit relaxed verdict (Tier 1 confirmation in CLI).
4091
4186
  */
4092
4187
  acceptUnverifiableAttestations?: boolean;
4188
+ /**
4189
+ * Recognition-Layer Path C primary build 2: hosts the importing
4190
+ * operator has explicitly allowed for outbound did:web resolution.
4191
+ * Empty array means resolution refuses to leave the fortress
4192
+ * (preserves no-outbound-by-default). The same allowlist is also
4193
+ * enforced at the kernel level by the operator's Castle Wall egress
4194
+ * filter; this option is the application-level coordinator.
4195
+ *
4196
+ * Absent + did_web present in manifest = the importer surfaces a
4197
+ * warning and proceeds with the manifest-signature check alone
4198
+ * (degraded confidence). The operator can re-run with the
4199
+ * allowlist set or with `skipDidWebVerify: true`.
4200
+ */
4201
+ didWebAllowedHosts?: string[];
4202
+ /**
4203
+ * Recognition-Layer Path C primary build 2: when true, the importer
4204
+ * skips did:web resolution entirely even if the manifest carries a
4205
+ * did_web binding. Operator surface: CLI flag
4206
+ * `--skip-did-web-verify`. Tradeoff is operator-visible: skipping
4207
+ * loses the recognition-layer cross-check that the bundle's claimed
4208
+ * origin matches the published DID Document.
4209
+ */
4210
+ skipDidWebVerify?: boolean;
4211
+ /**
4212
+ * Recognition-Layer Path C primary build 2: optional fetcher
4213
+ * override for tests. Defaults to globalThis.fetch via the did:web
4214
+ * foundation's resolver. Production callers leave undefined.
4215
+ */
4216
+ didWebFetcher?: ResolveDidWebOpts["fetcher"];
4217
+ /**
4218
+ * Recognition-Layer Path C primary build 2: resolution timeout.
4219
+ * Defaults to the did:web foundation's 5000ms default.
4220
+ */
4221
+ didWebTimeoutMs?: number;
4093
4222
  }
4094
4223
  /**
4095
4224
  * Structured error raised by `importExitBundle` for codes the CLI / hub want
@@ -7626,6 +7755,250 @@ declare class HandoffLog {
7626
7755
  private normalize;
7627
7756
  }
7628
7757
 
7758
+ /**
7759
+ * Sanctuary v1.3 WP-V1.3-3 Omega-2 Context-Transfer Extractor.
7760
+ *
7761
+ * Decomposes a handoff into the structured TRANSFERRED-vs-WITHHELD
7762
+ * breakdown the operator's Coordination view renders. Operates on a
7763
+ * `HandoffEntryDetail` (Omega-1 surface) and returns a
7764
+ * `ContextTransferBreakdown`.
7765
+ *
7766
+ * Why this matters: the operator needs to know not just THAT a
7767
+ * handoff happened, but WHAT crossed the boundary. Per-handoff
7768
+ * context-transfer breakdown makes Castle Layer 3 cooperative-MCP
7769
+ * integrity legible at the operator UX layer.
7770
+ *
7771
+ * Three resolution paths in fixed order; first one that produces
7772
+ * usable output wins. Higher paths produce higher confidence.
7773
+ *
7774
+ * Path A: structured-source events. Triggered when the source audit
7775
+ * details payload carries explicit `transferred` and / or `withheld`
7776
+ * arrays / objects. Future Tau-X work will wire the coordinator to
7777
+ * emit these explicitly; the extractor handles them today so when
7778
+ * those emissions arrive, no further code change is needed. Ships
7779
+ * with confidence 1.0.
7780
+ *
7781
+ * Path B: composition events. Triggered when the source audit
7782
+ * operation matches `composition_completed` (Concordia bridge).
7783
+ * Decomposes via the receipt-references graph: items in the receipt
7784
+ * are transferred; items in the source-state-snapshot but not in the
7785
+ * receipt are withheld. Composition events do not flow through the
7786
+ * audit log today (mesh-only signed envelopes; same finding as Phi-3
7787
+ * cross-agent-chatter watcher and Omega-1's HandoffLog union scope);
7788
+ * Path B is scaffolded so when composition wires audit emissions,
7789
+ * extraction extends. Ships with confidence 0.9 when present.
7790
+ *
7791
+ * Path C: heuristic fallback. Triggered when neither A nor B fires
7792
+ * (the common case at v1.3 Omega-2 since current Tau-3 audit
7793
+ * emissions are minimal and composition is mesh-only). Derives
7794
+ * transferred from the policy_rule_id (cross_harness_approval) or
7795
+ * task-scope category (v1.1_local_handoff via the source audit
7796
+ * payload's reason_class + status). Ships with confidence 0.5.
7797
+ *
7798
+ * LLM-assist fallback. Optional. Triggered when Path C returns a
7799
+ * low-confidence result (no clear category match) AND a substrate
7800
+ * selector is supplied. Routes through `selector.invokeClassify` on
7801
+ * the coordination surface. Failure is silent (degrade-not-destroy);
7802
+ * the caller still gets the heuristic Path C result with confidence
7803
+ * 0.3. Ships with confidence 0.6 on success.
7804
+ *
7805
+ * Castle-walking discipline:
7806
+ * - No new outbound surface. The substrate selector is the only
7807
+ * LLM-capable channel and is opt-in via dependency injection.
7808
+ * - Reads server-local audit log + Concordia receipts only.
7809
+ * - Encryption boundary holds.
7810
+ * - Multi-fortress isolation preserved by the caller-supplied
7811
+ * HandoffEntryDetail (which is fortress-scoped via Omega-1).
7812
+ */
7813
+
7814
+ /** Extractor dependency contract. */
7815
+ interface ContextTransferExtractorDeps {
7816
+ /** Optional LLM-assist substrate selector. Off by default. */
7817
+ substrateSelector?: SubstrateSelector;
7818
+ }
7819
+
7820
+ /**
7821
+ * Sanctuary v1.3 WP-V1.3-3 Omega-3 Workflow Grouper.
7822
+ *
7823
+ * CLOSES WP-V1.3-3 Coordination Handoff Visualization. Omega-1 (#191)
7824
+ * shipped the chronological handoff log; Omega-2 (#196) shipped the
7825
+ * per-handoff context-transfer breakdown; Omega-3 lifts isolated
7826
+ * handoff events into multi-handoff WORKFLOWS so the operator finally
7827
+ * sees the shape of a multi-agent collaboration as a single object:
7828
+ * who started it, who participated, how recently it was active, and
7829
+ * whether it is still in progress, stalled, or done.
7830
+ *
7831
+ * Pure functions. No I/O, no clock side effects beyond the optional
7832
+ * `now` argument for deterministic state determination. Tests inject
7833
+ * synthetic `HandoffEntry[]` and assert the grouping + state
7834
+ * decisions directly.
7835
+ *
7836
+ * Grouping algorithm:
7837
+ *
7838
+ * 1. Explicit link path: handoffs whose `workflow_link` field is
7839
+ * non-null group by that key. (At v1.3 Omega-1, Omega-1's
7840
+ * `normalize()` always sets the field to null. Omega-3 still
7841
+ * reads it because future Tau-X work will populate the field
7842
+ * from coordinator-emitted audit payloads, at which point
7843
+ * explicit grouping is the high-confidence path and the heuristic
7844
+ * becomes the fallback.)
7845
+ *
7846
+ * 2. Heuristic chain path: among handoffs without an explicit link,
7847
+ * sort by `observed_at` ascending and walk. A handoff joins an
7848
+ * existing workflow when (a) it shares at least one agent
7849
+ * (sender or recipient) with the most recent member of that
7850
+ * workflow AND (b) the time gap is at most HEURISTIC_WINDOW_MS
7851
+ * (5 minutes). Otherwise it starts a new workflow.
7852
+ *
7853
+ * This relaxes the literal "same source-target pair within 5
7854
+ * minutes" reading of the WP-V1.3-3 scope-lock to also handle
7855
+ * multi-hop chains like Cline -> OpenClaw -> Cursor, which is
7856
+ * what the operator-facing example in the scope-lock describes.
7857
+ * Without this relaxation, every hop in a chain becomes its own
7858
+ * "workflow" of one, and the dashboard surface loses the
7859
+ * legibility the WP-V1.3-3 acceptance gate promises. Documented
7860
+ * as a deviation in the PR body; consistent with how Phi-3
7861
+ * cross-agent-chatter shipped its connectivity heuristic.
7862
+ *
7863
+ * Root handoff: the oldest handoff in a workflow group. (At v1.3 there
7864
+ * is no audit-log surface for "this handoff was caused by handoff X",
7865
+ * so the chronological-oldest is the load-bearing root signal; when
7866
+ * Tau-X wires causal-link payloads, this rule extends without API
7867
+ * change.)
7868
+ *
7869
+ * State determination (in priority order):
7870
+ *
7871
+ * - `completed`: the last member's recipient is OPERATOR_PSEUDO_AGENT
7872
+ * (the workflow returned to the operator for approval / done),
7873
+ * OR the workflow has crossed >=2 hops and the last member returns
7874
+ * to the workflow's root agent (cycle closure).
7875
+ * - `stalled`: no member observed within STALL_THRESHOLD_MS (2h) of
7876
+ * `now`.
7877
+ * - `in_progress`: recent member within STALL_THRESHOLD_MS, no
7878
+ * completion signal.
7879
+ * - `unknown`: insufficient evidence (e.g., an empty member list,
7880
+ * which the grouper never emits but which we accept defensively
7881
+ * for downstream callers that synthesize Workflow objects).
7882
+ *
7883
+ * Castle-walking discipline:
7884
+ *
7885
+ * - No outbound surface. Pure computation over already-server-local
7886
+ * `HandoffEntry` records.
7887
+ * - No LLM call. The heuristic is rule-based.
7888
+ * - Multi-fortress isolation: the grouper takes whatever input it
7889
+ * receives; the caller (a `HandoffLog` instance scoped to ONE
7890
+ * fortress) is responsible for not mixing fortress data. The
7891
+ * route layer reads through `HandoffLog.query()` which already
7892
+ * enforces fortress boundary at the encryption layer.
7893
+ *
7894
+ * Out of scope for Omega-3 (deferred to v1.4+ federation): cross-
7895
+ * fortress workflow tracking. Workflow templating + operator-action
7896
+ * UI on stalled workflows ("auto-restart") are v1.5+ scope.
7897
+ */
7898
+
7899
+ /** Stable lifecycle-state enum surfaced into the operator UI. */
7900
+ type WorkflowState = "in_progress" | "completed" | "stalled" | "unknown";
7901
+ /**
7902
+ * One multi-handoff workflow grouped from the underlying handoff log.
7903
+ *
7904
+ * `workflow_id` is deterministic (SHA-256 of the root handoff's
7905
+ * `entry_id` truncated to 32 hex chars) so the same workflow re-
7906
+ * derives identical ids across server restarts. Tests and the SSE
7907
+ * stream rely on this stability for diff-based state-change
7908
+ * emission.
7909
+ *
7910
+ * `member_handoffs` is sorted oldest-first and INCLUDES the root.
7911
+ * `involved_agents` is deduplicated, alphabetically ordered. Empty
7912
+ * pseudo-agent strings are dropped; the OPERATOR_PSEUDO_AGENT is
7913
+ * preserved as a member because it signals completion.
7914
+ */
7915
+ interface Workflow {
7916
+ workflow_id: string;
7917
+ root_handoff: HandoffEntry;
7918
+ member_handoffs: HandoffEntry[];
7919
+ state: WorkflowState;
7920
+ started_at: string;
7921
+ last_activity_at: string;
7922
+ involved_agents: string[];
7923
+ }
7924
+
7925
+ /**
7926
+ * Sanctuary v1.3 WP-V1.3-3 Omega-3 Workflow State Tracker.
7927
+ *
7928
+ * Tracks the most-recently-observed `state` for each workflow_id so
7929
+ * the list-route handler can emit a `coordination_workflow_state_changed`
7930
+ * audit event when a workflow transitions (e.g., from `in_progress`
7931
+ * to `stalled`). Coordination state changes are operator-relevant
7932
+ * signals; the tracker makes them legible without coupling the pure
7933
+ * grouper to side effects.
7934
+ *
7935
+ * The tracker is fortress-scoped: callers construct one instance per
7936
+ * `HandoffLog` (which is itself per-fortress). Different fortresses
7937
+ * cannot leak state transitions into each other's audit logs because
7938
+ * each fortress has its own tracker holding its own snapshot map.
7939
+ *
7940
+ * Sovereignty invariants:
7941
+ *
7942
+ * - No outbound surface. The tracker is a stateful diff observer
7943
+ * over input from `groupHandoffsIntoWorkflows()`; it never reaches
7944
+ * the network and never reads storage on its own.
7945
+ * - No LLM call.
7946
+ * - Pure modulo the in-memory snapshot map. `observe()` is the only
7947
+ * mutating call.
7948
+ *
7949
+ * Threading: callers MUST NOT share a single tracker between
7950
+ * concurrent observers; the route handler in `handoff-routes.ts`
7951
+ * already holds the dispatch-side lock via the request lifecycle.
7952
+ */
7953
+
7954
+ /**
7955
+ * One emitted state-change event. The route handler audit-emits this
7956
+ * as `coordination_workflow_state_changed` and (optionally) pushes it
7957
+ * to SSE subscribers so the dashboard tab updates without a poll.
7958
+ */
7959
+ interface WorkflowStateChange {
7960
+ workflow_id: string;
7961
+ previous_state: WorkflowState | "unobserved";
7962
+ new_state: WorkflowState;
7963
+ observed_at: string;
7964
+ }
7965
+ interface WorkflowStateTrackerOptions {
7966
+ /**
7967
+ * Wall-clock provider for the emitted `observed_at` timestamp.
7968
+ * Defaults to a fresh `Date.now()` on each emit. Tests inject a
7969
+ * fixed clock so audit emissions stay deterministic.
7970
+ */
7971
+ now?: () => Date;
7972
+ }
7973
+ declare class WorkflowStateTracker {
7974
+ private readonly states;
7975
+ private readonly now;
7976
+ constructor(opts?: WorkflowStateTrackerOptions);
7977
+ /**
7978
+ * Diff the supplied workflow list against the last-observed states.
7979
+ * Returns the set of transitions detected this call; the tracker
7980
+ * mutates its internal map to reflect the new states.
7981
+ *
7982
+ * Transitions emitted:
7983
+ * - First observation of a workflow (`previous_state` is the
7984
+ * sentinel `unobserved`). Lets the route handler audit-emit
7985
+ * the initial state so the operator sees workflows as they
7986
+ * surface, not only when they change.
7987
+ * - Subsequent observation where `previous_state !== new_state`.
7988
+ */
7989
+ observe(workflows: ReadonlyArray<Workflow>): WorkflowStateChange[];
7990
+ /**
7991
+ * Drop a workflow's recorded state. Surfaced for tests + future
7992
+ * "operator dismissed this workflow" affordance; not currently
7993
+ * called by the production wiring.
7994
+ */
7995
+ forget(workflowId: string): void;
7996
+ /** Reset the tracker. Tests use this between runs. */
7997
+ reset(): void;
7998
+ /** Read-only view of the current snapshot. Useful for diagnostics. */
7999
+ snapshot(): ReadonlyMap<string, WorkflowState>;
8000
+ }
8001
+
7629
8002
  /**
7630
8003
  * Sanctuary v1.3 WP-V1.3-3 Omega-1 Coordination handoff HTTP routes.
7631
8004
  *
@@ -7754,6 +8127,8 @@ declare class DashboardApprovalChannel implements ApprovalChannel {
7754
8127
  */
7755
8128
  private handoffLog;
7756
8129
  private handoffEventBridge;
8130
+ private handoffContextTransfer;
8131
+ private workflowStateTracker;
7757
8132
  private handoffAuditLog;
7758
8133
  private handoffOperatorId;
7759
8134
  constructor(config: DashboardConfig);
@@ -7810,6 +8185,19 @@ declare class DashboardApprovalChannel implements ApprovalChannel {
7810
8185
  eventBridge?: HandoffEventBridge | null;
7811
8186
  auditLog?: AuditLog | null;
7812
8187
  operatorId?: string | null;
8188
+ /**
8189
+ * v1.3 WP-V1.3-3 Omega-2: context-transfer extractor deps. When
8190
+ * provided, the handoff detail route enriches its response with a
8191
+ * `context_transfer_breakdown` field.
8192
+ */
8193
+ contextTransfer?: ContextTransferExtractorDeps | null;
8194
+ /**
8195
+ * v1.3 WP-V1.3-3 Omega-3: workflow state tracker. When provided,
8196
+ * the workflow routes emit `coordination_workflow_state_changed`
8197
+ * audit events as the tracker observes transitions and push them
8198
+ * to SSE subscribers.
8199
+ */
8200
+ workflowStateTracker?: WorkflowStateTracker | null;
7813
8201
  }): void;
7814
8202
  /**
7815
8203
  * v1.3 WP-V1.3-10 dispatch entry point. Called from `handleRequest`