mindgraph-core 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.
Files changed (169) hide show
  1. package/dist/embeddings/embedder-interface.d.ts +15 -0
  2. package/dist/embeddings/embedder-interface.d.ts.map +1 -0
  3. package/dist/embeddings/embedder-interface.js +2 -0
  4. package/dist/embeddings/embedder-interface.js.map +1 -0
  5. package/dist/embeddings/ollama-embedder.d.ts +21 -0
  6. package/dist/embeddings/ollama-embedder.d.ts.map +1 -0
  7. package/dist/embeddings/ollama-embedder.js +78 -0
  8. package/dist/embeddings/ollama-embedder.js.map +1 -0
  9. package/dist/embeddings/transformers-embedder.d.ts +20 -0
  10. package/dist/embeddings/transformers-embedder.d.ts.map +1 -0
  11. package/dist/embeddings/transformers-embedder.js +61 -0
  12. package/dist/embeddings/transformers-embedder.js.map +1 -0
  13. package/dist/extraction/anthropic-extractor.d.ts +17 -0
  14. package/dist/extraction/anthropic-extractor.d.ts.map +1 -0
  15. package/dist/extraction/anthropic-extractor.js +43 -0
  16. package/dist/extraction/anthropic-extractor.js.map +1 -0
  17. package/dist/extraction/basic-extractor.d.ts +17 -0
  18. package/dist/extraction/basic-extractor.d.ts.map +1 -0
  19. package/dist/extraction/basic-extractor.js +135 -0
  20. package/dist/extraction/basic-extractor.js.map +1 -0
  21. package/dist/extraction/confidence-gate.d.ts +7 -0
  22. package/dist/extraction/confidence-gate.d.ts.map +1 -0
  23. package/dist/extraction/confidence-gate.js +13 -0
  24. package/dist/extraction/confidence-gate.js.map +1 -0
  25. package/dist/extraction/contradiction-detector.d.ts +46 -0
  26. package/dist/extraction/contradiction-detector.d.ts.map +1 -0
  27. package/dist/extraction/contradiction-detector.js +205 -0
  28. package/dist/extraction/contradiction-detector.js.map +1 -0
  29. package/dist/extraction/entity-index.d.ts +31 -0
  30. package/dist/extraction/entity-index.d.ts.map +1 -0
  31. package/dist/extraction/entity-index.js +90 -0
  32. package/dist/extraction/entity-index.js.map +1 -0
  33. package/dist/extraction/entity-resolver.d.ts +28 -0
  34. package/dist/extraction/entity-resolver.d.ts.map +1 -0
  35. package/dist/extraction/entity-resolver.js +111 -0
  36. package/dist/extraction/entity-resolver.js.map +1 -0
  37. package/dist/extraction/extractor-interface.d.ts +51 -0
  38. package/dist/extraction/extractor-interface.d.ts.map +1 -0
  39. package/dist/extraction/extractor-interface.js +2 -0
  40. package/dist/extraction/extractor-interface.js.map +1 -0
  41. package/dist/extraction/llm-extractor.d.ts +21 -0
  42. package/dist/extraction/llm-extractor.d.ts.map +1 -0
  43. package/dist/extraction/llm-extractor.js +97 -0
  44. package/dist/extraction/llm-extractor.js.map +1 -0
  45. package/dist/extraction/ollama-extractor.d.ts +18 -0
  46. package/dist/extraction/ollama-extractor.d.ts.map +1 -0
  47. package/dist/extraction/ollama-extractor.js +50 -0
  48. package/dist/extraction/ollama-extractor.js.map +1 -0
  49. package/dist/extraction/open-loop-detector.d.ts +24 -0
  50. package/dist/extraction/open-loop-detector.d.ts.map +1 -0
  51. package/dist/extraction/open-loop-detector.js +187 -0
  52. package/dist/extraction/open-loop-detector.js.map +1 -0
  53. package/dist/extraction/openai-extractor.d.ts +20 -0
  54. package/dist/extraction/openai-extractor.d.ts.map +1 -0
  55. package/dist/extraction/openai-extractor.js +44 -0
  56. package/dist/extraction/openai-extractor.js.map +1 -0
  57. package/dist/extraction/prompts/entity-extraction.d.ts +2 -0
  58. package/dist/extraction/prompts/entity-extraction.d.ts.map +1 -0
  59. package/dist/extraction/prompts/entity-extraction.js +42 -0
  60. package/dist/extraction/prompts/entity-extraction.js.map +1 -0
  61. package/dist/extraction/prompts/proposition-extraction.d.ts +2 -0
  62. package/dist/extraction/prompts/proposition-extraction.d.ts.map +1 -0
  63. package/dist/extraction/prompts/proposition-extraction.js +39 -0
  64. package/dist/extraction/prompts/proposition-extraction.js.map +1 -0
  65. package/dist/extraction/prompts/thought-extraction.d.ts +2 -0
  66. package/dist/extraction/prompts/thought-extraction.d.ts.map +1 -0
  67. package/dist/extraction/prompts/thought-extraction.js +41 -0
  68. package/dist/extraction/prompts/thought-extraction.js.map +1 -0
  69. package/dist/index.d.ts +41 -0
  70. package/dist/index.d.ts.map +1 -0
  71. package/dist/index.js +33 -0
  72. package/dist/index.js.map +1 -0
  73. package/dist/ingestion/chunk-id.d.ts +27 -0
  74. package/dist/ingestion/chunk-id.d.ts.map +1 -0
  75. package/dist/ingestion/chunk-id.js +45 -0
  76. package/dist/ingestion/chunk-id.js.map +1 -0
  77. package/dist/ingestion/chunker.d.ts +29 -0
  78. package/dist/ingestion/chunker.d.ts.map +1 -0
  79. package/dist/ingestion/chunker.js +182 -0
  80. package/dist/ingestion/chunker.js.map +1 -0
  81. package/dist/ingestion/hasher.d.ts +7 -0
  82. package/dist/ingestion/hasher.d.ts.map +1 -0
  83. package/dist/ingestion/hasher.js +18 -0
  84. package/dist/ingestion/hasher.js.map +1 -0
  85. package/dist/ingestion/pipeline.d.ts +58 -0
  86. package/dist/ingestion/pipeline.d.ts.map +1 -0
  87. package/dist/ingestion/pipeline.js +653 -0
  88. package/dist/ingestion/pipeline.js.map +1 -0
  89. package/dist/models/citation.d.ts +2 -0
  90. package/dist/models/citation.d.ts.map +1 -0
  91. package/dist/models/citation.js +2 -0
  92. package/dist/models/citation.js.map +1 -0
  93. package/dist/models/extraction-result.d.ts +2 -0
  94. package/dist/models/extraction-result.d.ts.map +1 -0
  95. package/dist/models/extraction-result.js +2 -0
  96. package/dist/models/extraction-result.js.map +1 -0
  97. package/dist/models/query-result.d.ts +2 -0
  98. package/dist/models/query-result.d.ts.map +1 -0
  99. package/dist/models/query-result.js +2 -0
  100. package/dist/models/query-result.js.map +1 -0
  101. package/dist/query/answer-builder.d.ts +15 -0
  102. package/dist/query/answer-builder.d.ts.map +1 -0
  103. package/dist/query/answer-builder.js +51 -0
  104. package/dist/query/answer-builder.js.map +1 -0
  105. package/dist/query/citation-builder.d.ts +19 -0
  106. package/dist/query/citation-builder.d.ts.map +1 -0
  107. package/dist/query/citation-builder.js +54 -0
  108. package/dist/query/citation-builder.js.map +1 -0
  109. package/dist/query/graph-data.d.ts +39 -0
  110. package/dist/query/graph-data.d.ts.map +1 -0
  111. package/dist/query/graph-data.js +115 -0
  112. package/dist/query/graph-data.js.map +1 -0
  113. package/dist/query/graph-search.d.ts +43 -0
  114. package/dist/query/graph-search.d.ts.map +1 -0
  115. package/dist/query/graph-search.js +315 -0
  116. package/dist/query/graph-search.js.map +1 -0
  117. package/dist/query/query-engine.d.ts +41 -0
  118. package/dist/query/query-engine.d.ts.map +1 -0
  119. package/dist/query/query-engine.js +178 -0
  120. package/dist/query/query-engine.js.map +1 -0
  121. package/dist/query/semantic-search.d.ts +26 -0
  122. package/dist/query/semantic-search.d.ts.map +1 -0
  123. package/dist/query/semantic-search.js +132 -0
  124. package/dist/query/semantic-search.js.map +1 -0
  125. package/dist/schema/edge-types.d.ts +95 -0
  126. package/dist/schema/edge-types.d.ts.map +1 -0
  127. package/dist/schema/edge-types.js +6 -0
  128. package/dist/schema/edge-types.js.map +1 -0
  129. package/dist/schema/node-types.d.ts +100 -0
  130. package/dist/schema/node-types.d.ts.map +1 -0
  131. package/dist/schema/node-types.js +6 -0
  132. package/dist/schema/node-types.js.map +1 -0
  133. package/dist/schema/types.d.ts +134 -0
  134. package/dist/schema/types.d.ts.map +1 -0
  135. package/dist/schema/types.js +52 -0
  136. package/dist/schema/types.js.map +1 -0
  137. package/dist/schema/validation.d.ts +6 -0
  138. package/dist/schema/validation.d.ts.map +1 -0
  139. package/dist/schema/validation.js +140 -0
  140. package/dist/schema/validation.js.map +1 -0
  141. package/dist/storage/export-import.d.ts +28 -0
  142. package/dist/storage/export-import.d.ts.map +1 -0
  143. package/dist/storage/export-import.js +189 -0
  144. package/dist/storage/export-import.js.map +1 -0
  145. package/dist/storage/memory/memory-adapter.d.ts +36 -0
  146. package/dist/storage/memory/memory-adapter.d.ts.map +1 -0
  147. package/dist/storage/memory/memory-adapter.js +231 -0
  148. package/dist/storage/memory/memory-adapter.js.map +1 -0
  149. package/dist/storage/sqlite/graph-traversal.d.ts +11 -0
  150. package/dist/storage/sqlite/graph-traversal.d.ts.map +1 -0
  151. package/dist/storage/sqlite/graph-traversal.js +79 -0
  152. package/dist/storage/sqlite/graph-traversal.js.map +1 -0
  153. package/dist/storage/sqlite/query-builder.d.ts +8 -0
  154. package/dist/storage/sqlite/query-builder.d.ts.map +1 -0
  155. package/dist/storage/sqlite/query-builder.js +55 -0
  156. package/dist/storage/sqlite/query-builder.js.map +1 -0
  157. package/dist/storage/sqlite/sqlite-adapter.d.ts +53 -0
  158. package/dist/storage/sqlite/sqlite-adapter.d.ts.map +1 -0
  159. package/dist/storage/sqlite/sqlite-adapter.js +497 -0
  160. package/dist/storage/sqlite/sqlite-adapter.js.map +1 -0
  161. package/dist/storage/storage-interface.d.ts +64 -0
  162. package/dist/storage/storage-interface.d.ts.map +1 -0
  163. package/dist/storage/storage-interface.js +2 -0
  164. package/dist/storage/storage-interface.js.map +1 -0
  165. package/dist/utils/retry-fetch.d.ts +20 -0
  166. package/dist/utils/retry-fetch.d.ts.map +1 -0
  167. package/dist/utils/retry-fetch.js +71 -0
  168. package/dist/utils/retry-fetch.js.map +1 -0
  169. package/package.json +28 -0
