@lindblad/complai-mcp 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/README.md ADDED
@@ -0,0 +1,303 @@
1
+ # COMPLAI MCP Server
2
+
3
+ An MCP (Model Context Protocol) server that provides compliance overview data to AI assistants.
4
+
5
+ **Package:** `@lindblad/complai-mcp`
6
+
7
+ ## Features
8
+
9
+ - **Compliance overview**: `complai_compliance_brief` - Get organization-wide compliance status
10
+ - **User authentication**: Log in with your COMPLAI credentials via browser (no secrets needed)
11
+ - **M2M authentication**: Alternative machine-to-machine auth for automation
12
+ - **AI-optimized responses**: Structured data with human-readable alerts
13
+ - **Mock mode**: Test without API credentials
14
+ - **Persistent sessions**: Login is saved locally - no need to re-authenticate
15
+
16
+ ## Installation
17
+
18
+ ### From npm (Recommended)
19
+
20
+ ```bash
21
+ # Install globally
22
+ npm install -g @lindblad/complai-mcp
23
+
24
+ # Or run directly with npx
25
+ npx @lindblad/complai-mcp
26
+ ```
27
+
28
+ ### From Source
29
+
30
+ ```bash
31
+ git clone <repo-url>
32
+ cd mcps/complai-brief
33
+ npm install
34
+ npm run build
35
+ ```
36
+
37
+ ## Quick Start with Cursor/Claude Desktop
38
+
39
+ ### Using npx (Easiest)
40
+
41
+ Add to your MCP configuration (`.cursor/mcp.json` or `claude_desktop_config.json`):
42
+
43
+ ```json
44
+ {
45
+ "mcpServers": {
46
+ "complai": {
47
+ "command": "npx",
48
+ "args": ["@lindblad/complai-mcp"],
49
+ "env": {
50
+ "COMPLAI_API_URL": "https://api.complai.com",
51
+ "COMPLAI_AUTH0_DOMAIN": "lindcon.eu.auth0.com",
52
+ "COMPLAI_AUTH0_CLIENT_ID": "your-client-id",
53
+ "COMPLAI_AUTH0_AUDIENCE": "https://api.complai.com",
54
+ "COMPLAI_ORGANIZATION_ID": "org_xxxxx"
55
+ }
56
+ }
57
+ }
58
+ }
59
+ ```
60
+
61
+ ### Using Global Install
62
+
63
+ ```json
64
+ {
65
+ "mcpServers": {
66
+ "complai": {
67
+ "command": "complai-mcp",
68
+ "env": {
69
+ "COMPLAI_API_URL": "https://api.complai.com",
70
+ "COMPLAI_AUTH0_DOMAIN": "lindcon.eu.auth0.com",
71
+ "COMPLAI_AUTH0_CLIENT_ID": "your-client-id",
72
+ "COMPLAI_AUTH0_AUDIENCE": "https://api.complai.com",
73
+ "COMPLAI_ORGANIZATION_ID": "org_xxxxx"
74
+ }
75
+ }
76
+ }
77
+ }
78
+ ```
79
+
80
+ ## Authentication Modes
81
+
82
+ ### User Authentication (Recommended)
83
+
84
+ No client secret required. Users authenticate via browser using their COMPLAI credentials.
85
+
86
+ 1. Configure without `COMPLAI_AUTH0_CLIENT_SECRET`:
87
+
88
+ ```json
89
+ {
90
+ "mcpServers": {
91
+ "complai": {
92
+ "command": "npx",
93
+ "args": ["@lindblad/complai-mcp"],
94
+ "env": {
95
+ "COMPLAI_API_URL": "https://api.complai.com",
96
+ "COMPLAI_AUTH0_DOMAIN": "lindcon.eu.auth0.com",
97
+ "COMPLAI_AUTH0_CLIENT_ID": "your-client-id",
98
+ "COMPLAI_AUTH0_AUDIENCE": "https://api.complai.com",
99
+ "COMPLAI_ORGANIZATION_ID": "org_xxxxx"
100
+ }
101
+ }
102
+ }
103
+ }
104
+ ```
105
+
106
+ 2. When you first use a COMPLAI tool, use `complai_login`:
107
+ - You'll get a URL and code
108
+ - Open the URL in your browser
109
+ - Enter the code and log in with your COMPLAI credentials
110
+ - Done! Your session is saved to `~/.complai/`
111
+
112
+ ### M2M Authentication (For Automation)
113
+
114
+ For scripts, CI/CD, or shared environments. Requires a client secret.
115
+
116
+ ```json
117
+ {
118
+ "mcpServers": {
119
+ "complai": {
120
+ "command": "npx",
121
+ "args": ["@lindblad/complai-mcp"],
122
+ "env": {
123
+ "COMPLAI_API_URL": "https://api.complai.com",
124
+ "COMPLAI_AUTH0_DOMAIN": "lindcon.eu.auth0.com",
125
+ "COMPLAI_AUTH0_CLIENT_ID": "your-m2m-client-id",
126
+ "COMPLAI_AUTH0_CLIENT_SECRET": "your-m2m-client-secret",
127
+ "COMPLAI_AUTH0_AUDIENCE": "https://api.complai.com",
128
+ "COMPLAI_ORGANIZATION_ID": "org_xxxxx"
129
+ }
130
+ }
131
+ }
132
+ }
133
+ ```
134
+
135
+ ### Mock Mode
136
+
137
+ For testing without any API connection:
138
+
139
+ ```json
140
+ {
141
+ "mcpServers": {
142
+ "complai": {
143
+ "command": "npx",
144
+ "args": ["@lindblad/complai-mcp"],
145
+ "env": {
146
+ "COMPLAI_MOCK_MODE": "true"
147
+ }
148
+ }
149
+ }
150
+ }
151
+ ```
152
+
153
+ ## Authentication Flow
154
+
155
+ ### First Time Setup (User Auth Mode)
156
+
157
+ When you start the server for the first time, it will prompt for authentication:
158
+
159
+ ```
160
+ COMPLAI MCP Server v0.1.0
161
+ ─────────────────────────
162
+ API: https://api.test.complai.com
163
+ Auth: User (Device Flow)
164
+
165
+ Authentication required. Starting device authorization flow...
166
+
167
+ ┌─────────────────────────────────────────────────────────────┐
168
+ │ Please complete authentication in your browser: │
169
+ │ │
170
+ │ 1. Open: https://complai-test.eu.auth0.com/activate │
171
+ │ 2. Enter: ABCD-EFGH │
172
+ │ │
173
+ │ Waiting for authentication... │
174
+ └─────────────────────────────────────────────────────────────┘
175
+
176
+ ✓ Authentication successful!
177
+
178
+ Starting server...
179
+ ✓ Server ready
180
+ ```
181
+
182
+ After logging in once, your session is saved to `~/.complai/` and you won't need to log in again.
183
+
184
+ ### Logging Out
185
+
186
+ To log out, delete the stored credentials:
187
+ ```bash
188
+ rm -rf ~/.complai/.credentials.enc
189
+ ```
190
+
191
+ ## Available Tools
192
+
193
+ ### `complai_list_organizations`
194
+
195
+ List all COMPLAI organizations the user has access to.
196
+
197
+ **Parameters:** None
198
+
199
+ **Response:**
200
+ ```json
201
+ {
202
+ "organizations": [
203
+ { "id": "org_xxx", "name": "Acme Corp" },
204
+ { "id": "org_yyy", "name": "Beta Inc" }
205
+ ],
206
+ "message": "User has access to 2 organizations. Ask which one to check."
207
+ }
208
+ ```
209
+
210
+ ### `complai_compliance_brief`
211
+
212
+ Get compliance status overview for a specific organization.
213
+
214
+ **Parameters:**
215
+ | Parameter | Type | Required | Description |
216
+ |-----------|------|----------|-------------|
217
+ | `organizationId` | string | Yes | The organization ID (from `complai_list_organizations`) |
218
+ | `workspaceId` | string | No | Filter results to a specific workspace |
219
+
220
+ **Response:**
221
+ ```json
222
+ {
223
+ "summary": {
224
+ "description": "Compliance overview as of 2026-01-15",
225
+ "dataRooms": 24,
226
+ "assets": 156,
227
+ "manufacturers": 42,
228
+ "totalTasks": 89,
229
+ "overdueActions": 7
230
+ },
231
+ "riskDistribution": [
232
+ { "level": "High", "count": 3, "percentage": 12.5 },
233
+ { "level": "Medium", "count": 8, "percentage": 33.3 },
234
+ { "level": "Low", "count": 13, "percentage": 54.2 }
235
+ ],
236
+ "taskStatus": {
237
+ "overdue": 12,
238
+ "dueThisWeek": 8,
239
+ "onTrack": 45,
240
+ "noDeadline": 24
241
+ },
242
+ "alerts": [
243
+ "7 corrective actions are past their deadline",
244
+ "12 tasks are overdue"
245
+ ]
246
+ }
247
+ ```
248
+
249
+ ## Development
250
+
251
+ ### Testing with MCP Inspector
252
+
253
+ ```bash
254
+ npm run inspector
255
+ ```
256
+
257
+ ### Project Structure
258
+
259
+ ```
260
+ complai-brief/
261
+ ├── src/
262
+ │ ├── index.ts # MCP server entry point
263
+ │ ├── types.ts # TypeScript interfaces
264
+ │ ├── tools/
265
+ │ │ └── compliance-brief.ts # Tool implementation
266
+ │ ├── auth/
267
+ │ │ ├── token-manager.ts # Unified token management
268
+ │ │ └── device-auth.ts # Device authorization flow
269
+ │ ├── api/
270
+ │ │ └── complai-client.ts # API client
271
+ │ └── config/
272
+ │ └── config-loader.ts # Configuration loading
273
+ ├── package.json
274
+ ├── tsconfig.json
275
+ └── README.md
276
+ ```
277
+
278
+ ## Error Handling
279
+
280
+ The server returns AI-friendly error messages:
281
+
282
+ | Error | Message |
283
+ |-------|---------|
284
+ | Authentication failed | "Authentication failed. Check your client credentials." |
285
+ | Network error | "Cannot reach COMPLAI API. Check your network connection." |
286
+ | Rate limited | "Rate limit exceeded. Try again in X seconds." |
287
+ | Permission denied | "You don't have access to this organization." |
288
+
289
+ ## Security
290
+
291
+ - **User auth mode**: Refresh tokens are stored encrypted in `~/.complai/` with AES-256-GCM
292
+ - **M2M mode**: Client secrets should be stored securely (environment variables recommended)
293
+ - Encryption keys are stored with restrictive permissions (600)
294
+ - Access tokens are cached in memory only (not persisted)
295
+ - All API calls use HTTPS
296
+ - MCP respects the same permissions as the COMPLAI web UI
297
+
298
+ ### Stored Files (User Auth Mode)
299
+
300
+ | File | Purpose |
301
+ |------|---------|
302
+ | `~/.complai/.credentials.enc` | Encrypted refresh token |
303
+ | `~/.complai/.key` | Encryption key (600 permissions) |
@@ -0,0 +1,46 @@
1
+ import { ComplaiConfig, DashboardOverviewResponse, UserProfile, AuditRoomsResponse } from '../types.js';
2
+ import { TokenManager } from '../auth/token-manager.js';
3
+ /**
4
+ * HTTP client for COMPLAI api-auth0 endpoints.
5
+ * Handles authentication, organization context, and error handling.
6
+ */
7
+ export declare class ComplaiClient {
8
+ private readonly tokenManager;
9
+ private readonly baseUrl;
10
+ private readonly defaultOrganizationId?;
11
+ constructor(config: ComplaiConfig, tokenManager: TokenManager);
12
+ /**
13
+ * Get the default organization ID if configured
14
+ */
15
+ getDefaultOrganizationId(): string | undefined;
16
+ /**
17
+ * Get current user profile including their organizations
18
+ */
19
+ getMe(): Promise<UserProfile>;
20
+ /**
21
+ * Get dashboard overview data for a specific organization
22
+ */
23
+ getDashboardOverview(organizationId: string, workspaceId?: string): Promise<DashboardOverviewResponse>;
24
+ /**
25
+ * Get audit rooms list with status overview
26
+ * Returns rooms with risk rating, engagement, task completion
27
+ */
28
+ getAuditRooms(organizationId: string, page?: number, pageSize?: number): Promise<AuditRoomsResponse>;
29
+ /**
30
+ * Make a GET request to the COMPLAI API
31
+ */
32
+ private get;
33
+ /**
34
+ * Make a POST request to the COMPLAI API
35
+ */
36
+ private post;
37
+ /**
38
+ * Make an authenticated request with retry on 401
39
+ */
40
+ private request;
41
+ /**
42
+ * Handle API errors with AI-friendly messages
43
+ */
44
+ private handleError;
45
+ }
46
+ //# sourceMappingURL=complai-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"complai-client.d.ts","sourceRoot":"","sources":["../../src/api/complai-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACxG,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAS;gBAEpC,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY;IAM7D;;OAEG;IACH,wBAAwB,IAAI,MAAM,GAAG,SAAS;IAI9C;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC;IAInC;;OAEG;IACG,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAQ5G;;;OAGG;IACG,aAAa,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,GAAE,MAAU,EAAE,QAAQ,GAAE,MAAW,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAKjH;;OAEG;YACW,GAAG;IAIjB;;OAEG;YACW,IAAI;IAIlB;;OAEG;YACW,OAAO;IA4CrB;;OAEG;YACW,WAAW;CAqB1B"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * HTTP client for COMPLAI api-auth0 endpoints.
3
+ * Handles authentication, organization context, and error handling.
4
+ */
5
+ export class ComplaiClient {
6
+ tokenManager;
7
+ baseUrl;
8
+ defaultOrganizationId;
9
+ constructor(config, tokenManager) {
10
+ this.tokenManager = tokenManager;
11
+ this.baseUrl = config.api.baseUrl.replace(/\/$/, ''); // Remove trailing slash
12
+ this.defaultOrganizationId = config.api.organizationId;
13
+ }
14
+ /**
15
+ * Get the default organization ID if configured
16
+ */
17
+ getDefaultOrganizationId() {
18
+ return this.defaultOrganizationId;
19
+ }
20
+ /**
21
+ * Get current user profile including their organizations
22
+ */
23
+ async getMe() {
24
+ return this.get('/api/v2/me');
25
+ }
26
+ /**
27
+ * Get dashboard overview data for a specific organization
28
+ */
29
+ async getDashboardOverview(organizationId, workspaceId) {
30
+ const filters = workspaceId
31
+ ? { items: [{ field: 'workspaceId', value: workspaceId }] }
32
+ : { items: [] };
33
+ return this.post('/api/v2/dashboards/charts/overview', { filters }, organizationId);
34
+ }
35
+ /**
36
+ * Get audit rooms list with status overview
37
+ * Returns rooms with risk rating, engagement, task completion
38
+ */
39
+ async getAuditRooms(organizationId, page = 1, pageSize = 20) {
40
+ const url = `/api/v2/audit-rooms?page=${page}&pageSize=${pageSize}&orderField=name&order=ASC`;
41
+ return this.get(url, organizationId);
42
+ }
43
+ /**
44
+ * Make a GET request to the COMPLAI API
45
+ */
46
+ async get(path, organizationId) {
47
+ return this.request('GET', path, undefined, organizationId);
48
+ }
49
+ /**
50
+ * Make a POST request to the COMPLAI API
51
+ */
52
+ async post(path, body, organizationId) {
53
+ return this.request('POST', path, body, organizationId);
54
+ }
55
+ /**
56
+ * Make an authenticated request with retry on 401
57
+ */
58
+ async request(method, path, body, organizationId) {
59
+ const makeRequest = async (token) => {
60
+ const url = `${this.baseUrl}${path}`;
61
+ const headers = {
62
+ 'Authorization': `Bearer ${token}`,
63
+ 'Content-Type': 'application/json',
64
+ };
65
+ // Add organization context header if specified
66
+ if (organizationId) {
67
+ headers['x-organization-id'] = organizationId;
68
+ }
69
+ const options = {
70
+ method,
71
+ headers,
72
+ };
73
+ if (body !== undefined) {
74
+ options.body = JSON.stringify(body);
75
+ }
76
+ return fetch(url, options);
77
+ };
78
+ // First attempt
79
+ let token = await this.tokenManager.getToken();
80
+ let response = await makeRequest(token);
81
+ // Retry once on 401 with fresh token
82
+ if (response.status === 401) {
83
+ this.tokenManager.invalidate();
84
+ token = await this.tokenManager.refreshToken();
85
+ response = await makeRequest(token);
86
+ }
87
+ // Handle errors
88
+ if (!response.ok) {
89
+ await this.handleError(response);
90
+ }
91
+ return (await response.json());
92
+ }
93
+ /**
94
+ * Handle API errors with AI-friendly messages
95
+ */
96
+ async handleError(response) {
97
+ const status = response.status;
98
+ const errorText = await response.text().catch(() => 'Unknown error');
99
+ console.error(`[DEBUG] API Error ${status}: ${errorText}`);
100
+ if (status === 401 || status === 403) {
101
+ throw new Error(`Access denied (${status}): ${errorText}`);
102
+ }
103
+ if (status === 429) {
104
+ const retryAfter = response.headers.get('Retry-After') || '60';
105
+ throw new Error(`Rate limit exceeded. Try again in ${retryAfter} seconds.`);
106
+ }
107
+ if (status >= 500) {
108
+ throw new Error('COMPLAI API is temporarily unavailable. Try again later.');
109
+ }
110
+ throw new Error(`API error (${status}): ${errorText}`);
111
+ }
112
+ }
113
+ //# sourceMappingURL=complai-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"complai-client.js","sourceRoot":"","sources":["../../src/api/complai-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Device Authorization Flow for Auth0
3
+ * Allows users to authenticate via browser without exposing client secrets
4
+ */
5
+ export interface DeviceAuthConfig {
6
+ domain: string;
7
+ clientId: string;
8
+ audience: string;
9
+ scope?: string;
10
+ }
11
+ export interface DeviceCodeResponse {
12
+ device_code: string;
13
+ user_code: string;
14
+ verification_uri: string;
15
+ verification_uri_complete: string;
16
+ expires_in: number;
17
+ interval: number;
18
+ }
19
+ export interface TokenResponse {
20
+ access_token: string;
21
+ refresh_token?: string;
22
+ token_type: string;
23
+ expires_in: number;
24
+ }
25
+ /**
26
+ * Device Authorization Manager
27
+ * Handles the device code flow and token storage
28
+ */
29
+ export declare class DeviceAuthManager {
30
+ private config;
31
+ private cachedAccessToken;
32
+ constructor(config: DeviceAuthConfig);
33
+ /**
34
+ * Get a valid access token, prompting for login if needed
35
+ */
36
+ getAccessToken(): Promise<string>;
37
+ /**
38
+ * Initiate device authorization flow
39
+ * Returns user instructions for completing authentication
40
+ */
41
+ initiateDeviceAuthorization(): Promise<{
42
+ userCode: string;
43
+ verificationUri: string;
44
+ verificationUriComplete: string;
45
+ expiresIn: number;
46
+ pollForToken: () => Promise<TokenResponse>;
47
+ }>;
48
+ /**
49
+ * Poll Auth0 for token after user completes authentication
50
+ */
51
+ private pollForToken;
52
+ /**
53
+ * Refresh the access token using a refresh token
54
+ */
55
+ private refreshAccessToken;
56
+ /**
57
+ * Cache access token in memory
58
+ */
59
+ private cacheToken;
60
+ /**
61
+ * Store refresh token encrypted on disk
62
+ */
63
+ private storeCredentials;
64
+ /**
65
+ * Load stored credentials from disk
66
+ */
67
+ private loadStoredCredentials;
68
+ /**
69
+ * Clear stored credentials (logout)
70
+ */
71
+ clearCredentials(): void;
72
+ /**
73
+ * Check if user is authenticated
74
+ */
75
+ isAuthenticated(): boolean;
76
+ /**
77
+ * Get or create encryption key
78
+ */
79
+ private getEncryptionKey;
80
+ /**
81
+ * Encrypt data using AES-256-GCM
82
+ */
83
+ private encrypt;
84
+ /**
85
+ * Decrypt data using AES-256-GCM
86
+ */
87
+ private decrypt;
88
+ private sleep;
89
+ }
90
+ /**
91
+ * Error thrown when authentication is required
92
+ */
93
+ export declare class AuthenticationRequiredError extends Error {
94
+ readonly domain: string;
95
+ readonly clientId: string;
96
+ constructor(message: string, domain: string, clientId: string);
97
+ }
98
+ //# sourceMappingURL=device-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-auth.d.ts","sourceRoot":"","sources":["../../src/auth/device-auth.ts"],"names":[],"mappings":"AAKA;;;GAGG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,yBAAyB,EAAE,MAAM,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAaD;;;GAGG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,iBAAiB,CAAqD;gBAElE,MAAM,EAAE,gBAAgB;IAOpC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAiCvC;;;OAGG;IACG,2BAA2B,IAAI,OAAO,CAAC;QAC3C,QAAQ,EAAE,MAAM,CAAC;QACjB,eAAe,EAAE,MAAM,CAAC;QACxB,uBAAuB,EAAE,MAAM,CAAC;QAChC,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;KAC5C,CAAC;IA2BF;;OAEG;YACW,YAAY;IAmD1B;;OAEG;YACW,kBAAkB;IAmBhC;;OAEG;IACH,OAAO,CAAC,UAAU;IAOlB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAkBxB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA0B7B;;OAEG;IACH,gBAAgB,IAAI,IAAI;IAOxB;;OAEG;IACH,eAAe,IAAI,OAAO;IAO1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAexB;;OAEG;IACH,OAAO,CAAC,OAAO;IAaf;;OAEG;IACH,OAAO,CAAC,OAAO;IAqBf,OAAO,CAAC,KAAK;CAGd;AAED;;GAEG;AACH,qBAAa,2BAA4B,SAAQ,KAAK;aAGlC,MAAM,EAAE,MAAM;aACd,QAAQ,EAAE,MAAM;gBAFhC,OAAO,EAAE,MAAM,EACC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM;CAKnC"}