@cyanheads/cyanheads-mcp-server 0.1.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.
Files changed (46) hide show
  1. package/AGENTS.md +367 -0
  2. package/CLAUDE.md +367 -0
  3. package/Dockerfile +99 -0
  4. package/LICENSE +201 -0
  5. package/README.md +143 -0
  6. package/changelog/0.1.x/0.1.0.md +12 -0
  7. package/changelog/0.1.x/0.1.1.md +38 -0
  8. package/changelog/template.md +127 -0
  9. package/dist/config/server-config.d.ts +19 -0
  10. package/dist/config/server-config.d.ts.map +1 -0
  11. package/dist/config/server-config.js +66 -0
  12. package/dist/config/server-config.js.map +1 -0
  13. package/dist/index.d.ts +7 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +26 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/mcp-server/tools/definitions/describe.tool.d.ts +67 -0
  18. package/dist/mcp-server/tools/definitions/describe.tool.d.ts.map +1 -0
  19. package/dist/mcp-server/tools/definitions/describe.tool.js +192 -0
  20. package/dist/mcp-server/tools/definitions/describe.tool.js.map +1 -0
  21. package/dist/mcp-server/tools/definitions/search.tool.d.ts +53 -0
  22. package/dist/mcp-server/tools/definitions/search.tool.d.ts.map +1 -0
  23. package/dist/mcp-server/tools/definitions/search.tool.js +123 -0
  24. package/dist/mcp-server/tools/definitions/search.tool.js.map +1 -0
  25. package/dist/services/catalog/catalog-service.d.ts +50 -0
  26. package/dist/services/catalog/catalog-service.d.ts.map +1 -0
  27. package/dist/services/catalog/catalog-service.js +233 -0
  28. package/dist/services/catalog/catalog-service.js.map +1 -0
  29. package/dist/services/catalog/embeddings-runtime.d.ts +21 -0
  30. package/dist/services/catalog/embeddings-runtime.d.ts.map +1 -0
  31. package/dist/services/catalog/embeddings-runtime.js +62 -0
  32. package/dist/services/catalog/embeddings-runtime.js.map +1 -0
  33. package/dist/services/catalog/remote-catalog-provider.d.ts +20 -0
  34. package/dist/services/catalog/remote-catalog-provider.d.ts.map +1 -0
  35. package/dist/services/catalog/remote-catalog-provider.js +84 -0
  36. package/dist/services/catalog/remote-catalog-provider.js.map +1 -0
  37. package/dist/services/catalog/snippets.d.ts +16 -0
  38. package/dist/services/catalog/snippets.d.ts.map +1 -0
  39. package/dist/services/catalog/snippets.js +51 -0
  40. package/dist/services/catalog/snippets.js.map +1 -0
  41. package/dist/services/catalog/types.d.ts +135 -0
  42. package/dist/services/catalog/types.d.ts.map +1 -0
  43. package/dist/services/catalog/types.js +8 -0
  44. package/dist/services/catalog/types.js.map +1 -0
  45. package/package.json +83 -0
  46. package/server.json +141 -0