@@ -0,0 +1,205 @@
1
+ import { NodeType, RelType } from '../schema/types.js';
2
+ import { v4 as uuid } from 'uuid';
3
+ /**
4
+ * Detects contradictions between propositions.
5
+ * Strategy: embedding similarity to find candidates, then topic-grounding filter,
6
+ * then heuristic conflict check.
7
+ */
8
+ export class ContradictionDetector {
9
+ constructor(storage, embedder) {
10
+ this.storage = storage;
11
+ this.embedder = embedder;
12
+ }
13
+ /**
14
+ * Find propositions that may contradict the given proposition.
15
+ * Uses embedding similarity to find candidates about the same topic,
16
+ * then filters by shared ABOUT targets (topic grounding).
17
+ */
18
+ async findCandidates(propositionId, topK = 10, similarityThreshold = 0.6) {
19
+ const propNode = await this.storage.getNode(propositionId);
20
+ if (!propNode)
21
+ return [];
22
+ const propData = propNode.data;
23
+ if (!this.embedder) {
24
+ return this.findCandidatesByText(propNode, propData);
25
+ }
26
+ // Embed the proposition statement
27
+ const propVector = await this.embedder.embed(propData.statement);
28
+ // Find similar propositions by embedding
29
+ const allProps = await this.storage.queryNodes({
30
+ nodeType: NodeType.Proposition,
31
+ limit: 1000,
32
+ });
33
+ const candidates = [];
34
+ // Get ABOUT targets for this proposition
35
+ const propAboutTargets = await this.getAboutTargetIds(propositionId);
36
+ for (const otherProp of allProps) {
37
+ if (otherProp.id === propositionId)
38
+ continue;
39
+ const otherData = otherProp.data;
40
+ const otherVector = await this.embedder.embed(otherData.statement);
41
+ const similarity = cosineSimilarity(propVector, otherVector);
42
+ if (similarity >= similarityThreshold) {
43
+ // Topic-grounding filter: require shared ABOUT targets
44
+ const otherAboutTargets = await this.getAboutTargetIds(otherProp.id);
45
+ let sharedTargets = propAboutTargets.filter((t) => otherAboutTargets.includes(t));
46
+ // Fallback: shared MENTIONS overlap from source chunks when ABOUT is empty
47
+ if (sharedTargets.length === 0) {
48
+ sharedTargets = await this.getSharedMentionTargets(propositionId, otherProp.id);
49
+ }
50
+ // Skip if no shared topic grounding at all
51
+ if (sharedTargets.length === 0 && propAboutTargets.length > 0 && otherAboutTargets.length > 0) {
52
+ continue;
53
+ }
54
+ // Check for negation difference or opposing claims
55
+ const isLikelyContradiction = propData.isNegated !== otherData.isNegated ||
56
+ this.statementsConflict(propData.statement, otherData.statement);
57
+ if (isLikelyContradiction) {
58
+ candidates.push({
59
+ propositionA: propNode,
60
+ propositionB: otherProp,
61
+ similarityScore: similarity,
62
+ sharedTargets,
63
+ method: 'negation_heuristic',
64
+ evidence: {
65
+ p1Span: propData.statement.slice(0, 100),
66
+ p2Span: otherData.statement.slice(0, 100),
67
+ },
68
+ });
69
+ }
70
+ }
71
+ }
72
+ return candidates.sort((a, b) => b.similarityScore - a.similarityScore).slice(0, topK);
73
+ }
74
+ /**
75
+ * Create CONTRADICTS edges for confirmed contradictions with enriched data.
76
+ */
77
+ async createContradictionEdges(candidates) {
78
+ const edgeIds = [];
79
+ for (const candidate of candidates) {
80
+ const edgeId = `edge:contradicts:${uuid()}`;
81
+ const now = new Date().toISOString();
82
+ const edgeAB = {
83
+ id: edgeId,
84
+ sourceId: candidate.propositionA.id,
85
+ targetId: candidate.propositionB.id,
86
+ relType: RelType.CONTRADICTS,
87
+ data: {
88
+ strength: candidate.similarityScore,
89
+ method: candidate.method,
90
+ sharedTargets: candidate.sharedTargets,
91
+ evidence: candidate.evidence,
92
+ explanation: `Detected via ${candidate.method}: opposing claims with ${candidate.sharedTargets.length} shared topic(s)`,
93
+ },
94
+ createdAt: now,
95
+ };
96
+ await this.storage.upsertEdge(edgeAB);
97
+ edgeIds.push(edgeId);
98
+ }
99
+ return edgeIds;
100
+ }
101
+ /**
102
+ * Get ABOUT edge target IDs for a proposition.
103
+ */
104
+ async getAboutTargetIds(propId) {
105
+ const aboutEdges = await this.storage.queryEdges({
106
+ sourceId: propId,
107
+ relType: RelType.ABOUT,
108
+ });
109
+ return aboutEdges.map((e) => e.targetId);
110
+ }
111
+ /**
112
+ * Fallback: find shared entity/concept mentions from source chunks.
113
+ */
114
+ async getSharedMentionTargets(propAId, propBId) {
115
+ const chunkIdsA = await this.getSourceChunkIds(propAId);
116
+ const chunkIdsB = await this.getSourceChunkIds(propBId);
117
+ const mentionTargetsA = new Set();
118
+ for (const chunkId of chunkIdsA) {
119
+ const mentions = await this.storage.queryEdges({
120
+ sourceId: chunkId,
121
+ relType: RelType.MENTIONS,
122
+ });
123
+ for (const m of mentions)
124
+ mentionTargetsA.add(m.targetId);
125
+ }
126
+ const mentionTargetsB = new Set();
127
+ for (const chunkId of chunkIdsB) {
128
+ const mentions = await this.storage.queryEdges({
129
+ sourceId: chunkId,
130
+ relType: RelType.MENTIONS,
131
+ });
132
+ for (const m of mentions)
133
+ mentionTargetsB.add(m.targetId);
134
+ }
135
+ return [...mentionTargetsA].filter((t) => mentionTargetsB.has(t));
136
+ }
137
+ async getSourceChunkIds(propId) {
138
+ const derivedEdges = await this.storage.queryEdges({
139
+ sourceId: propId,
140
+ relType: RelType.DERIVED_FROM,
141
+ });
142
+ return derivedEdges.map((e) => e.targetId);
143
+ }
144
+ async findCandidatesByText(propNode, propData) {
145
+ const keywords = propData.statement
146
+ .toLowerCase()
147
+ .split(/\s+/)
148
+ .filter((w) => w.length > 3);
149
+ const allProps = await this.storage.queryNodes({
150
+ nodeType: NodeType.Proposition,
151
+ limit: 500,
152
+ });
153
+ const propAboutTargets = await this.getAboutTargetIds(propNode.id);
154
+ const candidates = [];
155
+ for (const otherProp of allProps) {
156
+ if (otherProp.id === propNode.id)
157
+ continue;
158
+ const otherData = otherProp.data;
159
+ const otherKeywords = otherData.statement
160
+ .toLowerCase()
161
+ .split(/\s+/)
162
+ .filter((w) => w.length > 3);
163
+ const overlap = keywords.filter((k) => otherKeywords.includes(k));
164
+ const overlapScore = overlap.length / Math.max(keywords.length, 1);
165
+ if (overlapScore > 0.3 && propData.isNegated !== otherData.isNegated) {
166
+ const otherAboutTargets = await this.getAboutTargetIds(otherProp.id);
167
+ let sharedTargets = propAboutTargets.filter((t) => otherAboutTargets.includes(t));
168
+ if (sharedTargets.length === 0) {
169
+ sharedTargets = await this.getSharedMentionTargets(propNode.id, otherProp.id);
170
+ }
171
+ candidates.push({
172
+ propositionA: propNode,
173
+ propositionB: otherProp,
174
+ similarityScore: overlapScore,
175
+ sharedTargets,
176
+ method: 'negation_heuristic',
177
+ evidence: {
178
+ p1Span: propData.statement.slice(0, 100),
179
+ p2Span: otherData.statement.slice(0, 100),
180
+ },
181
+ });
182
+ }
183
+ }
184
+ return candidates;
185
+ }
186
+ statementsConflict(a, b) {
187
+ const negationWords = ['not', 'never', "don't", "doesn't", "isn't", "aren't", "won't", "can't", 'no', 'neither', 'nor', 'without'];
188
+ const aWords = new Set(a.toLowerCase().split(/\s+/));
189
+ const bWords = new Set(b.toLowerCase().split(/\s+/));
190
+ const aNeg = negationWords.some((w) => aWords.has(w));
191
+ const bNeg = negationWords.some((w) => bWords.has(w));
192
+ return aNeg !== bNeg;
193
+ }
194
+ }
195
+ function cosineSimilarity(a, b) {
196
+ let dot = 0, normA = 0, normB = 0;
197
+ for (let i = 0; i < a.length; i++) {
198
+ dot += a[i] * b[i];
199
+ normA += a[i] * a[i];
200
+ normB += b[i] * b[i];
201
+ }
202
+ const denom = Math.sqrt(normA) * Math.sqrt(normB);
203
+ return denom === 0 ? 0 : dot / denom;
204
+ }
205
+ //# sourceMappingURL=contradiction-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contradiction-detector.js","sourceRoot":"","sources":["../../src/extraction/contradiction-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { StorageAdapter } from '../storage/storage-interface.js';
2
+ /**
3
+ * In-memory index mapping normalized names and aliases to entity/concept IDs.
4
+ * Loaded from storage once, then kept current as entities are stored.
5
+ */
6
+ export declare class EntityIndex {
7
+ private nameToId;
8
+ private aliasToId;
9
+ /**
10
+ * Populate the index from all existing entity and concept nodes in storage.
11
+ */
12
+ loadFromStorage(storage: StorageAdapter): Promise<void>;
13
+ /**
14
+ * Find an existing node ID that matches the given name or any of its aliases.
15
+ */
16
+ findMatch(name: string, aliases: string[]): string | null;
17
+ /**
18
+ * Register a node's name and aliases in the index.
19
+ */
20
+ register(nodeId: string, name: string, aliases: string[]): void;
21
+ /**
22
+ * Remove all index entries pointing to a given node ID.
23
+ */
24
+ remove(nodeId: string): void;
25
+ /**
26
+ * Clear all index entries.
27
+ */
28
+ clear(): void;
29
+ private normalize;
30
+ }
31
+ //# sourceMappingURL=entity-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-index.d.ts","sourceRoot":"","sources":["../../src/extraction/entity-index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAGtE;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,SAAS,CAA6B;IAE9C;;OAEG;IACG,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB7D;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI;IAmBzD;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI;IAO/D;;OAEG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAc5B;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb,OAAO,CAAC,SAAS;CAGlB"}
@@ -0,0 +1,90 @@
1
+ import { NodeType } from '../schema/types.js';
2
+ /**
3
+ * In-memory index mapping normalized names and aliases to entity/concept IDs.
4
+ * Loaded from storage once, then kept current as entities are stored.
5
+ */
6
+ export class EntityIndex {
7
+ constructor() {
8
+ this.nameToId = new Map(); // normalized name → node ID
9
+ this.aliasToId = new Map(); // normalized alias → node ID
10
+ }
11
+ /**
12
+ * Populate the index from all existing entity and concept nodes in storage.
13
+ */
14
+ async loadFromStorage(storage) {
15
+ const entities = await storage.queryNodes({ nodeType: NodeType.Entity });
16
+ for (const entity of entities) {
17
+ const data = entity.data;
18
+ const name = data.name;
19
+ const aliases = data.aliases ?? [];
20
+ this.register(entity.id, name, aliases);
21
+ }
22
+ const concepts = await storage.queryNodes({ nodeType: NodeType.Concept });
23
+ for (const concept of concepts) {
24
+ const data = concept.data;
25
+ const name = data.name;
26
+ const aliases = data.aliases ?? [];
27
+ this.register(concept.id, name, aliases);
28
+ }
29
+ }
30
+ /**
31
+ * Find an existing node ID that matches the given name or any of its aliases.
32
+ */
33
+ findMatch(name, aliases) {
34
+ const norm = this.normalize(name);
35
+ // Direct name match
36
+ if (this.nameToId.has(norm))
37
+ return this.nameToId.get(norm);
38
+ // Name matches an existing alias
39
+ if (this.aliasToId.has(norm))
40
+ return this.aliasToId.get(norm);
41
+ // Any of our aliases match an existing name or alias
42
+ for (const alias of aliases) {
43
+ const normAlias = this.normalize(alias);
44
+ if (this.nameToId.has(normAlias))
45
+ return this.nameToId.get(normAlias);
46
+ if (this.aliasToId.has(normAlias))
47
+ return this.aliasToId.get(normAlias);
48
+ }
49
+ return null;
50
+ }
51
+ /**
52
+ * Register a node's name and aliases in the index.
53
+ */
54
+ register(nodeId, name, aliases) {
55
+ this.nameToId.set(this.normalize(name), nodeId);
56
+ for (const alias of aliases) {
57
+ this.aliasToId.set(this.normalize(alias), nodeId);
58
+ }
59
+ }
60
+ /**
61
+ * Remove all index entries pointing to a given node ID.
62
+ */
63
+ remove(nodeId) {
64
+ const nameKeys = [];
65
+ for (const [key, id] of this.nameToId) {
66
+ if (id === nodeId)
67
+ nameKeys.push(key);
68
+ }
69
+ for (const key of nameKeys)
70
+ this.nameToId.delete(key);
71
+ const aliasKeys = [];
72
+ for (const [key, id] of this.aliasToId) {
73
+ if (id === nodeId)
74
+ aliasKeys.push(key);
75
+ }
76
+ for (const key of aliasKeys)
77
+ this.aliasToId.delete(key);
78
+ }
79
+ /**
80
+ * Clear all index entries.
81
+ */
82
+ clear() {
83
+ this.nameToId.clear();
84
+ this.aliasToId.clear();
85
+ }
86
+ normalize(name) {
87
+ return name.toLowerCase().replace(/[^a-z0-9]/g, '_').replace(/_+/g, '_').replace(/^_|_$/g, '');
88
+ }
89
+ }
90
+ //# sourceMappingURL=entity-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-index.js","sourceRoot":"","sources":["../../src/extraction/entity-index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { ExtractedEntity, ExtractedConcept } from './extractor-interface.js';
2
+ export declare class EntityResolver {
3
+ private entities;
4
+ private concepts;
5
+ /**
6
+ * Add entities from an extraction result.
7
+ * Merges with existing entries if names/aliases match.
8
+ */
9
+ addEntities(entities: ExtractedEntity[]): void;
10
+ /**
11
+ * Add concepts from an extraction result.
12
+ */
13
+ addConcepts(concepts: ExtractedConcept[]): void;
14
+ /**
15
+ * Get all resolved entities.
16
+ */
17
+ getResolvedEntities(): ExtractedEntity[];
18
+ /**
19
+ * Get all resolved concepts.
20
+ */
21
+ getResolvedConcepts(): ExtractedConcept[];
22
+ /**
23
+ * Reset the resolver state.
24
+ */
25
+ clear(): void;
26
+ private normalizeKey;
27
+ }
28
+ //# sourceMappingURL=entity-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-resolver.d.ts","sourceRoot":"","sources":["../../src/extraction/entity-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAuBlF,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAqC;IACrD,OAAO,CAAC,QAAQ,CAAsC;IAEtD;;;OAGG;IACH,WAAW,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,IAAI;IA2C9C;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,IAAI;IAwB/C;;OAEG;IACH,mBAAmB,IAAI,eAAe,EAAE;IAWxC;;OAEG;IACH,mBAAmB,IAAI,gBAAgB,EAAE;IASzC;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb,OAAO,CAAC,YAAY;CAGrB"}
@@ -0,0 +1,111 @@
1
+ export class EntityResolver {
2
+ constructor() {
3
+ this.entities = new Map();
4
+ this.concepts = new Map();
5
+ }
6
+ /**
7
+ * Add entities from an extraction result.
8
+ * Merges with existing entries if names/aliases match.
9
+ */
10
+ addEntities(entities) {
11
+ for (const entity of entities) {
12
+ const key = this.normalizeKey(entity.name);
13
+ const aliasKeys = entity.aliases.map((a) => this.normalizeKey(a));
14
+ // Check if any name or alias matches existing
15
+ let existing;
16
+ let existingKey;
17
+ for (const [k, v] of this.entities) {
18
+ if (k === key || aliasKeys.includes(k) || v.aliases.has(key)) {
19
+ existing = v;
20
+ existingKey = k;
21
+ break;
22
+ }
23
+ }
24
+ if (existing && existingKey) {
25
+ // Merge
26
+ existing.aliases.add(entity.name);
27
+ for (const alias of entity.aliases) {
28
+ existing.aliases.add(alias);
29
+ }
30
+ existing.aliases.delete(existing.canonicalName);
31
+ existing.confidence = Math.max(existing.confidence, entity.confidence);
32
+ if (entity.description && !existing.description) {
33
+ existing.description = entity.description;
34
+ }
35
+ existing.spans.push(...entity.spans);
36
+ }
37
+ else {
38
+ // New entity
39
+ this.entities.set(key, {
40
+ canonicalName: entity.name,
41
+ entityType: entity.entityType,
42
+ aliases: new Set(entity.aliases),
43
+ description: entity.description,
44
+ confidence: entity.confidence,
45
+ spans: [...entity.spans],
46
+ });
47
+ }
48
+ }
49
+ }
50
+ /**
51
+ * Add concepts from an extraction result.
52
+ */
53
+ addConcepts(concepts) {
54
+ for (const concept of concepts) {
55
+ const key = this.normalizeKey(concept.name);
56
+ const existing = this.concepts.get(key);
57
+ if (existing) {
58
+ existing.confidence = Math.max(existing.confidence, concept.confidence);
59
+ if (concept.description && !existing.description) {
60
+ existing.description = concept.description;
61
+ }
62
+ if (concept.domain && !existing.domain) {
63
+ existing.domain = concept.domain;
64
+ }
65
+ }
66
+ else {
67
+ this.concepts.set(key, {
68
+ canonicalName: concept.name,
69
+ domain: concept.domain,
70
+ description: concept.description,
71
+ confidence: concept.confidence,
72
+ });
73
+ }
74
+ }
75
+ }
76
+ /**
77
+ * Get all resolved entities.
78
+ */
79
+ getResolvedEntities() {
80
+ return Array.from(this.entities.values()).map((e) => ({
81
+ name: e.canonicalName,
82
+ entityType: e.entityType,
83
+ aliases: Array.from(e.aliases),
84
+ description: e.description,
85
+ confidence: e.confidence,
86
+ spans: e.spans,
87
+ }));
88
+ }
89
+ /**
90
+ * Get all resolved concepts.
91
+ */
92
+ getResolvedConcepts() {
93
+ return Array.from(this.concepts.values()).map((c) => ({
94
+ name: c.canonicalName,
95
+ domain: c.domain,
96
+ description: c.description,
97
+ confidence: c.confidence,
98
+ }));
99
+ }
100
+ /**
101
+ * Reset the resolver state.
102
+ */
103
+ clear() {
104
+ this.entities.clear();
105
+ this.concepts.clear();
106
+ }
107
+ normalizeKey(name) {
108
+ return name.toLowerCase().replace(/[^a-z0-9]/g, '_').replace(/_+/g, '_').replace(/^_|_$/g, '');
109
+ }
110
+ }
111
+ //# sourceMappingURL=entity-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-resolver.js","sourceRoot":"","sources":["../../src/extraction/entity-resolver.ts"],"names":[],"mappings":"AAuBA,MAAM,OAAO,cAAc;IAA3B;QACU,aAAQ,GAAG,IAAI,GAAG,EAA0B,CAAC;QAC7C,aAAQ,GAAG,IAAI,GAAG,EAA2B,CAAC;IAiHxD,CAAC;IA/GC;;;OAGG;IACH,WAAW,CAAC,QAA2B;QACrC,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC3C,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;YAElE,8CAA8C;YAC9C,IAAI,QAAoC,CAAC;YACzC,IAAI,WAA+B,CAAC;YAEpC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACnC,IAAI,CAAC,KAAK,GAAG,IAAI,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC7D,QAAQ,GAAG,CAAC,CAAC;oBACb,WAAW,GAAG,CAAC,CAAC;oBAChB,MAAM;gBACR,CAAC;YACH,CAAC;YAED,IAAI,QAAQ,IAAI,WAAW,EAAE,CAAC;gBAC5B,QAAQ;gBACR,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAClC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;oBACnC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBAC9B,CAAC;gBACD,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;gBAChD,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;gBACvE,IAAI,MAAM,CAAC,WAAW,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;oBAChD,QAAQ,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;gBAC5C,CAAC;gBACD,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YACvC,CAAC;iBAAM,CAAC;gBACN,aAAa;gBACb,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE;oBACrB,aAAa,EAAE,MAAM,CAAC,IAAI;oBAC1B,UAAU,EAAE,MAAM,CAAC,UAAU;oBAC7B,OAAO,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;oBAChC,WAAW,EAAE,MAAM,CAAC,WAAW;oBAC/B,UAAU,EAAE,MAAM,CAAC,UAAU;oBAC7B,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC;iBACzB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,QAA4B;QACtC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAExC,IAAI,QAAQ,EAAE,CAAC;gBACb,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;gBACxE,IAAI,OAAO,CAAC,WAAW,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;oBACjD,QAAQ,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;gBAC7C,CAAC;gBACD,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;oBACvC,QAAQ,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;gBACnC,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE;oBACrB,aAAa,EAAE,OAAO,CAAC,IAAI;oBAC3B,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,WAAW,EAAE,OAAO,CAAC,WAAW;oBAChC,UAAU,EAAE,OAAO,CAAC,UAAU;iBAC/B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,mBAAmB;QACjB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpD,IAAI,EAAE,CAAC,CAAC,aAAa;YACrB,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;YAC9B,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,KAAK,EAAE,CAAC,CAAC,KAAK;SACf,CAAC,CAAC,CAAC;IACN,CAAC;IAED;;OAEG;IACH,mBAAmB;QACjB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpD,IAAI,EAAE,CAAC,CAAC,aAAa;YACrB,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,UAAU,EAAE,CAAC,CAAC,UAAU;SACzB,CAAC,CAAC,CAAC;IACN,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IAEO,YAAY,CAAC,IAAY;QAC/B,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACjG,CAAC;CACF"}
@@ -0,0 +1,51 @@
1
+ import type { Chunk } from '../ingestion/chunker.js';
2
+ export interface ExtractedEntity {
3
+ name: string;
4
+ entityType: 'person' | 'organization' | 'product' | 'work' | 'other';
5
+ aliases: string[];
6
+ description: string;
7
+ confidence: number;
8
+ spans: Array<{
9
+ start: number;
10
+ end: number;
11
+ }>;
12
+ }
13
+ export interface ExtractedConcept {
14
+ name: string;
15
+ domain: string;
16
+ description: string;
17
+ confidence: number;
18
+ }
19
+ export interface ExtractedProposition {
20
+ statement: string;
21
+ domain: string;
22
+ confidence: number;
23
+ isNegated: boolean;
24
+ quoteText: string;
25
+ quoteStart: number;
26
+ quoteEnd: number;
27
+ }
28
+ export interface ExtractedThought {
29
+ statement: string;
30
+ stance: 'for' | 'against' | 'neutral';
31
+ subject: string;
32
+ confidence: number;
33
+ implications: string[];
34
+ quoteText: string;
35
+ quoteStart: number;
36
+ quoteEnd: number;
37
+ }
38
+ export interface ExtractionResult {
39
+ entities: ExtractedEntity[];
40
+ concepts: ExtractedConcept[];
41
+ propositions: ExtractedProposition[];
42
+ thoughts: ExtractedThought[];
43
+ }
44
+ export interface ExtractionProvider {
45
+ readonly name: string;
46
+ /** Check if this extractor is available. */
47
+ isAvailable(): Promise<boolean>;
48
+ /** Extract structured information from a chunk. */
49
+ extract(chunk: Chunk, noteContent: string): Promise<ExtractionResult>;
50
+ }
51
+ //# sourceMappingURL=extractor-interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor-interface.d.ts","sourceRoot":"","sources":["../../src/extraction/extractor-interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,QAAQ,GAAG,cAAc,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IACrE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,KAAK,GAAG,SAAS,GAAG,SAAS,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,YAAY,EAAE,oBAAoB,EAAE,CAAC;IACrC,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,4CAA4C;IAC5C,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAEhC,mDAAmD;IACnD,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;CACvE"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=extractor-interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor-interface.js","sourceRoot":"","sources":["../../src/extraction/extractor-interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ import type { Chunk } from '../ingestion/chunker.js';
2
+ import type { ExtractionProvider, ExtractionResult, ExtractedEntity, ExtractedConcept, ExtractedProposition, ExtractedThought } from './extractor-interface.js';
3
+ /**
4
+ * Abstract base class for LLM-based extractors.
5
+ * Contains shared extraction/parsing logic; subclasses implement callLLM() and isAvailable().
6
+ */
7
+ export declare abstract class LLMExtractor implements ExtractionProvider {
8
+ abstract readonly name: string;
9
+ abstract isAvailable(): Promise<boolean>;
10
+ protected abstract callLLM(prompt: string): Promise<string>;
11
+ extract(chunk: Chunk, _noteContent: string): Promise<ExtractionResult>;
12
+ protected extractEntitiesAndConcepts(chunk: Chunk): Promise<{
13
+ entities: ExtractedEntity[];
14
+ concepts: ExtractedConcept[];
15
+ }>;
16
+ protected extractPropositions(chunk: Chunk): Promise<ExtractedProposition[]>;
17
+ protected extractThoughts(chunk: Chunk): Promise<ExtractedThought[]>;
18
+ /** Strip markdown code fences that some LLMs wrap JSON in. */
19
+ protected stripCodeFences(text: string): string;
20
+ }
21
+ //# sourceMappingURL=llm-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-extractor.d.ts","sourceRoot":"","sources":["../../src/extraction/llm-extractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EACjB,MAAM,0BAA0B,CAAC;AAKlC;;;GAGG;AACH,8BAAsB,YAAa,YAAW,kBAAkB;IAC9D,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAE/B,QAAQ,CAAC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAExC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAErD,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;cAmB5D,0BAA0B,CACxC,KAAK,EAAE,KAAK,GACX,OAAO,CAAC;QAAE,QAAQ,EAAE,eAAe,EAAE,CAAC;QAAC,QAAQ,EAAE,gBAAgB,EAAE,CAAA;KAAE,CAAC;cA2BzD,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;cAoBlE,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAuB1E,8DAA8D;IAC9D,SAAS,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CAOhD"}