@axonflow/openclaw 0.1.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/CHANGELOG.md +19 -0
- package/LICENSE +21 -0
- package/README.md +141 -0
- package/dist/audit.d.ts +23 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +26 -0
- package/dist/audit.js.map +1 -0
- package/dist/axonflow-client.d.ts +47 -0
- package/dist/axonflow-client.d.ts.map +1 -0
- package/dist/axonflow-client.js +180 -0
- package/dist/axonflow-client.js.map +1 -0
- package/dist/config.d.ts +47 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +56 -0
- package/dist/config.js.map +1 -0
- package/dist/governance.d.ts +40 -0
- package/dist/governance.d.ts.map +1 -0
- package/dist/governance.js +64 -0
- package/dist/governance.js.map +1 -0
- package/dist/index.d.ts +78 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +94 -0
- package/dist/index.js.map +1 -0
- package/dist/llm-audit.d.ts +55 -0
- package/dist/llm-audit.d.ts.map +1 -0
- package/dist/llm-audit.js +60 -0
- package/dist/llm-audit.js.map +1 -0
- package/dist/message-guard.d.ts +25 -0
- package/dist/message-guard.d.ts.map +1 -0
- package/dist/message-guard.js +46 -0
- package/dist/message-guard.js.map +1 -0
- package/openclaw.plugin.json +96 -0
- package/package.json +93 -0
- package/policies/README.md +118 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.0] - 2026-04-01
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `before_tool_call` hook: evaluates tool arguments against AxonFlow policies before execution. Blocks dangerous commands, detects PII in tool input, enforces rate limits.
|
|
8
|
+
- `after_tool_call` hook: logs every tool execution to AxonFlow's audit trail for compliance evidence.
|
|
9
|
+
- `message_sending` hook: scans outbound messages to user channels (Telegram, Discord, Slack, WhatsApp) for PII and secrets. Can cancel or redact before delivery.
|
|
10
|
+
- `llm_input` hook: records prompt, model, and provider at the start of each LLM call to AxonFlow's audit trail.
|
|
11
|
+
- `llm_output` hook: records LLM response, token usage, and latency. Correlates with `llm_input` for complete LLM call audit entries.
|
|
12
|
+
- High-risk tool approval: configurable tool list triggers OpenClaw's native approval flow even when AxonFlow allows the call.
|
|
13
|
+
- Configurable governance scope: govern all tools, specific tools only, or exclude specific tools.
|
|
14
|
+
- Fail-open/fail-closed: `onError` config controls behavior when AxonFlow is unreachable.
|
|
15
|
+
- Starter policy documentation with SQL setup for OpenClaw production baseline.
|
|
16
|
+
|
|
17
|
+
### Not Yet Supported
|
|
18
|
+
|
|
19
|
+
- Tool result transcript scanning: OpenClaw's `tool_result_persist` hook is sync-only, preventing async HTTP calls to AxonFlow. Upstream issue filed (openclaw/openclaw#58558). Outbound messages ARE scanned via `message_sending`.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AxonFlow
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# @axonflow/openclaw
|
|
2
|
+
|
|
3
|
+
**Policy enforcement, approval gates, and audit trails for [OpenClaw](https://github.com/openclaw/openclaw).**
|
|
4
|
+
|
|
5
|
+
OpenClaw handles agent runtime, tool execution, MCP connectivity, and channel delivery. AxonFlow adds a governance layer for production use: inspect tool inputs before execution, scan outbound messages before delivery, and record tool + LLM activity for review, security, and compliance.
|
|
6
|
+
|
|
7
|
+
This plugin is useful when you want to:
|
|
8
|
+
- block dangerous tool calls before they run
|
|
9
|
+
- require approval for selected high-risk tools
|
|
10
|
+
- prevent PII or secrets from being sent to users
|
|
11
|
+
- keep an audit trail of agent activity with policy context
|
|
12
|
+
|
|
13
|
+
Much of the OpenClaw ecosystem today focuses on routing, memory, integrations, and observability. This plugin focuses on governance: policy enforcement, approval gates, and reviewable audit trails.
|
|
14
|
+
|
|
15
|
+
## What v0.1.0 Covers
|
|
16
|
+
|
|
17
|
+
| Hook | Purpose |
|
|
18
|
+
|------|---------|
|
|
19
|
+
| `before_tool_call` | Evaluate tool inputs against AxonFlow policies before execution |
|
|
20
|
+
| `after_tool_call` | Record tool execution in AxonFlow audit trail |
|
|
21
|
+
| `message_sending` | Scan outbound messages for PII/secrets before delivery |
|
|
22
|
+
| `llm_input` | Record prompt, model, and provider for audit |
|
|
23
|
+
| `llm_output` | Record response summary, token usage, and latency for audit |
|
|
24
|
+
|
|
25
|
+
## Current Limitation
|
|
26
|
+
|
|
27
|
+
Tool results written into the OpenClaw session transcript are not yet scanned by this plugin. OpenClaw's `tool_result_persist` hook is synchronous today, so it cannot call AxonFlow's HTTP policy APIs.
|
|
28
|
+
|
|
29
|
+
What is protected today:
|
|
30
|
+
- tool inputs before execution
|
|
31
|
+
- outbound messages before delivery
|
|
32
|
+
- tool and LLM audit trails
|
|
33
|
+
|
|
34
|
+
What is not protected yet:
|
|
35
|
+
- tool results entering the LLM context through the session transcript
|
|
36
|
+
|
|
37
|
+
If OpenClaw adds async support for `tool_result_persist`, AxonFlow can add transcript/result scanning immediately. Upstream issue: [openclaw/openclaw#58558](https://github.com/openclaw/openclaw/issues/58558).
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
openclaw plugins install @axonflow/openclaw
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Configure
|
|
46
|
+
|
|
47
|
+
In your OpenClaw config:
|
|
48
|
+
|
|
49
|
+
```yaml
|
|
50
|
+
plugins:
|
|
51
|
+
@axonflow/openclaw:
|
|
52
|
+
endpoint: http://localhost:8080
|
|
53
|
+
clientId: your-client-id
|
|
54
|
+
clientSecret: your-secret
|
|
55
|
+
highRiskTools:
|
|
56
|
+
- web_fetch
|
|
57
|
+
- message
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Configuration Options
|
|
61
|
+
|
|
62
|
+
| Option | Required | Default | Description |
|
|
63
|
+
|--------|----------|---------|-------------|
|
|
64
|
+
| `endpoint` | Yes | — | AxonFlow agent gateway URL |
|
|
65
|
+
| `clientId` | Yes | — | AxonFlow client ID |
|
|
66
|
+
| `clientSecret` | Yes | — | AxonFlow client secret |
|
|
67
|
+
| `highRiskTools` | No | `[]` | Tools that require human approval even when policy allows |
|
|
68
|
+
| `governedTools` | No | `[]` (all) | Tools to govern. Empty = all tools. |
|
|
69
|
+
| `excludedTools` | No | `[]` | Tools to exclude from governance |
|
|
70
|
+
| `defaultOperation` | No | `"execute"` | Operation type for mcp_check_input (`"execute"` or `"query"`) |
|
|
71
|
+
| `onError` | No | `"block"` | Behavior when AxonFlow is unreachable: `"block"` (fail-closed) or `"allow"` (fail-open) |
|
|
72
|
+
|
|
73
|
+
## How It Works
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
User sends message → OpenClaw receives
|
|
77
|
+
│
|
|
78
|
+
▼
|
|
79
|
+
┌─────────────────────────────────────────────┐
|
|
80
|
+
│ llm_input (audit) │
|
|
81
|
+
│ → Record prompt, model, provider │
|
|
82
|
+
└─────────────────────────────────────────────┘
|
|
83
|
+
│
|
|
84
|
+
▼
|
|
85
|
+
LLM generates response (may include tool calls)
|
|
86
|
+
│
|
|
87
|
+
▼
|
|
88
|
+
┌─────────────────────────────────────────────┐
|
|
89
|
+
│ llm_output (audit) │
|
|
90
|
+
│ → Record response, tokens, latency │
|
|
91
|
+
└─────────────────────────────────────────────┘
|
|
92
|
+
│
|
|
93
|
+
▼ (if tool calls in response)
|
|
94
|
+
┌─────────────────────────────────────────────┐
|
|
95
|
+
│ before_tool_call (governance) │
|
|
96
|
+
│ → mcp_check_input(openclaw.{tool}, args) │
|
|
97
|
+
│ → BLOCK / REQUIRE APPROVAL / ALLOW │
|
|
98
|
+
└─────────────────────────────────────────────┘
|
|
99
|
+
│
|
|
100
|
+
▼
|
|
101
|
+
Tool executes (web_fetch, message, MCP, etc.)
|
|
102
|
+
│
|
|
103
|
+
▼
|
|
104
|
+
Tool result persisted to session transcript
|
|
105
|
+
(not scanned — pending async hook support)
|
|
106
|
+
│
|
|
107
|
+
▼
|
|
108
|
+
┌─────────────────────────────────────────────┐
|
|
109
|
+
│ after_tool_call (audit) │
|
|
110
|
+
│ → audit_tool_call(tool, params, result) │
|
|
111
|
+
└─────────────────────────────────────────────┘
|
|
112
|
+
│
|
|
113
|
+
▼
|
|
114
|
+
┌─────────────────────────────────────────────┐
|
|
115
|
+
│ message_sending (governance) │
|
|
116
|
+
│ → mcp_check_output(openclaw.message_sending) │
|
|
117
|
+
│ → CANCEL / REDACT / ALLOW │
|
|
118
|
+
└─────────────────────────────────────────────┘
|
|
119
|
+
│
|
|
120
|
+
▼
|
|
121
|
+
Message delivered to user channel
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Prerequisites
|
|
125
|
+
|
|
126
|
+
- [AxonFlow](https://github.com/getaxonflow/axonflow) running (Docker or production)
|
|
127
|
+
- OpenClaw 1.0+
|
|
128
|
+
|
|
129
|
+
## Starter Policies
|
|
130
|
+
|
|
131
|
+
See [policies/README.md](./policies/README.md) for recommended policy setup for OpenClaw deployments, including protections against reverse shells, credential exfiltration, SSRF, path traversal, and agent config file poisoning.
|
|
132
|
+
|
|
133
|
+
## Links
|
|
134
|
+
|
|
135
|
+
- [AxonFlow Documentation](https://docs.getaxonflow.com)
|
|
136
|
+
- [OpenClaw Integration Guide](https://docs.getaxonflow.com/docs/integration/openclaw/)
|
|
137
|
+
- [Policy Enforcement](https://docs.getaxonflow.com/docs/mcp/policy-enforcement/)
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
MIT
|
package/dist/audit.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* after_tool_call hook — audit logging.
|
|
3
|
+
*
|
|
4
|
+
* Records every tool execution to AxonFlow's audit trail.
|
|
5
|
+
* Fire-and-forget: audit failures do not block tool execution.
|
|
6
|
+
*/
|
|
7
|
+
import type { AxonFlowClient } from "./axonflow-client.js";
|
|
8
|
+
import type { AxonFlowPluginConfig } from "./config.js";
|
|
9
|
+
/**
|
|
10
|
+
* Create the after_tool_call hook handler.
|
|
11
|
+
*
|
|
12
|
+
* Logs tool execution details to AxonFlow for compliance audit.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createAfterToolCallHandler(client: AxonFlowClient, config: AxonFlowPluginConfig): (event: {
|
|
15
|
+
toolName: string;
|
|
16
|
+
params: Record<string, unknown>;
|
|
17
|
+
runId?: string;
|
|
18
|
+
toolCallId?: string;
|
|
19
|
+
result?: unknown;
|
|
20
|
+
error?: string;
|
|
21
|
+
durationMs?: number;
|
|
22
|
+
}) => Promise<void>;
|
|
23
|
+
//# sourceMappingURL=audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGxD;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,oBAAoB,IAEd,OAAO;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,KAAG,OAAO,CAAC,IAAI,CAAC,CAiBlB"}
|
package/dist/audit.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* after_tool_call hook — audit logging.
|
|
3
|
+
*
|
|
4
|
+
* Records every tool execution to AxonFlow's audit trail.
|
|
5
|
+
* Fire-and-forget: audit failures do not block tool execution.
|
|
6
|
+
*/
|
|
7
|
+
import { shouldGovernTool } from "./config.js";
|
|
8
|
+
/**
|
|
9
|
+
* Create the after_tool_call hook handler.
|
|
10
|
+
*
|
|
11
|
+
* Logs tool execution details to AxonFlow for compliance audit.
|
|
12
|
+
*/
|
|
13
|
+
export function createAfterToolCallHandler(client, config) {
|
|
14
|
+
return async (event) => {
|
|
15
|
+
if (!shouldGovernTool(event.toolName, config)) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
await client.auditToolCall(event.toolName, event.params, event.result, event.error, event.durationMs);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// Fire-and-forget: audit failures must not interfere with tool pipeline
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CACxC,MAAsB,EACtB,MAA4B;IAE5B,OAAO,KAAK,EAAE,KAQb,EAAiB,EAAE;QAClB,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC;YAC9C,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,aAAa,CACxB,KAAK,CAAC,QAAQ,EACd,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,KAAK,EACX,KAAK,CAAC,UAAU,CACjB,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,wEAAwE;QAC1E,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight AxonFlow API client for the plugin.
|
|
3
|
+
*
|
|
4
|
+
* Uses direct HTTP calls to avoid requiring the full @axonflow/sdk
|
|
5
|
+
* as a runtime dependency.
|
|
6
|
+
*/
|
|
7
|
+
import type { AxonFlowPluginConfig } from "./config.js";
|
|
8
|
+
export interface MCPCheckInputResponse {
|
|
9
|
+
allowed: boolean;
|
|
10
|
+
block_reason?: string;
|
|
11
|
+
policies_evaluated: number;
|
|
12
|
+
}
|
|
13
|
+
export interface MCPCheckOutputResponse {
|
|
14
|
+
allowed: boolean;
|
|
15
|
+
block_reason?: string;
|
|
16
|
+
redacted_data?: unknown;
|
|
17
|
+
policies_evaluated: number;
|
|
18
|
+
}
|
|
19
|
+
export declare class AxonFlowClient {
|
|
20
|
+
private readonly endpoint;
|
|
21
|
+
private readonly authHeader;
|
|
22
|
+
private readonly tenantId;
|
|
23
|
+
constructor(config: AxonFlowPluginConfig);
|
|
24
|
+
private baseHeaders;
|
|
25
|
+
mcpCheckInput(connectorType: string, statement: string, operation?: string): Promise<MCPCheckInputResponse>;
|
|
26
|
+
mcpCheckOutput(connectorType: string, message: string): Promise<MCPCheckOutputResponse>;
|
|
27
|
+
/**
|
|
28
|
+
* Log a tool execution to the audit trail.
|
|
29
|
+
* Uses POST /api/v1/audit/tool-call (requires X-Tenant-ID header).
|
|
30
|
+
*/
|
|
31
|
+
auditToolCall(toolName: string, params: Record<string, unknown>, result?: unknown, error?: string, durationMs?: number): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Log an LLM call to the audit trail.
|
|
34
|
+
*
|
|
35
|
+
* Uses the same audit/tool-call endpoint with tool_type "llm_call".
|
|
36
|
+
* The dedicated audit/llm-call endpoint requires context_id (from pre_check)
|
|
37
|
+
* which the plugin doesn't have. This approach logs LLM calls as tool-call
|
|
38
|
+
* audit entries, providing audit evidence without requiring prior context.
|
|
39
|
+
*/
|
|
40
|
+
auditLLMCall(provider: string, model: string, query: string, responseSummary: string, tokenUsage: {
|
|
41
|
+
prompt_tokens: number;
|
|
42
|
+
completion_tokens: number;
|
|
43
|
+
total_tokens: number;
|
|
44
|
+
}, latencyMs: number): Promise<void>;
|
|
45
|
+
healthCheck(): Promise<boolean>;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=axonflow-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"axonflow-client.d.ts","sourceRoot":"","sources":["../src/axonflow-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAExD,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAyBD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,MAAM,EAAE,oBAAoB;IAYxC,OAAO,CAAC,WAAW;IAQb,aAAa,CACjB,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,EACjB,SAAS,GAAE,MAAkB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IA2C3B,cAAc,CAClB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,sBAAsB,CAAC;IA2ClC;;;OAGG;IACG,aAAa,CACjB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,MAAM,CAAC,EAAE,OAAO,EAChB,KAAK,CAAC,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC;IAqBhB;;;;;;;OAOG;IACG,YAAY,CAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,EACtF,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAoBV,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;CAQtC"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight AxonFlow API client for the plugin.
|
|
3
|
+
*
|
|
4
|
+
* Uses direct HTTP calls to avoid requiring the full @axonflow/sdk
|
|
5
|
+
* as a runtime dependency.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Extract policies_evaluated count from API response.
|
|
9
|
+
* The platform returns this as a top-level number on 403 responses,
|
|
10
|
+
* or inside policy_info.policies_evaluated (which can be a number or
|
|
11
|
+
* array of policy names) on 200 responses.
|
|
12
|
+
*/
|
|
13
|
+
function extractPoliciesEvaluated(data) {
|
|
14
|
+
if (typeof data["policies_evaluated"] === "number") {
|
|
15
|
+
return data["policies_evaluated"];
|
|
16
|
+
}
|
|
17
|
+
const policyInfo = data["policy_info"];
|
|
18
|
+
if (typeof policyInfo === "object" && policyInfo !== null) {
|
|
19
|
+
const pi = policyInfo;
|
|
20
|
+
if (typeof pi["policies_evaluated"] === "number") {
|
|
21
|
+
return pi["policies_evaluated"];
|
|
22
|
+
}
|
|
23
|
+
if (Array.isArray(pi["policies_evaluated"])) {
|
|
24
|
+
return pi["policies_evaluated"].length;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
export class AxonFlowClient {
|
|
30
|
+
endpoint;
|
|
31
|
+
authHeader;
|
|
32
|
+
tenantId;
|
|
33
|
+
constructor(config) {
|
|
34
|
+
this.endpoint = config.endpoint.replace(/\/+$/, "");
|
|
35
|
+
const credentials = Buffer.from(`${config.clientId}:${config.clientSecret}`).toString("base64");
|
|
36
|
+
this.authHeader = `Basic ${credentials}`;
|
|
37
|
+
// clientId serves as tenantId for single-tenant setups.
|
|
38
|
+
// The Agent proxy normally injects X-Tenant-ID after auth, but
|
|
39
|
+
// direct Orchestrator calls (audit/tool-call) require it explicitly.
|
|
40
|
+
this.tenantId = config.clientId;
|
|
41
|
+
}
|
|
42
|
+
baseHeaders() {
|
|
43
|
+
return {
|
|
44
|
+
"Content-Type": "application/json",
|
|
45
|
+
Authorization: this.authHeader,
|
|
46
|
+
"X-Tenant-ID": this.tenantId,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async mcpCheckInput(connectorType, statement, operation = "execute") {
|
|
50
|
+
const url = `${this.endpoint}/api/v1/mcp/check-input`;
|
|
51
|
+
const response = await fetch(url, {
|
|
52
|
+
method: "POST",
|
|
53
|
+
headers: this.baseHeaders(),
|
|
54
|
+
body: JSON.stringify({
|
|
55
|
+
connector_type: connectorType,
|
|
56
|
+
statement,
|
|
57
|
+
operation,
|
|
58
|
+
}),
|
|
59
|
+
});
|
|
60
|
+
const data = (await response.json());
|
|
61
|
+
if (response.status === 403) {
|
|
62
|
+
return {
|
|
63
|
+
allowed: false,
|
|
64
|
+
block_reason: typeof data["block_reason"] === "string"
|
|
65
|
+
? data["block_reason"]
|
|
66
|
+
: typeof data["error"] === "string"
|
|
67
|
+
? data["error"]
|
|
68
|
+
: "Blocked by policy",
|
|
69
|
+
policies_evaluated: extractPoliciesEvaluated(data),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
throw new Error(`AxonFlow check-input failed: ${response.status} ${typeof data["error"] === "string" ? data["error"] : ""}`);
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
allowed: data["allowed"] === true,
|
|
77
|
+
block_reason: typeof data["block_reason"] === "string"
|
|
78
|
+
? data["block_reason"]
|
|
79
|
+
: undefined,
|
|
80
|
+
policies_evaluated: extractPoliciesEvaluated(data),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
async mcpCheckOutput(connectorType, message) {
|
|
84
|
+
const url = `${this.endpoint}/api/v1/mcp/check-output`;
|
|
85
|
+
const response = await fetch(url, {
|
|
86
|
+
method: "POST",
|
|
87
|
+
headers: this.baseHeaders(),
|
|
88
|
+
body: JSON.stringify({
|
|
89
|
+
connector_type: connectorType,
|
|
90
|
+
message,
|
|
91
|
+
}),
|
|
92
|
+
});
|
|
93
|
+
const data = (await response.json());
|
|
94
|
+
if (response.status === 403) {
|
|
95
|
+
return {
|
|
96
|
+
allowed: false,
|
|
97
|
+
block_reason: typeof data["block_reason"] === "string"
|
|
98
|
+
? data["block_reason"]
|
|
99
|
+
: typeof data["error"] === "string"
|
|
100
|
+
? data["error"]
|
|
101
|
+
: "Blocked by policy",
|
|
102
|
+
policies_evaluated: extractPoliciesEvaluated(data),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
if (!response.ok) {
|
|
106
|
+
throw new Error(`AxonFlow check-output failed: ${response.status} ${typeof data["error"] === "string" ? data["error"] : ""}`);
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
allowed: data["allowed"] === true,
|
|
110
|
+
block_reason: typeof data["block_reason"] === "string"
|
|
111
|
+
? data["block_reason"]
|
|
112
|
+
: undefined,
|
|
113
|
+
redacted_data: data["redacted_data"] ?? undefined,
|
|
114
|
+
policies_evaluated: extractPoliciesEvaluated(data),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Log a tool execution to the audit trail.
|
|
119
|
+
* Uses POST /api/v1/audit/tool-call (requires X-Tenant-ID header).
|
|
120
|
+
*/
|
|
121
|
+
async auditToolCall(toolName, params, result, error, durationMs) {
|
|
122
|
+
const url = `${this.endpoint}/api/v1/audit/tool-call`;
|
|
123
|
+
try {
|
|
124
|
+
await fetch(url, {
|
|
125
|
+
method: "POST",
|
|
126
|
+
headers: this.baseHeaders(),
|
|
127
|
+
body: JSON.stringify({
|
|
128
|
+
tool_name: toolName,
|
|
129
|
+
tool_type: "openclaw",
|
|
130
|
+
input: params,
|
|
131
|
+
output: result != null ? { result: JSON.stringify(result).slice(0, 500) } : undefined,
|
|
132
|
+
success: error == null,
|
|
133
|
+
error_message: error,
|
|
134
|
+
duration_ms: durationMs,
|
|
135
|
+
}),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// Audit failures are non-fatal
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Log an LLM call to the audit trail.
|
|
144
|
+
*
|
|
145
|
+
* Uses the same audit/tool-call endpoint with tool_type "llm_call".
|
|
146
|
+
* The dedicated audit/llm-call endpoint requires context_id (from pre_check)
|
|
147
|
+
* which the plugin doesn't have. This approach logs LLM calls as tool-call
|
|
148
|
+
* audit entries, providing audit evidence without requiring prior context.
|
|
149
|
+
*/
|
|
150
|
+
async auditLLMCall(provider, model, query, responseSummary, tokenUsage, latencyMs) {
|
|
151
|
+
const url = `${this.endpoint}/api/v1/audit/tool-call`;
|
|
152
|
+
try {
|
|
153
|
+
await fetch(url, {
|
|
154
|
+
method: "POST",
|
|
155
|
+
headers: this.baseHeaders(),
|
|
156
|
+
body: JSON.stringify({
|
|
157
|
+
tool_name: `${provider}.${model}`,
|
|
158
|
+
tool_type: "llm_call",
|
|
159
|
+
input: { query: query.slice(0, 500) },
|
|
160
|
+
output: { response_summary: responseSummary.slice(0, 200), token_usage: tokenUsage },
|
|
161
|
+
success: true,
|
|
162
|
+
duration_ms: latencyMs,
|
|
163
|
+
}),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// Audit failures are non-fatal
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
async healthCheck() {
|
|
171
|
+
try {
|
|
172
|
+
const response = await fetch(`${this.endpoint}/health`);
|
|
173
|
+
return response.ok;
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=axonflow-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"axonflow-client.js","sourceRoot":"","sources":["../src/axonflow-client.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the AxonFlow governance plugin.
|
|
3
|
+
*
|
|
4
|
+
* All configuration is read from the OpenClaw plugin config system
|
|
5
|
+
* (openclaw.plugin.json or runtime config).
|
|
6
|
+
*/
|
|
7
|
+
export interface AxonFlowPluginConfig {
|
|
8
|
+
/** AxonFlow agent gateway endpoint (e.g., "http://localhost:8080"). */
|
|
9
|
+
endpoint: string;
|
|
10
|
+
/** AxonFlow client ID for authentication. */
|
|
11
|
+
clientId: string;
|
|
12
|
+
/** AxonFlow client secret for authentication. */
|
|
13
|
+
clientSecret: string;
|
|
14
|
+
/**
|
|
15
|
+
* Tools that require human approval even when AxonFlow allows them.
|
|
16
|
+
* Uses OpenClaw's native approval flow (Telegram/Discord/approve command).
|
|
17
|
+
*/
|
|
18
|
+
highRiskTools?: string[];
|
|
19
|
+
/**
|
|
20
|
+
* Tools to govern. If empty, ALL tools are governed.
|
|
21
|
+
* Use this to selectively enable governance on specific tools.
|
|
22
|
+
*/
|
|
23
|
+
governedTools?: string[];
|
|
24
|
+
/**
|
|
25
|
+
* Tools to exclude from governance. Takes precedence over governedTools.
|
|
26
|
+
*/
|
|
27
|
+
excludedTools?: string[];
|
|
28
|
+
/**
|
|
29
|
+
* Operation type sent to mcp_check_input.
|
|
30
|
+
* Defaults to "execute". Set to "query" for read-only tool setups.
|
|
31
|
+
*/
|
|
32
|
+
defaultOperation?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Behavior when AxonFlow is unreachable (network error, timeout).
|
|
35
|
+
* - "block" (default): treat errors as policy blocks (fail-closed)
|
|
36
|
+
* - "allow": allow tool execution to proceed (fail-open)
|
|
37
|
+
*
|
|
38
|
+
* Fail-open prevents AxonFlow outages from breaking all tool execution.
|
|
39
|
+
* Fail-closed is safer but can cascade AxonFlow failures to the agent.
|
|
40
|
+
*/
|
|
41
|
+
onError?: "block" | "allow";
|
|
42
|
+
}
|
|
43
|
+
/** Validate plugin config and return defaults. */
|
|
44
|
+
export declare function resolveConfig(raw: Record<string, unknown> | undefined): AxonFlowPluginConfig;
|
|
45
|
+
/** Check if a tool should be governed based on config. */
|
|
46
|
+
export declare function shouldGovernTool(toolName: string, config: AxonFlowPluginConfig): boolean;
|
|
47
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,oBAAoB;IACnC,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;IAEjB,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAC;IAEjB,iDAAiD;IACjD,YAAY,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CAC7B;AAED,kDAAkD;AAClD,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GACvC,oBAAoB,CA0CtB;AAED,0DAA0D;AAC1D,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAWT"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the AxonFlow governance plugin.
|
|
3
|
+
*
|
|
4
|
+
* All configuration is read from the OpenClaw plugin config system
|
|
5
|
+
* (openclaw.plugin.json or runtime config).
|
|
6
|
+
*/
|
|
7
|
+
/** Validate plugin config and return defaults. */
|
|
8
|
+
export function resolveConfig(raw) {
|
|
9
|
+
if (!raw) {
|
|
10
|
+
throw new Error("AxonFlow plugin requires configuration. Set endpoint, clientId, and clientSecret in your OpenClaw plugin config.");
|
|
11
|
+
}
|
|
12
|
+
const endpoint = raw["endpoint"];
|
|
13
|
+
if (typeof endpoint !== "string" || !endpoint) {
|
|
14
|
+
throw new Error("AxonFlow plugin: 'endpoint' is required (e.g., 'http://localhost:8080')");
|
|
15
|
+
}
|
|
16
|
+
const clientId = raw["clientId"];
|
|
17
|
+
if (typeof clientId !== "string" || !clientId) {
|
|
18
|
+
throw new Error("AxonFlow plugin: 'clientId' is required");
|
|
19
|
+
}
|
|
20
|
+
const clientSecret = raw["clientSecret"];
|
|
21
|
+
if (typeof clientSecret !== "string" || !clientSecret) {
|
|
22
|
+
throw new Error("AxonFlow plugin: 'clientSecret' is required");
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
endpoint,
|
|
26
|
+
clientId,
|
|
27
|
+
clientSecret,
|
|
28
|
+
highRiskTools: Array.isArray(raw["highRiskTools"])
|
|
29
|
+
? raw["highRiskTools"]
|
|
30
|
+
: [],
|
|
31
|
+
governedTools: Array.isArray(raw["governedTools"])
|
|
32
|
+
? raw["governedTools"]
|
|
33
|
+
: [],
|
|
34
|
+
excludedTools: Array.isArray(raw["excludedTools"])
|
|
35
|
+
? raw["excludedTools"]
|
|
36
|
+
: [],
|
|
37
|
+
defaultOperation: typeof raw["defaultOperation"] === "string"
|
|
38
|
+
? raw["defaultOperation"]
|
|
39
|
+
: "execute",
|
|
40
|
+
onError: raw["onError"] === "allow" ? "allow" : "block",
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** Check if a tool should be governed based on config. */
|
|
44
|
+
export function shouldGovernTool(toolName, config) {
|
|
45
|
+
// Excluded tools take precedence
|
|
46
|
+
if (config.excludedTools && config.excludedTools.includes(toolName)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
// If governedTools is specified, only those are governed
|
|
50
|
+
if (config.governedTools && config.governedTools.length > 0) {
|
|
51
|
+
return config.governedTools.includes(toolName);
|
|
52
|
+
}
|
|
53
|
+
// Default: govern all tools
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA8CH,kDAAkD;AAClD,MAAM,UAAU,aAAa,CAC3B,GAAwC;IAExC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,kHAAkH,CACnH,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC;IACjC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,yEAAyE,CAAC,CAAC;IAC7F,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC;IACjC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IAED,MAAM,YAAY,GAAG,GAAG,CAAC,cAAc,CAAC,CAAC;IACzC,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,CAAC,YAAY,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IAED,OAAO;QACL,QAAQ;QACR,QAAQ;QACR,YAAY;QACZ,aAAa,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YAChD,CAAC,CAAE,GAAG,CAAC,eAAe,CAAc;YACpC,CAAC,CAAC,EAAE;QACN,aAAa,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YAChD,CAAC,CAAE,GAAG,CAAC,eAAe,CAAc;YACpC,CAAC,CAAC,EAAE;QACN,aAAa,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YAChD,CAAC,CAAE,GAAG,CAAC,eAAe,CAAc;YACpC,CAAC,CAAC,EAAE;QACN,gBAAgB,EACd,OAAO,GAAG,CAAC,kBAAkB,CAAC,KAAK,QAAQ;YACzC,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC;YACzB,CAAC,CAAC,SAAS;QACf,OAAO,EACL,GAAG,CAAC,SAAS,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO;KACjD,CAAC;AACJ,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,gBAAgB,CAC9B,QAAgB,EAChB,MAA4B;IAE5B,iCAAiC;IACjC,IAAI,MAAM,CAAC,aAAa,IAAI,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpE,OAAO,KAAK,CAAC;IACf,CAAC;IACD,yDAAyD;IACzD,IAAI,MAAM,CAAC,aAAa,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5D,OAAO,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACjD,CAAC;IACD,4BAA4B;IAC5B,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* before_tool_call hook — input governance.
|
|
3
|
+
*
|
|
4
|
+
* Evaluates tool arguments against AxonFlow policies before execution.
|
|
5
|
+
* Can block the call, require human approval, or allow through.
|
|
6
|
+
*/
|
|
7
|
+
import type { AxonFlowClient } from "./axonflow-client.js";
|
|
8
|
+
import type { AxonFlowPluginConfig } from "./config.js";
|
|
9
|
+
/** Result type matching OpenClaw's PluginHookBeforeToolCallResult. */
|
|
10
|
+
export interface BeforeToolCallResult {
|
|
11
|
+
params?: Record<string, unknown>;
|
|
12
|
+
block?: boolean;
|
|
13
|
+
blockReason?: string;
|
|
14
|
+
requireApproval?: {
|
|
15
|
+
title: string;
|
|
16
|
+
description: string;
|
|
17
|
+
severity?: "info" | "warning" | "critical";
|
|
18
|
+
timeoutMs?: number;
|
|
19
|
+
timeoutBehavior?: "allow" | "deny";
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/** Derive connector_type from tool name for AxonFlow policy evaluation. */
|
|
23
|
+
export declare function deriveConnectorType(toolName: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Create the before_tool_call hook handler.
|
|
26
|
+
*
|
|
27
|
+
* Decision logic:
|
|
28
|
+
* 1. If tool is excluded from governance: allow through (no check)
|
|
29
|
+
* 2. Call mcp_check_input with tool args serialized as JSON
|
|
30
|
+
* 3. If blocked by policy: return { block: true, blockReason }
|
|
31
|
+
* 4. If tool is in highRiskTools AND allowed: return { requireApproval }
|
|
32
|
+
* 5. Otherwise: allow through
|
|
33
|
+
*/
|
|
34
|
+
export declare function createBeforeToolCallHandler(client: AxonFlowClient, config: AxonFlowPluginConfig): (event: {
|
|
35
|
+
toolName: string;
|
|
36
|
+
params: Record<string, unknown>;
|
|
37
|
+
runId?: string;
|
|
38
|
+
toolCallId?: string;
|
|
39
|
+
}) => Promise<BeforeToolCallResult | undefined>;
|
|
40
|
+
//# sourceMappingURL=governance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"governance.d.ts","sourceRoot":"","sources":["../src/governance.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGxD,sEAAsE;AACtE,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC;QAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,eAAe,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;KACpC,CAAC;CACH;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,oBAAoB,IAEd,OAAO;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,KAAG,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,CAkD9C"}
|