@animalabs/agent-framework 0.32.0 → 0.33.0
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/README.md +204 -14
- package/dist/src/admission/admit.d.ts +18 -0
- package/dist/src/admission/admit.d.ts.map +1 -1
- package/dist/src/admission/admit.js +16 -3
- package/dist/src/admission/admit.js.map +1 -1
- package/dist/src/agent.d.ts +185 -78
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +279 -102
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/mcp-server-core.d.ts.map +1 -1
- package/dist/src/api/mcp-server-core.js +50 -12
- package/dist/src/api/mcp-server-core.js.map +1 -1
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +4 -20
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/code-execution/isolate/scripts.d.ts +12 -8
- package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -1
- package/dist/src/code-execution/isolate/scripts.js +24 -0
- package/dist/src/code-execution/isolate/scripts.js.map +1 -1
- package/dist/src/config-checks.d.ts +7 -0
- package/dist/src/config-checks.d.ts.map +1 -1
- package/dist/src/config-checks.js +14 -0
- package/dist/src/config-checks.js.map +1 -1
- package/dist/src/context-manager-errors.d.ts +25 -0
- package/dist/src/context-manager-errors.d.ts.map +1 -0
- package/dist/src/context-manager-errors.js +31 -0
- package/dist/src/context-manager-errors.js.map +1 -0
- package/dist/src/context-options.d.ts +67 -0
- package/dist/src/context-options.d.ts.map +1 -0
- package/dist/src/context-options.js +85 -0
- package/dist/src/context-options.js.map +1 -0
- package/dist/src/deferred-import.d.ts +93 -0
- package/dist/src/deferred-import.d.ts.map +1 -0
- package/dist/src/deferred-import.js +177 -0
- package/dist/src/deferred-import.js.map +1 -0
- package/dist/src/dendrite/audience.d.ts +223 -0
- package/dist/src/dendrite/audience.d.ts.map +1 -0
- package/dist/src/dendrite/audience.js +202 -0
- package/dist/src/dendrite/audience.js.map +1 -0
- package/dist/src/dendrite/index.d.ts +5 -3
- package/dist/src/dendrite/index.d.ts.map +1 -1
- package/dist/src/dendrite/index.js +2 -1
- package/dist/src/dendrite/index.js.map +1 -1
- package/dist/src/dendrite/presets.d.ts +10 -5
- package/dist/src/dendrite/presets.d.ts.map +1 -1
- package/dist/src/dendrite/presets.js +17 -5
- package/dist/src/dendrite/presets.js.map +1 -1
- package/dist/src/dendrite/registry.d.ts +62 -7
- package/dist/src/dendrite/registry.d.ts.map +1 -1
- package/dist/src/dendrite/registry.js +179 -10
- package/dist/src/dendrite/registry.js.map +1 -1
- package/dist/src/dendrite/types.d.ts +91 -8
- package/dist/src/dendrite/types.d.ts.map +1 -1
- package/dist/src/foreign-rounds.d.ts +69 -0
- package/dist/src/foreign-rounds.d.ts.map +1 -0
- package/dist/src/foreign-rounds.js +152 -0
- package/dist/src/foreign-rounds.js.map +1 -0
- package/dist/src/framework.d.ts +1976 -818
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +7566 -3422
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +85 -15
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +421 -47
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/gate/index.d.ts +1 -1
- package/dist/src/gate/index.d.ts.map +1 -1
- package/dist/src/gate/index.js.map +1 -1
- package/dist/src/gate/rule-scope.d.ts +30 -0
- package/dist/src/gate/rule-scope.d.ts.map +1 -0
- package/dist/src/gate/rule-scope.js +41 -0
- package/dist/src/gate/rule-scope.js.map +1 -0
- package/dist/src/gate/suppress-script-worker.d.ts +2 -0
- package/dist/src/gate/suppress-script-worker.d.ts.map +1 -0
- package/dist/src/gate/suppress-script-worker.js +103 -0
- package/dist/src/gate/suppress-script-worker.js.map +1 -0
- package/dist/src/gate/suppress-scripts.d.ts +105 -0
- package/dist/src/gate/suppress-scripts.d.ts.map +1 -0
- package/dist/src/gate/suppress-scripts.js +403 -0
- package/dist/src/gate/suppress-scripts.js.map +1 -0
- package/dist/src/gate/suppression-review.d.ts +143 -0
- package/dist/src/gate/suppression-review.d.ts.map +1 -0
- package/dist/src/gate/suppression-review.js +463 -0
- package/dist/src/gate/suppression-review.js.map +1 -0
- package/dist/src/gate/suppression-stats.d.ts +125 -0
- package/dist/src/gate/suppression-stats.d.ts.map +1 -0
- package/dist/src/gate/suppression-stats.js +214 -0
- package/dist/src/gate/suppression-stats.js.map +1 -0
- package/dist/src/gate/types.d.ts +135 -7
- package/dist/src/gate/types.d.ts.map +1 -1
- package/dist/src/gate/wake-onboarding.d.ts +119 -0
- package/dist/src/gate/wake-onboarding.d.ts.map +1 -0
- package/dist/src/gate/wake-onboarding.js +277 -0
- package/dist/src/gate/wake-onboarding.js.map +1 -0
- package/dist/src/held-writes.d.ts +31 -23
- package/dist/src/held-writes.d.ts.map +1 -1
- package/dist/src/held-writes.js +44 -59
- package/dist/src/held-writes.js.map +1 -1
- package/dist/src/index.d.ts +5 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/jsonrpc-envelope.d.ts +69 -0
- package/dist/src/jsonrpc-envelope.d.ts.map +1 -0
- package/dist/src/jsonrpc-envelope.js +66 -0
- package/dist/src/jsonrpc-envelope.js.map +1 -0
- package/dist/src/mcpl/channel-registry.d.ts +131 -15
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +290 -46
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/checkpoint-manager.d.ts +2 -4
- package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
- package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
- package/dist/src/mcpl/feature-set-manager.d.ts +2 -4
- package/dist/src/mcpl/feature-set-manager.d.ts.map +1 -1
- package/dist/src/mcpl/feature-set-manager.js.map +1 -1
- package/dist/src/mcpl/inbound-source.d.ts +2 -1
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
- package/dist/src/mcpl/inbound-source.js +2 -1
- package/dist/src/mcpl/inbound-source.js.map +1 -1
- package/dist/src/mcpl/inference-router.d.ts +6 -6
- package/dist/src/mcpl/inference-router.d.ts.map +1 -1
- package/dist/src/mcpl/inference-router.js.map +1 -1
- package/dist/src/mcpl/push-coalescer.d.ts +132 -22
- package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
- package/dist/src/mcpl/push-coalescer.js +105 -15
- package/dist/src/mcpl/push-coalescer.js.map +1 -1
- package/dist/src/mcpl/push-handler.d.ts +9 -7
- package/dist/src/mcpl/push-handler.d.ts.map +1 -1
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +13 -10
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +134 -56
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/tool-classes.d.ts.map +1 -1
- package/dist/src/mcpl/tool-classes.js +3 -0
- package/dist/src/mcpl/tool-classes.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +8 -2
- package/dist/src/mcpl/types.d.ts.map +1 -1
- package/dist/src/mcpl/types.js.map +1 -1
- package/dist/src/module-registry.d.ts +24 -1
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +68 -18
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/discord/index.d.ts +45 -8
- package/dist/src/modules/discord/index.d.ts.map +1 -1
- package/dist/src/modules/discord/index.js +237 -86
- package/dist/src/modules/discord/index.js.map +1 -1
- package/dist/src/modules/history/index.d.ts +59 -0
- package/dist/src/modules/history/index.d.ts.map +1 -1
- package/dist/src/modules/history/index.js +432 -67
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/modules/history/semantic.d.ts +6 -5
- package/dist/src/modules/history/semantic.d.ts.map +1 -1
- package/dist/src/modules/history/semantic.js +15 -22
- package/dist/src/modules/history/semantic.js.map +1 -1
- package/dist/src/modules/workspace/disk-agreement.d.ts +1 -1
- package/dist/src/modules/workspace/disk-agreement.js +1 -1
- package/dist/src/modules/workspace/index.d.ts +28 -7
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +76 -22
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/notice-tags.d.ts +10 -1
- package/dist/src/notice-tags.d.ts.map +1 -1
- package/dist/src/notice-tags.js +10 -1
- package/dist/src/notice-tags.js.map +1 -1
- package/dist/src/operator-log.d.ts +36 -3
- package/dist/src/operator-log.d.ts.map +1 -1
- package/dist/src/operator-log.js +2 -2
- package/dist/src/operator-log.js.map +1 -1
- package/dist/src/presentation.d.ts +746 -0
- package/dist/src/presentation.d.ts.map +1 -0
- package/dist/src/presentation.js +1435 -0
- package/dist/src/presentation.js.map +1 -0
- package/dist/src/prose-drafts.d.ts +15 -11
- package/dist/src/prose-drafts.d.ts.map +1 -1
- package/dist/src/prose-drafts.js +16 -12
- package/dist/src/prose-drafts.js.map +1 -1
- package/dist/src/read-marks.d.ts +192 -0
- package/dist/src/read-marks.d.ts.map +1 -0
- package/dist/src/read-marks.js +242 -0
- package/dist/src/read-marks.js.map +1 -0
- package/dist/src/recovery/offline-branch.d.ts +91 -6
- package/dist/src/recovery/offline-branch.d.ts.map +1 -1
- package/dist/src/recovery/offline-branch.js +273 -29
- package/dist/src/recovery/offline-branch.js.map +1 -1
- package/dist/src/recovery/recover-cli.js +22 -3
- package/dist/src/recovery/recover-cli.js.map +1 -1
- package/dist/src/send-tools.d.ts +5 -9
- package/dist/src/send-tools.d.ts.map +1 -1
- package/dist/src/send-tools.js +40 -7
- package/dist/src/send-tools.js.map +1 -1
- package/dist/src/stored-injections.d.ts +2 -2
- package/dist/src/stored-injections.js +2 -2
- package/dist/src/stored-removal.d.ts +17 -4
- package/dist/src/stored-removal.d.ts.map +1 -1
- package/dist/src/stored-removal.js +29 -5
- package/dist/src/stored-removal.js.map +1 -1
- package/dist/src/tool-result-guard.d.ts +12 -1
- package/dist/src/tool-result-guard.d.ts.map +1 -1
- package/dist/src/tool-result-guard.js +42 -8
- package/dist/src/tool-result-guard.js.map +1 -1
- package/dist/src/tune-out/coordinator.d.ts +1159 -79
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +3709 -363
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/tune-out/tools.d.ts +114 -17
- package/dist/src/tune-out/tools.d.ts.map +1 -1
- package/dist/src/tune-out/tools.js +87 -27
- package/dist/src/tune-out/tools.js.map +1 -1
- package/dist/src/tune-out/window-anchor.d.ts +143 -0
- package/dist/src/tune-out/window-anchor.d.ts.map +1 -0
- package/dist/src/tune-out/window-anchor.js +202 -0
- package/dist/src/tune-out/window-anchor.js.map +1 -0
- package/dist/src/types/agent.d.ts +82 -20
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/events.d.ts +2 -0
- package/dist/src/types/events.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +32 -12
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +180 -69
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +510 -36
- package/dist/src/types/trace.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/admission/admit.ts +32 -3
- package/src/agent.ts +323 -120
- package/src/api/mcp-server-core.ts +54 -17
- package/src/api/server.ts +4 -23
- package/src/code-execution/isolate/scripts.ts +28 -3
- package/src/config-checks.ts +14 -0
- package/src/context-manager-errors.ts +37 -0
- package/src/context-options.ts +96 -0
- package/src/deferred-import.ts +239 -0
- package/src/dendrite/audience.ts +315 -0
- package/src/dendrite/index.ts +14 -2
- package/src/dendrite/presets.ts +18 -6
- package/src/dendrite/registry.ts +209 -12
- package/src/dendrite/types.ts +92 -8
- package/src/foreign-rounds.ts +199 -0
- package/src/framework.ts +7804 -3546
- package/src/gate/event-gate.ts +428 -65
- package/src/gate/index.ts +3 -0
- package/src/gate/rule-scope.ts +45 -0
- package/src/gate/suppress-script-worker.ts +89 -0
- package/src/gate/suppress-scripts.ts +414 -0
- package/src/gate/suppression-review.ts +517 -0
- package/src/gate/suppression-stats.ts +314 -0
- package/src/gate/types.ts +141 -7
- package/src/gate/wake-onboarding.ts +309 -0
- package/src/held-writes.ts +49 -60
- package/src/index.ts +9 -2
- package/src/jsonrpc-envelope.ts +81 -0
- package/src/mcpl/channel-registry.ts +353 -85
- package/src/mcpl/checkpoint-manager.ts +3 -2
- package/src/mcpl/feature-set-manager.ts +2 -1
- package/src/mcpl/inbound-source.ts +2 -1
- package/src/mcpl/inference-router.ts +7 -4
- package/src/mcpl/push-coalescer.ts +193 -34
- package/src/mcpl/push-handler.ts +10 -5
- package/src/mcpl/server-connection.ts +141 -60
- package/src/mcpl/tool-classes.ts +3 -0
- package/src/mcpl/types.ts +8 -2
- package/src/module-registry.ts +73 -17
- package/src/modules/discord/index.ts +229 -81
- package/src/modules/history/index.ts +439 -70
- package/src/modules/history/semantic.ts +15 -21
- package/src/modules/workspace/disk-agreement.ts +1 -1
- package/src/modules/workspace/index.ts +85 -23
- package/src/notice-tags.ts +10 -1
- package/src/operator-log.ts +36 -3
- package/src/presentation.ts +1676 -0
- package/src/prose-drafts.ts +16 -12
- package/src/read-marks.ts +328 -0
- package/src/recovery/offline-branch.ts +346 -32
- package/src/recovery/recover-cli.ts +21 -3
- package/src/send-tools.ts +40 -7
- package/src/stored-injections.ts +2 -2
- package/src/stored-removal.ts +31 -7
- package/src/tool-result-guard.ts +41 -7
- package/src/tune-out/coordinator.ts +4089 -457
- package/src/tune-out/tools.ts +160 -43
- package/src/tune-out/window-anchor.ts +277 -0
- package/src/types/agent.ts +86 -20
- package/src/types/events.ts +2 -0
- package/src/types/framework.ts +32 -12
- package/src/types/module.ts +181 -68
- package/src/types/trace.ts +542 -40
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the agent's suppress rules have kept out of its context
|
|
3
|
+
* (`suppression_stats`), read from the stored rows themselves: each carries
|
|
4
|
+
* the record a suppress rule stamped on it as it arrived
|
|
5
|
+
* (`metadata.suppressed = { rule, eventType }`, the framework's
|
|
6
|
+
* suppressedRow). The rows are the record, so the counts cover every start
|
|
7
|
+
* of the host and follow the branch the store is on, and nothing beside
|
|
8
|
+
* them is kept.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** A stored row as these stats read it: the parts of context-manager's StoredMessage they use. */
|
|
12
|
+
export interface SuppressionStatsRow {
|
|
13
|
+
id: string;
|
|
14
|
+
timestamp: Date | number | string;
|
|
15
|
+
content: ReadonlyArray<{ type: string; text?: unknown }>;
|
|
16
|
+
metadata?: Record<string, unknown>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** A rule in gate.json, as the stats name it. */
|
|
20
|
+
export interface SuppressRuleInForce {
|
|
21
|
+
name: string;
|
|
22
|
+
/** Events it suppressed since this process started (the gate's matchCount for it). */
|
|
23
|
+
sinceStart: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface SuppressionStatsOptions {
|
|
27
|
+
/** Only this rule's rows. */
|
|
28
|
+
rule?: string;
|
|
29
|
+
/** How many of each rule's newest rows to show, with a preview. Default 3, at most 20. */
|
|
30
|
+
recent?: number;
|
|
31
|
+
/** Only rows stored at or after this time (ms). */
|
|
32
|
+
sinceMs?: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** One suppressed row, as the stats show it. */
|
|
36
|
+
export interface SuppressedEventShown {
|
|
37
|
+
id: string;
|
|
38
|
+
at: string;
|
|
39
|
+
eventType: string;
|
|
40
|
+
source?: string;
|
|
41
|
+
channel?: string;
|
|
42
|
+
author?: string;
|
|
43
|
+
preview: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** One rule's stats. */
|
|
47
|
+
export interface RuleSuppressionStats {
|
|
48
|
+
rule: string;
|
|
49
|
+
/** Whether gate.json has a suppress rule of that name now. */
|
|
50
|
+
inForce: boolean;
|
|
51
|
+
/** Present for a rule in force: what it suppressed since this process started. */
|
|
52
|
+
sinceStart?: number;
|
|
53
|
+
/** Stored rows it suppressed (within `since`, when given). */
|
|
54
|
+
suppressed: number;
|
|
55
|
+
/** Their text, in characters. */
|
|
56
|
+
characters: number;
|
|
57
|
+
first?: string;
|
|
58
|
+
last?: string;
|
|
59
|
+
/** Rows by the server (or module source) they came from, the most first; past ten, the rest as "(others)". */
|
|
60
|
+
bySource: Record<string, number>;
|
|
61
|
+
/** Rows by the event type they arrived as. */
|
|
62
|
+
byEventType: Record<string, number>;
|
|
63
|
+
/** The newest rows, newest first. */
|
|
64
|
+
recent: SuppressedEventShown[];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface SuppressionStats {
|
|
68
|
+
rules: RuleSuppressionStats[];
|
|
69
|
+
/** Every stored suppressed row counted (within `since`, when given). */
|
|
70
|
+
total: number;
|
|
71
|
+
totalCharacters: number;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Longest preview shown, in characters. */
|
|
75
|
+
export const SUPPRESSION_PREVIEW_CHARS = 160;
|
|
76
|
+
/** Most recent rows shown per rule. */
|
|
77
|
+
export const MAX_RECENT = 20;
|
|
78
|
+
const DEFAULT_RECENT = 3;
|
|
79
|
+
const MAX_KEYS = 10;
|
|
80
|
+
|
|
81
|
+
/** The record a row carries when a suppress rule took it, or undefined. */
|
|
82
|
+
export function suppressionRecordOf(metadata: Record<string, unknown> | undefined): { rule: string; eventType?: string; source?: string } | undefined {
|
|
83
|
+
const record = metadata?.suppressed;
|
|
84
|
+
if (!record || typeof record !== 'object') return undefined;
|
|
85
|
+
const { rule, eventType, source } = record as { rule?: unknown; eventType?: unknown; source?: unknown };
|
|
86
|
+
if (typeof rule !== 'string') return undefined;
|
|
87
|
+
return {
|
|
88
|
+
rule,
|
|
89
|
+
...(typeof eventType === 'string' && eventType !== '' ? { eventType } : {}),
|
|
90
|
+
...(typeof source === 'string' && source !== '' ? { source } : {}),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Where a suppressed row came from: the source its record names (a module's, which its metadata may not), else its server. */
|
|
95
|
+
function sourceOf(row: SuppressionStatsRow, record: { source?: string } | undefined): string | undefined {
|
|
96
|
+
if (record?.source) return record.source;
|
|
97
|
+
const serverId = row.metadata?.serverId;
|
|
98
|
+
return typeof serverId === 'string' && serverId !== '' ? serverId : undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** The author a row names: a channel message's `author.name`, or a push event's `authorName`. */
|
|
102
|
+
function authorOf(md: Record<string, unknown>): string | undefined {
|
|
103
|
+
const name = (md.author as { name?: unknown } | undefined)?.name ?? md.authorName;
|
|
104
|
+
return typeof name === 'string' && name !== '' ? name : undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const textOf = (row: SuppressionStatsRow): string =>
|
|
108
|
+
row.content.filter((b) => b.type === 'text' && typeof b.text === 'string').map((b) => b.text as string).join('\n');
|
|
109
|
+
|
|
110
|
+
const msOf = (timestamp: SuppressionStatsRow['timestamp']): number =>
|
|
111
|
+
timestamp instanceof Date ? timestamp.getTime() : typeof timestamp === 'number' ? timestamp : Date.parse(timestamp);
|
|
112
|
+
|
|
113
|
+
const isoOf = (ms: number): string => (Number.isFinite(ms) ? new Date(ms).toISOString() : 'unknown');
|
|
114
|
+
|
|
115
|
+
/** A text on one line, cut at SUPPRESSION_PREVIEW_CHARS characters (code points), with an ellipsis where cut. */
|
|
116
|
+
function previewOf(text: string): string {
|
|
117
|
+
const line = text.replace(/\s+/g, ' ').trim();
|
|
118
|
+
const chars = [...line];
|
|
119
|
+
return chars.length <= SUPPRESSION_PREVIEW_CHARS ? line : `${chars.slice(0, SUPPRESSION_PREVIEW_CHARS - 1).join('')}…`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Counts, the largest first; past MAX_KEYS, the rest summed as "(others)". Built from entries, so any name, "__proto__" included, is a key of its own. */
|
|
123
|
+
function topCounts(counts: Map<string, number>): Record<string, number> {
|
|
124
|
+
const sorted = [...counts].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));
|
|
125
|
+
const entries: Array<[string, number]> = sorted.slice(0, MAX_KEYS);
|
|
126
|
+
const rest = sorted.slice(MAX_KEYS).reduce((sum, [, n]) => sum + n, 0);
|
|
127
|
+
if (rest > 0) entries.push(['(others)', rest]);
|
|
128
|
+
return Object.fromEntries(entries);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function shown(row: SuppressionStatsRow, record: { eventType?: string; source?: string } | undefined): SuppressedEventShown {
|
|
132
|
+
const md = row.metadata ?? {};
|
|
133
|
+
const source = sourceOf(row, record);
|
|
134
|
+
const channel = typeof md.channelId === 'string' && md.channelId !== '' ? md.channelId : undefined;
|
|
135
|
+
const author = authorOf(md);
|
|
136
|
+
return {
|
|
137
|
+
id: row.id,
|
|
138
|
+
at: isoOf(msOf(row.timestamp)),
|
|
139
|
+
eventType: record?.eventType ?? 'unknown',
|
|
140
|
+
...(source ? { source } : {}),
|
|
141
|
+
...(channel ? { channel } : {}),
|
|
142
|
+
...(author ? { author } : {}),
|
|
143
|
+
preview: previewOf(textOf(row)),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* The stats for `rows` (a message slot, oldest first), with every suppress
|
|
149
|
+
* rule in force listed even where it has hidden nothing yet. Rules in force
|
|
150
|
+
* come first, in gate.json's order; rules no longer in force follow, the
|
|
151
|
+
* most recently active first.
|
|
152
|
+
*/
|
|
153
|
+
export function suppressionStats(
|
|
154
|
+
rows: Iterable<SuppressionStatsRow>,
|
|
155
|
+
inForce: readonly SuppressRuleInForce[],
|
|
156
|
+
opts: SuppressionStatsOptions = {},
|
|
157
|
+
): SuppressionStats {
|
|
158
|
+
const recentWanted = Math.max(0, Math.min(MAX_RECENT, Math.floor(opts.recent ?? DEFAULT_RECENT)));
|
|
159
|
+
interface Tally {
|
|
160
|
+
suppressed: number; characters: number; first: number; last: number;
|
|
161
|
+
bySource: Map<string, number>; byEventType: Map<string, number>;
|
|
162
|
+
recent: Array<{ row: SuppressionStatsRow; record: { eventType?: string; source?: string } }>;
|
|
163
|
+
}
|
|
164
|
+
const tallies = new Map<string, Tally>();
|
|
165
|
+
let total = 0;
|
|
166
|
+
let totalCharacters = 0;
|
|
167
|
+
for (const row of rows) {
|
|
168
|
+
const record = suppressionRecordOf(row.metadata);
|
|
169
|
+
if (!record) continue;
|
|
170
|
+
if (opts.rule !== undefined && record.rule !== opts.rule) continue;
|
|
171
|
+
const at = msOf(row.timestamp);
|
|
172
|
+
if (opts.sinceMs !== undefined && !(at >= opts.sinceMs)) continue;
|
|
173
|
+
let tally = tallies.get(record.rule);
|
|
174
|
+
if (!tally) {
|
|
175
|
+
tally = { suppressed: 0, characters: 0, first: at, last: at, bySource: new Map(), byEventType: new Map(), recent: [] };
|
|
176
|
+
tallies.set(record.rule, tally);
|
|
177
|
+
}
|
|
178
|
+
const characters = [...textOf(row)].length;
|
|
179
|
+
tally.suppressed++;
|
|
180
|
+
tally.characters += characters;
|
|
181
|
+
if (at < tally.first) tally.first = at;
|
|
182
|
+
if (at > tally.last) tally.last = at;
|
|
183
|
+
const source = sourceOf(row, record) ?? '(none)';
|
|
184
|
+
tally.bySource.set(source, (tally.bySource.get(source) ?? 0) + 1);
|
|
185
|
+
const eventType = record.eventType ?? 'unknown';
|
|
186
|
+
tally.byEventType.set(eventType, (tally.byEventType.get(eventType) ?? 0) + 1);
|
|
187
|
+
if (recentWanted > 0) {
|
|
188
|
+
tally.recent.push({ row, record });
|
|
189
|
+
if (tally.recent.length > recentWanted) tally.recent.shift();
|
|
190
|
+
}
|
|
191
|
+
total++;
|
|
192
|
+
totalCharacters += characters;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const ruleStats = (name: string, rule: SuppressRuleInForce | undefined): RuleSuppressionStats => {
|
|
196
|
+
const tally = tallies.get(name);
|
|
197
|
+
return {
|
|
198
|
+
rule: name,
|
|
199
|
+
inForce: rule !== undefined,
|
|
200
|
+
...(rule !== undefined ? { sinceStart: rule.sinceStart } : {}),
|
|
201
|
+
suppressed: tally?.suppressed ?? 0,
|
|
202
|
+
characters: tally?.characters ?? 0,
|
|
203
|
+
...(tally ? { first: isoOf(tally.first), last: isoOf(tally.last) } : {}),
|
|
204
|
+
bySource: tally ? topCounts(tally.bySource) : {},
|
|
205
|
+
byEventType: tally ? topCounts(tally.byEventType) : {},
|
|
206
|
+
recent: tally ? tally.recent.slice().reverse().map(({ row, record }) => shown(row, record)) : [],
|
|
207
|
+
};
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const listed = new Set<string>();
|
|
211
|
+
const out: RuleSuppressionStats[] = [];
|
|
212
|
+
for (const rule of inForce) {
|
|
213
|
+
if (listed.has(rule.name) || (opts.rule !== undefined && rule.name !== opts.rule)) continue;
|
|
214
|
+
listed.add(rule.name);
|
|
215
|
+
out.push(ruleStats(rule.name, rule));
|
|
216
|
+
}
|
|
217
|
+
const gone = [...tallies.keys()].filter((name) => !listed.has(name))
|
|
218
|
+
.sort((a, b) => tallies.get(b)!.last - tallies.get(a)!.last || a.localeCompare(b));
|
|
219
|
+
for (const name of gone) out.push(ruleStats(name, undefined));
|
|
220
|
+
return { rules: out, total, totalCharacters };
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** One suppressed row, as a dump or the review reads it: its text in full, any other block named. */
|
|
224
|
+
export interface SuppressedEventRecord {
|
|
225
|
+
id: string;
|
|
226
|
+
/** ISO 8601. */
|
|
227
|
+
at: string;
|
|
228
|
+
rule: string;
|
|
229
|
+
eventType: string;
|
|
230
|
+
source?: string;
|
|
231
|
+
channel?: string;
|
|
232
|
+
author?: string;
|
|
233
|
+
/** Its text blocks, joined; a block of another kind as `[image]`, `[audio]` and so on. */
|
|
234
|
+
text: string;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export interface SuppressedRecordsOptions {
|
|
238
|
+
rule?: string;
|
|
239
|
+
/** Rows stored at or after this time (ms). */
|
|
240
|
+
sinceMs?: number;
|
|
241
|
+
/** Rows stored before this time (ms). */
|
|
242
|
+
untilMs?: number;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** A row's content as text: text blocks as written, any other block named in brackets. */
|
|
246
|
+
function fullTextOf(row: SuppressionStatsRow): string {
|
|
247
|
+
return row.content
|
|
248
|
+
.map((b) => (b.type === 'text' && typeof b.text === 'string' ? b.text : `[${b.type}]`))
|
|
249
|
+
.join('\n');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** The suppressed rows among `rows`, oldest first, their text in full; times are when each was stored. */
|
|
253
|
+
export function suppressedRecords(rows: Iterable<SuppressionStatsRow>, opts: SuppressedRecordsOptions = {}): SuppressedEventRecord[] {
|
|
254
|
+
const out: SuppressedEventRecord[] = [];
|
|
255
|
+
for (const row of rows) {
|
|
256
|
+
const record = suppressionRecordOf(row.metadata);
|
|
257
|
+
if (!record || (opts.rule !== undefined && record.rule !== opts.rule)) continue;
|
|
258
|
+
const at = msOf(row.timestamp);
|
|
259
|
+
if (opts.sinceMs !== undefined && !(at >= opts.sinceMs)) continue;
|
|
260
|
+
if (opts.untilMs !== undefined && !(at < opts.untilMs)) continue;
|
|
261
|
+
const { source, channel, author } = shown(row, record);
|
|
262
|
+
out.push({
|
|
263
|
+
id: row.id,
|
|
264
|
+
at: isoOf(at),
|
|
265
|
+
rule: record.rule,
|
|
266
|
+
eventType: record.eventType ?? 'unknown',
|
|
267
|
+
...(source ? { source } : {}),
|
|
268
|
+
...(channel ? { channel } : {}),
|
|
269
|
+
...(author ? { author } : {}),
|
|
270
|
+
text: fullTextOf(row),
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
return out;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** A dump's file formats: one JSON object a line, or a transcript to read. */
|
|
277
|
+
export type SuppressedDumpFormat = 'jsonl' | 'text';
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* A dump's file content, at most `maxBytes` (UTF-8): the newest records that
|
|
281
|
+
* fit, oldest first, and how many older ones were left out to fit. A
|
|
282
|
+
* transcript opens with a header naming what it holds (`title`, given how
|
|
283
|
+
* many it holds and the oldest's time) and, when some were left out, how many.
|
|
284
|
+
*/
|
|
285
|
+
export function renderSuppressedDump(
|
|
286
|
+
records: readonly SuppressedEventRecord[],
|
|
287
|
+
format: SuppressedDumpFormat,
|
|
288
|
+
opts: { maxBytes: number; title: string | ((written: number, first: string) => string) },
|
|
289
|
+
): { content: string; written: number; omitted: number } {
|
|
290
|
+
const entry = (r: SuppressedEventRecord): string => format === 'jsonl'
|
|
291
|
+
? `${JSON.stringify(r)}\n`
|
|
292
|
+
: `[${r.at}] ${r.rule} · ${r.eventType}${r.source ? ` · ${r.source}` : ''}${r.channel ? ` · ${r.channel}` : ''}`
|
|
293
|
+
+ `${r.author ? ` · ${r.author}` : ''} · ${r.id}\n${r.text}\n\n`;
|
|
294
|
+
const entries = records.map(entry);
|
|
295
|
+
const titleOf = (from: number): string => typeof opts.title === 'string'
|
|
296
|
+
? opts.title
|
|
297
|
+
: opts.title(entries.length - from, records[from]?.at ?? '');
|
|
298
|
+
const header = (from: number): string => format === 'jsonl'
|
|
299
|
+
? ''
|
|
300
|
+
: `# ${titleOf(from)}\n${from > 0 ? `(${from} older events left out to fit)\n` : ''}\n`;
|
|
301
|
+
// The most records, newest first, that fit beside the header they make:
|
|
302
|
+
// the header names how many were left out, so it's sized for each count.
|
|
303
|
+
let bytes = 0;
|
|
304
|
+
let from = entries.length;
|
|
305
|
+
let best = entries.length;
|
|
306
|
+
while (from > 0) {
|
|
307
|
+
bytes += Buffer.byteLength(entries[from - 1]!);
|
|
308
|
+
from--;
|
|
309
|
+
if (Buffer.byteLength(header(from)) + bytes <= opts.maxBytes) best = from;
|
|
310
|
+
else if (bytes > opts.maxBytes) break;
|
|
311
|
+
}
|
|
312
|
+
if (best === entries.length) return { content: '', written: 0, omitted: entries.length };
|
|
313
|
+
return { content: header(best) + entries.slice(best).join(''), written: entries.length - best, omitted: best };
|
|
314
|
+
}
|
package/src/gate/types.ts
CHANGED
|
@@ -179,6 +179,81 @@ export interface GatePolicy {
|
|
|
179
179
|
* fire" has no meaning distinct from the behavior itself.
|
|
180
180
|
*/
|
|
181
181
|
passthrough?: boolean;
|
|
182
|
+
/**
|
|
183
|
+
* Suppression: an event this rule takes is stored in the chronicle and
|
|
184
|
+
* never rendered into the residents' context. It isn't compiled, injected
|
|
185
|
+
* at a tool boundary, folded into memory, woken for, or counted as the
|
|
186
|
+
* latest inbound. The framework decides this once, as the event arrives
|
|
187
|
+
* (`EventGate.decideSuppression`), and stamps the row
|
|
188
|
+
* (`metadata.suppressed = { rule, eventType }`). The view filters read only
|
|
189
|
+
* that stamp, so changing the rule later never changes what was already
|
|
190
|
+
* rendered or hidden: a removed rule stops suppressing from then on, and
|
|
191
|
+
* the rows it hid stay hidden.
|
|
192
|
+
*
|
|
193
|
+
* The rule needs `behavior: "defer"` (or the legacy `"skip"`), so a release
|
|
194
|
+
* that doesn't know `suppress` defers its events instead of waking the
|
|
195
|
+
* agent on them, and a match that narrows something. Rules stay
|
|
196
|
+
* first-match, with three exceptions: an event addressed to the agent
|
|
197
|
+
* (`chat:addressed`), a heartbeat, and console or API input are never
|
|
198
|
+
* suppressed. The rule lets them by, and the rules after it decide them.
|
|
199
|
+
* A suppress rule decides no wake for an event suppression was asked about
|
|
200
|
+
* (`evaluate` and `probe` pass over it there, `GateEventInfo.suppressionAsked`);
|
|
201
|
+
* where suppression wasn't asked, it defers, as its behavior says.
|
|
202
|
+
*/
|
|
203
|
+
suppress?: SuppressConfig;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** A suppress rule's own settings (GatePolicy.suppress). */
|
|
207
|
+
export interface SuppressConfig {
|
|
208
|
+
/**
|
|
209
|
+
* What the rule is for, in the agent's words ("the eye going on and off").
|
|
210
|
+
* Required: the periodic review (SuppressionReviewOptions), where the host
|
|
211
|
+
* runs it, checks a sample of the events the rule hid against it.
|
|
212
|
+
*/
|
|
213
|
+
description: string;
|
|
214
|
+
/**
|
|
215
|
+
* The agent's own logic for the rule, when matching isn't enough: the
|
|
216
|
+
* source of a function `(event, state) => boolean`, called for each event
|
|
217
|
+
* the rule's match takes that reaches it (one an earlier rule decides, an
|
|
218
|
+
* addressed one, or the heartbeat's never does), only `true` hiding it. `event` is the event's type,
|
|
219
|
+
* source, channel, author, tags, text, arrival time (`at`, ms) and
|
|
220
|
+
* metadata. `state` is the rule's own JSON object, which the script reads
|
|
221
|
+
* and changes as it likes, kept between events and across restarts
|
|
222
|
+
* (suppress-scripts.ts), and started afresh when the script changes or the
|
|
223
|
+
* rule is removed. So a rule can hide repeats, count, or keep a window of
|
|
224
|
+
* its own. A script that throws or runs past its time counts as saying
|
|
225
|
+
* show: the event goes on to the rules after it. Left out, every event the
|
|
226
|
+
* rule matches is hidden.
|
|
227
|
+
*/
|
|
228
|
+
script?: string;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* The periodic review of what suppress rules hid (src/gate/suppression-review.ts):
|
|
233
|
+
* every `intervalMs`, for each rule that hid events since the last review, a
|
|
234
|
+
* small model reads the rule's description and the events it hid (a sample,
|
|
235
|
+
* past `maxEventsPerRule`) and flags any that don't fit the description or
|
|
236
|
+
* that the agent would plausibly need to see. The agent is told what each
|
|
237
|
+
* rule hid and what was flagged, in a `[suppression review]` notice; a
|
|
238
|
+
* flagged event wakes it.
|
|
239
|
+
*/
|
|
240
|
+
export interface SuppressionReviewOptions {
|
|
241
|
+
/** False turns the review off. Default true. */
|
|
242
|
+
enabled?: boolean;
|
|
243
|
+
/** How often, in ms. Default 2 hours; at least 10 minutes. */
|
|
244
|
+
intervalMs?: number;
|
|
245
|
+
/** The reviewer's model, as the host's membrane names it. Default `claude-haiku-5-5`. */
|
|
246
|
+
model?: string;
|
|
247
|
+
/** When the agent is told: after every review in which a rule hid something (`"always"`, the default), or only when an event was flagged (`"flagged"`). */
|
|
248
|
+
notify?: 'always' | 'flagged';
|
|
249
|
+
/** Whether a flagged event wakes the agent, which is a full turn of its own model, so a false flag costs that turn. Default true. */
|
|
250
|
+
wakeOnFlag?: boolean;
|
|
251
|
+
/** The most events of one rule the reviewer reads in one review, spread across the period. Default 60. */
|
|
252
|
+
maxEventsPerRule?: number;
|
|
253
|
+
/** How long one rule's review may take, in ms. Default 60,000. */
|
|
254
|
+
timeoutMs?: number;
|
|
255
|
+
/** The reviewer's effort (`output_config.effort`); `"none"` sends none. Default `"low"`. */
|
|
256
|
+
effort?: 'low' | 'medium' | 'high' | 'none';
|
|
182
257
|
}
|
|
183
258
|
|
|
184
259
|
// ---------------------------------------------------------------------------
|
|
@@ -223,6 +298,21 @@ export interface GateOptions {
|
|
|
223
298
|
* null), the judge is wired with its defaults; it runs only for `judge`
|
|
224
299
|
* rules, so a gate with none makes no judge calls. */
|
|
225
300
|
judge?: ReplyJudgeOptions | null;
|
|
301
|
+
/**
|
|
302
|
+
* The periodic review of what suppress rules hid (SuppressionReviewOptions).
|
|
303
|
+
* On by default wherever a gate is; false turns it off.
|
|
304
|
+
*/
|
|
305
|
+
suppressionReview?: SuppressionReviewOptions | false;
|
|
306
|
+
/** How long a suppress rule's script may take for one event before the event is shown (ms). Default 50. */
|
|
307
|
+
suppressScriptTimeoutMs?: number;
|
|
308
|
+
/**
|
|
309
|
+
* Wake onboarding (gate/wake-onboarding.ts): the first event from an MCPL
|
|
310
|
+
* server that the agent's rules let go by without deciding about it brings
|
|
311
|
+
* the agent that server's suggested treatment (MCPL RFC-001 §5), once per
|
|
312
|
+
* declared ontology, with `wake_accept_suggestions` / `wake_decline` to
|
|
313
|
+
* answer. On unless set to false.
|
|
314
|
+
*/
|
|
315
|
+
onboarding?: boolean;
|
|
226
316
|
}
|
|
227
317
|
|
|
228
318
|
/**
|
|
@@ -280,6 +370,17 @@ export interface JudgeEventSummary {
|
|
|
280
370
|
at: number;
|
|
281
371
|
}
|
|
282
372
|
|
|
373
|
+
/** The kinds of UpcomingWake. */
|
|
374
|
+
export type UpcomingWakeKind =
|
|
375
|
+
| 'heartbeat'
|
|
376
|
+
| 'reminder'
|
|
377
|
+
| 'self-wake'
|
|
378
|
+
| 'sleep-end'
|
|
379
|
+
| 'debounce'
|
|
380
|
+
| 'judge-batch'
|
|
381
|
+
| 'queued'
|
|
382
|
+
| 'provider-hold';
|
|
383
|
+
|
|
283
384
|
/**
|
|
284
385
|
* Something that will (or, for a batch going to the judge, may) wake the
|
|
285
386
|
* agent with no new event: what the judge is told would happen if it answers
|
|
@@ -292,6 +393,9 @@ export interface UpcomingWake {
|
|
|
292
393
|
certain: boolean;
|
|
293
394
|
/** What it is, as the judge is told ("its own skip_reply timer"). */
|
|
294
395
|
what: string;
|
|
396
|
+
/** What it is, in a word that quotes nothing, for healthSnapshot: `what` can
|
|
397
|
+
* quote a reminder or a queue reason. The judge isn't told it. */
|
|
398
|
+
kind?: UpcomingWakeKind;
|
|
295
399
|
}
|
|
296
400
|
|
|
297
401
|
/** What the gate asks the reply judge for one batch. */
|
|
@@ -403,6 +507,20 @@ export interface GateEventInfo {
|
|
|
403
507
|
paths?: string[];
|
|
404
508
|
/** Event tags (MCPL RFC-001), already implication-expanded by the host. */
|
|
405
509
|
tags?: string[];
|
|
510
|
+
/** The agents admission delivered a targeted event to (its targetAgents).
|
|
511
|
+
* A debounced batch wakes each agent with the events it may see, those
|
|
512
|
+
* naming it and those naming no agent, and agents that may see the same
|
|
513
|
+
* events share one line. Absent for an untargeted event, whose batch wakes
|
|
514
|
+
* every agent getAgentNames lists. */
|
|
515
|
+
recipients?: readonly string[];
|
|
516
|
+
/**
|
|
517
|
+
* Set when the framework asked whether the event is suppressed before it
|
|
518
|
+
* asked about its wake (decideSuppression), so a suppress rule that
|
|
519
|
+
* matches it let it by. Left out, a suppress rule defers the events it
|
|
520
|
+
* matches, as its behavior says: suppression wasn't asked, as for an event
|
|
521
|
+
* that lands where no view hides suppressed rows.
|
|
522
|
+
*/
|
|
523
|
+
suppressionAsked?: boolean;
|
|
406
524
|
}
|
|
407
525
|
|
|
408
526
|
/** An MCPL event whose content the framework stored at arrival, as a
|
|
@@ -421,13 +539,13 @@ export interface GateEntryRef {
|
|
|
421
539
|
* than wrote: its batch was one event whose entry was still the newest in
|
|
422
540
|
* the window when the batch fired (EventGate's `isNewestEntry`). A fresh
|
|
423
541
|
* start of the wake's turn decides it (the framework's placeWakeLines): the
|
|
424
|
-
* delivery agent's
|
|
425
|
-
*
|
|
426
|
-
*
|
|
427
|
-
*
|
|
428
|
-
*
|
|
429
|
-
* later fresh start of the same wake. Its text
|
|
430
|
-
* written (wakeLineText), so its age is true then.
|
|
542
|
+
* delivery agent's start, and on a presented window each resident's own
|
|
543
|
+
* start, decides its own line, leaving it out while that entry is still
|
|
544
|
+
* the newest in its window and writing it once something follows; a
|
|
545
|
+
* co-resident whose window isn't presented places none; two or more such
|
|
546
|
+
* lines are each written; and none is written while the host is quiesced.
|
|
547
|
+
* A line left out stays for a later fresh start of the same wake. Its text
|
|
548
|
+
* is rendered when it's written (wakeLineText), so its age is true then.
|
|
431
549
|
*
|
|
432
550
|
* Every request for one wake carries the same object: the framework writes
|
|
433
551
|
* each line once by its identity, across the wake's retries and holds. A
|
|
@@ -452,6 +570,15 @@ export interface GatePolicyStats {
|
|
|
452
570
|
behavior: GateBehavior;
|
|
453
571
|
matchCount: number;
|
|
454
572
|
lastMatchTimestamp: number | null;
|
|
573
|
+
/**
|
|
574
|
+
* Present on a suppress rule: its settings, and with a script, how the
|
|
575
|
+
* script has run since this process started. Its `matchCount` and
|
|
576
|
+
* `lastMatchTimestamp` count the events it took since then: those it
|
|
577
|
+
* suppressed, and those it only deferred where suppression wasn't asked
|
|
578
|
+
* (a channel under conversation routing). `suppression_stats` reads the
|
|
579
|
+
* stamped rows themselves, so its counts cover every start.
|
|
580
|
+
*/
|
|
581
|
+
suppress?: SuppressConfig & { scriptStatus?: import('./suppress-scripts.js').SuppressScriptStatus };
|
|
455
582
|
debounceState?: {
|
|
456
583
|
pendingCount: number;
|
|
457
584
|
nextDeliveryMs: number | null;
|
|
@@ -504,6 +631,13 @@ export interface GateStatus {
|
|
|
504
631
|
* same hazards wake_add_rule warns about at install time.
|
|
505
632
|
*/
|
|
506
633
|
shadowWarnings: string[];
|
|
634
|
+
/**
|
|
635
|
+
* The first rule that takes MCPL servers' events without naming a server, a
|
|
636
|
+
* channel or a tag (gate/wake-onboarding.ts placementFor): every server
|
|
637
|
+
* connected later is handled by it until a rule for that server goes ahead of
|
|
638
|
+
* it. Absent when there is none.
|
|
639
|
+
*/
|
|
640
|
+
catchAll?: { rule: string; note: string };
|
|
507
641
|
/** Total events the gate has evaluated since startup. */
|
|
508
642
|
totalEvaluations: number;
|
|
509
643
|
/**
|