@tethral/acr-mcp 1.0.0 → 2.0.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 +38 -32
- package/dist/src/env-detect.d.ts +15 -0
- package/dist/src/env-detect.js +22 -0
- package/dist/src/env-detect.js.map +1 -1
- package/dist/src/middleware/correlation-window.d.ts +68 -0
- package/dist/src/middleware/correlation-window.js +113 -0
- package/dist/src/middleware/correlation-window.js.map +1 -0
- package/dist/src/server.d.ts +3 -0
- package/dist/src/server.js +31 -8
- package/dist/src/server.js.map +1 -1
- package/dist/src/session-state.d.ts +3 -0
- package/dist/src/session-state.js +11 -0
- package/dist/src/session-state.js.map +1 -1
- package/dist/src/tools/acknowledge-threat.js +11 -6
- package/dist/src/tools/acknowledge-threat.js.map +1 -1
- package/dist/src/tools/check-entity.js +57 -58
- package/dist/src/tools/check-entity.js.map +1 -1
- package/dist/src/tools/check-environment.js +8 -4
- package/dist/src/tools/check-environment.js.map +1 -1
- package/dist/src/tools/disable-deep-composition.d.ts +20 -0
- package/dist/src/tools/disable-deep-composition.js +45 -0
- package/dist/src/tools/disable-deep-composition.js.map +1 -0
- package/dist/src/tools/get-coverage.d.ts +2 -0
- package/dist/src/tools/get-coverage.js +67 -0
- package/dist/src/tools/get-coverage.js.map +1 -0
- package/dist/src/tools/get-failure-registry.d.ts +2 -0
- package/dist/src/tools/get-failure-registry.js +75 -0
- package/dist/src/tools/get-failure-registry.js.map +1 -0
- package/dist/src/tools/get-friction-report.js +30 -21
- package/dist/src/tools/get-friction-report.js.map +1 -1
- package/dist/src/tools/get-interaction-log.js +22 -25
- package/dist/src/tools/get-interaction-log.js.map +1 -1
- package/dist/src/tools/get-my-agent.js +5 -1
- package/dist/src/tools/get-my-agent.js.map +1 -1
- package/dist/src/tools/get-network-status.js +11 -8
- package/dist/src/tools/get-network-status.js.map +1 -1
- package/dist/src/tools/get-notifications.js +9 -10
- package/dist/src/tools/get-notifications.js.map +1 -1
- package/dist/src/tools/get-profile.d.ts +2 -0
- package/dist/src/tools/get-profile.js +89 -0
- package/dist/src/tools/get-profile.js.map +1 -0
- package/dist/src/tools/get-skill-tracker.js +16 -14
- package/dist/src/tools/get-skill-tracker.js.map +1 -1
- package/dist/src/tools/get-skill-versions.js +14 -11
- package/dist/src/tools/get-skill-versions.js.map +1 -1
- package/dist/src/tools/get-stable-corridors.d.ts +2 -0
- package/dist/src/tools/get-stable-corridors.js +65 -0
- package/dist/src/tools/get-stable-corridors.js.map +1 -0
- package/dist/src/tools/get-trend.d.ts +2 -0
- package/dist/src/tools/get-trend.js +75 -0
- package/dist/src/tools/get-trend.js.map +1 -0
- package/dist/src/tools/log-interaction.d.ts +2 -1
- package/dist/src/tools/log-interaction.js +109 -34
- package/dist/src/tools/log-interaction.js.map +1 -1
- package/dist/src/tools/register-agent.js +67 -15
- package/dist/src/tools/register-agent.js.map +1 -1
- package/dist/src/tools/search-skills.js +33 -19
- package/dist/src/tools/search-skills.js.map +1 -1
- package/dist/src/tools/summarize-my-agent.d.ts +2 -0
- package/dist/src/tools/summarize-my-agent.js +100 -0
- package/dist/src/tools/summarize-my-agent.js.map +1 -0
- package/dist/src/tools/update-composition.js +67 -13
- package/dist/src/tools/update-composition.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @tethral/acr-mcp
|
|
2
2
|
|
|
3
|
-
MCP server for the [ACR](https://acr.nfkey.ai) (Agent Composition Records) network.
|
|
3
|
+
MCP server for the [ACR](https://acr.nfkey.ai) (Agent Composition Records) network. Log agent interactions, build an interaction profile, and query it through behavioral lenses. Get notified if ACR observes that your composition may be jeopardized.
|
|
4
4
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
@@ -26,55 +26,61 @@ npx @tethral/acr-mcp-http # HTTP transport
|
|
|
26
26
|
|
|
27
27
|
Your agent auto-registers on first use and gets a human-readable name (e.g. `anthropic-amber-fox`).
|
|
28
28
|
|
|
29
|
-
## What
|
|
29
|
+
## What It Does
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
ACR is an **interaction profile registry** — not a security product, not a skill store.
|
|
32
|
+
|
|
33
|
+
1. **Agent registers** — composition is recorded (what skills, MCPs, tools it has)
|
|
34
|
+
2. **Agent logs interactions** — every external tool call, API request, or MCP interaction
|
|
35
|
+
3. **Signals compile into an interaction profile** — timing, chain position, retries, anomaly flags, and more
|
|
36
|
+
4. **Lenses interpret the profile** — friction is the first and most developed lens (bottlenecks, chain overhead, retry waste, population baselines)
|
|
37
|
+
5. **Anomaly signal notifications** — if ACR observes anomaly signals affecting a component in your composition, you get a notification. We're not a security check — we register and propagate signals, like HIBP or contact tracing.
|
|
35
38
|
|
|
36
39
|
## Tools (14)
|
|
37
40
|
|
|
38
|
-
###
|
|
41
|
+
### Interaction logging (the foundation)
|
|
39
42
|
| Tool | Purpose |
|
|
40
43
|
|------|---------|
|
|
41
|
-
| `
|
|
42
|
-
| `
|
|
43
|
-
| `get_skill_versions` | Version history for a skill — is your version current? How many versions behind? |
|
|
44
|
+
| `log_interaction` | Record an interaction — every lens depends on this. Call after every external tool call, API request, or MCP interaction. |
|
|
45
|
+
| `get_interaction_log` | Raw interaction history with network context (target health, baselines, anomaly signals). |
|
|
44
46
|
|
|
45
|
-
###
|
|
47
|
+
### Friction lens
|
|
46
48
|
| Tool | Purpose |
|
|
47
49
|
|------|---------|
|
|
48
|
-
| `
|
|
49
|
-
| `acknowledge_threat` | Acknowledge a threat notification after reviewing with the user. Expires in 30 days. |
|
|
50
|
+
| `get_friction_report` | Query the friction lens of your interaction profile. Top-target breakdown with p95 latencies, chain analysis, retry overhead, population drift. |
|
|
50
51
|
|
|
51
|
-
###
|
|
52
|
+
### Identity & composition
|
|
52
53
|
| Tool | Purpose |
|
|
53
54
|
|------|---------|
|
|
54
|
-
| `
|
|
55
|
-
| `register_agent` |
|
|
55
|
+
| `get_my_agent` | Your agent identity, provider, status, environment context. |
|
|
56
|
+
| `register_agent` | Explicit registration (auto-registration is the default on first call). |
|
|
57
|
+
| `update_composition` | Update your composition without re-registering. Preserves agent identity. |
|
|
56
58
|
|
|
57
|
-
###
|
|
59
|
+
### Anomaly signal notifications
|
|
58
60
|
| Tool | Purpose |
|
|
59
61
|
|------|---------|
|
|
60
|
-
| `
|
|
61
|
-
| `
|
|
62
|
-
| `
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
|
66
|
-
|
|
62
|
+
| `check_environment` | Active anomaly signals and network observations. Call on startup. |
|
|
63
|
+
| `get_notifications` | Unread anomaly signal notifications about components in your composition. |
|
|
64
|
+
| `acknowledge_threat` | Acknowledge a notification after reviewing with your operator. Expires in 30 days. |
|
|
65
|
+
|
|
66
|
+
### Network observation
|
|
67
|
+
| Tool | Purpose |
|
|
68
|
+
|------|---------|
|
|
69
|
+
| `get_network_status` | Network-wide observation dashboard — agent/system totals, signal rates, skill anomalies, escalations. |
|
|
70
|
+
| `get_skill_tracker` | Adoption and anomaly signals for skills observed by the network. |
|
|
67
71
|
|
|
68
|
-
|
|
72
|
+
### Lookups
|
|
73
|
+
| Tool | Purpose |
|
|
74
|
+
|------|---------|
|
|
75
|
+
| `check_entity` | Ask the network what it knows about a specific skill, agent, or system. |
|
|
76
|
+
| `search_skills` | Query the network's knowledge of a skill by name. |
|
|
77
|
+
| `get_skill_versions` | Version history for a skill hash — which version you're on, how it has changed. |
|
|
69
78
|
|
|
70
|
-
|
|
79
|
+
## About the Skill Registry
|
|
71
80
|
|
|
72
|
-
|
|
73
|
-
- **High**: Code execution (`eval`, `child_process`), filesystem traversal, destructive ops
|
|
74
|
-
- **Medium**: Obfuscation (base64, hex), excessive permissions, dependency confusion
|
|
75
|
-
- **Low**: Missing metadata (author, version, description), oversized content
|
|
81
|
+
ACR maintains an observation layer on skills that exist in public registries (npm, GitHub, etc.). We update it continuously. **We are not a security check.** If we observe anomaly signals affecting a component in an agent's composition, we propagate that observation as a notification. Because we do not track the agent's owner, we have no mechanism to notify them beyond the agent's activities.
|
|
76
82
|
|
|
77
|
-
|
|
83
|
+
Agents don't get skills from ACR — we observe skills that already exist in the ecosystem and keep track of behavioral signals tied to them.
|
|
78
84
|
|
|
79
85
|
## Configuration
|
|
80
86
|
|
|
@@ -85,7 +91,7 @@ Skills scoring **below 50/100** are **BLOCKED** — content redacted, agents see
|
|
|
85
91
|
|
|
86
92
|
## Data Collection
|
|
87
93
|
|
|
88
|
-
ACR collects interaction **metadata only**: target system names, timing, status, and provider class. No request/response content, API keys, prompts, or PII is collected. [Full terms](https://acr.nfkey.ai/terms).
|
|
94
|
+
ACR collects interaction **metadata only**: target system names, timing, status, and provider class. No request/response content, API keys, prompts, or PII is collected. We intentionally don't track the agent's owner. [Full terms](https://acr.nfkey.ai/terms).
|
|
89
95
|
|
|
90
96
|
## License
|
|
91
97
|
|
package/dist/src/env-detect.d.ts
CHANGED
|
@@ -8,3 +8,18 @@ export interface EnvironmentContext {
|
|
|
8
8
|
export declare function detectEnvironment(transportType: 'stdio' | 'streamable-http'): EnvironmentContext;
|
|
9
9
|
/** OS release string, useful for debugging but not stored by default. */
|
|
10
10
|
export declare function getOsRelease(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Observe the agent's composition from the MCP's vantage point.
|
|
13
|
+
*
|
|
14
|
+
* This is the MCP-observed side of the two-source composition pattern.
|
|
15
|
+
* The MCP doesn't have a portable way to enumerate an agent's skills and
|
|
16
|
+
* MCPs across all MCP hosts — that requires host integration (Claude Code
|
|
17
|
+
* plugin in Phase 2, similar plugins for other hosts). In Phase 1 this
|
|
18
|
+
* is a stub that returns empty: the plumbing is in place so the
|
|
19
|
+
* agent_composition_sources table and the profile's composition_delta
|
|
20
|
+
* computation work as soon as any observation is populated.
|
|
21
|
+
*
|
|
22
|
+
* Keep this pure and fast. No file I/O, no network, no parsing of
|
|
23
|
+
* arbitrary files. It should always return in <1ms.
|
|
24
|
+
*/
|
|
25
|
+
export declare function observeComposition(): Record<string, unknown>;
|
package/dist/src/env-detect.js
CHANGED
|
@@ -27,4 +27,26 @@ export function detectEnvironment(transportType) {
|
|
|
27
27
|
export function getOsRelease() {
|
|
28
28
|
return release();
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Observe the agent's composition from the MCP's vantage point.
|
|
32
|
+
*
|
|
33
|
+
* This is the MCP-observed side of the two-source composition pattern.
|
|
34
|
+
* The MCP doesn't have a portable way to enumerate an agent's skills and
|
|
35
|
+
* MCPs across all MCP hosts — that requires host integration (Claude Code
|
|
36
|
+
* plugin in Phase 2, similar plugins for other hosts). In Phase 1 this
|
|
37
|
+
* is a stub that returns empty: the plumbing is in place so the
|
|
38
|
+
* agent_composition_sources table and the profile's composition_delta
|
|
39
|
+
* computation work as soon as any observation is populated.
|
|
40
|
+
*
|
|
41
|
+
* Keep this pure and fast. No file I/O, no network, no parsing of
|
|
42
|
+
* arbitrary files. It should always return in <1ms.
|
|
43
|
+
*/
|
|
44
|
+
export function observeComposition() {
|
|
45
|
+
// Phase 1: MCP observation returns an empty composition. Phase 2's
|
|
46
|
+
// host plugins (Claude Code, Cursor, etc.) populate the mcp_observed
|
|
47
|
+
// source directly by calling the server API, bypassing this function.
|
|
48
|
+
// This keeps the MCP compute-thin and the observation source
|
|
49
|
+
// correctly attributed to whichever host integration produced it.
|
|
50
|
+
return {};
|
|
51
|
+
}
|
|
30
52
|
//# sourceMappingURL=env-detect.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env-detect.js","sourceRoot":"","sources":["../../src/env-detect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAU5C,SAAS,gBAAgB;IACvB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC9C,IAAI,QAAQ;QAAE,OAAO,QAA8C,CAAC;IAEpE,MAAM,KAAK,GAAG,QAAQ,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IACvC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5B,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC/B,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,aAA0C;IAE1C,OAAO;QACL,YAAY,EAAE,gBAAgB,EAAE;QAChC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,QAAQ;QACtD,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI;QAC1C,cAAc,EAAE,aAAa;KAC9B,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,YAAY;IAC1B,OAAO,OAAO,EAAE,CAAC;AACnB,CAAC"}
|
|
1
|
+
{"version":3,"file":"env-detect.js","sourceRoot":"","sources":["../../src/env-detect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAU5C,SAAS,gBAAgB;IACvB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC9C,IAAI,QAAQ;QAAE,OAAO,QAA8C,CAAC;IAEpE,MAAM,KAAK,GAAG,QAAQ,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IACvC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5B,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC/B,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,aAA0C;IAE1C,OAAO;QACL,YAAY,EAAE,gBAAgB,EAAE;QAChC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,QAAQ;QACtD,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI;QAC1C,cAAc,EAAE,aAAa;KAC9B,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,YAAY;IAC1B,OAAO,OAAO,EAAE,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,kBAAkB;IAChC,mEAAmE;IACnE,qEAAqE;IACrE,sEAAsE;IACtE,6DAA6D;IAC7D,kEAAkE;IAClE,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Correlation window for the ACR MCP.
|
|
3
|
+
*
|
|
4
|
+
* A passive in-process buffer of ~60 seconds of recent receipt correlation
|
|
5
|
+
* keys. The window is used at receipt emit time to tag a new receipt with a
|
|
6
|
+
* `preceded_by` link when it's part of the same in-flight workflow as a
|
|
7
|
+
* recent prior receipt. Beyond 60 seconds, correlation is the server's job.
|
|
8
|
+
*
|
|
9
|
+
* Design choices and their rationale (see proposals/mcp-compute-boundary.md
|
|
10
|
+
* constraint #3):
|
|
11
|
+
*
|
|
12
|
+
* - In-process only. No disk, no persistence, no tmpfile. The window is lost
|
|
13
|
+
* on process restart, which is fine: the authoritative record lives on
|
|
14
|
+
* the server, and 60 seconds is short enough that restart rarely matters.
|
|
15
|
+
* - Passive. No pattern matching forward or reverse. No aggregation. No
|
|
16
|
+
* prediction. The window holds correlation keys and nothing else.
|
|
17
|
+
* - Eager eviction on insert. No setInterval, no background sweeper, no
|
|
18
|
+
* timers. Eviction runs once per insert, O(n) over at-most-hundreds of
|
|
19
|
+
* entries. No background work.
|
|
20
|
+
* - One window per session. Instantiated in server.ts and passed by
|
|
21
|
+
* reference into the tools that need it. Not a module-level singleton, so
|
|
22
|
+
* the HTTP transport with concurrent sessions doesn't share state across
|
|
23
|
+
* agents.
|
|
24
|
+
* - Framed as a privacy + lightweight design choice. Users get useful
|
|
25
|
+
* interaction data without persistent surveillance state on their machine.
|
|
26
|
+
*/
|
|
27
|
+
export interface CorrelationEntry {
|
|
28
|
+
receipt_id: string;
|
|
29
|
+
chain_id: string | null;
|
|
30
|
+
target_system_id: string;
|
|
31
|
+
/** Unix ms timestamp when the receipt was produced. */
|
|
32
|
+
created_at_ms: number;
|
|
33
|
+
}
|
|
34
|
+
export declare class CorrelationWindow {
|
|
35
|
+
private readonly entries;
|
|
36
|
+
private readonly windowMs;
|
|
37
|
+
private readonly maxEntries;
|
|
38
|
+
constructor(windowMs?: number, maxEntries?: number);
|
|
39
|
+
/**
|
|
40
|
+
* Record a receipt's correlation keys into the window. Runs eviction of
|
|
41
|
+
* expired entries on every insert — no background sweeper.
|
|
42
|
+
*
|
|
43
|
+
* If the window is at its hard cap after eviction (indicates either a
|
|
44
|
+
* very high tool-call rate or a bug), the oldest entries are dropped.
|
|
45
|
+
* This is a safety net, not a normal path.
|
|
46
|
+
*/
|
|
47
|
+
record(entry: CorrelationEntry): void;
|
|
48
|
+
/**
|
|
49
|
+
* Find a recent receipt that should be linked as `preceded_by` for a new
|
|
50
|
+
* receipt. Prefers the most recent entry in the same chain_id. Returns the
|
|
51
|
+
* target_system_id of the match (that's what `preceded_by` stores), or
|
|
52
|
+
* null if nothing links.
|
|
53
|
+
*
|
|
54
|
+
* If currentChainId is null, we don't attempt cross-chain linking — the
|
|
55
|
+
* agent didn't declare a chain, so the server will reconstruct any
|
|
56
|
+
* linkage from its full history.
|
|
57
|
+
*/
|
|
58
|
+
findPrecededBy(currentChainId: string | null, nowMs: number): string | null;
|
|
59
|
+
/**
|
|
60
|
+
* Evict entries older than the window. Called on every record() and
|
|
61
|
+
* every findPrecededBy() call. No background timers.
|
|
62
|
+
*/
|
|
63
|
+
private evictExpired;
|
|
64
|
+
/** Current number of entries in the window. Used by tests and observability. */
|
|
65
|
+
size(): number;
|
|
66
|
+
/** Clear the window. Used by tests; not expected in production code paths. */
|
|
67
|
+
clear(): void;
|
|
68
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Correlation window for the ACR MCP.
|
|
3
|
+
*
|
|
4
|
+
* A passive in-process buffer of ~60 seconds of recent receipt correlation
|
|
5
|
+
* keys. The window is used at receipt emit time to tag a new receipt with a
|
|
6
|
+
* `preceded_by` link when it's part of the same in-flight workflow as a
|
|
7
|
+
* recent prior receipt. Beyond 60 seconds, correlation is the server's job.
|
|
8
|
+
*
|
|
9
|
+
* Design choices and their rationale (see proposals/mcp-compute-boundary.md
|
|
10
|
+
* constraint #3):
|
|
11
|
+
*
|
|
12
|
+
* - In-process only. No disk, no persistence, no tmpfile. The window is lost
|
|
13
|
+
* on process restart, which is fine: the authoritative record lives on
|
|
14
|
+
* the server, and 60 seconds is short enough that restart rarely matters.
|
|
15
|
+
* - Passive. No pattern matching forward or reverse. No aggregation. No
|
|
16
|
+
* prediction. The window holds correlation keys and nothing else.
|
|
17
|
+
* - Eager eviction on insert. No setInterval, no background sweeper, no
|
|
18
|
+
* timers. Eviction runs once per insert, O(n) over at-most-hundreds of
|
|
19
|
+
* entries. No background work.
|
|
20
|
+
* - One window per session. Instantiated in server.ts and passed by
|
|
21
|
+
* reference into the tools that need it. Not a module-level singleton, so
|
|
22
|
+
* the HTTP transport with concurrent sessions doesn't share state across
|
|
23
|
+
* agents.
|
|
24
|
+
* - Framed as a privacy + lightweight design choice. Users get useful
|
|
25
|
+
* interaction data without persistent surveillance state on their machine.
|
|
26
|
+
*/
|
|
27
|
+
/** Defaults to 60 seconds. Overridable for tests only. */
|
|
28
|
+
const DEFAULT_WINDOW_MS = 60_000;
|
|
29
|
+
/**
|
|
30
|
+
* Hard cap on entries held in the window, as a safety net in case eviction
|
|
31
|
+
* has a bug or the MCP is under unusual load. 500 is plenty for a 60s
|
|
32
|
+
* window at realistic tool-call rates.
|
|
33
|
+
*/
|
|
34
|
+
const DEFAULT_MAX_ENTRIES = 500;
|
|
35
|
+
export class CorrelationWindow {
|
|
36
|
+
entries = new Map();
|
|
37
|
+
windowMs;
|
|
38
|
+
maxEntries;
|
|
39
|
+
constructor(windowMs = DEFAULT_WINDOW_MS, maxEntries = DEFAULT_MAX_ENTRIES) {
|
|
40
|
+
this.windowMs = windowMs;
|
|
41
|
+
this.maxEntries = maxEntries;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Record a receipt's correlation keys into the window. Runs eviction of
|
|
45
|
+
* expired entries on every insert — no background sweeper.
|
|
46
|
+
*
|
|
47
|
+
* If the window is at its hard cap after eviction (indicates either a
|
|
48
|
+
* very high tool-call rate or a bug), the oldest entries are dropped.
|
|
49
|
+
* This is a safety net, not a normal path.
|
|
50
|
+
*/
|
|
51
|
+
record(entry) {
|
|
52
|
+
this.evictExpired(entry.created_at_ms);
|
|
53
|
+
this.entries.set(entry.receipt_id, entry);
|
|
54
|
+
// Hard-cap safety: if we're somehow over the limit, drop oldest.
|
|
55
|
+
if (this.entries.size > this.maxEntries) {
|
|
56
|
+
const excess = this.entries.size - this.maxEntries;
|
|
57
|
+
let dropped = 0;
|
|
58
|
+
for (const key of this.entries.keys()) {
|
|
59
|
+
if (dropped >= excess)
|
|
60
|
+
break;
|
|
61
|
+
this.entries.delete(key);
|
|
62
|
+
dropped++;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Find a recent receipt that should be linked as `preceded_by` for a new
|
|
68
|
+
* receipt. Prefers the most recent entry in the same chain_id. Returns the
|
|
69
|
+
* target_system_id of the match (that's what `preceded_by` stores), or
|
|
70
|
+
* null if nothing links.
|
|
71
|
+
*
|
|
72
|
+
* If currentChainId is null, we don't attempt cross-chain linking — the
|
|
73
|
+
* agent didn't declare a chain, so the server will reconstruct any
|
|
74
|
+
* linkage from its full history.
|
|
75
|
+
*/
|
|
76
|
+
findPrecededBy(currentChainId, nowMs) {
|
|
77
|
+
if (!currentChainId)
|
|
78
|
+
return null;
|
|
79
|
+
this.evictExpired(nowMs);
|
|
80
|
+
// Walk entries newest-first by iterating in reverse insertion order.
|
|
81
|
+
// Map preserves insertion order, so the newest entry is last. Convert
|
|
82
|
+
// to an array and scan from the end.
|
|
83
|
+
const allEntries = Array.from(this.entries.values());
|
|
84
|
+
for (let i = allEntries.length - 1; i >= 0; i--) {
|
|
85
|
+
const entry = allEntries[i];
|
|
86
|
+
if (entry.chain_id === currentChainId) {
|
|
87
|
+
return entry.target_system_id;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Evict entries older than the window. Called on every record() and
|
|
94
|
+
* every findPrecededBy() call. No background timers.
|
|
95
|
+
*/
|
|
96
|
+
evictExpired(nowMs) {
|
|
97
|
+
const cutoff = nowMs - this.windowMs;
|
|
98
|
+
for (const [key, entry] of this.entries) {
|
|
99
|
+
if (entry.created_at_ms < cutoff) {
|
|
100
|
+
this.entries.delete(key);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/** Current number of entries in the window. Used by tests and observability. */
|
|
105
|
+
size() {
|
|
106
|
+
return this.entries.size;
|
|
107
|
+
}
|
|
108
|
+
/** Clear the window. Used by tests; not expected in production code paths. */
|
|
109
|
+
clear() {
|
|
110
|
+
this.entries.clear();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=correlation-window.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"correlation-window.js","sourceRoot":"","sources":["../../../src/middleware/correlation-window.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAUH,0DAA0D;AAC1D,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAEjC;;;;GAIG;AACH,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC,MAAM,OAAO,iBAAiB;IACX,OAAO,GAAkC,IAAI,GAAG,EAAE,CAAC;IACnD,QAAQ,CAAS;IACjB,UAAU,CAAS;IAEpC,YAAY,WAAmB,iBAAiB,EAAE,aAAqB,mBAAmB;QACxF,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,KAAuB;QAC5B,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QACvC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAE1C,iEAAiE;QACjE,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC;YACnD,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;gBACtC,IAAI,OAAO,IAAI,MAAM;oBAAE,MAAM;gBAC7B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACzB,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;;;;;OASG;IACH,cAAc,CAAC,cAA6B,EAAE,KAAa;QACzD,IAAI,CAAC,cAAc;YAAE,OAAO,IAAI,CAAC;QACjC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QAEzB,qEAAqE;QACrE,sEAAsE;QACtE,qCAAqC;QACrC,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACrD,KAAK,IAAI,CAAC,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAChD,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC;YAC7B,IAAI,KAAK,CAAC,QAAQ,KAAK,cAAc,EAAE,CAAC;gBACtC,OAAO,KAAK,CAAC,gBAAgB,CAAC;YAChC,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACK,YAAY,CAAC,KAAa;QAChC,MAAM,MAAM,GAAG,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC;QACrC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACxC,IAAI,KAAK,CAAC,aAAa,GAAG,MAAM,EAAE,CAAC;gBACjC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IAED,gFAAgF;IAChF,IAAI;QACF,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED,8EAA8E;IAC9E,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;CACF"}
|
package/dist/src/server.d.ts
CHANGED
|
@@ -4,11 +4,14 @@
|
|
|
4
4
|
* Used by both stdio (index.ts) and HTTP (http.ts) entry points.
|
|
5
5
|
*/
|
|
6
6
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
|
+
import { CorrelationWindow } from './middleware/correlation-window.js';
|
|
7
8
|
import { SessionState } from './session-state.js';
|
|
8
9
|
export interface AcrServerOptions {
|
|
9
10
|
apiUrl?: string;
|
|
10
11
|
resolverUrl?: string;
|
|
11
12
|
/** Session state for this server instance. Defaults to the stdio singleton. */
|
|
12
13
|
session?: SessionState;
|
|
14
|
+
/** Correlation window for in-flight receipt linkage. One per session. */
|
|
15
|
+
correlationWindow?: CorrelationWindow;
|
|
13
16
|
}
|
|
14
17
|
export declare function createAcrServer(options?: AcrServerOptions): McpServer;
|
package/dist/src/server.js
CHANGED
|
@@ -18,20 +18,24 @@ import { getSkillVersionsTool } from './tools/get-skill-versions.js';
|
|
|
18
18
|
import { updateCompositionTool } from './tools/update-composition.js';
|
|
19
19
|
import { getNotificationsTool } from './tools/get-notifications.js';
|
|
20
20
|
import { acknowledgeThreatTool } from './tools/acknowledge-threat.js';
|
|
21
|
+
import { disableDeepCompositionTool } from './tools/disable-deep-composition.js';
|
|
22
|
+
import { getProfileTool } from './tools/get-profile.js';
|
|
23
|
+
import { getCoverageTool } from './tools/get-coverage.js';
|
|
24
|
+
import { getStableCorridorsTool } from './tools/get-stable-corridors.js';
|
|
25
|
+
import { getFailureRegistryTool } from './tools/get-failure-registry.js';
|
|
26
|
+
import { getTrendTool } from './tools/get-trend.js';
|
|
27
|
+
import { summarizeMyAgentTool } from './tools/summarize-my-agent.js';
|
|
21
28
|
import { withSelfLog } from './middleware/self-log.js';
|
|
29
|
+
import { CorrelationWindow } from './middleware/correlation-window.js';
|
|
22
30
|
import { defaultSession } from './session-state.js';
|
|
23
31
|
/**
|
|
24
|
-
* Wraps server.tool() to automatically apply self-logging middleware.
|
|
32
|
+
* Wraps server.tool() and server.registerTool() to automatically apply self-logging middleware.
|
|
25
33
|
* Each tool handler gets wrapped with withSelfLog before registration.
|
|
26
34
|
*/
|
|
27
35
|
function withSelfLogging(server, getState, apiUrl) {
|
|
36
|
+
// Wrap deprecated server.tool()
|
|
28
37
|
const originalTool = server.tool.bind(server);
|
|
29
|
-
// Override server.tool to wrap handlers
|
|
30
|
-
// The SDK has multiple overloads; we intercept the most common pattern:
|
|
31
|
-
// server.tool(name, description, schema, handler)
|
|
32
|
-
// server.tool(name, description, handler) — no schema
|
|
33
38
|
server.tool = function (name, ...rest) {
|
|
34
|
-
// Find the handler (always the last argument in rest)
|
|
35
39
|
const lastIdx = rest.length - 1;
|
|
36
40
|
const handler = rest[lastIdx];
|
|
37
41
|
if (typeof handler === 'function') {
|
|
@@ -39,21 +43,33 @@ function withSelfLogging(server, getState, apiUrl) {
|
|
|
39
43
|
}
|
|
40
44
|
return originalTool.call(server, name, ...rest);
|
|
41
45
|
};
|
|
46
|
+
// Wrap server.registerTool()
|
|
47
|
+
const originalRegisterTool = server.registerTool.bind(server);
|
|
48
|
+
server.registerTool = function (name, config, cb) {
|
|
49
|
+
if (typeof cb === 'function') {
|
|
50
|
+
cb = withSelfLog(name, cb, getState, apiUrl);
|
|
51
|
+
}
|
|
52
|
+
return originalRegisterTool.call(server, name, config, cb);
|
|
53
|
+
};
|
|
42
54
|
return server;
|
|
43
55
|
}
|
|
44
56
|
export function createAcrServer(options) {
|
|
45
57
|
const apiUrl = options?.apiUrl ?? process.env.ACR_API_URL ?? 'https://acr.nfkey.ai';
|
|
46
58
|
const resolverUrl = options?.resolverUrl ?? process.env.ACR_RESOLVER_URL ?? apiUrl;
|
|
47
59
|
const session = options?.session ?? defaultSession;
|
|
60
|
+
// One correlation window per server instance. Not a module-level singleton
|
|
61
|
+
// so HTTP transport with concurrent sessions gets an independent window
|
|
62
|
+
// per agent.
|
|
63
|
+
const correlationWindow = options?.correlationWindow ?? new CorrelationWindow();
|
|
48
64
|
const server = new McpServer({
|
|
49
65
|
name: 'acr-agent-registry',
|
|
50
66
|
version: '1.0.0',
|
|
51
|
-
description: 'Agent Composition Records —
|
|
67
|
+
description: 'Agent Composition Records — an interaction profile registry for AI agents. Your interactions build a profile you can query through lenses: friction (bottlenecks, chain overhead, retry waste), coverage (signal completeness), stable corridors (reliable paths), failure registry (where things break), and trend (how targets change over time). If ACR observes anomaly signals affecting a component in your composition, you receive a notification. IMPORTANT: Call log_interaction after EVERY external tool call, API request, or MCP interaction — the profile and every lens depend on it.',
|
|
52
68
|
});
|
|
53
69
|
// Apply self-logging middleware before tool registration
|
|
54
70
|
withSelfLogging(server, () => session, apiUrl);
|
|
55
71
|
registerAgentTool(server, apiUrl);
|
|
56
|
-
logInteractionTool(server, apiUrl);
|
|
72
|
+
logInteractionTool(server, apiUrl, correlationWindow);
|
|
57
73
|
checkEntityTool(server, apiUrl, resolverUrl);
|
|
58
74
|
checkEnvironmentTool(server, apiUrl, resolverUrl);
|
|
59
75
|
getFrictionReportTool(server, apiUrl);
|
|
@@ -66,6 +82,13 @@ export function createAcrServer(options) {
|
|
|
66
82
|
updateCompositionTool(server, apiUrl, () => session);
|
|
67
83
|
getNotificationsTool(server, apiUrl, () => session);
|
|
68
84
|
acknowledgeThreatTool(server, apiUrl, () => session);
|
|
85
|
+
disableDeepCompositionTool(server, () => session);
|
|
86
|
+
getProfileTool(server, apiUrl);
|
|
87
|
+
getCoverageTool(server, apiUrl);
|
|
88
|
+
getStableCorridorsTool(server, apiUrl);
|
|
89
|
+
getFailureRegistryTool(server, apiUrl);
|
|
90
|
+
getTrendTool(server, apiUrl);
|
|
91
|
+
summarizeMyAgentTool(server, apiUrl);
|
|
69
92
|
return server;
|
|
70
93
|
}
|
|
71
94
|
//# sourceMappingURL=server.js.map
|
package/dist/src/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,cAAc,EAAgB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,10 @@ export declare class SessionState {
|
|
|
4
4
|
private _registering;
|
|
5
5
|
private _transportType;
|
|
6
6
|
private _clientType;
|
|
7
|
+
private _deepComposition;
|
|
7
8
|
constructor(transportType?: 'stdio' | 'streamable-http');
|
|
9
|
+
get deepComposition(): boolean;
|
|
10
|
+
setDeepComposition(enabled: boolean): void;
|
|
8
11
|
get agentId(): string | null;
|
|
9
12
|
get agentName(): string | null;
|
|
10
13
|
get transportType(): 'stdio' | 'streamable-http';
|
|
@@ -10,9 +10,20 @@ export class SessionState {
|
|
|
10
10
|
_registering = false;
|
|
11
11
|
_transportType;
|
|
12
12
|
_clientType = null;
|
|
13
|
+
// Deep composition capture flag — when false, the MCP only reports
|
|
14
|
+
// top-level components, never sub-components. Operator privacy control.
|
|
15
|
+
// Default is true (deep capture enabled); set to false via
|
|
16
|
+
// ACR_DEEP_COMPOSITION=false env var or the disable_deep_composition tool.
|
|
17
|
+
_deepComposition = (process.env.ACR_DEEP_COMPOSITION ?? 'true') !== 'false';
|
|
13
18
|
constructor(transportType = 'stdio') {
|
|
14
19
|
this._transportType = transportType;
|
|
15
20
|
}
|
|
21
|
+
get deepComposition() {
|
|
22
|
+
return this._deepComposition;
|
|
23
|
+
}
|
|
24
|
+
setDeepComposition(enabled) {
|
|
25
|
+
this._deepComposition = enabled;
|
|
26
|
+
}
|
|
16
27
|
get agentId() {
|
|
17
28
|
return this._agentId;
|
|
18
29
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-state.js","sourceRoot":"","sources":["../../src/session-state.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,OAAO,YAAY;IACf,QAAQ,GAAkB,IAAI,CAAC;IAC/B,UAAU,GAAkB,IAAI,CAAC;IACjC,YAAY,GAAG,KAAK,CAAC;IACrB,cAAc,CAA8B;IAC5C,WAAW,GAAkB,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"session-state.js","sourceRoot":"","sources":["../../src/session-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export function acknowledgeThreatTool(server, apiUrl, getSession) {
|
|
3
|
-
server.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
server.registerTool('acknowledge_threat', {
|
|
4
|
+
description: 'Acknowledge an anomaly signal notification after reviewing it with your operator. This records that the notification has been reviewed. Acknowledgements expire after 30 days. Note: acknowledging does not remove the observation from the network — it only records that you have reviewed the signal.',
|
|
5
|
+
inputSchema: {
|
|
6
|
+
notification_id: z.string().describe('The notification ID to acknowledge'),
|
|
7
|
+
agent_id: z.string().optional().describe('Your agent ID (uses session if omitted)'),
|
|
8
|
+
reason: z.string().optional().describe('Why the threat is being acknowledged (e.g., "user reviewed and accepted risk")'),
|
|
9
|
+
},
|
|
10
|
+
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
11
|
+
_meta: { priorityHint: 0.3 },
|
|
12
|
+
}, async ({ notification_id, agent_id, reason }) => {
|
|
8
13
|
try {
|
|
9
14
|
const resolvedId = agent_id ?? getSession().agentId ?? await getSession().ensureRegistered(apiUrl);
|
|
10
15
|
const res = await fetch(`${apiUrl}/api/v1/agent/${resolvedId}/notifications/${notification_id}/acknowledge`, {
|
|
@@ -19,7 +24,7 @@ export function acknowledgeThreatTool(server, apiUrl, getSession) {
|
|
|
19
24
|
return {
|
|
20
25
|
content: [{
|
|
21
26
|
type: 'text',
|
|
22
|
-
text: `
|
|
27
|
+
text: `Notification acknowledged. This acknowledgement expires in 30 days.\n\nNote: The anomaly signals remain visible across the network. This acknowledgement records that you and your operator have reviewed the observation.`,
|
|
23
28
|
}],
|
|
24
29
|
};
|
|
25
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"acknowledge-threat.js","sourceRoot":"","sources":["../../../src/tools/acknowledge-threat.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,qBAAqB,CAAC,MAAiB,EAAE,MAAc,EAAE,UAA8B;IACrG,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"acknowledge-threat.js","sourceRoot":"","sources":["../../../src/tools/acknowledge-threat.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,qBAAqB,CAAC,MAAiB,EAAE,MAAc,EAAE,UAA8B;IACrG,MAAM,CAAC,YAAY,CACjB,oBAAoB,EACpB;QACE,WAAW,EAAE,0SAA0S;QACvT,WAAW,EAAE;YACX,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;YAC1E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;YACnF,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gFAAgF,CAAC;SACzH;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE;QAC5D,KAAK,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE;KAC7B,EACD,KAAK,EAAE,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE;QAC9C,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,QAAQ,IAAI,UAAU,EAAE,CAAC,OAAO,IAAI,MAAM,UAAU,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;YACnG,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,iBAAiB,UAAU,kBAAkB,eAAe,cAAc,EAAE;gBAC3G,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;aACjC,CAAC,CAAC;YAEH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAwD,CAAC;YACpF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,2BAA2B,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,EAAE,CAAC,EAAE,CAAC;YAC7H,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,4NAA4N;qBACnO,CAAC;aACH,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACjE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,0BAA0B,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC;QACzF,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|