caedora-mcp 0.2.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.
Files changed (50) hide show
  1. package/README.md +71 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +100 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/lib/conventions.d.ts +3 -0
  7. package/dist/lib/conventions.d.ts.map +1 -0
  8. package/dist/lib/conventions.js +12 -0
  9. package/dist/lib/conventions.js.map +1 -0
  10. package/dist/lib/frontmatter.d.ts +23 -0
  11. package/dist/lib/frontmatter.d.ts.map +1 -0
  12. package/dist/lib/frontmatter.js +139 -0
  13. package/dist/lib/frontmatter.js.map +1 -0
  14. package/dist/lib/okf.d.ts +55 -0
  15. package/dist/lib/okf.d.ts.map +1 -0
  16. package/dist/lib/okf.js +276 -0
  17. package/dist/lib/okf.js.map +1 -0
  18. package/dist/providers/github.d.ts +26 -0
  19. package/dist/providers/github.d.ts.map +1 -0
  20. package/dist/providers/github.js +144 -0
  21. package/dist/providers/github.js.map +1 -0
  22. package/dist/providers/local-node.d.ts +25 -0
  23. package/dist/providers/local-node.d.ts.map +1 -0
  24. package/dist/providers/local-node.js +112 -0
  25. package/dist/providers/local-node.js.map +1 -0
  26. package/dist/providers/types.d.ts +25 -0
  27. package/dist/providers/types.d.ts.map +1 -0
  28. package/dist/providers/types.js +21 -0
  29. package/dist/providers/types.js.map +1 -0
  30. package/dist/server.d.ts +13 -0
  31. package/dist/server.d.ts.map +1 -0
  32. package/dist/server.js +43 -0
  33. package/dist/server.js.map +1 -0
  34. package/dist/tools/operations.d.ts +60 -0
  35. package/dist/tools/operations.d.ts.map +1 -0
  36. package/dist/tools/operations.js +48 -0
  37. package/dist/tools/operations.js.map +1 -0
  38. package/dist/tools/read.d.ts +49 -0
  39. package/dist/tools/read.d.ts.map +1 -0
  40. package/dist/tools/read.js +74 -0
  41. package/dist/tools/read.js.map +1 -0
  42. package/dist/tools/search.d.ts +77 -0
  43. package/dist/tools/search.d.ts.map +1 -0
  44. package/dist/tools/search.js +107 -0
  45. package/dist/tools/search.js.map +1 -0
  46. package/dist/tools/write.d.ts +89 -0
  47. package/dist/tools/write.d.ts.map +1 -0
  48. package/dist/tools/write.js +114 -0
  49. package/dist/tools/write.js.map +1 -0
  50. package/package.json +59 -0
