@1mcp/agent 0.22.3 → 0.23.1
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/build/commands/mcp/tokens.d.ts +6 -0
- package/build/commands/mcp/tokens.d.ts.map +1 -1
- package/build/commands/mcp/tokens.js +179 -66
- package/build/commands/mcp/tokens.js.map +1 -1
- package/build/commands/preset/interactive.js +1 -2
- package/build/commands/preset/interactive.js.map +1 -1
- package/build/commands/preset/list.js +3 -6
- package/build/commands/preset/list.js.map +1 -1
- package/build/commands/preset/show.js +0 -1
- package/build/commands/preset/show.js.map +1 -1
- package/build/commands/serve/index.d.ts +6 -0
- package/build/commands/serve/index.d.ts.map +1 -1
- package/build/commands/serve/index.js +12 -0
- package/build/commands/serve/index.js.map +1 -1
- package/build/commands/serve/serve.d.ts +1 -0
- package/build/commands/serve/serve.d.ts.map +1 -1
- package/build/commands/serve/serve.js +85 -4
- package/build/commands/serve/serve.js.map +1 -1
- package/build/constants.d.ts +6 -1
- package/build/constants.d.ts.map +1 -1
- package/build/constants.js +9 -1
- package/build/constants.js.map +1 -1
- package/build/core/client/clientManager.d.ts +13 -0
- package/build/core/client/clientManager.d.ts.map +1 -1
- package/build/core/client/clientManager.js +48 -0
- package/build/core/client/clientManager.js.map +1 -1
- package/build/core/filtering/filteringService.d.ts +85 -0
- package/build/core/filtering/filteringService.d.ts.map +1 -0
- package/build/core/filtering/filteringService.js +253 -0
- package/build/core/filtering/filteringService.js.map +1 -0
- package/build/core/instructions/instructionAggregator.d.ts +107 -0
- package/build/core/instructions/instructionAggregator.d.ts.map +1 -0
- package/build/core/instructions/instructionAggregator.js +277 -0
- package/build/core/instructions/instructionAggregator.js.map +1 -0
- package/build/core/instructions/templateTypes.d.ts +79 -0
- package/build/core/instructions/templateTypes.d.ts.map +1 -0
- package/build/core/instructions/templateTypes.js +91 -0
- package/build/core/instructions/templateTypes.js.map +1 -0
- package/build/core/instructions/templateValidator.d.ts +82 -0
- package/build/core/instructions/templateValidator.d.ts.map +1 -0
- package/build/core/instructions/templateValidator.js +244 -0
- package/build/core/instructions/templateValidator.js.map +1 -0
- package/build/core/server/serverManager.d.ts +11 -0
- package/build/core/server/serverManager.d.ts.map +1 -1
- package/build/core/server/serverManager.js +38 -1
- package/build/core/server/serverManager.js.map +1 -1
- package/build/core/types/client.d.ts +2 -0
- package/build/core/types/client.d.ts.map +1 -1
- package/build/core/types/server.d.ts +2 -1
- package/build/core/types/server.d.ts.map +1 -1
- package/build/core/types/server.js.map +1 -1
- package/build/handlers/requestHandlers.d.ts.map +1 -1
- package/build/handlers/requestHandlers.js +14 -42
- package/build/handlers/requestHandlers.js.map +1 -1
- package/build/server.d.ts +3 -0
- package/build/server.d.ts.map +1 -1
- package/build/server.js +13 -0
- package/build/server.js.map +1 -1
- package/build/transport/http/routes/sseRoutes.d.ts +1 -1
- package/build/transport/http/routes/sseRoutes.d.ts.map +1 -1
- package/build/transport/http/routes/sseRoutes.js +2 -1
- package/build/transport/http/routes/sseRoutes.js.map +1 -1
- package/build/transport/http/routes/streamableHttpRoutes.d.ts +1 -1
- package/build/transport/http/routes/streamableHttpRoutes.d.ts.map +1 -1
- package/build/transport/http/routes/streamableHttpRoutes.js +2 -1
- package/build/transport/http/routes/streamableHttpRoutes.js.map +1 -1
- package/build/transport/http/server.d.ts +3 -1
- package/build/transport/http/server.d.ts.map +1 -1
- package/build/transport/http/server.js +6 -3
- package/build/transport/http/server.js.map +1 -1
- package/build/utils/presetManager.d.ts +0 -4
- package/build/utils/presetManager.d.ts.map +1 -1
- package/build/utils/presetManager.js +0 -16
- package/build/utils/presetManager.js.map +1 -1
- package/build/utils/presetTypes.d.ts +0 -3
- package/build/utils/presetTypes.d.ts.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { ClientStatus } from '../types/client.js';
|
|
2
|
+
import { TagQueryParser } from '../../utils/tagQueryParser.js';
|
|
3
|
+
import { TagQueryEvaluator } from '../../utils/tagQueryEvaluator.js';
|
|
4
|
+
import { normalizeTag } from '../../utils/sanitization.js';
|
|
5
|
+
import logger from '../../logger/logger.js';
|
|
6
|
+
/**
|
|
7
|
+
* Unified filtering service that consolidates all filtering logic across the application.
|
|
8
|
+
* This service provides a single source of truth for filtering MCP server connections
|
|
9
|
+
* based on various criteria including tags, capabilities, and advanced expressions.
|
|
10
|
+
*/
|
|
11
|
+
export class FilteringService {
|
|
12
|
+
/**
|
|
13
|
+
* Get filtered connections based on inbound connection configuration
|
|
14
|
+
* This is the main entry point for filtering and should be used by most components
|
|
15
|
+
*
|
|
16
|
+
* @param connections Map of outbound connections to filter
|
|
17
|
+
* @param config Inbound connection configuration containing filter criteria
|
|
18
|
+
* @returns Filtered map of connections
|
|
19
|
+
*/
|
|
20
|
+
static getFilteredConnections(connections, config) {
|
|
21
|
+
logger.debug('FilteringService: Filtering connections', {
|
|
22
|
+
totalConnections: connections.size,
|
|
23
|
+
filterMode: config.tagFilterMode,
|
|
24
|
+
tags: config.tags,
|
|
25
|
+
hasTagExpression: !!config.tagExpression,
|
|
26
|
+
hasTagQuery: !!config.tagQuery,
|
|
27
|
+
});
|
|
28
|
+
// Only include connected clients in filtering
|
|
29
|
+
const connectedClients = new Map();
|
|
30
|
+
for (const [name, connection] of connections) {
|
|
31
|
+
if (connection.status === ClientStatus.Connected) {
|
|
32
|
+
connectedClients.set(name, connection);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
logger.debug('FilteringService: Connected clients', {
|
|
36
|
+
connectedCount: connectedClients.size,
|
|
37
|
+
connectedNames: Array.from(connectedClients.keys()),
|
|
38
|
+
});
|
|
39
|
+
if (!config.tagFilterMode || config.tagFilterMode === 'none') {
|
|
40
|
+
logger.debug('FilteringService: No filtering specified, returning all connected clients');
|
|
41
|
+
return connectedClients;
|
|
42
|
+
}
|
|
43
|
+
const filter = this.createFilter(config);
|
|
44
|
+
const filteredConnections = filter(connectedClients);
|
|
45
|
+
logger.debug('FilteringService: Filtering completed', {
|
|
46
|
+
filteredCount: filteredConnections.size,
|
|
47
|
+
filteredNames: Array.from(filteredConnections.keys()),
|
|
48
|
+
});
|
|
49
|
+
return filteredConnections;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Create a filter function based on inbound connection configuration
|
|
53
|
+
*
|
|
54
|
+
* @param config Inbound connection configuration
|
|
55
|
+
* @returns Filter function that can be applied to connections
|
|
56
|
+
*/
|
|
57
|
+
static createFilter(config) {
|
|
58
|
+
if (config.tagFilterMode === 'preset' && config.tagQuery) {
|
|
59
|
+
return this.byTagQuery(config.tagQuery);
|
|
60
|
+
}
|
|
61
|
+
else if (config.tagFilterMode === 'advanced' && config.tagExpression) {
|
|
62
|
+
return this.byTagExpression(config.tagExpression);
|
|
63
|
+
}
|
|
64
|
+
else if (config.tagFilterMode === 'simple-or' || config.tags) {
|
|
65
|
+
return this.byTags(config.tags);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// No filtering - return function that passes all clients through
|
|
69
|
+
return this.byTags(undefined);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Filter connections by tags using OR logic
|
|
74
|
+
* If no tags are provided, all connections are returned
|
|
75
|
+
*
|
|
76
|
+
* @param tags Array of tags to filter by
|
|
77
|
+
* @returns Filter function
|
|
78
|
+
*/
|
|
79
|
+
static byTags(tags) {
|
|
80
|
+
return (connections) => {
|
|
81
|
+
logger.debug(`FilteringService.byTags: Filtering for tags: ${tags ? tags.join(', ') : 'none'}`);
|
|
82
|
+
if (!tags || tags.length === 0) {
|
|
83
|
+
logger.debug('FilteringService.byTags: No tags specified, returning all connections');
|
|
84
|
+
return connections;
|
|
85
|
+
}
|
|
86
|
+
// Normalize the filter tags for consistent comparison
|
|
87
|
+
const normalizedFilterTags = tags.map((tag) => normalizeTag(tag));
|
|
88
|
+
return Array.from(connections.entries()).reduce((filtered, [name, connection]) => {
|
|
89
|
+
const clientTags = connection.transport.tags || [];
|
|
90
|
+
// Normalize client tags for comparison
|
|
91
|
+
const normalizedClientTags = clientTags.map((tag) => normalizeTag(tag));
|
|
92
|
+
const hasMatchingTags = normalizedClientTags.some((clientTag) => normalizedFilterTags.includes(clientTag));
|
|
93
|
+
logger.debug(`FilteringService.byTags: Connection ${name}`, {
|
|
94
|
+
clientTags,
|
|
95
|
+
normalizedClientTags,
|
|
96
|
+
requiredTags: tags,
|
|
97
|
+
normalizedRequiredTags: normalizedFilterTags,
|
|
98
|
+
hasMatchingTags,
|
|
99
|
+
});
|
|
100
|
+
if (hasMatchingTags) {
|
|
101
|
+
filtered.set(name, connection);
|
|
102
|
+
}
|
|
103
|
+
return filtered;
|
|
104
|
+
}, new Map());
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Filter connections by advanced tag expression
|
|
109
|
+
*
|
|
110
|
+
* @param expression Parsed tag expression to evaluate
|
|
111
|
+
* @returns Filter function
|
|
112
|
+
*/
|
|
113
|
+
static byTagExpression(expression) {
|
|
114
|
+
return (connections) => {
|
|
115
|
+
logger.debug(`FilteringService.byTagExpression: Filtering with expression: ${TagQueryParser.expressionToString(expression)}`);
|
|
116
|
+
return Array.from(connections.entries()).reduce((filtered, [name, connection]) => {
|
|
117
|
+
const clientTags = connection.transport.tags || [];
|
|
118
|
+
const matches = TagQueryParser.evaluate(expression, clientTags);
|
|
119
|
+
logger.debug(`FilteringService.byTagExpression: Connection ${name}`, {
|
|
120
|
+
clientTags,
|
|
121
|
+
expression: TagQueryParser.expressionToString(expression),
|
|
122
|
+
matches,
|
|
123
|
+
});
|
|
124
|
+
if (matches) {
|
|
125
|
+
filtered.set(name, connection);
|
|
126
|
+
}
|
|
127
|
+
return filtered;
|
|
128
|
+
}, new Map());
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Filter connections by MongoDB-style tag query
|
|
133
|
+
*
|
|
134
|
+
* @param query Tag query to evaluate
|
|
135
|
+
* @returns Filter function
|
|
136
|
+
*/
|
|
137
|
+
static byTagQuery(query) {
|
|
138
|
+
return (connections) => {
|
|
139
|
+
logger.debug('FilteringService.byTagQuery: Filtering with tag query', { query });
|
|
140
|
+
const filtered = new Map();
|
|
141
|
+
for (const [name, connection] of connections.entries()) {
|
|
142
|
+
if (connection.status !== ClientStatus.Connected) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const clientTags = connection.transport.tags || [];
|
|
146
|
+
try {
|
|
147
|
+
if (TagQueryEvaluator.evaluate(query, clientTags)) {
|
|
148
|
+
filtered.set(name, connection);
|
|
149
|
+
logger.debug(`FilteringService.byTagQuery: Connection ${name} matches query`, {
|
|
150
|
+
clientTags,
|
|
151
|
+
query,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
logger.warn(`FilteringService.byTagQuery: Failed to evaluate query for connection ${name}`, {
|
|
157
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
158
|
+
clientTags,
|
|
159
|
+
query,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return filtered;
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Filter connections by server capabilities
|
|
168
|
+
*
|
|
169
|
+
* @param requiredCapabilities Capabilities that must be present
|
|
170
|
+
* @returns Filter function
|
|
171
|
+
*/
|
|
172
|
+
static byCapabilities(requiredCapabilities) {
|
|
173
|
+
return (connections) => {
|
|
174
|
+
const requiredCaps = Object.keys(requiredCapabilities);
|
|
175
|
+
logger.debug(`FilteringService.byCapabilities: Filtering for capabilities: ${requiredCaps.join(', ')}`);
|
|
176
|
+
return Array.from(connections.entries()).reduce((filtered, [name, connection]) => {
|
|
177
|
+
const clientCaps = connection.capabilities ? Object.keys(connection.capabilities) : [];
|
|
178
|
+
const hasCapabilities = requiredCaps.every((cap) => connection.capabilities && cap in connection.capabilities);
|
|
179
|
+
logger.debug(`FilteringService.byCapabilities: Connection ${name}`, {
|
|
180
|
+
clientCapabilities: clientCaps,
|
|
181
|
+
requiredCapabilities: requiredCaps,
|
|
182
|
+
hasCapabilities,
|
|
183
|
+
clientCapabilitiesObject: connection.capabilities,
|
|
184
|
+
});
|
|
185
|
+
if (hasCapabilities) {
|
|
186
|
+
filtered.set(name, connection);
|
|
187
|
+
}
|
|
188
|
+
return filtered;
|
|
189
|
+
}, new Map());
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Combine multiple filters using AND logic
|
|
194
|
+
* All filters must pass for a connection to be included
|
|
195
|
+
*
|
|
196
|
+
* @param filters Array of filter functions to combine
|
|
197
|
+
* @returns Combined filter function
|
|
198
|
+
*/
|
|
199
|
+
static combineFilters(...filters) {
|
|
200
|
+
return (connections) => {
|
|
201
|
+
logger.debug(`FilteringService.combineFilters: Starting with ${connections.size} connections`, {
|
|
202
|
+
connectionNames: Array.from(connections.keys()),
|
|
203
|
+
filterCount: filters.length,
|
|
204
|
+
});
|
|
205
|
+
const result = filters.reduce((filteredConnections, filter, index) => {
|
|
206
|
+
const beforeCount = filteredConnections.size;
|
|
207
|
+
const afterFiltering = filter(filteredConnections);
|
|
208
|
+
const afterCount = afterFiltering.size;
|
|
209
|
+
logger.debug(`FilteringService.combineFilters: Filter ${index} reduced connections from ${beforeCount} to ${afterCount}`, {
|
|
210
|
+
beforeNames: Array.from(filteredConnections.keys()),
|
|
211
|
+
afterNames: Array.from(afterFiltering.keys()),
|
|
212
|
+
});
|
|
213
|
+
return afterFiltering;
|
|
214
|
+
}, connections);
|
|
215
|
+
logger.debug(`FilteringService.combineFilters: Final result has ${result.size} connections`, {
|
|
216
|
+
finalNames: Array.from(result.keys()),
|
|
217
|
+
});
|
|
218
|
+
return result;
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Get a summary of filtering results for logging and debugging
|
|
223
|
+
*
|
|
224
|
+
* @param originalConnections Original connection map before filtering
|
|
225
|
+
* @param filteredConnections Filtered connection map after filtering
|
|
226
|
+
* @param config Filter configuration used
|
|
227
|
+
* @returns Summary object with filtering statistics
|
|
228
|
+
*/
|
|
229
|
+
static getFilteringSummary(originalConnections, filteredConnections, config) {
|
|
230
|
+
const originalNames = Array.from(originalConnections.keys());
|
|
231
|
+
const filteredNames = Array.from(filteredConnections.keys());
|
|
232
|
+
const removedNames = originalNames.filter((name) => !filteredNames.includes(name));
|
|
233
|
+
let filterType = 'none';
|
|
234
|
+
if (config.tagFilterMode === 'preset') {
|
|
235
|
+
filterType = 'preset';
|
|
236
|
+
}
|
|
237
|
+
else if (config.tagFilterMode === 'advanced') {
|
|
238
|
+
filterType = 'advanced';
|
|
239
|
+
}
|
|
240
|
+
else if (config.tagFilterMode === 'simple-or' || config.tags) {
|
|
241
|
+
filterType = 'simple-or';
|
|
242
|
+
}
|
|
243
|
+
return {
|
|
244
|
+
original: originalConnections.size,
|
|
245
|
+
filtered: filteredConnections.size,
|
|
246
|
+
removed: removedNames.length,
|
|
247
|
+
filterType,
|
|
248
|
+
filteredNames: filteredNames.sort(),
|
|
249
|
+
removedNames: removedNames.sort(),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=filteringService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filteringService.js","sourceRoot":"","sources":["../../../src/core/filtering/filteringService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { OutboundConnections, InboundConnectionConfig } from '../types/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Events emitted by InstructionAggregator
|
|
5
|
+
*/
|
|
6
|
+
export interface InstructionAggregatorEvents {
|
|
7
|
+
'instructions-changed': () => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Aggregates instructions from multiple MCP servers into a single instruction string.
|
|
11
|
+
* Provides both simple concatenation and filtered instructions with educational templates.
|
|
12
|
+
* The aggregator acts as an educational prompt to help LLMs understand 1MCP better.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const aggregator = new InstructionAggregator();
|
|
17
|
+
* aggregator.on('instructions-changed', () => {
|
|
18
|
+
* // Server instructions have changed
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* // When server comes online
|
|
22
|
+
* aggregator.setInstructions('server1', 'Server 1 instructions');
|
|
23
|
+
*
|
|
24
|
+
* // Get filtered instructions for a client
|
|
25
|
+
* const filtered = aggregator.getFilteredInstructions(config, connections);
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare class InstructionAggregator extends EventEmitter {
|
|
29
|
+
private serverInstructions;
|
|
30
|
+
private isInitialized;
|
|
31
|
+
constructor();
|
|
32
|
+
/**
|
|
33
|
+
* Set or update instructions for a specific server
|
|
34
|
+
* @param serverName The name of the server
|
|
35
|
+
* @param instructions The instruction string from the server, or undefined to remove
|
|
36
|
+
*/
|
|
37
|
+
setInstructions(serverName: string, instructions: string | undefined): void;
|
|
38
|
+
/**
|
|
39
|
+
* Remove instructions for a specific server
|
|
40
|
+
* @param serverName The name of the server to remove
|
|
41
|
+
*/
|
|
42
|
+
removeServer(serverName: string): void;
|
|
43
|
+
/**
|
|
44
|
+
* Get filtered instructions for a specific client based on their configuration
|
|
45
|
+
* This is the main method that should be used by server connections
|
|
46
|
+
*
|
|
47
|
+
* @param config Client's inbound connection configuration
|
|
48
|
+
* @param connections All available outbound connections
|
|
49
|
+
* @returns Formatted instruction string with educational template or custom template
|
|
50
|
+
*/
|
|
51
|
+
getFilteredInstructions(config: InboundConnectionConfig, connections: OutboundConnections): string;
|
|
52
|
+
/**
|
|
53
|
+
* Get the number of servers that have provided instructions
|
|
54
|
+
* @returns The count of servers with instructions
|
|
55
|
+
*/
|
|
56
|
+
getServerCount(): number;
|
|
57
|
+
/**
|
|
58
|
+
* Get a list of server names that have provided instructions
|
|
59
|
+
* @returns Array of server names
|
|
60
|
+
*/
|
|
61
|
+
getServerNames(): string[];
|
|
62
|
+
/**
|
|
63
|
+
* Check if a specific server has instructions
|
|
64
|
+
* @param serverName The server name to check
|
|
65
|
+
* @returns True if the server has instructions
|
|
66
|
+
*/
|
|
67
|
+
hasInstructions(serverName: string): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Get instructions for a specific server
|
|
70
|
+
* @param serverName The server name
|
|
71
|
+
* @returns The instructions for the server, or undefined if not found
|
|
72
|
+
*/
|
|
73
|
+
getServerInstructions(serverName: string): string | undefined;
|
|
74
|
+
/**
|
|
75
|
+
* Clear all instructions (useful for testing)
|
|
76
|
+
*/
|
|
77
|
+
clear(): void;
|
|
78
|
+
/**
|
|
79
|
+
* Get filter context description for the template
|
|
80
|
+
*/
|
|
81
|
+
private getFilterContext;
|
|
82
|
+
/**
|
|
83
|
+
* Get a summary of current instruction state for logging
|
|
84
|
+
*/
|
|
85
|
+
getSummary(): string;
|
|
86
|
+
/**
|
|
87
|
+
* Render a Handlebars template with template variables
|
|
88
|
+
* @param template Template string (custom or default)
|
|
89
|
+
* @param filteredConnections Filtered server connections
|
|
90
|
+
* @param config Client configuration
|
|
91
|
+
* @returns Rendered template string
|
|
92
|
+
*/
|
|
93
|
+
private renderTemplate;
|
|
94
|
+
/**
|
|
95
|
+
* Generate template variables for rendering
|
|
96
|
+
* @param filteredConnections Filtered server connections
|
|
97
|
+
* @param config Client configuration
|
|
98
|
+
* @returns Template variables object
|
|
99
|
+
*/
|
|
100
|
+
private generateTemplateVariables;
|
|
101
|
+
/**
|
|
102
|
+
* Cleanup method to remove all event listeners
|
|
103
|
+
* Should be called when the aggregator is no longer needed
|
|
104
|
+
*/
|
|
105
|
+
cleanup(): void;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=instructionAggregator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructionAggregator.d.ts","sourceRoot":"","sources":["../../../src/core/instructions/instructionAggregator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAItC,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAQjF;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,sBAAsB,EAAE,MAAM,IAAI,CAAC;CACpC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,qBAAsB,SAAQ,YAAY;IACrD,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,aAAa,CAAkB;;IAOvC;;;;OAIG;IACI,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAuBlF;;;OAGG;IACI,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAU7C;;;;;;;OAOG;IACI,uBAAuB,CAAC,MAAM,EAAE,uBAAuB,EAAE,WAAW,EAAE,mBAAmB,GAAG,MAAM;IAsCzG;;;OAGG;IACI,cAAc,IAAI,MAAM;IAI/B;;;OAGG;IACI,cAAc,IAAI,MAAM,EAAE;IAIjC;;;;OAIG;IACI,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAInD;;;;OAIG;IACI,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIpE;;OAEG;IACI,KAAK,IAAI,IAAI;IAUpB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAoBxB;;OAEG;IACI,UAAU,IAAI,MAAM;IAM3B;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAoCtB;;;;;OAKG;IACH,OAAO,CAAC,yBAAyB;IA2DjC;;;OAGG;IACI,OAAO,IAAI,IAAI;CAcvB"}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import Handlebars from 'handlebars';
|
|
3
|
+
import logger from '../../logger/logger.js';
|
|
4
|
+
import { FilteringService } from '../filtering/filteringService.js';
|
|
5
|
+
import { DEFAULT_TEMPLATE_CONFIG, DEFAULT_INSTRUCTION_TEMPLATE, } from './templateTypes.js';
|
|
6
|
+
/**
|
|
7
|
+
* Aggregates instructions from multiple MCP servers into a single instruction string.
|
|
8
|
+
* Provides both simple concatenation and filtered instructions with educational templates.
|
|
9
|
+
* The aggregator acts as an educational prompt to help LLMs understand 1MCP better.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const aggregator = new InstructionAggregator();
|
|
14
|
+
* aggregator.on('instructions-changed', () => {
|
|
15
|
+
* // Server instructions have changed
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* // When server comes online
|
|
19
|
+
* aggregator.setInstructions('server1', 'Server 1 instructions');
|
|
20
|
+
*
|
|
21
|
+
* // Get filtered instructions for a client
|
|
22
|
+
* const filtered = aggregator.getFilteredInstructions(config, connections);
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export class InstructionAggregator extends EventEmitter {
|
|
26
|
+
serverInstructions = new Map();
|
|
27
|
+
isInitialized = false;
|
|
28
|
+
constructor() {
|
|
29
|
+
super();
|
|
30
|
+
this.setMaxListeners(50);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Set or update instructions for a specific server
|
|
34
|
+
* @param serverName The name of the server
|
|
35
|
+
* @param instructions The instruction string from the server, or undefined to remove
|
|
36
|
+
*/
|
|
37
|
+
setInstructions(serverName, instructions) {
|
|
38
|
+
const previousInstructions = this.serverInstructions.get(serverName);
|
|
39
|
+
const hasChanges = previousInstructions !== instructions;
|
|
40
|
+
if (instructions?.trim()) {
|
|
41
|
+
this.serverInstructions.set(serverName, instructions.trim());
|
|
42
|
+
logger.debug(`Updated instructions for server: ${serverName}`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
this.serverInstructions.delete(serverName);
|
|
46
|
+
logger.debug(`Removed instructions for server: ${serverName}`);
|
|
47
|
+
}
|
|
48
|
+
if (!this.isInitialized) {
|
|
49
|
+
this.isInitialized = true;
|
|
50
|
+
logger.debug('InstructionAggregator initialized');
|
|
51
|
+
}
|
|
52
|
+
if (hasChanges) {
|
|
53
|
+
logger.info(`Instructions changed. Total servers with instructions: ${this.serverInstructions.size}`);
|
|
54
|
+
this.emit('instructions-changed');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Remove instructions for a specific server
|
|
59
|
+
* @param serverName The name of the server to remove
|
|
60
|
+
*/
|
|
61
|
+
removeServer(serverName) {
|
|
62
|
+
const hadInstructions = this.serverInstructions.has(serverName);
|
|
63
|
+
this.serverInstructions.delete(serverName);
|
|
64
|
+
if (hadInstructions) {
|
|
65
|
+
logger.info(`Removed server instructions: ${serverName}. Remaining servers: ${this.serverInstructions.size}`);
|
|
66
|
+
this.emit('instructions-changed');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get filtered instructions for a specific client based on their configuration
|
|
71
|
+
* This is the main method that should be used by server connections
|
|
72
|
+
*
|
|
73
|
+
* @param config Client's inbound connection configuration
|
|
74
|
+
* @param connections All available outbound connections
|
|
75
|
+
* @returns Formatted instruction string with educational template or custom template
|
|
76
|
+
*/
|
|
77
|
+
getFilteredInstructions(config, connections) {
|
|
78
|
+
logger.debug('InstructionAggregator: Getting filtered instructions', {
|
|
79
|
+
filterMode: config.tagFilterMode,
|
|
80
|
+
totalConnections: connections.size,
|
|
81
|
+
totalInstructions: this.serverInstructions.size,
|
|
82
|
+
hasCustomTemplate: !!config.customTemplate,
|
|
83
|
+
});
|
|
84
|
+
// Filter connections based on client configuration
|
|
85
|
+
const filteredConnections = FilteringService.getFilteredConnections(connections, config);
|
|
86
|
+
// Get filtering summary for logging
|
|
87
|
+
const filteringSummary = FilteringService.getFilteringSummary(connections, filteredConnections, config);
|
|
88
|
+
logger.info('InstructionAggregator: Filtering applied', filteringSummary);
|
|
89
|
+
// Try custom template first, fall back to default if it fails
|
|
90
|
+
if (config.customTemplate) {
|
|
91
|
+
logger.info('InstructionAggregator: Trying custom template', { templateLength: config.customTemplate.length });
|
|
92
|
+
try {
|
|
93
|
+
return this.renderTemplate(config.customTemplate, filteredConnections, config);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
97
|
+
// Log detailed error for debugging
|
|
98
|
+
logger.error('InstructionAggregator: Custom template failed, falling back to default template', {
|
|
99
|
+
error: errorMessage,
|
|
100
|
+
templateLength: config.customTemplate.length,
|
|
101
|
+
});
|
|
102
|
+
// Fall back to default template
|
|
103
|
+
return this.renderTemplate(DEFAULT_INSTRUCTION_TEMPLATE, filteredConnections, config);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// Use default template directly
|
|
108
|
+
return this.renderTemplate(DEFAULT_INSTRUCTION_TEMPLATE, filteredConnections, config);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Get the number of servers that have provided instructions
|
|
113
|
+
* @returns The count of servers with instructions
|
|
114
|
+
*/
|
|
115
|
+
getServerCount() {
|
|
116
|
+
return this.serverInstructions.size;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Get a list of server names that have provided instructions
|
|
120
|
+
* @returns Array of server names
|
|
121
|
+
*/
|
|
122
|
+
getServerNames() {
|
|
123
|
+
return Array.from(this.serverInstructions.keys()).sort();
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Check if a specific server has instructions
|
|
127
|
+
* @param serverName The server name to check
|
|
128
|
+
* @returns True if the server has instructions
|
|
129
|
+
*/
|
|
130
|
+
hasInstructions(serverName) {
|
|
131
|
+
return this.serverInstructions.has(serverName);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get instructions for a specific server
|
|
135
|
+
* @param serverName The server name
|
|
136
|
+
* @returns The instructions for the server, or undefined if not found
|
|
137
|
+
*/
|
|
138
|
+
getServerInstructions(serverName) {
|
|
139
|
+
return this.serverInstructions.get(serverName);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Clear all instructions (useful for testing)
|
|
143
|
+
*/
|
|
144
|
+
clear() {
|
|
145
|
+
const hadInstructions = this.serverInstructions.size > 0;
|
|
146
|
+
this.serverInstructions.clear();
|
|
147
|
+
if (hadInstructions) {
|
|
148
|
+
logger.debug('Cleared all server instructions');
|
|
149
|
+
this.emit('instructions-changed');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Get filter context description for the template
|
|
154
|
+
*/
|
|
155
|
+
getFilterContext(config) {
|
|
156
|
+
if (!config.tagFilterMode || config.tagFilterMode === 'none') {
|
|
157
|
+
return '';
|
|
158
|
+
}
|
|
159
|
+
if (config.tagFilterMode === 'simple-or' && config.tags?.length) {
|
|
160
|
+
return ` (filtered by tags: ${config.tags.join(', ')})`;
|
|
161
|
+
}
|
|
162
|
+
if (config.tagFilterMode === 'advanced' && config.tagExpression) {
|
|
163
|
+
return ' (filtered by advanced expression)';
|
|
164
|
+
}
|
|
165
|
+
if (config.tagFilterMode === 'preset') {
|
|
166
|
+
return ' (filtered by preset)';
|
|
167
|
+
}
|
|
168
|
+
return ' (filtered)';
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Get a summary of current instruction state for logging
|
|
172
|
+
*/
|
|
173
|
+
getSummary() {
|
|
174
|
+
const serverCount = this.serverInstructions.size;
|
|
175
|
+
const serverNames = this.getServerNames();
|
|
176
|
+
return `${serverCount} servers with instructions: ${serverNames.join(', ')}`;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Render a Handlebars template with template variables
|
|
180
|
+
* @param template Template string (custom or default)
|
|
181
|
+
* @param filteredConnections Filtered server connections
|
|
182
|
+
* @param config Client configuration
|
|
183
|
+
* @returns Rendered template string
|
|
184
|
+
*/
|
|
185
|
+
renderTemplate(template, filteredConnections, config) {
|
|
186
|
+
// Validate template size before processing
|
|
187
|
+
// Priority: config > default
|
|
188
|
+
const templateSizeLimit = config.templateSizeLimit || DEFAULT_TEMPLATE_CONFIG.templateSizeLimit;
|
|
189
|
+
if (template.length > templateSizeLimit) {
|
|
190
|
+
const sizeMB = (template.length / 1024 / 1024).toFixed(1);
|
|
191
|
+
const limitMB = (templateSizeLimit / 1024 / 1024).toFixed(1);
|
|
192
|
+
throw new Error(`Template too large: ${sizeMB}MB (max ${limitMB}MB). ` +
|
|
193
|
+
'Consider splitting into smaller files or removing unnecessary content. ' +
|
|
194
|
+
'Large templates can cause memory issues and slow performance.');
|
|
195
|
+
}
|
|
196
|
+
// Compile template directly
|
|
197
|
+
const compiledTemplate = Handlebars.compile(template, { noEscape: true });
|
|
198
|
+
// Generate template variables
|
|
199
|
+
const variables = this.generateTemplateVariables(filteredConnections, config);
|
|
200
|
+
// Render template
|
|
201
|
+
const rendered = compiledTemplate(variables);
|
|
202
|
+
logger.debug('InstructionAggregator: Template rendered successfully', {
|
|
203
|
+
templateLength: template.length,
|
|
204
|
+
variableCount: Object.keys(variables).length,
|
|
205
|
+
renderedLength: rendered.length,
|
|
206
|
+
});
|
|
207
|
+
return rendered;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Generate template variables for rendering
|
|
211
|
+
* @param filteredConnections Filtered server connections
|
|
212
|
+
* @param config Client configuration
|
|
213
|
+
* @returns Template variables object
|
|
214
|
+
*/
|
|
215
|
+
generateTemplateVariables(filteredConnections, config) {
|
|
216
|
+
// Get server data for both arrays and individual server objects
|
|
217
|
+
const availableServers = [];
|
|
218
|
+
const serverInstructionSections = [];
|
|
219
|
+
const servers = [];
|
|
220
|
+
// Sort filtered connections by name for consistent output
|
|
221
|
+
const sortedConnections = Array.from(filteredConnections.entries()).sort(([a], [b]) => a.localeCompare(b));
|
|
222
|
+
for (const [serverName, _connection] of sortedConnections) {
|
|
223
|
+
const serverInstructions = this.serverInstructions.get(serverName);
|
|
224
|
+
if (serverInstructions?.trim()) {
|
|
225
|
+
availableServers.push(serverName);
|
|
226
|
+
serverInstructionSections.push(`<${serverName}>\n${serverInstructions.trim()}\n</${serverName}>`);
|
|
227
|
+
// Add individual server data for iteration
|
|
228
|
+
servers.push({
|
|
229
|
+
name: serverName,
|
|
230
|
+
instructions: serverInstructions.trim(),
|
|
231
|
+
hasInstructions: true,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const serverCount = availableServers.length;
|
|
236
|
+
const hasServers = serverCount > 0;
|
|
237
|
+
// Merge configuration with defaults
|
|
238
|
+
const templateConfig = {
|
|
239
|
+
...DEFAULT_TEMPLATE_CONFIG,
|
|
240
|
+
title: config.title || DEFAULT_TEMPLATE_CONFIG.title,
|
|
241
|
+
toolPattern: config.toolPattern || DEFAULT_TEMPLATE_CONFIG.toolPattern,
|
|
242
|
+
examples: config.examples || DEFAULT_TEMPLATE_CONFIG.examples,
|
|
243
|
+
};
|
|
244
|
+
return {
|
|
245
|
+
// Server state
|
|
246
|
+
serverCount,
|
|
247
|
+
hasServers,
|
|
248
|
+
serverList: availableServers.join('\n'),
|
|
249
|
+
serverNames: availableServers,
|
|
250
|
+
servers,
|
|
251
|
+
pluralServers: serverCount === 1 ? 'server' : 'servers',
|
|
252
|
+
isAre: serverCount === 1 ? 'is' : 'are',
|
|
253
|
+
// Content
|
|
254
|
+
instructions: serverInstructionSections.join('\n\n'),
|
|
255
|
+
filterContext: this.getFilterContext(config),
|
|
256
|
+
// Configuration
|
|
257
|
+
toolPattern: templateConfig.toolPattern,
|
|
258
|
+
title: templateConfig.title,
|
|
259
|
+
examples: templateConfig.examples,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Cleanup method to remove all event listeners
|
|
264
|
+
* Should be called when the aggregator is no longer needed
|
|
265
|
+
*/
|
|
266
|
+
cleanup() {
|
|
267
|
+
logger.debug('InstructionAggregator: Starting cleanup');
|
|
268
|
+
// Clear all event listeners
|
|
269
|
+
this.removeAllListeners();
|
|
270
|
+
// Clear server instructions
|
|
271
|
+
this.serverInstructions.clear();
|
|
272
|
+
// Reset initialization state
|
|
273
|
+
this.isInitialized = false;
|
|
274
|
+
logger.info('InstructionAggregator: Cleanup completed - all listeners cleared');
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
//# sourceMappingURL=instructionAggregator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructionAggregator.js","sourceRoot":"","sources":["../../../src/core/instructions/instructionAggregator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,MAAM,MAAM,wBAAwB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEpE,OAAO,EAGL,uBAAuB,EACvB,4BAA4B,GAC7B,MAAM,oBAAoB,CAAC;AAS5B;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,OAAO,qBAAsB,SAAQ,YAAY;IAC7C,kBAAkB,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC/C,aAAa,GAAY,KAAK,CAAC;IAEvC;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC;IAED;;;;OAIG;IACI,eAAe,CAAC,UAAkB,EAAE,YAAgC;QACzE,MAAM,oBAAoB,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACrE,MAAM,UAAU,GAAG,oBAAoB,KAAK,YAAY,CAAC;QAEzD,IAAI,YAAY,EAAE,IAAI,EAAE,EAAE,CAAC;YACzB,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,UAAU,EAAE,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7D,MAAM,CAAC,KAAK,CAAC,oCAAoC,UAAU,EAAE,CAAC,CAAC;QACjE,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAC3C,MAAM,CAAC,KAAK,CAAC,oCAAoC,UAAU,EAAE,CAAC,CAAC;QACjE,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAC1B,MAAM,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACpD,CAAC;QAED,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,0DAA0D,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC;YACtG,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,YAAY,CAAC,UAAkB;QACpC,MAAM,eAAe,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAChE,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAE3C,IAAI,eAAe,EAAE,CAAC;YACpB,MAAM,CAAC,IAAI,CAAC,gCAAgC,UAAU,wBAAwB,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC;YAC9G,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACI,uBAAuB,CAAC,MAA+B,EAAE,WAAgC;QAC9F,MAAM,CAAC,KAAK,CAAC,sDAAsD,EAAE;YACnE,UAAU,EAAE,MAAM,CAAC,aAAa;YAChC,gBAAgB,EAAE,WAAW,CAAC,IAAI;YAClC,iBAAiB,EAAE,IAAI,CAAC,kBAAkB,CAAC,IAAI;YAC/C,iBAAiB,EAAE,CAAC,CAAC,MAAM,CAAC,cAAc;SAC3C,CAAC,CAAC;QAEH,mDAAmD;QACnD,MAAM,mBAAmB,GAAG,gBAAgB,CAAC,sBAAsB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAEzF,oCAAoC;QACpC,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,mBAAmB,CAAC,WAAW,EAAE,mBAAmB,EAAE,MAAM,CAAC,CAAC;QACxG,MAAM,CAAC,IAAI,CAAC,0CAA0C,EAAE,gBAAgB,CAAC,CAAC;QAE1E,8DAA8D;QAC9D,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC,+CAA+C,EAAE,EAAE,cAAc,EAAE,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC;YAC/G,IAAI,CAAC;gBACH,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,cAAc,EAAE,mBAAmB,EAAE,MAAM,CAAC,CAAC;YACjF,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAE5E,mCAAmC;gBACnC,MAAM,CAAC,KAAK,CAAC,iFAAiF,EAAE;oBAC9F,KAAK,EAAE,YAAY;oBACnB,cAAc,EAAE,MAAM,CAAC,cAAc,CAAC,MAAM;iBAC7C,CAAC,CAAC;gBAEH,gCAAgC;gBAChC,OAAO,IAAI,CAAC,cAAc,CAAC,4BAA4B,EAAE,mBAAmB,EAAE,MAAM,CAAC,CAAC;YACxF,CAAC;QACH,CAAC;aAAM,CAAC;YACN,gCAAgC;YAChC,OAAO,IAAI,CAAC,cAAc,CAAC,4BAA4B,EAAE,mBAAmB,EAAE,MAAM,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,cAAc;QACnB,OAAO,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC;IACtC,CAAC;IAED;;;OAGG;IACI,cAAc;QACnB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3D,CAAC;IAED;;;;OAIG;IACI,eAAe,CAAC,UAAkB;QACvC,OAAO,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACjD,CAAC;IAED;;;;OAIG;IACI,qBAAqB,CAAC,UAAkB;QAC7C,OAAO,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACjD,CAAC;IAED;;OAEG;IACI,KAAK;QACV,MAAM,eAAe,GAAG,IAAI,CAAC,kBAAkB,CAAC,IAAI,GAAG,CAAC,CAAC;QACzD,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,CAAC;QAEhC,IAAI,eAAe,EAAE,CAAC;YACpB,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;YAChD,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED;;OAEG;IACK,gBAAgB,CAAC,MAA+B;QACtD,IAAI,CAAC,MAAM,CAAC,aAAa,IAAI,MAAM,CAAC,aAAa,KAAK,MAAM,EAAE,CAAC;YAC7D,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,IAAI,MAAM,CAAC,aAAa,KAAK,WAAW,IAAI,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;YAChE,OAAO,uBAAuB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;QAC1D,CAAC;QAED,IAAI,MAAM,CAAC,aAAa,KAAK,UAAU,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;YAChE,OAAO,oCAAoC,CAAC;QAC9C,CAAC;QAED,IAAI,MAAM,CAAC,aAAa,KAAK,QAAQ,EAAE,CAAC;YACtC,OAAO,uBAAuB,CAAC;QACjC,CAAC;QAED,OAAO,aAAa,CAAC;IACvB,CAAC;IAED;;OAEG;IACI,UAAU;QACf,MAAM,WAAW,GAAG,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC;QACjD,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QAC1C,OAAO,GAAG,WAAW,+BAA+B,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAC/E,CAAC;IAED;;;;;;OAMG;IACK,cAAc,CACpB,QAAgB,EAChB,mBAAwC,EACxC,MAA+B;QAE/B,2CAA2C;QAC3C,6BAA6B;QAC7B,MAAM,iBAAiB,GAAG,MAAM,CAAC,iBAAiB,IAAI,uBAAuB,CAAC,iBAAiB,CAAC;QAChG,IAAI,QAAQ,CAAC,MAAM,GAAG,iBAAiB,EAAE,CAAC;YACxC,MAAM,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC1D,MAAM,OAAO,GAAG,CAAC,iBAAiB,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC7D,MAAM,IAAI,KAAK,CACb,uBAAuB,MAAM,WAAW,OAAO,OAAO;gBACpD,yEAAyE;gBACzE,+DAA+D,CAClE,CAAC;QACJ,CAAC;QAED,4BAA4B;QAC5B,MAAM,gBAAgB,GAAG,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAE1E,8BAA8B;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,yBAAyB,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;QAE9E,kBAAkB;QAClB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAE7C,MAAM,CAAC,KAAK,CAAC,uDAAuD,EAAE;YACpE,cAAc,EAAE,QAAQ,CAAC,MAAM;YAC/B,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM;YAC5C,cAAc,EAAE,QAAQ,CAAC,MAAM;SAChC,CAAC,CAAC;QAEH,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;OAKG;IACK,yBAAyB,CAC/B,mBAAwC,EACxC,MAA+B;QAE/B,gEAAgE;QAChE,MAAM,gBAAgB,GAAa,EAAE,CAAC;QACtC,MAAM,yBAAyB,GAAa,EAAE,CAAC;QAC/C,MAAM,OAAO,GAAiB,EAAE,CAAC;QAEjC,0DAA0D;QAC1D,MAAM,iBAAiB,GAAG,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;QAE3G,KAAK,MAAM,CAAC,UAAU,EAAE,WAAW,CAAC,IAAI,iBAAiB,EAAE,CAAC;YAC1D,MAAM,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACnE,IAAI,kBAAkB,EAAE,IAAI,EAAE,EAAE,CAAC;gBAC/B,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAClC,yBAAyB,CAAC,IAAI,CAAC,IAAI,UAAU,MAAM,kBAAkB,CAAC,IAAI,EAAE,OAAO,UAAU,GAAG,CAAC,CAAC;gBAElG,2CAA2C;gBAC3C,OAAO,CAAC,IAAI,CAAC;oBACX,IAAI,EAAE,UAAU;oBAChB,YAAY,EAAE,kBAAkB,CAAC,IAAI,EAAE;oBACvC,eAAe,EAAE,IAAI;iBACtB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,MAAM,WAAW,GAAG,gBAAgB,CAAC,MAAM,CAAC;QAC5C,MAAM,UAAU,GAAG,WAAW,GAAG,CAAC,CAAC;QAEnC,oCAAoC;QACpC,MAAM,cAAc,GAAG;YACrB,GAAG,uBAAuB;YAC1B,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,uBAAuB,CAAC,KAAK;YACpD,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,uBAAuB,CAAC,WAAW;YACtE,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,uBAAuB,CAAC,QAAQ;SAC9D,CAAC;QAEF,OAAO;YACL,eAAe;YACf,WAAW;YACX,UAAU;YACV,UAAU,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;YACvC,WAAW,EAAE,gBAAgB;YAC7B,OAAO;YACP,aAAa,EAAE,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;YACvD,KAAK,EAAE,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK;YAEvC,UAAU;YACV,YAAY,EAAE,yBAAyB,CAAC,IAAI,CAAC,MAAM,CAAC;YACpD,aAAa,EAAE,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC;YAE5C,gBAAgB;YAChB,WAAW,EAAE,cAAc,CAAC,WAAW;YACvC,KAAK,EAAE,cAAc,CAAC,KAAK;YAC3B,QAAQ,EAAE,cAAc,CAAC,QAAQ;SAClC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACI,OAAO;QACZ,MAAM,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAExD,4BAA4B;QAC5B,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAE1B,4BAA4B;QAC5B,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,CAAC;QAEhC,6BAA6B;QAC7B,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;QAE3B,MAAM,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;IAClF,CAAC;CACF"}
|