@sanctuary-framework/mcp-server 1.2.4 → 1.2.6
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 +1873 -123
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1873 -123
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +1582 -102
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +391 -4
- package/dist/index.d.ts +391 -4
- package/dist/index.js +1582 -102
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -252,6 +252,43 @@ interface ApprovalChannelConfig {
|
|
|
252
252
|
webhook_url?: string;
|
|
253
253
|
webhook_secret?: string;
|
|
254
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* WP-V1.3-10 Upsilon-2: cross-harness approval-redirect mode.
|
|
257
|
+
*
|
|
258
|
+
* `mode` selects how the underlying channel and the aggregator interact when
|
|
259
|
+
* a Tier 1/2 approval fires for a wrapped agent:
|
|
260
|
+
*
|
|
261
|
+
* - `replace`: the underlying channel is bypassed; the gate's
|
|
262
|
+
* `requestApproval()` blocks awaiting the operator's decision through
|
|
263
|
+
* the aggregator HTTP `approve`/`deny` routes (or any other surface that
|
|
264
|
+
* calls `aggregator.resolve()`). Default behavior when redirect is
|
|
265
|
+
* enabled.
|
|
266
|
+
* - `notify`: both the underlying channel AND the aggregator run; the
|
|
267
|
+
* first decision wins. Right shape for harnesses (e.g. Mastra) where
|
|
268
|
+
* full local-prompt suppression is not viable, so the operator still
|
|
269
|
+
* sees the prompt locally but ALSO can resolve from the unified inbox.
|
|
270
|
+
*
|
|
271
|
+
* `per_agent` is a stub for v1.4 multi-agent fortresses: a map of
|
|
272
|
+
* `agent_id -> {enabled, mode}` overrides. v1.x ignores this field; the
|
|
273
|
+
* fortress-level `enabled` + `mode` apply to every wrapped agent in the
|
|
274
|
+
* fortress (which is currently single-agent in practice). v1.4 adds
|
|
275
|
+
* agent-id propagation through the gate signature and consults this map.
|
|
276
|
+
*/
|
|
277
|
+
interface ApprovalRedirectPerAgentOverride {
|
|
278
|
+
enabled?: boolean;
|
|
279
|
+
mode?: "replace" | "notify";
|
|
280
|
+
}
|
|
281
|
+
interface ApprovalRedirectConfig {
|
|
282
|
+
/** Master toggle. When false, redirect-mode is off across the fortress. */
|
|
283
|
+
enabled: boolean;
|
|
284
|
+
/** How the underlying channel and the aggregator coexist. */
|
|
285
|
+
mode: "replace" | "notify";
|
|
286
|
+
/**
|
|
287
|
+
* Per-agent overrides. v1.x stub — populated entries are validated and
|
|
288
|
+
* persisted but not enforced. Reserved for v1.4 multi-agent fortresses.
|
|
289
|
+
*/
|
|
290
|
+
per_agent?: Record<string, ApprovalRedirectPerAgentOverride>;
|
|
291
|
+
}
|
|
255
292
|
/** Complete Principal Policy */
|
|
256
293
|
interface PrincipalPolicy {
|
|
257
294
|
version: number;
|
|
@@ -270,6 +307,13 @@ interface PrincipalPolicy {
|
|
|
270
307
|
* days when absent; values <= 0 fall back to the default.
|
|
271
308
|
*/
|
|
272
309
|
concierge_memory_retention_days?: number;
|
|
310
|
+
/**
|
|
311
|
+
* WP-V1.3-10 Upsilon-2: cross-harness approval-redirect mode. Optional;
|
|
312
|
+
* defaults to `{ enabled: false, mode: "replace" }` (preserves legacy
|
|
313
|
+
* behavior). Operator-toggled via `sanctuary agents config <tenant>
|
|
314
|
+
* --approval-redirect=<bool>` or by editing principal-policy.yaml.
|
|
315
|
+
*/
|
|
316
|
+
approval_redirect?: ApprovalRedirectConfig;
|
|
273
317
|
}
|
|
274
318
|
/** Approval request sent to the human */
|
|
275
319
|
interface ApprovalRequest {
|
|
@@ -5183,6 +5227,24 @@ interface ReadThreadOptions {
|
|
|
5183
5227
|
/** Cap the number of turns returned (oldest-first within the bundle). */
|
|
5184
5228
|
limit?: number;
|
|
5185
5229
|
}
|
|
5230
|
+
/**
|
|
5231
|
+
* Stable failure-reason enum for `readThreadStrict` (WP-V1.3-9 Tau-2).
|
|
5232
|
+
* Mirrors the shape carried by `operator_concierge_memory_read_failed`
|
|
5233
|
+
* audit payloads so the service emits the cause verbatim.
|
|
5234
|
+
*/
|
|
5235
|
+
type ConciergeMemoryReadFailure = "decrypt_failed" | "schema_mismatch" | "oversize_bundle" | "io_failed" | "unknown";
|
|
5236
|
+
/**
|
|
5237
|
+
* Discriminated result for `readThreadStrict`. The fold-read path uses
|
|
5238
|
+
* this so an empty thread (no bundle) does not look the same as a
|
|
5239
|
+
* corrupted bundle (which must trigger graceful degradation).
|
|
5240
|
+
*/
|
|
5241
|
+
type ReadThreadStrictResult = {
|
|
5242
|
+
ok: true;
|
|
5243
|
+
turns: ConciergeTurn[];
|
|
5244
|
+
} | {
|
|
5245
|
+
ok: false;
|
|
5246
|
+
reason: ConciergeMemoryReadFailure;
|
|
5247
|
+
};
|
|
5186
5248
|
interface ListThreadsOptions {
|
|
5187
5249
|
/** Cap the number of summaries returned. */
|
|
5188
5250
|
limit?: number;
|
|
@@ -5210,6 +5272,21 @@ declare class ConciergeMemoryStore {
|
|
|
5210
5272
|
* audit events; the caller (HTTP route handler) owns audit semantics.
|
|
5211
5273
|
*/
|
|
5212
5274
|
readThread(threadId: string, opts?: ReadThreadOptions): Promise<ConciergeTurn[]>;
|
|
5275
|
+
/**
|
|
5276
|
+
* Read turns with explicit failure surfacing (WP-V1.3-9 Tau-2). Where
|
|
5277
|
+
* `readThread` collapses every failure mode to an empty array, this
|
|
5278
|
+
* variant returns a discriminated result so the multi-turn fold path
|
|
5279
|
+
* can degrade cleanly + emit `operator_concierge_memory_read_failed`
|
|
5280
|
+
* with a concrete cause.
|
|
5281
|
+
*
|
|
5282
|
+
* - No bundle on disk → `{ ok: true, turns: [] }` (a fresh thread).
|
|
5283
|
+
* - Bundle present, decode + decrypt + schema check pass → ok with turns.
|
|
5284
|
+
* - Bundle present, oversize → `{ ok: false, reason: "oversize_bundle" }`.
|
|
5285
|
+
* - Bundle present, decryption fails → `{ ok: false, reason: "decrypt_failed" }`.
|
|
5286
|
+
* - Bundle present, schema mismatch (version / thread_id) → `schema_mismatch`.
|
|
5287
|
+
* - Storage IO error → `io_failed`.
|
|
5288
|
+
*/
|
|
5289
|
+
readThreadStrict(threadId: string, opts?: ReadThreadOptions): Promise<ReadThreadStrictResult>;
|
|
5213
5290
|
/**
|
|
5214
5291
|
* Enumerate concierge threads in this fortress with summary metadata.
|
|
5215
5292
|
* Sorted newest-first by last_turn_at.
|
|
@@ -5238,6 +5315,35 @@ declare class ConciergeMemoryStore {
|
|
|
5238
5315
|
private withLock;
|
|
5239
5316
|
}
|
|
5240
5317
|
|
|
5318
|
+
/**
|
|
5319
|
+
* Closed enum of categories the router may classify a query into. Adding
|
|
5320
|
+
* a category requires updating: this enum, the keyword table, the
|
|
5321
|
+
* fetcher interface, every wiring fetcher, and the test surface.
|
|
5322
|
+
*/
|
|
5323
|
+
type ContextCategory = "templates" | "agent_state" | "agent_activity" | "audit_log" | "sentinel_findings" | "anomaly_alerts" | "recent_receipts" | "verascore_deltas";
|
|
5324
|
+
/**
|
|
5325
|
+
* Caller-supplied data sources. Each fetcher returns plain text the
|
|
5326
|
+
* router stitches into the rendered section. Returning the empty string
|
|
5327
|
+
* (or whitespace only) is treated as "nothing to fold for this category"
|
|
5328
|
+
* and the category drops out of the final categoriesIncluded list.
|
|
5329
|
+
*/
|
|
5330
|
+
interface ContextFetchers {
|
|
5331
|
+
templates: () => Promise<string>;
|
|
5332
|
+
agent_state: (agentNameHint: string | null) => Promise<string>;
|
|
5333
|
+
agent_activity: (agentNameHint: string | null) => Promise<string>;
|
|
5334
|
+
audit_log: () => Promise<string>;
|
|
5335
|
+
sentinel_findings: () => Promise<string>;
|
|
5336
|
+
anomaly_alerts: () => Promise<string>;
|
|
5337
|
+
recent_receipts: () => Promise<string>;
|
|
5338
|
+
verascore_deltas: () => Promise<string>;
|
|
5339
|
+
}
|
|
5340
|
+
/**
|
|
5341
|
+
* Auxiliary classifier the caller may supply for the LLM-assist fallback
|
|
5342
|
+
* path. Invoked only when keyword classification returns zero matches
|
|
5343
|
+
* AND the query is non-trivial (>= 8 chars, not a clear greeting).
|
|
5344
|
+
*/
|
|
5345
|
+
type LlmAssistClassifier = (query: string, categories: readonly ContextCategory[]) => Promise<ContextCategory | "none">;
|
|
5346
|
+
|
|
5241
5347
|
/**
|
|
5242
5348
|
* Sanctuary MCP Server — Operator Chat Service
|
|
5243
5349
|
*
|
|
@@ -5342,13 +5448,72 @@ interface OperatorChatServiceDeps {
|
|
|
5342
5448
|
/**
|
|
5343
5449
|
* WP-V1.3-9 Tau-1: optional foundation memory store. When wired,
|
|
5344
5450
|
* `sendConcierge` dual-writes each operator+concierge turn pair into
|
|
5345
|
-
* the memory store under a session-scoped thread_id.
|
|
5346
|
-
*
|
|
5451
|
+
* the memory store under a session-scoped thread_id. Tau-2 adds a
|
|
5452
|
+
* read-fold path that surfaces the prior turns to the substrate so
|
|
5453
|
+
* the concierge maintains coherence across a multi-turn session.
|
|
5347
5454
|
*
|
|
5348
5455
|
* Omit at construction time to disable memory-side persistence; the
|
|
5349
5456
|
* existing `OperatorChatStore` write keeps working unchanged.
|
|
5350
5457
|
*/
|
|
5351
5458
|
conciergeMemory?: ConciergeMemoryStore;
|
|
5459
|
+
/**
|
|
5460
|
+
* WP-V1.3-9 Tau-2: maximum prior turns folded into the substrate
|
|
5461
|
+
* context per round-trip. Defaults to
|
|
5462
|
+
* `DEFAULT_CONCIERGE_HISTORY_WINDOW_TURNS` (10). The current operator
|
|
5463
|
+
* turn is always present; this caps history only.
|
|
5464
|
+
*/
|
|
5465
|
+
conciergeHistoryWindowTurns?: number;
|
|
5466
|
+
/**
|
|
5467
|
+
* WP-V1.3-9 Tau-2: prior turns older than this many milliseconds are
|
|
5468
|
+
* excluded from the active fold even when they remain on disk.
|
|
5469
|
+
* Defaults to `DEFAULT_CONCIERGE_HISTORY_FRESHNESS_MS` (24h).
|
|
5470
|
+
*/
|
|
5471
|
+
conciergeHistoryFreshnessMs?: number;
|
|
5472
|
+
/**
|
|
5473
|
+
* WP-V1.3-9 Tau-2: rough token budget for the prior-conversation
|
|
5474
|
+
* portion of the substrate context. Estimated as ~4 chars per token.
|
|
5475
|
+
* Defaults to `DEFAULT_CONCIERGE_HISTORY_TOKEN_BUDGET` (500). The
|
|
5476
|
+
* static reference block + fortress sections are NOT subject to this
|
|
5477
|
+
* budget; only the prior-conversation fold is pruned oldest-first.
|
|
5478
|
+
*/
|
|
5479
|
+
conciergeHistoryTokenBudget?: number;
|
|
5480
|
+
/**
|
|
5481
|
+
* WP-V1.3-9 Tau-2: how long an active session may stay quiet before
|
|
5482
|
+
* the next `sendConcierge` allocates a fresh thread_id. Defaults to
|
|
5483
|
+
* `DEFAULT_CONCIERGE_SESSION_TTL_MS` (24h). Does not delete the prior
|
|
5484
|
+
* thread; it remains readable through the memory store.
|
|
5485
|
+
*/
|
|
5486
|
+
conciergeSessionTtlMs?: number;
|
|
5487
|
+
/**
|
|
5488
|
+
* Optional clock for the session-TTL + freshness checks. Tests inject
|
|
5489
|
+
* a deterministic clock; production lets the default `Date.now`-based
|
|
5490
|
+
* implementation run.
|
|
5491
|
+
*/
|
|
5492
|
+
conciergeClock?: () => number;
|
|
5493
|
+
/**
|
|
5494
|
+
* WP-V1.3-9 Tau-3: caller-supplied fetchers for dynamic context
|
|
5495
|
+
* injection. When wired alongside the substrate selector, every
|
|
5496
|
+
* `sendConcierge` round-trip routes the operator's query through the
|
|
5497
|
+
* concierge-context-router and folds matching live data into the
|
|
5498
|
+
* substrate prompt between the static Sanctuary reference and the
|
|
5499
|
+
* prior-turns fold. Omit to disable dynamic context (the static
|
|
5500
|
+
* reference + prior-turns paths keep working unchanged).
|
|
5501
|
+
*/
|
|
5502
|
+
conciergeContextFetchers?: ContextFetchers;
|
|
5503
|
+
/**
|
|
5504
|
+
* WP-V1.3-9 Tau-3: optional LLM-assist classifier for queries that
|
|
5505
|
+
* fail keyword classification. Coordinator-CTO bake: when wired, the
|
|
5506
|
+
* service routes the auxiliary classifier call through the substrate
|
|
5507
|
+
* selector at the same `concierge` surface, so the auxiliary call
|
|
5508
|
+
* shares the operator's substrate choice and never opens a new
|
|
5509
|
+
* outbound surface.
|
|
5510
|
+
*/
|
|
5511
|
+
conciergeContextLlmAssist?: LlmAssistClassifier;
|
|
5512
|
+
/**
|
|
5513
|
+
* WP-V1.3-9 Tau-3: rough token budget for the dynamic-context fold.
|
|
5514
|
+
* Defaults to `DEFAULT_CONCIERGE_DYNAMIC_CONTEXT_BUDGET` (2000).
|
|
5515
|
+
*/
|
|
5516
|
+
conciergeDynamicContextBudget?: number;
|
|
5352
5517
|
}
|
|
5353
5518
|
declare class OperatorChatService {
|
|
5354
5519
|
private store;
|
|
@@ -5359,6 +5524,14 @@ declare class OperatorChatService {
|
|
|
5359
5524
|
private piiFilter?;
|
|
5360
5525
|
private conciergeMaxTokens;
|
|
5361
5526
|
private memory?;
|
|
5527
|
+
private historyWindowTurns;
|
|
5528
|
+
private historyFreshnessMs;
|
|
5529
|
+
private historyTokenBudget;
|
|
5530
|
+
private sessionTtlMs;
|
|
5531
|
+
private clock;
|
|
5532
|
+
private contextFetchers?;
|
|
5533
|
+
private contextLlmAssist?;
|
|
5534
|
+
private dynamicContextBudget;
|
|
5362
5535
|
/**
|
|
5363
5536
|
* In-memory thread_id assigned to the active concierge session.
|
|
5364
5537
|
* The first sendConcierge call after construction allocates a fresh
|
|
@@ -5366,6 +5539,14 @@ declare class OperatorChatService {
|
|
|
5366
5539
|
* folds the prior turns into context. Cleared by `resetConciergeMemoryThread`.
|
|
5367
5540
|
*/
|
|
5368
5541
|
private activeMemoryThreadId?;
|
|
5542
|
+
/**
|
|
5543
|
+
* Wall-clock ms of the most recent sendConcierge that touched the
|
|
5544
|
+
* active session thread. Drives the WP-V1.3-9 Tau-2 session-TTL
|
|
5545
|
+
* check: a fresh sendConcierge after `sessionTtlMs` of quiet
|
|
5546
|
+
* allocates a new thread_id even though the prior one is still
|
|
5547
|
+
* readable from the memory store.
|
|
5548
|
+
*/
|
|
5549
|
+
private lastInteractionAt?;
|
|
5369
5550
|
constructor(deps: OperatorChatServiceDeps);
|
|
5370
5551
|
/**
|
|
5371
5552
|
* Operator submit on the concierge surface. Persists the operator's
|
|
@@ -5378,6 +5559,13 @@ declare class OperatorChatService {
|
|
|
5378
5559
|
* operator sees on the page (no silent dropping).
|
|
5379
5560
|
*/
|
|
5380
5561
|
sendConcierge(query: string): Promise<ConciergeResponse>;
|
|
5562
|
+
/**
|
|
5563
|
+
* Emit the WP-V1.3-9 Tau-2 graceful-degradation audit event. Pulled
|
|
5564
|
+
* out of `sendConcierge` so the read-fold path stays readable. Emits
|
|
5565
|
+
* with `result: "failure"` since the concierge fell back to
|
|
5566
|
+
* single-turn mode for this round-trip.
|
|
5567
|
+
*/
|
|
5568
|
+
private emitMemoryReadFailed;
|
|
5381
5569
|
/**
|
|
5382
5570
|
* Read the persisted concierge thread, oldest message first. Returns
|
|
5383
5571
|
* an empty array when no thread exists yet.
|
|
@@ -5424,6 +5612,14 @@ declare class OperatorChatService {
|
|
|
5424
5612
|
* ## Sanctuary reference
|
|
5425
5613
|
* <static domain reference block>
|
|
5426
5614
|
*
|
|
5615
|
+
* ## Live fortress context ← WP-V1.3-9 Tau-3, when present
|
|
5616
|
+
* ### <Category>
|
|
5617
|
+
* <fetcher payload>
|
|
5618
|
+
*
|
|
5619
|
+
* ## Prior conversation ← WP-V1.3-9 Tau-2, when present
|
|
5620
|
+
* OPERATOR: ...
|
|
5621
|
+
* CONCIERGE: ...
|
|
5622
|
+
*
|
|
5427
5623
|
* ## Recent activity
|
|
5428
5624
|
* <recentActivity output>
|
|
5429
5625
|
*
|
|
@@ -5433,8 +5629,39 @@ declare class OperatorChatService {
|
|
|
5433
5629
|
* ## Open inbox
|
|
5434
5630
|
* <openInbox output>
|
|
5435
5631
|
* ```
|
|
5632
|
+
*
|
|
5633
|
+
* The substrate selector ships a `context: string` shape (not a
|
|
5634
|
+
* messages array), so multi-turn coherence is folded as a structured
|
|
5635
|
+
* prior-conversation section with explicit OPERATOR / CONCIERGE
|
|
5636
|
+
* boundaries. Coordinator-CTO guidance: prefer messages-array shape
|
|
5637
|
+
* if available; the v1.2 selector does not expose one, so structured
|
|
5638
|
+
* serialization is the canonical path for v1.3.
|
|
5436
5639
|
*/
|
|
5437
5640
|
private assembleConciergeContext;
|
|
5641
|
+
/**
|
|
5642
|
+
* Run the WP-V1.3-9 Tau-3 dynamic-context fold for a single round-
|
|
5643
|
+
* trip. Fail-soft on every axis: missing fetchers short-circuit to
|
|
5644
|
+
* an empty fold, fetcher failures emit a per-category audit event
|
|
5645
|
+
* and are omitted from the rendered section, an LLM-assist failure
|
|
5646
|
+
* proceeds with no fold. Returns the rendered section + the list of
|
|
5647
|
+
* categories whose data made it into the section (used for the
|
|
5648
|
+
* round-trip audit emission).
|
|
5649
|
+
*/
|
|
5650
|
+
private runDynamicContextFold;
|
|
5651
|
+
/**
|
|
5652
|
+
* Emit the WP-V1.3-9 Tau-3 fetcher-failure audit event. Pulled out
|
|
5653
|
+
* of the fold path so the dynamic-context handler stays readable.
|
|
5654
|
+
* Emits with `result: "failure"` since the named category dropped
|
|
5655
|
+
* from the rendered section for this round-trip.
|
|
5656
|
+
*/
|
|
5657
|
+
private emitContextFetcherFailed;
|
|
5658
|
+
/**
|
|
5659
|
+
* Render the prior-conversation section with token-budget enforcement
|
|
5660
|
+
* (WP-V1.3-9 Tau-2). Drops oldest turns first when the rendered
|
|
5661
|
+
* section exceeds `historyTokenBudget`. Returns an empty string when
|
|
5662
|
+
* the input is empty or when the budget excludes every turn.
|
|
5663
|
+
*/
|
|
5664
|
+
private formatPriorTurnsSection;
|
|
5438
5665
|
private emit;
|
|
5439
5666
|
}
|
|
5440
5667
|
|
|
@@ -5918,6 +6145,87 @@ interface V11Bindings {
|
|
|
5918
6145
|
operatorChatService?: OperatorChatService;
|
|
5919
6146
|
}
|
|
5920
6147
|
|
|
6148
|
+
/**
|
|
6149
|
+
* Sanctuary v1.3 WP-V1.3-10 Cross-Harness Approval Inbox Upsilon-3
|
|
6150
|
+
*
|
|
6151
|
+
* At-rest encrypted persistence for full request payloads tied to
|
|
6152
|
+
* AggregatedApproval entries. Sibling store to ApprovalAggregator: the
|
|
6153
|
+
* aggregator's own entry record (status, provenance, hashes) is persisted
|
|
6154
|
+
* by the aggregator class under `_approval_aggregator`; this store holds
|
|
6155
|
+
* the original request payload separately under
|
|
6156
|
+
* `_approval_aggregator_payloads` so the operator can replay the full
|
|
6157
|
+
* payload after a server restart.
|
|
6158
|
+
*
|
|
6159
|
+
* Storage layout:
|
|
6160
|
+
* namespace: `_approval_aggregator_payloads`
|
|
6161
|
+
* key: `payload.{aggregator_id}` (one record per approval)
|
|
6162
|
+
* payload: AES-256-GCM ciphertext of the JSON-serialised bundle.
|
|
6163
|
+
* key: `l2-approval-aggregator-payload-v1` HKDF subkey of fortress
|
|
6164
|
+
* master.
|
|
6165
|
+
* AAD: UTF-8 bytes of `aggregator_id`. Swapping records across
|
|
6166
|
+
* aggregator_ids breaks the auth tag. Castle-walking
|
|
6167
|
+
* discipline: the encryption boundary holds even against
|
|
6168
|
+
* on-disk shuffle.
|
|
6169
|
+
*
|
|
6170
|
+
* Retention:
|
|
6171
|
+
* Each bundle carries an ISO-8601 `retention_until`. `pruneExpired()`
|
|
6172
|
+
* iterates payloads and drops entries whose retention_until is in the
|
|
6173
|
+
* past. Default retention is 30 days, mirroring the audit-log retention
|
|
6174
|
+
* envelope. Operator override flows through the aggregator's deps.
|
|
6175
|
+
*
|
|
6176
|
+
* Multi-fortress isolation:
|
|
6177
|
+
* The HKDF subkey is derived from the fortress master key. Two
|
|
6178
|
+
* fortresses never produce identical encryption keys for identical
|
|
6179
|
+
* aggregator_ids. Isolation is enforced cryptographically; the AAD
|
|
6180
|
+
* binds the ciphertext to a specific aggregator_id within a fortress.
|
|
6181
|
+
*/
|
|
6182
|
+
|
|
6183
|
+
interface AggregatorPayloadStoreOptions {
|
|
6184
|
+
/** Storage backend that persists the encrypted bundles. */
|
|
6185
|
+
storage: StorageBackend;
|
|
6186
|
+
/** 32-byte fortress master key. */
|
|
6187
|
+
masterKey: Uint8Array;
|
|
6188
|
+
/** Stable fortress id stamped on every bundle for audit clarity. */
|
|
6189
|
+
fortressId: string;
|
|
6190
|
+
/** Operator-tunable retention window. Default 30 days. */
|
|
6191
|
+
retentionDays?: number;
|
|
6192
|
+
}
|
|
6193
|
+
/**
|
|
6194
|
+
* Encrypted, AAD-bound, retention-aware payload persistence for the
|
|
6195
|
+
* cross-harness approval inbox.
|
|
6196
|
+
*/
|
|
6197
|
+
declare class AggregatorPayloadStore {
|
|
6198
|
+
private readonly storage;
|
|
6199
|
+
private readonly encryptionKey;
|
|
6200
|
+
private readonly fortressId;
|
|
6201
|
+
private readonly retentionDays;
|
|
6202
|
+
constructor(opts: AggregatorPayloadStoreOptions);
|
|
6203
|
+
/**
|
|
6204
|
+
* Persist `payload` under the given aggregator_id. Idempotent; calling
|
|
6205
|
+
* twice with the same id rewrites the bundle (retention_until is
|
|
6206
|
+
* recomputed). Returns the bundle's retention_until ISO-8601 timestamp
|
|
6207
|
+
* so callers can log it.
|
|
6208
|
+
*/
|
|
6209
|
+
savePayload(aggregatorId: string, payload: unknown): Promise<string>;
|
|
6210
|
+
/**
|
|
6211
|
+
* Read the persisted payload for the aggregator_id. Returns null if no
|
|
6212
|
+
* bundle exists, the bundle is corrupted, or AAD binding fails.
|
|
6213
|
+
*/
|
|
6214
|
+
loadPayload(aggregatorId: string): Promise<unknown>;
|
|
6215
|
+
/**
|
|
6216
|
+
* Delete the persisted payload. Returns true when a bundle was removed,
|
|
6217
|
+
* false when none existed.
|
|
6218
|
+
*/
|
|
6219
|
+
deletePayload(aggregatorId: string): Promise<boolean>;
|
|
6220
|
+
/**
|
|
6221
|
+
* Drop expired payload bundles. Returns the count of bundles pruned.
|
|
6222
|
+
* Caller wires this into the cocoon-unlock initialization path.
|
|
6223
|
+
*/
|
|
6224
|
+
pruneExpired(now?: Date): Promise<{
|
|
6225
|
+
pruned: number;
|
|
6226
|
+
}>;
|
|
6227
|
+
}
|
|
6228
|
+
|
|
5921
6229
|
/**
|
|
5922
6230
|
* Sanctuary v1.3 WP-V1.3-10 Cross-Harness Approval Inbox Upsilon-1
|
|
5923
6231
|
*
|
|
@@ -5955,6 +6263,19 @@ interface V11Bindings {
|
|
|
5955
6263
|
* - `expired`: pending past TTL on a `list()` poll without a resolution.
|
|
5956
6264
|
*/
|
|
5957
6265
|
type AggregatedApprovalStatus = "pending" | "approved" | "denied" | "timeout" | "expired";
|
|
6266
|
+
/**
|
|
6267
|
+
* One step in the Castle Architecture enforcement chain that led to this
|
|
6268
|
+
* approval. Layers are: l1 (Castle Wall, OS-level egress), l2 (Sentinel +
|
|
6269
|
+
* cooperative MCP gate), l3 (selective disclosure), l4 (reputation).
|
|
6270
|
+
* v1.3 Upsilon-3 ships the schema; default resolver populates a single
|
|
6271
|
+
* `l2` entry. Future Castle Wall wiring will extend the chain when a
|
|
6272
|
+
* payload's egress was first observed by the kernel filter.
|
|
6273
|
+
*/
|
|
6274
|
+
interface EnforcementLayerEvent {
|
|
6275
|
+
layer: "l1" | "l2" | "l3" | "l4";
|
|
6276
|
+
event: string;
|
|
6277
|
+
timestamp: string;
|
|
6278
|
+
}
|
|
5958
6279
|
/**
|
|
5959
6280
|
* Normalized record the aggregator stores per approval. Field set is
|
|
5960
6281
|
* additive-stable; new fields go behind `?` so existing dashboards keep
|
|
@@ -5999,6 +6320,15 @@ interface AggregatedApproval {
|
|
|
5999
6320
|
* (the cross-link signal lives on the aggregator side only).
|
|
6000
6321
|
*/
|
|
6001
6322
|
hub_inbox_item_id?: string;
|
|
6323
|
+
/**
|
|
6324
|
+
* Castle Architecture enforcement-layer chain that led to this
|
|
6325
|
+
* approval. Populated by the optional `resolveEnforcementChain` deps
|
|
6326
|
+
* hook; default returns a single `l2` step (cooperative MCP gate
|
|
6327
|
+
* fired). Persisted with the entry so the operator-replay surface can
|
|
6328
|
+
* render the enforcement context after a server restart. v1.3
|
|
6329
|
+
* Upsilon-3.
|
|
6330
|
+
*/
|
|
6331
|
+
enforcement_chain?: EnforcementLayerEvent[];
|
|
6002
6332
|
}
|
|
6003
6333
|
/**
|
|
6004
6334
|
* Source-context resolver. Called once per ingest to map gate context to
|
|
@@ -6087,6 +6417,23 @@ interface ApprovalAggregatorDeps {
|
|
|
6087
6417
|
* hub inbox store.
|
|
6088
6418
|
*/
|
|
6089
6419
|
resolveHubInboxItemId?: (event: ApprovalGateEvent) => string | undefined;
|
|
6420
|
+
/**
|
|
6421
|
+
* Optional at-rest payload store. When provided, the aggregator
|
|
6422
|
+
* persists each request payload via `savePayload` on ingest, and
|
|
6423
|
+
* rehydrates payloads on `getFullPayload` if the in-memory map lost
|
|
6424
|
+
* them (e.g. after a server restart). Upsilon-3 surface; absent in
|
|
6425
|
+
* Upsilon-1 / Upsilon-2 deployments, where payloads remain in-memory
|
|
6426
|
+
* only.
|
|
6427
|
+
*/
|
|
6428
|
+
payloadStore?: AggregatorPayloadStore;
|
|
6429
|
+
/**
|
|
6430
|
+
* Optional resolver for the Castle Architecture enforcement chain
|
|
6431
|
+
* leading to this approval. Default returns a single `l2` step
|
|
6432
|
+
* (cooperative MCP gate fired). When the Castle Wall (Layer 1) ships,
|
|
6433
|
+
* its kernel-filter observer can populate richer chains by passing a
|
|
6434
|
+
* resolver here.
|
|
6435
|
+
*/
|
|
6436
|
+
resolveEnforcementChain?: (event: ApprovalGateEvent) => EnforcementLayerEvent[];
|
|
6090
6437
|
}
|
|
6091
6438
|
/**
|
|
6092
6439
|
* Aggregator state. The map is hydrated lazily from the encrypted
|
|
@@ -6103,6 +6450,8 @@ declare class ApprovalAggregator {
|
|
|
6103
6450
|
private readonly now;
|
|
6104
6451
|
private readonly resolveSourceContext;
|
|
6105
6452
|
private readonly resolveHubInboxItemId;
|
|
6453
|
+
private readonly payloadStore;
|
|
6454
|
+
private readonly resolveEnforcementChain;
|
|
6106
6455
|
/** Cached entries by `aggregator_id`. */
|
|
6107
6456
|
private readonly entries;
|
|
6108
6457
|
/** Dedup index: `${harness}|${agent}|${audit_id}` -> aggregator_id. */
|
|
@@ -6141,10 +6490,48 @@ declare class ApprovalAggregator {
|
|
|
6141
6490
|
}): Promise<AggregatedApproval[]>;
|
|
6142
6491
|
/**
|
|
6143
6492
|
* Return the original (unhashed) request payload for the entry. Returns
|
|
6144
|
-
* `null` when the entry is unknown
|
|
6145
|
-
*
|
|
6493
|
+
* `null` when the entry is unknown. When the in-memory payload map has
|
|
6494
|
+
* been evicted (e.g. after a server restart) and a `payloadStore` was
|
|
6495
|
+
* provided, the at-rest bundle is decrypted and the in-memory map is
|
|
6496
|
+
* refilled. Audit emission lives on the `*WithAudit` variant; this base
|
|
6497
|
+
* accessor is silent so internal callers can read without polluting the
|
|
6498
|
+
* audit trail.
|
|
6146
6499
|
*/
|
|
6147
6500
|
getFullPayload(aggregatorId: string): Promise<unknown>;
|
|
6501
|
+
/**
|
|
6502
|
+
* Return the entry record for the given id, or null when unknown.
|
|
6503
|
+
* Idempotent. v1.3 Upsilon-3.
|
|
6504
|
+
*/
|
|
6505
|
+
getEntry(aggregatorId: string): Promise<AggregatedApproval | null>;
|
|
6506
|
+
/**
|
|
6507
|
+
* Audited variant of `getFullPayload`. Emits the
|
|
6508
|
+
* `cross_harness_approval_payload_decrypted` audit event before
|
|
6509
|
+
* returning. Used by the operator-facing /payload replay route.
|
|
6510
|
+
* v1.3 Upsilon-3.
|
|
6511
|
+
*/
|
|
6512
|
+
getFullPayloadWithAudit(aggregatorId: string, operatorId: string): Promise<unknown>;
|
|
6513
|
+
/**
|
|
6514
|
+
* Return the audit-log entries that led to and surround this approval.
|
|
6515
|
+
* Best-effort matching: aggregator-side emissions (AGGREGATED, RESOLVED,
|
|
6516
|
+
* DEDUPED, replay events) all carry `details.aggregator_id` and link
|
|
6517
|
+
* directly. Gate-side emissions (`gate_*:operation`) do not carry the
|
|
6518
|
+
* aggregator id at v1.3, so they are matched via timestamp window
|
|
6519
|
+
* (entry.created_at to entry.resolved_at + 1s, or expires_at + 1s while
|
|
6520
|
+
* pending) and operation suffix. Emits AUDIT_TRAIL_VIEWED on call.
|
|
6521
|
+
* v1.3 Upsilon-3.
|
|
6522
|
+
*/
|
|
6523
|
+
getAuditTrail(aggregatorId: string, operatorId: string): Promise<AuditEntry[]>;
|
|
6524
|
+
/**
|
|
6525
|
+
* List historical (resolved) approvals. Excludes pending entries by
|
|
6526
|
+
* design: `list()` is the pending-inbox surface and `getHistory()` is
|
|
6527
|
+
* the resolved-replay surface. Emits REPLAYED on each call. v1.3
|
|
6528
|
+
* Upsilon-3.
|
|
6529
|
+
*/
|
|
6530
|
+
getHistory(opts: {
|
|
6531
|
+
status?: AggregatedApprovalStatus;
|
|
6532
|
+
sinceTs?: string;
|
|
6533
|
+
limit?: number;
|
|
6534
|
+
} | undefined, operatorId: string): Promise<AggregatedApproval[]>;
|
|
6148
6535
|
/**
|
|
6149
6536
|
* Resolve an entry. Used by both:
|
|
6150
6537
|
* 1. The gate wire-up on channel-decision return.
|