@@ -0,0 +1,192 @@
1
+ /**
2
+ * @fileoverview cyanheads_describe — return connection URL and per-client install snippets
3
+ * for a named tool or server.
4
+ * Uses z.discriminatedUnion on 'kind' so the linter walks each branch independently
5
+ * and format() can dispatch cleanly.
6
+ * @module mcp-server/tools/definitions/describe
7
+ */
8
+ import { tool, z } from '@cyanheads/mcp-ts-core';
9
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
10
+ import { getCatalogService } from '../../../services/catalog/catalog-service.js';
11
+ import { buildAllSnippets } from '../../../services/catalog/snippets.js';
12
+ export const describeTool = tool('cyanheads_describe', {
13
+ title: 'Describe Fleet Tool or Server',
14
+ description: 'Return the description, connection URL, and per-client install snippets for a named tool or ' +
15
+ 'server. For tools: the description and the server it belongs to. ' +
16
+ 'For servers: connection URL and install snippets for every supported client (or one specific ' +
17
+ 'client when the client parameter is specified). Call cyanheads_search first to find valid names.',
18
+ annotations: { readOnlyHint: true, openWorldHint: false },
19
+ auth: ['tool:cyanheads_describe:read'],
20
+ input: z.object({
21
+ name: z
22
+ .string()
23
+ .min(1)
24
+ .describe('Tool name (snake_case, e.g. "earthquake_search") or server name ' +
25
+ '(kebab-case, e.g. "earthquake-mcp-server"). Use cyanheads_search to discover valid names.'),
26
+ kind: z
27
+ .enum(['tool', 'server'])
28
+ .optional()
29
+ .describe('Whether name refers to a tool or server. Omit to auto-detect: names containing ' +
30
+ 'underscores are treated as tools; names containing hyphens are treated as servers.'),
31
+ client: z
32
+ .enum(['claude-desktop', 'claude-code', 'cursor', 'cline'])
33
+ .optional()
34
+ .describe('Return the install snippet for this specific client only. ' +
35
+ 'Omit to return snippets for all supported clients.'),
36
+ }),
37
+ output: z.object({
38
+ result: z
39
+ .discriminatedUnion('kind', [
40
+ z.object({
41
+ kind: z.literal('tool').describe('Resolved as a tool entry.'),
42
+ name: z.string().describe('Resolved name (as looked up).'),
43
+ description: z.string().describe('Brief description of what the tool does.'),
44
+ server: z.string().describe('Server package name that owns this tool.'),
45
+ }),
46
+ z.object({
47
+ kind: z.literal('server').describe('Resolved as a server entry.'),
48
+ name: z.string().describe('Resolved name (as looked up).'),
49
+ displayName: z.string().describe('Human-readable server label.'),
50
+ description: z.string().describe('Brief description of what the server does.'),
51
+ version: z.string().describe('Published version captured at fleet-generation time.'),
52
+ npm: z.string().describe('npm package name (e.g. "@cyanheads/arxiv-mcp-server").'),
53
+ github: z.string().describe('GitHub repository URL.'),
54
+ endpoint: z.string().describe('HTTP SSE endpoint for the hosted deployment.'),
55
+ auth: z
56
+ .string()
57
+ .describe('Auth requirement for the hosted deployment (currently always "none").'),
58
+ toolCount: z.number().describe('Number of tools exposed by this server.'),
59
+ installSnippets: z
60
+ .array(z
61
+ .object({
62
+ client: z
63
+ .enum(['claude-desktop', 'claude-code', 'cursor', 'cline'])
64
+ .describe('MCP client this snippet targets.'),
65
+ label: z.string().describe('Human-readable install method label.'),
66
+ payload: z.string().describe('Install payload (JSON fragment or CLI command).'),
67
+ })
68
+ .describe('A single install instruction entry.'))
69
+ .describe('Install instructions, one per supported client (or filtered by input.client).'),
70
+ }),
71
+ ])
72
+ .describe('The resolved entry — either a tool detail or a server detail depending on the resolved kind.'),
73
+ }),
74
+ errors: [
75
+ {
76
+ reason: 'not_found',
77
+ code: JsonRpcErrorCode.NotFound,
78
+ when: 'No tool or server with the given name exists in the catalog.',
79
+ recovery: 'Use cyanheads_search to find the correct name, then call cyanheads_describe again.',
80
+ },
81
+ {
82
+ reason: 'ambiguous_kind',
83
+ code: JsonRpcErrorCode.InvalidParams,
84
+ when: 'Name matches both a tool and a server (collision in catalog).',
85
+ recovery: 'Set the kind parameter to "tool" or "server" to disambiguate.',
86
+ },
87
+ {
88
+ reason: 'catalog_empty',
89
+ code: JsonRpcErrorCode.ServiceUnavailable,
90
+ when: 'Catalog has not finished loading.',
91
+ recovery: 'Retry in a few seconds; the catalog is still loading.',
92
+ retryable: true,
93
+ },
94
+ ],
95
+ // biome-ignore lint/suspicious/useAwait: handler has no I/O but must return a Promise for the framework
96
+ async handler(input, ctx) {
97
+ ctx.log.info('Describing catalog entry', { name: input.name, kind: input.kind });
98
+ const catalog = getCatalogService();
99
+ // Resolve kind: explicit > auto-detect from name format.
100
+ let resolvedKind = input.kind;
101
+ if (!resolvedKind) {
102
+ // Fleet invariant: tool names use underscores, server names use hyphens.
103
+ if (input.name.includes('_')) {
104
+ resolvedKind = 'tool';
105
+ }
106
+ else if (input.name.includes('-')) {
107
+ resolvedKind = 'server';
108
+ }
109
+ }
110
+ const toolEntry = resolvedKind !== 'server' ? catalog.getTool(input.name) : null;
111
+ const serverEntry = resolvedKind !== 'tool' ? catalog.getServer(input.name) : null;
112
+ // Ambiguity check (can happen if resolvedKind is undefined and name has neither _ nor -).
113
+ if (toolEntry && serverEntry) {
114
+ throw ctx.fail('ambiguous_kind', `"${input.name}" matches both a tool and a server`, {
115
+ ...ctx.recoveryFor('ambiguous_kind'),
116
+ name: input.name,
117
+ });
118
+ }
119
+ if (toolEntry) {
120
+ return {
121
+ result: {
122
+ kind: 'tool',
123
+ name: input.name,
124
+ description: toolEntry.description,
125
+ server: toolEntry.serverRecord.name,
126
+ },
127
+ };
128
+ }
129
+ if (serverEntry) {
130
+ const allSnippets = buildAllSnippets(serverEntry);
131
+ const snippets = input.client
132
+ ? allSnippets.filter((s) => s.client === input.client)
133
+ : allSnippets;
134
+ return {
135
+ result: {
136
+ kind: 'server',
137
+ name: input.name,
138
+ displayName: serverEntry.displayName,
139
+ description: serverEntry.description,
140
+ version: serverEntry.version,
141
+ npm: serverEntry.npm,
142
+ github: serverEntry.github,
143
+ endpoint: serverEntry.endpoint,
144
+ auth: serverEntry.auth,
145
+ toolCount: serverEntry.tools.length,
146
+ installSnippets: snippets,
147
+ },
148
+ };
149
+ }
150
+ throw ctx.fail('not_found', `No tool or server named "${input.name}" in the catalog`, {
151
+ ...ctx.recoveryFor('not_found'),
152
+ name: input.name,
153
+ });
154
+ },
155
+ format: ({ result }) => {
156
+ const lines = [];
157
+ if (result.kind === 'tool') {
158
+ lines.push(`# Tool: ${result.name}`);
159
+ lines.push(`**Server:** ${result.server}`);
160
+ lines.push('');
161
+ lines.push(`**Kind:** tool`);
162
+ lines.push('');
163
+ lines.push(`## Description`);
164
+ lines.push(result.description);
165
+ }
166
+ else {
167
+ lines.push(`# Server: ${result.name}`);
168
+ lines.push(`**Kind:** server`);
169
+ lines.push(`**Display name:** ${result.displayName}`);
170
+ lines.push(`**Version:** ${result.version}`);
171
+ lines.push(`**npm:** ${result.npm}`);
172
+ lines.push(`**GitHub:** ${result.github}`);
173
+ lines.push(`**Auth:** ${result.auth}`);
174
+ lines.push(`**Tool count:** ${result.toolCount}`);
175
+ lines.push(`**Endpoint:** ${result.endpoint}`);
176
+ lines.push('');
177
+ lines.push('## Description');
178
+ lines.push(result.description);
179
+ lines.push('');
180
+ lines.push('## Install Snippets');
181
+ for (const snippet of result.installSnippets) {
182
+ lines.push(`### ${snippet.label} (${snippet.client})`);
183
+ lines.push('```');
184
+ lines.push(snippet.payload);
185
+ lines.push('```');
186
+ lines.push('');
187
+ }
188
+ }
189
+ return [{ type: 'text', text: lines.join('\n') }];
190
+ },
191
+ });
192
+ //# sourceMappingURL=describe.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"describe.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/describe.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @fileoverview cyanheads_search — semantic search across fleet tools and servers.
3
+ * Embeds the query at runtime and dot-products against in-memory L2-normalized
4
+ * document vectors loaded from fleet.json.
5
+ * @module mcp-server/tools/definitions/search
6
+ */
7
+ import { z } from '@cyanheads/mcp-ts-core';
8
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
9
+ export declare const searchTool: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
10
+ query: z.ZodString;
11
+ scope: z.ZodDefault<z.ZodEnum<{
12
+ tools: "tools";
13
+ servers: "servers";
14
+ }>>;
15
+ category: z.ZodOptional<z.ZodEnum<{
16
+ research: "research";
17
+ government: "government";
18
+ "public-data": "public-data";
19
+ utility: "utility";
20
+ }>>;
21
+ limit: z.ZodDefault<z.ZodNumber>;
22
+ }, z.core.$strip>, z.ZodObject<{
23
+ results: z.ZodArray<z.ZodObject<{
24
+ name: z.ZodString;
25
+ server: z.ZodString;
26
+ brief: z.ZodString;
27
+ category: z.ZodEnum<{
28
+ research: "research";
29
+ government: "government";
30
+ "public-data": "public-data";
31
+ utility: "utility";
32
+ }>;
33
+ score: z.ZodNumber;
34
+ }, z.core.$strip>>;
35
+ totalMatched: z.ZodNumber;
36
+ query: z.ZodString;
37
+ scope: z.ZodEnum<{
38
+ tools: "tools";
39
+ servers: "servers";
40
+ }>;
41
+ }, z.core.$strip>, readonly [{
42
+ readonly reason: "no_results";
43
+ readonly code: JsonRpcErrorCode.NotFound;
44
+ readonly when: "Query produced no relevant matches.";
45
+ readonly recovery: "Broaden the query, remove the category filter, or try scope \"servers\" to find the right server first.";
46
+ }, {
47
+ readonly reason: "catalog_empty";
48
+ readonly code: JsonRpcErrorCode.ServiceUnavailable;
49
+ readonly when: "Catalog has not finished loading.";
50
+ readonly recovery: "Retry in a few seconds; the catalog is still loading.";
51
+ readonly retryable: true;
52
+ }]>;
53
+ //# sourceMappingURL=search.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/search.tool.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0IrB,CAAC"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * @fileoverview cyanheads_search — semantic search across fleet tools and servers.
3
+ * Embeds the query at runtime and dot-products against in-memory L2-normalized
4
+ * document vectors loaded from fleet.json.
5
+ * @module mcp-server/tools/definitions/search
6
+ */
7
+ import { tool, z } from '@cyanheads/mcp-ts-core';
8
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
9
+ import { getCatalogService } from '../../../services/catalog/catalog-service.js';
10
+ export const searchTool = tool('cyanheads_search', {
11
+ title: 'Search Fleet Tools and Servers',
12
+ description: 'Search fleet tools and servers by natural-language description. Returns ranked matches with ' +
13
+ 'brief summaries and the server each tool belongs to. Use scope "servers" to find which ' +
14
+ 'server handles a workflow; use the default scope "tools" to find specific tools. ' +
15
+ 'Call cyanheads_describe on a result name to get install snippets and the connection URL.',
16
+ annotations: { readOnlyHint: true, openWorldHint: false },
17
+ auth: ['tool:cyanheads_search:read'],
18
+ input: z.object({
19
+ query: z
20
+ .string()
21
+ .min(1)
22
+ .describe('Natural language search query. Describe what you want to accomplish, a workflow, or a capability area.'),
23
+ scope: z
24
+ .enum(['tools', 'servers'])
25
+ .default('tools')
26
+ .describe('What to search. "tools" returns individual tool matches; "servers" returns server-level matches.'),
27
+ category: z
28
+ .enum(['research', 'government', 'public-data', 'utility'])
29
+ .optional()
30
+ .describe('Filter by catalog category. Omit to search all categories.'),
31
+ limit: z
32
+ .number()
33
+ .int()
34
+ .min(1)
35
+ .max(20)
36
+ .default(5)
37
+ .describe('Maximum number of results to return (1-20). Default 5.'),
38
+ }),
39
+ output: z.object({
40
+ results: z
41
+ .array(z
42
+ .object({
43
+ name: z
44
+ .string()
45
+ .describe('Tool name (snake_case) or server name (kebab-case) depending on scope.'),
46
+ server: z
47
+ .string()
48
+ .describe('Server package name that owns this tool (e.g. "arxiv-mcp-server"). Same as name when scope is "servers".'),
49
+ brief: z.string().describe('One-line summary of what this tool or server does.'),
50
+ category: z
51
+ .enum(['research', 'government', 'public-data', 'utility'])
52
+ .describe('Catalog category for the owning server.'),
53
+ score: z
54
+ .number()
55
+ .describe('Cosine similarity between query and entry, in [0, 1]. Higher is better. Compare only within a single response.'),
56
+ })
57
+ .describe('A single search result entry.'))
58
+ .describe('Ranked matches, best first.'),
59
+ totalMatched: z.number().describe('Total relevant matches before the limit was applied.'),
60
+ query: z.string().describe('The query that was searched.'),
61
+ scope: z.enum(['tools', 'servers']).describe('Scope that was searched.'),
62
+ }),
63
+ errors: [
64
+ {
65
+ reason: 'no_results',
66
+ code: JsonRpcErrorCode.NotFound,
67
+ when: 'Query produced no relevant matches.',
68
+ recovery: 'Broaden the query, remove the category filter, or try scope "servers" to find the right server first.',
69
+ },
70
+ {
71
+ reason: 'catalog_empty',
72
+ code: JsonRpcErrorCode.ServiceUnavailable,
73
+ when: 'Catalog has not finished loading.',
74
+ recovery: 'Retry in a few seconds; the catalog is still loading.',
75
+ retryable: true,
76
+ },
77
+ ],
78
+ async handler(input, ctx) {
79
+ ctx.log.info('Searching catalog', {
80
+ query: input.query,
81
+ scope: input.scope,
82
+ limit: input.limit,
83
+ });
84
+ const catalog = getCatalogService();
85
+ const allResults = await catalog.search({
86
+ query: input.query,
87
+ scope: input.scope,
88
+ ...(input.category ? { category: input.category } : {}),
89
+ });
90
+ const totalMatched = allResults.length;
91
+ if (totalMatched === 0) {
92
+ throw ctx.fail('no_results', `No ${input.scope} matched "${input.query}"`, {
93
+ ...ctx.recoveryFor('no_results'),
94
+ query: input.query,
95
+ scope: input.scope,
96
+ category: input.category,
97
+ });
98
+ }
99
+ const results = allResults.slice(0, input.limit);
100
+ ctx.log.info('Search complete', { totalMatched, returned: results.length });
101
+ return {
102
+ results,
103
+ totalMatched,
104
+ query: input.query,
105
+ scope: input.scope,
106
+ };
107
+ },
108
+ format: (result) => {
109
+ const lines = [
110
+ `**Query:** ${result.query} **Scope:** ${result.scope}`,
111
+ `**Matched:** ${result.totalMatched} total, showing ${result.results.length}`,
112
+ '',
113
+ ];
114
+ for (const item of result.results) {
115
+ lines.push(`### ${item.name}`);
116
+ lines.push(`**Server:** ${item.server} | **Category:** ${item.category} | **Score:** ${item.score.toFixed(3)}`);
117
+ lines.push(item.brief);
118
+ lines.push('');
119
+ }
120
+ return [{ type: 'text', text: lines.join('\n') }];
121
+ },
122
+ });
123
+ //# sourceMappingURL=search.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/search.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @fileoverview CatalogService — fleet catalog with semantic search.
3
+ * Loads fleet.json (v2 with baked embeddings) at startup, packs vectors into a
4
+ * Float32Array for cache locality, and serves cosine-similarity search by
5
+ * embedding the query at runtime and dot-producting against the in-memory index.
6
+ * Polls the remote payload on a configurable interval; atomic swap on change.
7
+ * @module services/catalog/catalog-service
8
+ */
9
+ import type { ServerConfig } from '../../config/server-config.js';
10
+ import { type IEmbeddingsRuntime } from './embeddings-runtime.js';
11
+ import type { CatalogCategory, CatalogRecord, CatalogSearchResult, CatalogTool, ICatalogService } from './types.js';
12
+ type CatalogServiceConfig = Pick<ServerConfig, 'catalogUrl' | 'catalogFetchTimeoutMs' | 'catalogRefreshSeconds' | 'embeddingModelId' | 'similarityFloor'>;
13
+ export declare class CatalogService implements ICatalogService {
14
+ private _index;
15
+ private readonly _provider;
16
+ private readonly _embeddings;
17
+ private readonly _config;
18
+ private _refreshTimer;
19
+ constructor(config: CatalogServiceConfig, embeddings?: IEmbeddingsRuntime);
20
+ initialize(): Promise<void>;
21
+ search(params: {
22
+ query: string;
23
+ scope: 'tools' | 'servers';
24
+ category?: CatalogCategory;
25
+ limit?: number;
26
+ }): Promise<CatalogSearchResult[]>;
27
+ getTool(name: string): (CatalogTool & {
28
+ serverRecord: CatalogRecord;
29
+ }) | null;
30
+ getServer(name: string): CatalogRecord | null;
31
+ listCategories(): CatalogCategory[];
32
+ stats(): {
33
+ toolCount: number;
34
+ serverCount: number;
35
+ initializedAt: string;
36
+ embeddingModel: string;
37
+ };
38
+ /** Stop the background refresh timer (test-only / shutdown). */
39
+ shutdown(): void;
40
+ private _assertModelMatch;
41
+ private _buildIndex;
42
+ private _maybeRefresh;
43
+ private _assertInitialized;
44
+ }
45
+ export declare function initCatalogService(config: CatalogServiceConfig, embeddings?: IEmbeddingsRuntime): void;
46
+ export declare function getCatalogService(): CatalogService;
47
+ /** Test-only reset. */
48
+ export declare function resetCatalogServiceForTests(): void;
49
+ export {};
50
+ //# sourceMappingURL=catalog-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-service.d.ts","sourceRoot":"","sources":["../../../src/services/catalog/catalog-service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,KAAK,kBAAkB,EAAiC,MAAM,yBAAyB,CAAC;AAEjG,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,mBAAmB,EACnB,WAAW,EAEX,eAAe,EAChB,MAAM,YAAY,CAAC;AAoBpB,KAAK,oBAAoB,GAAG,IAAI,CAC9B,YAAY,EACV,YAAY,GACZ,uBAAuB,GACvB,uBAAuB,GACvB,kBAAkB,GAClB,iBAAiB,CACpB,CAAC;AAMF,qBAAa,cAAe,YAAW,eAAe;IACpD,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4B;IACtD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAC/C,OAAO,CAAC,aAAa,CAA+C;gBAExD,MAAM,EAAE,oBAAoB,EAAE,UAAU,CAAC,EAAE,kBAAkB;IAMnE,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB3B,MAAM,CAAC,MAAM,EAAE;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,OAAO,GAAG,SAAS,CAAC;QAC3B,QAAQ,CAAC,EAAE,eAAe,CAAC;QAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAkDlC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,WAAW,GAAG;QAAE,YAAY,EAAE,aAAa,CAAA;KAAE,CAAC,GAAG,IAAI;IAK7E,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAK7C,cAAc,IAAI,eAAe,EAAE;IAOnC,KAAK,IAAI;QACP,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;KACxB;IAUD,gEAAgE;IAChE,QAAQ,IAAI,IAAI;IAWhB,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,WAAW;YAwDL,aAAa;IA2B3B,OAAO,CAAC,kBAAkB;CAQ3B;AAsBD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,oBAAoB,EAC5B,UAAU,CAAC,EAAE,kBAAkB,GAC9B,IAAI,CAEN;AAED,wBAAgB,iBAAiB,IAAI,cAAc,CAQlD;AAED,uBAAuB;AACvB,wBAAgB,2BAA2B,IAAI,IAAI,CAGlD"}