@sanctuary-framework/mcp-server 1.2.5 → 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 +864 -35
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +864 -35
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +847 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +239 -3
- package/dist/index.d.ts +239 -3
- package/dist/index.js +847 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -5315,6 +5315,35 @@ declare class ConciergeMemoryStore {
|
|
|
5315
5315
|
private withLock;
|
|
5316
5316
|
}
|
|
5317
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
|
+
|
|
5318
5347
|
/**
|
|
5319
5348
|
* Sanctuary MCP Server — Operator Chat Service
|
|
5320
5349
|
*
|
|
@@ -5461,6 +5490,30 @@ interface OperatorChatServiceDeps {
|
|
|
5461
5490
|
* implementation run.
|
|
5462
5491
|
*/
|
|
5463
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;
|
|
5464
5517
|
}
|
|
5465
5518
|
declare class OperatorChatService {
|
|
5466
5519
|
private store;
|
|
@@ -5476,6 +5529,9 @@ declare class OperatorChatService {
|
|
|
5476
5529
|
private historyTokenBudget;
|
|
5477
5530
|
private sessionTtlMs;
|
|
5478
5531
|
private clock;
|
|
5532
|
+
private contextFetchers?;
|
|
5533
|
+
private contextLlmAssist?;
|
|
5534
|
+
private dynamicContextBudget;
|
|
5479
5535
|
/**
|
|
5480
5536
|
* In-memory thread_id assigned to the active concierge session.
|
|
5481
5537
|
* The first sendConcierge call after construction allocates a fresh
|
|
@@ -5556,10 +5612,13 @@ declare class OperatorChatService {
|
|
|
5556
5612
|
* ## Sanctuary reference
|
|
5557
5613
|
* <static domain reference block>
|
|
5558
5614
|
*
|
|
5615
|
+
* ## Live fortress context ← WP-V1.3-9 Tau-3, when present
|
|
5616
|
+
* ### <Category>
|
|
5617
|
+
* <fetcher payload>
|
|
5618
|
+
*
|
|
5559
5619
|
* ## Prior conversation ← WP-V1.3-9 Tau-2, when present
|
|
5560
5620
|
* OPERATOR: ...
|
|
5561
5621
|
* CONCIERGE: ...
|
|
5562
|
-
* ---
|
|
5563
5622
|
*
|
|
5564
5623
|
* ## Recent activity
|
|
5565
5624
|
* <recentActivity output>
|
|
@@ -5579,6 +5638,23 @@ declare class OperatorChatService {
|
|
|
5579
5638
|
* serialization is the canonical path for v1.3.
|
|
5580
5639
|
*/
|
|
5581
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;
|
|
5582
5658
|
/**
|
|
5583
5659
|
* Render the prior-conversation section with token-budget enforcement
|
|
5584
5660
|
* (WP-V1.3-9 Tau-2). Drops oldest turns first when the rendered
|
|
@@ -6069,6 +6145,87 @@ interface V11Bindings {
|
|
|
6069
6145
|
operatorChatService?: OperatorChatService;
|
|
6070
6146
|
}
|
|
6071
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
|
+
|
|
6072
6229
|
/**
|
|
6073
6230
|
* Sanctuary v1.3 WP-V1.3-10 Cross-Harness Approval Inbox Upsilon-1
|
|
6074
6231
|
*
|
|
@@ -6106,6 +6263,19 @@ interface V11Bindings {
|
|
|
6106
6263
|
* - `expired`: pending past TTL on a `list()` poll without a resolution.
|
|
6107
6264
|
*/
|
|
6108
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
|
+
}
|
|
6109
6279
|
/**
|
|
6110
6280
|
* Normalized record the aggregator stores per approval. Field set is
|
|
6111
6281
|
* additive-stable; new fields go behind `?` so existing dashboards keep
|
|
@@ -6150,6 +6320,15 @@ interface AggregatedApproval {
|
|
|
6150
6320
|
* (the cross-link signal lives on the aggregator side only).
|
|
6151
6321
|
*/
|
|
6152
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[];
|
|
6153
6332
|
}
|
|
6154
6333
|
/**
|
|
6155
6334
|
* Source-context resolver. Called once per ingest to map gate context to
|
|
@@ -6238,6 +6417,23 @@ interface ApprovalAggregatorDeps {
|
|
|
6238
6417
|
* hub inbox store.
|
|
6239
6418
|
*/
|
|
6240
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[];
|
|
6241
6437
|
}
|
|
6242
6438
|
/**
|
|
6243
6439
|
* Aggregator state. The map is hydrated lazily from the encrypted
|
|
@@ -6254,6 +6450,8 @@ declare class ApprovalAggregator {
|
|
|
6254
6450
|
private readonly now;
|
|
6255
6451
|
private readonly resolveSourceContext;
|
|
6256
6452
|
private readonly resolveHubInboxItemId;
|
|
6453
|
+
private readonly payloadStore;
|
|
6454
|
+
private readonly resolveEnforcementChain;
|
|
6257
6455
|
/** Cached entries by `aggregator_id`. */
|
|
6258
6456
|
private readonly entries;
|
|
6259
6457
|
/** Dedup index: `${harness}|${agent}|${audit_id}` -> aggregator_id. */
|
|
@@ -6292,10 +6490,48 @@ declare class ApprovalAggregator {
|
|
|
6292
6490
|
}): Promise<AggregatedApproval[]>;
|
|
6293
6491
|
/**
|
|
6294
6492
|
* Return the original (unhashed) request payload for the entry. Returns
|
|
6295
|
-
* `null` when the entry is unknown
|
|
6296
|
-
*
|
|
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.
|
|
6297
6499
|
*/
|
|
6298
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[]>;
|
|
6299
6535
|
/**
|
|
6300
6536
|
* Resolve an entry. Used by both:
|
|
6301
6537
|
* 1. The gate wire-up on channel-decision return.
|
package/dist/index.d.ts
CHANGED
|
@@ -5315,6 +5315,35 @@ declare class ConciergeMemoryStore {
|
|
|
5315
5315
|
private withLock;
|
|
5316
5316
|
}
|
|
5317
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
|
+
|
|
5318
5347
|
/**
|
|
5319
5348
|
* Sanctuary MCP Server — Operator Chat Service
|
|
5320
5349
|
*
|
|
@@ -5461,6 +5490,30 @@ interface OperatorChatServiceDeps {
|
|
|
5461
5490
|
* implementation run.
|
|
5462
5491
|
*/
|
|
5463
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;
|
|
5464
5517
|
}
|
|
5465
5518
|
declare class OperatorChatService {
|
|
5466
5519
|
private store;
|
|
@@ -5476,6 +5529,9 @@ declare class OperatorChatService {
|
|
|
5476
5529
|
private historyTokenBudget;
|
|
5477
5530
|
private sessionTtlMs;
|
|
5478
5531
|
private clock;
|
|
5532
|
+
private contextFetchers?;
|
|
5533
|
+
private contextLlmAssist?;
|
|
5534
|
+
private dynamicContextBudget;
|
|
5479
5535
|
/**
|
|
5480
5536
|
* In-memory thread_id assigned to the active concierge session.
|
|
5481
5537
|
* The first sendConcierge call after construction allocates a fresh
|
|
@@ -5556,10 +5612,13 @@ declare class OperatorChatService {
|
|
|
5556
5612
|
* ## Sanctuary reference
|
|
5557
5613
|
* <static domain reference block>
|
|
5558
5614
|
*
|
|
5615
|
+
* ## Live fortress context ← WP-V1.3-9 Tau-3, when present
|
|
5616
|
+
* ### <Category>
|
|
5617
|
+
* <fetcher payload>
|
|
5618
|
+
*
|
|
5559
5619
|
* ## Prior conversation ← WP-V1.3-9 Tau-2, when present
|
|
5560
5620
|
* OPERATOR: ...
|
|
5561
5621
|
* CONCIERGE: ...
|
|
5562
|
-
* ---
|
|
5563
5622
|
*
|
|
5564
5623
|
* ## Recent activity
|
|
5565
5624
|
* <recentActivity output>
|
|
@@ -5579,6 +5638,23 @@ declare class OperatorChatService {
|
|
|
5579
5638
|
* serialization is the canonical path for v1.3.
|
|
5580
5639
|
*/
|
|
5581
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;
|
|
5582
5658
|
/**
|
|
5583
5659
|
* Render the prior-conversation section with token-budget enforcement
|
|
5584
5660
|
* (WP-V1.3-9 Tau-2). Drops oldest turns first when the rendered
|
|
@@ -6069,6 +6145,87 @@ interface V11Bindings {
|
|
|
6069
6145
|
operatorChatService?: OperatorChatService;
|
|
6070
6146
|
}
|
|
6071
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
|
+
|
|
6072
6229
|
/**
|
|
6073
6230
|
* Sanctuary v1.3 WP-V1.3-10 Cross-Harness Approval Inbox Upsilon-1
|
|
6074
6231
|
*
|
|
@@ -6106,6 +6263,19 @@ interface V11Bindings {
|
|
|
6106
6263
|
* - `expired`: pending past TTL on a `list()` poll without a resolution.
|
|
6107
6264
|
*/
|
|
6108
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
|
+
}
|
|
6109
6279
|
/**
|
|
6110
6280
|
* Normalized record the aggregator stores per approval. Field set is
|
|
6111
6281
|
* additive-stable; new fields go behind `?` so existing dashboards keep
|
|
@@ -6150,6 +6320,15 @@ interface AggregatedApproval {
|
|
|
6150
6320
|
* (the cross-link signal lives on the aggregator side only).
|
|
6151
6321
|
*/
|
|
6152
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[];
|
|
6153
6332
|
}
|
|
6154
6333
|
/**
|
|
6155
6334
|
* Source-context resolver. Called once per ingest to map gate context to
|
|
@@ -6238,6 +6417,23 @@ interface ApprovalAggregatorDeps {
|
|
|
6238
6417
|
* hub inbox store.
|
|
6239
6418
|
*/
|
|
6240
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[];
|
|
6241
6437
|
}
|
|
6242
6438
|
/**
|
|
6243
6439
|
* Aggregator state. The map is hydrated lazily from the encrypted
|
|
@@ -6254,6 +6450,8 @@ declare class ApprovalAggregator {
|
|
|
6254
6450
|
private readonly now;
|
|
6255
6451
|
private readonly resolveSourceContext;
|
|
6256
6452
|
private readonly resolveHubInboxItemId;
|
|
6453
|
+
private readonly payloadStore;
|
|
6454
|
+
private readonly resolveEnforcementChain;
|
|
6257
6455
|
/** Cached entries by `aggregator_id`. */
|
|
6258
6456
|
private readonly entries;
|
|
6259
6457
|
/** Dedup index: `${harness}|${agent}|${audit_id}` -> aggregator_id. */
|
|
@@ -6292,10 +6490,48 @@ declare class ApprovalAggregator {
|
|
|
6292
6490
|
}): Promise<AggregatedApproval[]>;
|
|
6293
6491
|
/**
|
|
6294
6492
|
* Return the original (unhashed) request payload for the entry. Returns
|
|
6295
|
-
* `null` when the entry is unknown
|
|
6296
|
-
*
|
|
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.
|
|
6297
6499
|
*/
|
|
6298
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[]>;
|
|
6299
6535
|
/**
|
|
6300
6536
|
* Resolve an entry. Used by both:
|
|
6301
6537
|
* 1. The gate wire-up on channel-decision return.
|