package/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # caedora-mcp
2
+
3
+ An MCP server for reading, searching, validating, and maintaining Open Knowledge
4
+ Format bundles. It exposes structured concept metadata, cross-links, backlinks,
5
+ source ingestion, progressive indexes, and bundle logs to MCP-aware agents.
6
+
7
+ ## Run
8
+
9
+ ```bash
10
+ npx caedora-mcp --bundle /path/to/knowledge-bundle
11
+ ```
12
+
13
+ The legacy `--vault` flag remains an alias for `--bundle`.
14
+
15
+ For GitHub-hosted bundles:
16
+
17
+ ```bash
18
+ GITHUB_TOKEN=github_pat_xxx npx caedora-mcp --github owner/repository
19
+ ```
20
+
21
+ Add `--read-only` to disable all write tools.
22
+
23
+ ## Connect an MCP client
24
+
25
+ The server speaks stdio, so any MCP-aware client uses the same config block:
26
+
27
+ ```json
28
+ {
29
+ "mcpServers": {
30
+ "caedora": {
31
+ "command": "npx",
32
+ "args": ["-y", "caedora-mcp", "--bundle", "/absolute/path/to/your-vault"]
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
38
+ Config file locations:
39
+
40
+ - **Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json`
41
+ (macOS) / `%APPDATA%\Claude\claude_desktop_config.json` (Windows)
42
+ - **Cursor** — `~/.cursor/mcp.json`
43
+ - **Gemini CLI** — `~/.gemini/settings.json`
44
+ - **Claude Code** — already has file tools; run `claude` from the vault folder, and
45
+ optionally add this server for indexed search, graph traversal, and conformant writes.
46
+
47
+ ## Read tools
48
+
49
+ - `list_concepts(folder?, type?)`
50
+ - `read_concept(path)`
51
+ - `search_concepts(query, tag?, type?, limit?)`
52
+ - `grep_concepts(regex, flags?, limit?)`
53
+ - `list_tags()`
54
+ - `list_types()`
55
+ - `concepts_by_tag(tag)`
56
+ - `concept_graph(path?)`
57
+ - `lint_bundle(recordLint?)`
58
+
59
+ ## Write tools
60
+
61
+ - `create_concept(...)`
62
+ - `update_concept(...)`
63
+ - `rename_concept(from, to)`
64
+ - `delete_concept(path)`
65
+ - `ingest_source(...)`
66
+ - `rebuild_indexes()`
67
+ - `record_query(summary, conceptPaths?)`
68
+
69
+ Every mutation preserves producer-defined YAML fields, maintains timestamps,
70
+ regenerates hierarchical indexes, and records significant operations in
71
+ `log.md`. Reserved `index.md` and `log.md` documents are protected.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import path from 'node:path';
4
+ import { buildServer } from './server.js';
5
+ import { LocalNodeProvider } from './providers/local-node.js';
6
+ import { GitHubNodeProvider } from './providers/github.js';
7
+ function parseArgs(argv) {
8
+ const out = { readOnly: false, help: false };
9
+ for (let index = 0; index < argv.length; index++) {
10
+ switch (argv[index]) {
11
+ case '--bundle':
12
+ case '--vault':
13
+ out.bundle = argv[++index];
14
+ break;
15
+ case '--github':
16
+ out.github = argv[++index];
17
+ break;
18
+ case '--pat':
19
+ out.pat = argv[++index];
20
+ break;
21
+ case '--read-only':
22
+ out.readOnly = true;
23
+ break;
24
+ case '-h':
25
+ case '--help':
26
+ out.help = true;
27
+ break;
28
+ default:
29
+ if (argv[index].startsWith('--')) {
30
+ console.error(`Unknown flag: ${argv[index]}`);
31
+ process.exit(2);
32
+ }
33
+ }
34
+ }
35
+ return out;
36
+ }
37
+ function printHelp() {
38
+ console.error(`caedora-mcp - MCP server for OKF knowledge bundles
39
+
40
+ Usage:
41
+ caedora-mcp --bundle <path>
42
+ caedora-mcp --github <owner>/<repo> --pat <token>
43
+ caedora-mcp --bundle <path> --read-only
44
+
45
+ Options:
46
+ --bundle <path> Serve a local OKF bundle.
47
+ --vault <path> Legacy alias for --bundle.
48
+ --github owner/repo Serve a GitHub-hosted OKF bundle.
49
+ --pat <token> GitHub personal access token. Falls back to GITHUB_TOKEN.
50
+ --read-only Disable all write tools.
51
+ -h, --help Show this help.
52
+
53
+ The server speaks stdio. Example MCP configuration:
54
+
55
+ {
56
+ "mcpServers": {
57
+ "caedora": {
58
+ "command": "npx",
59
+ "args": ["-y", "caedora-mcp", "--bundle", "/path/to/bundle"]
60
+ }
61
+ }
62
+ }
63
+ `);
64
+ }
65
+ async function main() {
66
+ const args = parseArgs(process.argv.slice(2));
67
+ if (args.help) {
68
+ printHelp();
69
+ process.exit(0);
70
+ }
71
+ let provider;
72
+ if (args.bundle) {
73
+ provider = new LocalNodeProvider(path.resolve(args.bundle));
74
+ }
75
+ else if (args.github) {
76
+ const [owner, repo] = args.github.split('/');
77
+ if (!owner || !repo) {
78
+ console.error('--github must be in the form owner/repo');
79
+ process.exit(2);
80
+ }
81
+ const token = args.pat ?? process.env.GITHUB_TOKEN;
82
+ if (!token) {
83
+ console.error('Missing --pat (or GITHUB_TOKEN) for --github mode');
84
+ process.exit(2);
85
+ }
86
+ provider = new GitHubNodeProvider(token, owner, repo);
87
+ }
88
+ else {
89
+ console.error('Must provide either --bundle <path> or --github owner/repo');
90
+ printHelp();
91
+ process.exit(2);
92
+ }
93
+ const server = buildServer({ provider, readOnly: args.readOnly });
94
+ await server.connect(new StdioServerTransport());
95
+ }
96
+ main().catch((error) => {
97
+ console.error(`caedora-mcp: fatal error - ${error instanceof Error ? error.message : String(error)}`);
98
+ process.exit(1);
99
+ });
100
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function stemFromPath(path: string): string;
2
+ export declare function titleFromPath(path: string): string;
3
+ //# sourceMappingURL=conventions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conventions.d.ts","sourceRoot":"","sources":["../../src/lib/conventions.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMlD"}
@@ -0,0 +1,12 @@
1
+ export function stemFromPath(path) {
2
+ const name = path.split('/').pop() ?? path;
3
+ return name.replace(/\.md$/i, '');
4
+ }
5
+ export function titleFromPath(path) {
6
+ return stemFromPath(path)
7
+ .split(/[-_]+/)
8
+ .filter(Boolean)
9
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
10
+ .join(' ');
11
+ }
12
+ //# sourceMappingURL=conventions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conventions.js","sourceRoot":"","sources":["../../src/lib/conventions.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,IAAI,CAAA;IAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;AACnC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,YAAY,CAAC,IAAI,CAAC;SACtB,KAAK,CAAC,OAAO,CAAC;SACd,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SAC3D,IAAI,CAAC,GAAG,CAAC,CAAA;AACd,CAAC"}
@@ -0,0 +1,23 @@
1
+ export interface Frontmatter {
2
+ type: string;
3
+ title: string;
4
+ description: string;
5
+ resource: string;
6
+ tags: string[];
7
+ timestamp: string;
8
+ extra: Record<string, unknown>;
9
+ }
10
+ export declare function emptyFrontmatter(overrides?: Partial<Frontmatter>): Frontmatter;
11
+ export declare function parseFrontmatter(markdown: string): {
12
+ frontmatter: Frontmatter;
13
+ body: string;
14
+ hasFrontmatter: boolean;
15
+ error: string | null;
16
+ };
17
+ export declare function serializeFrontmatter(frontmatter: Frontmatter): string;
18
+ export declare function combine(frontmatter: Frontmatter, body: string): string;
19
+ export declare function createConceptFrontmatter(title: string, type: string, overrides?: Partial<Frontmatter>): Frontmatter;
20
+ export declare function normalizeTag(raw: string): string;
21
+ export declare function uniqueTags(tags: string[]): string[];
22
+ export declare function slugifyFilename(raw: string): string;
23
+ //# sourceMappingURL=frontmatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/lib/frontmatter.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC/B;AAYD,wBAAgB,gBAAgB,CAAC,SAAS,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,CAWlF;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM;;;;WAO5B,MAAM,GAAG,IAAI;EAwCjC;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAarE;AAED,wBAAgB,OAAO,CAAC,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,OAAO,CAAC,WAAW,CAAM,GACnC,WAAW,CASb;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOhD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAEnD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CASnD"}
@@ -0,0 +1,139 @@
1
+ import { parseDocument, stringify } from 'yaml';
2
+ const FENCE = /^---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*\r?\n?/;
3
+ const STANDARD_KEYS = new Set([
4
+ 'type',
5
+ 'title',
6
+ 'description',
7
+ 'resource',
8
+ 'tags',
9
+ 'timestamp',
10
+ ]);
11
+ export function emptyFrontmatter(overrides = {}) {
12
+ return {
13
+ type: '',
14
+ title: '',
15
+ description: '',
16
+ resource: '',
17
+ tags: [],
18
+ timestamp: '',
19
+ extra: {},
20
+ ...overrides,
21
+ };
22
+ }
23
+ export function parseFrontmatter(markdown) {
24
+ const match = markdown.match(FENCE);
25
+ if (!match) {
26
+ return {
27
+ frontmatter: emptyFrontmatter(),
28
+ body: markdown,
29
+ hasFrontmatter: false,
30
+ error: null,
31
+ };
32
+ }
33
+ try {
34
+ const document = parseDocument(match[1], { prettyErrors: false, uniqueKeys: false });
35
+ if (document.errors.length > 0)
36
+ throw new Error(document.errors[0].message);
37
+ const value = document.toJS();
38
+ if (!isRecord(value))
39
+ throw new Error('YAML frontmatter must be a mapping.');
40
+ const extra = {};
41
+ for (const [key, fieldValue] of Object.entries(value)) {
42
+ if (!STANDARD_KEYS.has(key))
43
+ extra[key] = fieldValue;
44
+ }
45
+ return {
46
+ frontmatter: {
47
+ type: stringValue(value.type),
48
+ title: stringValue(value.title),
49
+ description: stringValue(value.description),
50
+ resource: stringValue(value.resource),
51
+ tags: uniqueTags(Array.isArray(value.tags)
52
+ ? value.tags.filter((item) => typeof item === 'string')
53
+ : typeof value.tags === 'string'
54
+ ? value.tags.split(/[\s,]+/)
55
+ : []),
56
+ timestamp: stringValue(value.timestamp),
57
+ extra,
58
+ },
59
+ body: markdown.slice(match[0].length),
60
+ hasFrontmatter: true,
61
+ error: null,
62
+ };
63
+ }
64
+ catch (error) {
65
+ return {
66
+ frontmatter: emptyFrontmatter(),
67
+ body: markdown.slice(match[0].length),
68
+ hasFrontmatter: true,
69
+ error: error instanceof Error ? error.message : 'Invalid YAML frontmatter.',
70
+ };
71
+ }
72
+ }
73
+ export function serializeFrontmatter(frontmatter) {
74
+ const data = {};
75
+ if (frontmatter.type.trim())
76
+ data.type = frontmatter.type.trim();
77
+ if (frontmatter.title.trim())
78
+ data.title = frontmatter.title.trim();
79
+ if (frontmatter.description.trim())
80
+ data.description = frontmatter.description.trim();
81
+ if (frontmatter.resource.trim())
82
+ data.resource = frontmatter.resource.trim();
83
+ if (frontmatter.tags.length > 0)
84
+ data.tags = uniqueTags(frontmatter.tags);
85
+ if (frontmatter.timestamp.trim())
86
+ data.timestamp = frontmatter.timestamp.trim();
87
+ for (const [key, value] of Object.entries(frontmatter.extra)) {
88
+ if (!STANDARD_KEYS.has(key) && value !== undefined)
89
+ data[key] = value;
90
+ }
91
+ if (Object.keys(data).length === 0)
92
+ return '';
93
+ return `---\n${stringify(data, { lineWidth: 0 }).trimEnd()}\n---\n`;
94
+ }
95
+ export function combine(frontmatter, body) {
96
+ return `${serializeFrontmatter(frontmatter)}\n${body.replace(/^\n+/, '')}`;
97
+ }
98
+ export function createConceptFrontmatter(title, type, overrides = {}) {
99
+ return emptyFrontmatter({
100
+ type: type.trim(),
101
+ title: title.trim(),
102
+ timestamp: new Date().toISOString(),
103
+ ...overrides,
104
+ tags: uniqueTags(overrides.tags ?? []),
105
+ extra: overrides.extra ?? {},
106
+ });
107
+ }
108
+ export function normalizeTag(raw) {
109
+ return raw
110
+ .trim()
111
+ .replace(/^#/, '')
112
+ .replace(/\s+/g, '-')
113
+ .toLowerCase()
114
+ .replace(/[^a-z0-9_-]/g, '');
115
+ }
116
+ export function uniqueTags(tags) {
117
+ return [...new Set(tags.map(normalizeTag).filter(Boolean))];
118
+ }
119
+ export function slugifyFilename(raw) {
120
+ const stem = raw.replace(/\.md$/i, '');
121
+ return stem
122
+ .normalize('NFKD')
123
+ .replace(/[\u0300-\u036f]/g, '')
124
+ .toLowerCase()
125
+ .replace(/['"]/g, '')
126
+ .replace(/[^a-z0-9]+/g, '-')
127
+ .replace(/^-+|-+$/g, '') || 'untitled';
128
+ }
129
+ function stringValue(value) {
130
+ if (value === null || value === undefined)
131
+ return '';
132
+ if (value instanceof Date)
133
+ return value.toISOString();
134
+ return typeof value === 'string' ? value : String(value);
135
+ }
136
+ function isRecord(value) {
137
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
138
+ }
139
+ //# sourceMappingURL=frontmatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/lib/frontmatter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import { type VaultProvider } from '../providers/types.js';
2
+ export declare const OKF_VERSION = "0.1";
3
+ export declare const INDEX_FILENAME = "index.md";
4
+ export declare const LOG_FILENAME = "log.md";
5
+ export declare function isReservedPath(path: string): boolean;
6
+ export declare function isConceptPath(path: string): boolean;
7
+ export declare function conceptId(path: string): string;
8
+ export declare function extractLinks(markdown: string, sourcePath: string): {
9
+ label: string;
10
+ href: string;
11
+ targetPath: string | null;
12
+ targetId: string | null;
13
+ external: boolean;
14
+ }[];
15
+ export declare function resolveBundleLink(sourcePath: string, href: string): string | null;
16
+ export declare function validateBundle(provider: VaultProvider): Promise<{
17
+ version: string;
18
+ conformant: boolean;
19
+ concepts: number;
20
+ links: number;
21
+ brokenLinks: number;
22
+ issues: {
23
+ path: string;
24
+ severity: "error" | "warning";
25
+ code: string;
26
+ message: string;
27
+ }[];
28
+ }>;
29
+ export declare function buildConceptCatalog(provider: VaultProvider): Promise<{
30
+ id: string;
31
+ path: string;
32
+ type: string;
33
+ title: string;
34
+ description: string;
35
+ resource: string;
36
+ tags: string[];
37
+ timestamp: string;
38
+ links: {
39
+ label: string;
40
+ href: string;
41
+ targetPath: string | null;
42
+ targetId: string | null;
43
+ external: boolean;
44
+ }[];
45
+ conformant: boolean;
46
+ }[]>;
47
+ export declare function rebuildIndexes(provider: VaultProvider): Promise<{
48
+ updated: string[];
49
+ }>;
50
+ export declare function appendLog(provider: VaultProvider, action: string, message: string): Promise<{
51
+ path: string;
52
+ action: string;
53
+ recorded: boolean;
54
+ }>;
55
+ //# sourceMappingURL=okf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"okf.d.ts","sourceRoot":"","sources":["../../src/lib/okf.ts"],"names":[],"mappings":"AAIA,OAAO,EAAsC,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAE9F,eAAO,MAAM,WAAW,QAAQ,CAAA;AAChC,eAAO,MAAM,cAAc,aAAa,CAAA;AACxC,eAAO,MAAM,YAAY,WAAW,CAAA;AAEpC,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGpD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;WAGtD,MAAM;UACP,MAAM;gBACA,MAAM,GAAG,IAAI;cACf,MAAM,GAAG,IAAI;cACb,OAAO;IAcpB;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASjF;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,aAAa;;;;;;;cAI9B,MAAM;kBAAY,OAAO,GAAG,SAAS;cAAQ,MAAM;iBAAW,MAAM;;GA4CjG;AAED,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,aAAa;;;;;;;;;;eAjFtD,MAAM;cACP,MAAM;oBACA,MAAM,GAAG,IAAI;kBACf,MAAM,GAAG,IAAI;kBACb,OAAO;;;KAiGpB;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,aAAa;;GAiB3D;AAED,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,aAAa,EACvB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM;;;;GAmBhB"}