stellar-memory 0.5.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 (197) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +362 -0
  3. package/dist/api/routes/analytics.d.ts +15 -0
  4. package/dist/api/routes/analytics.js +131 -0
  5. package/dist/api/routes/analytics.js.map +1 -0
  6. package/dist/api/routes/conflicts.d.ts +12 -0
  7. package/dist/api/routes/conflicts.js +67 -0
  8. package/dist/api/routes/conflicts.js.map +1 -0
  9. package/dist/api/routes/consolidation.d.ts +11 -0
  10. package/dist/api/routes/consolidation.js +63 -0
  11. package/dist/api/routes/consolidation.js.map +1 -0
  12. package/dist/api/routes/constellation.d.ts +4 -0
  13. package/dist/api/routes/constellation.js +84 -0
  14. package/dist/api/routes/constellation.js.map +1 -0
  15. package/dist/api/routes/memories.d.ts +4 -0
  16. package/dist/api/routes/memories.js +219 -0
  17. package/dist/api/routes/memories.js.map +1 -0
  18. package/dist/api/routes/observations.d.ts +10 -0
  19. package/dist/api/routes/observations.js +42 -0
  20. package/dist/api/routes/observations.js.map +1 -0
  21. package/dist/api/routes/orbit.d.ts +4 -0
  22. package/dist/api/routes/orbit.js +71 -0
  23. package/dist/api/routes/orbit.js.map +1 -0
  24. package/dist/api/routes/projects.d.ts +15 -0
  25. package/dist/api/routes/projects.js +121 -0
  26. package/dist/api/routes/projects.js.map +1 -0
  27. package/dist/api/routes/scan.d.ts +4 -0
  28. package/dist/api/routes/scan.js +403 -0
  29. package/dist/api/routes/scan.js.map +1 -0
  30. package/dist/api/routes/sun.d.ts +4 -0
  31. package/dist/api/routes/sun.js +43 -0
  32. package/dist/api/routes/sun.js.map +1 -0
  33. package/dist/api/routes/system.d.ts +4 -0
  34. package/dist/api/routes/system.js +70 -0
  35. package/dist/api/routes/system.js.map +1 -0
  36. package/dist/api/routes/temporal.d.ts +13 -0
  37. package/dist/api/routes/temporal.js +82 -0
  38. package/dist/api/routes/temporal.js.map +1 -0
  39. package/dist/api/server.d.ts +2 -0
  40. package/dist/api/server.js +99 -0
  41. package/dist/api/server.js.map +1 -0
  42. package/dist/api/websocket.d.ts +53 -0
  43. package/dist/api/websocket.js +168 -0
  44. package/dist/api/websocket.js.map +1 -0
  45. package/dist/cli/index.d.ts +12 -0
  46. package/dist/cli/index.js +35 -0
  47. package/dist/cli/index.js.map +1 -0
  48. package/dist/cli/init.d.ts +10 -0
  49. package/dist/cli/init.js +163 -0
  50. package/dist/cli/init.js.map +1 -0
  51. package/dist/engine/analytics.d.ts +93 -0
  52. package/dist/engine/analytics.js +437 -0
  53. package/dist/engine/analytics.js.map +1 -0
  54. package/dist/engine/conflict.d.ts +54 -0
  55. package/dist/engine/conflict.js +322 -0
  56. package/dist/engine/conflict.js.map +1 -0
  57. package/dist/engine/consolidation.d.ts +83 -0
  58. package/dist/engine/consolidation.js +368 -0
  59. package/dist/engine/consolidation.js.map +1 -0
  60. package/dist/engine/constellation.d.ts +66 -0
  61. package/dist/engine/constellation.js +382 -0
  62. package/dist/engine/constellation.js.map +1 -0
  63. package/dist/engine/corona.d.ts +53 -0
  64. package/dist/engine/corona.js +181 -0
  65. package/dist/engine/corona.js.map +1 -0
  66. package/dist/engine/embedding.d.ts +44 -0
  67. package/dist/engine/embedding.js +168 -0
  68. package/dist/engine/embedding.js.map +1 -0
  69. package/dist/engine/gravity.d.ts +63 -0
  70. package/dist/engine/gravity.js +121 -0
  71. package/dist/engine/gravity.js.map +1 -0
  72. package/dist/engine/multiproject.d.ts +75 -0
  73. package/dist/engine/multiproject.js +241 -0
  74. package/dist/engine/multiproject.js.map +1 -0
  75. package/dist/engine/observation.d.ts +82 -0
  76. package/dist/engine/observation.js +357 -0
  77. package/dist/engine/observation.js.map +1 -0
  78. package/dist/engine/orbit.d.ts +91 -0
  79. package/dist/engine/orbit.js +249 -0
  80. package/dist/engine/orbit.js.map +1 -0
  81. package/dist/engine/planet.d.ts +64 -0
  82. package/dist/engine/planet.js +432 -0
  83. package/dist/engine/planet.js.map +1 -0
  84. package/dist/engine/procedural.d.ts +71 -0
  85. package/dist/engine/procedural.js +259 -0
  86. package/dist/engine/procedural.js.map +1 -0
  87. package/dist/engine/quality.d.ts +48 -0
  88. package/dist/engine/quality.js +245 -0
  89. package/dist/engine/quality.js.map +1 -0
  90. package/dist/engine/repository.d.ts +79 -0
  91. package/dist/engine/repository.js +13 -0
  92. package/dist/engine/repository.js.map +1 -0
  93. package/dist/engine/sun.d.ts +61 -0
  94. package/dist/engine/sun.js +240 -0
  95. package/dist/engine/sun.js.map +1 -0
  96. package/dist/engine/temporal.d.ts +67 -0
  97. package/dist/engine/temporal.js +283 -0
  98. package/dist/engine/temporal.js.map +1 -0
  99. package/dist/engine/types.d.ts +179 -0
  100. package/dist/engine/types.js +27 -0
  101. package/dist/engine/types.js.map +1 -0
  102. package/dist/index.d.ts +2 -0
  103. package/dist/index.js +60 -0
  104. package/dist/index.js.map +1 -0
  105. package/dist/mcp/connector-registry.d.ts +20 -0
  106. package/dist/mcp/connector-registry.js +35 -0
  107. package/dist/mcp/connector-registry.js.map +1 -0
  108. package/dist/mcp/server.d.ts +13 -0
  109. package/dist/mcp/server.js +242 -0
  110. package/dist/mcp/server.js.map +1 -0
  111. package/dist/mcp/tools/daemon-tool.d.ts +16 -0
  112. package/dist/mcp/tools/daemon-tool.js +58 -0
  113. package/dist/mcp/tools/daemon-tool.js.map +1 -0
  114. package/dist/mcp/tools/ingestion-tools.d.ts +20 -0
  115. package/dist/mcp/tools/ingestion-tools.js +34 -0
  116. package/dist/mcp/tools/ingestion-tools.js.map +1 -0
  117. package/dist/mcp/tools/memory-tools.d.ts +122 -0
  118. package/dist/mcp/tools/memory-tools.js +1037 -0
  119. package/dist/mcp/tools/memory-tools.js.map +1 -0
  120. package/dist/scanner/cloud/github.d.ts +34 -0
  121. package/dist/scanner/cloud/github.js +260 -0
  122. package/dist/scanner/cloud/github.js.map +1 -0
  123. package/dist/scanner/cloud/google-drive.d.ts +30 -0
  124. package/dist/scanner/cloud/google-drive.js +289 -0
  125. package/dist/scanner/cloud/google-drive.js.map +1 -0
  126. package/dist/scanner/cloud/notion.d.ts +33 -0
  127. package/dist/scanner/cloud/notion.js +231 -0
  128. package/dist/scanner/cloud/notion.js.map +1 -0
  129. package/dist/scanner/cloud/slack.d.ts +38 -0
  130. package/dist/scanner/cloud/slack.js +282 -0
  131. package/dist/scanner/cloud/slack.js.map +1 -0
  132. package/dist/scanner/cloud/types.d.ts +73 -0
  133. package/dist/scanner/cloud/types.js +9 -0
  134. package/dist/scanner/cloud/types.js.map +1 -0
  135. package/dist/scanner/index.d.ts +35 -0
  136. package/dist/scanner/index.js +420 -0
  137. package/dist/scanner/index.js.map +1 -0
  138. package/dist/scanner/local/filesystem.d.ts +33 -0
  139. package/dist/scanner/local/filesystem.js +203 -0
  140. package/dist/scanner/local/filesystem.js.map +1 -0
  141. package/dist/scanner/local/git.d.ts +24 -0
  142. package/dist/scanner/local/git.js +161 -0
  143. package/dist/scanner/local/git.js.map +1 -0
  144. package/dist/scanner/local/parsers/code.d.ts +3 -0
  145. package/dist/scanner/local/parsers/code.js +127 -0
  146. package/dist/scanner/local/parsers/code.js.map +1 -0
  147. package/dist/scanner/local/parsers/index.d.ts +11 -0
  148. package/dist/scanner/local/parsers/index.js +24 -0
  149. package/dist/scanner/local/parsers/index.js.map +1 -0
  150. package/dist/scanner/local/parsers/json-parser.d.ts +3 -0
  151. package/dist/scanner/local/parsers/json-parser.js +117 -0
  152. package/dist/scanner/local/parsers/json-parser.js.map +1 -0
  153. package/dist/scanner/local/parsers/markdown.d.ts +3 -0
  154. package/dist/scanner/local/parsers/markdown.js +120 -0
  155. package/dist/scanner/local/parsers/markdown.js.map +1 -0
  156. package/dist/scanner/local/parsers/text.d.ts +3 -0
  157. package/dist/scanner/local/parsers/text.js +41 -0
  158. package/dist/scanner/local/parsers/text.js.map +1 -0
  159. package/dist/scanner/metadata-scanner.d.ts +67 -0
  160. package/dist/scanner/metadata-scanner.js +356 -0
  161. package/dist/scanner/metadata-scanner.js.map +1 -0
  162. package/dist/scanner/types.d.ts +47 -0
  163. package/dist/scanner/types.js +19 -0
  164. package/dist/scanner/types.js.map +1 -0
  165. package/dist/service/daemon.d.ts +23 -0
  166. package/dist/service/daemon.js +105 -0
  167. package/dist/service/daemon.js.map +1 -0
  168. package/dist/service/scheduler.d.ts +73 -0
  169. package/dist/service/scheduler.js +281 -0
  170. package/dist/service/scheduler.js.map +1 -0
  171. package/dist/storage/database.d.ts +10 -0
  172. package/dist/storage/database.js +265 -0
  173. package/dist/storage/database.js.map +1 -0
  174. package/dist/storage/queries.d.ts +85 -0
  175. package/dist/storage/queries.js +865 -0
  176. package/dist/storage/queries.js.map +1 -0
  177. package/dist/storage/sqlite-repository.d.ts +32 -0
  178. package/dist/storage/sqlite-repository.js +68 -0
  179. package/dist/storage/sqlite-repository.js.map +1 -0
  180. package/dist/storage/vec.d.ts +62 -0
  181. package/dist/storage/vec.js +111 -0
  182. package/dist/storage/vec.js.map +1 -0
  183. package/dist/utils/config.d.ts +5 -0
  184. package/dist/utils/config.js +60 -0
  185. package/dist/utils/config.js.map +1 -0
  186. package/dist/utils/logger.d.ts +36 -0
  187. package/dist/utils/logger.js +86 -0
  188. package/dist/utils/logger.js.map +1 -0
  189. package/dist/utils/time.d.ts +21 -0
  190. package/dist/utils/time.js +42 -0
  191. package/dist/utils/time.js.map +1 -0
  192. package/dist/utils/tokenizer.d.ts +13 -0
  193. package/dist/utils/tokenizer.js +46 -0
  194. package/dist/utils/tokenizer.js.map +1 -0
  195. package/package.json +77 -0
  196. package/scripts/check-node.mjs +36 -0
  197. package/scripts/setup.mjs +157 -0
@@ -0,0 +1,382 @@
1
+ /**
2
+ * constellation.ts — Knowledge Graph engine module
3
+ *
4
+ * Memories form a "constellation" — a graph where edges represent semantic
5
+ * and structural relationships between memory planets.
6
+ *
7
+ * Relationships are inferred using fast, local keyword heuristics:
8
+ * - Type-based rules (error → decision = caused_by, etc.)
9
+ * - Contradiction detection (negation/replacement keywords near shared terms)
10
+ * - Content reference detection (one memory's text mentions another's keywords)
11
+ * - Shared tag overlap (same domain/topic)
12
+ * - Default fallback: related_to
13
+ *
14
+ * All functions are synchronous except extractRelationships, which is async
15
+ * because it may use vector similarity as the primary similarity signal.
16
+ */
17
+ import { randomUUID } from 'node:crypto';
18
+ import { createEdge, getEdges, getConstellation, deleteEdge, getMemoryByIds, searchMemories, } from '../storage/queries.js';
19
+ import { getDatabase } from '../storage/database.js';
20
+ import { generateEmbedding } from './embedding.js';
21
+ import { searchByVector } from '../storage/vec.js';
22
+ import { createLogger } from '../utils/logger.js';
23
+ const log = createLogger('constellation');
24
+ /** Minimum similarity weight required to create an edge. */
25
+ const WEIGHT_THRESHOLD = 0.3;
26
+ /** Maximum number of similar memories to evaluate per new memory. */
27
+ const TOP_K = 5;
28
+ // ---------------------------------------------------------------------------
29
+ // Relationship inference
30
+ // ---------------------------------------------------------------------------
31
+ /**
32
+ * Negation and replacement signal words. If both memories share a significant
33
+ * keyword AND one of them contains these signals near that keyword, the
34
+ * relationship is likely a contradiction.
35
+ */
36
+ const CONTRADICTION_SIGNALS = [
37
+ 'instead', 'replaced', 'switched', 'no longer', 'not ', "don't", "doesn't",
38
+ 'removed', 'deprecated', 'reverted', 'cancelled', 'abandoned',
39
+ '대신', '변경', '제거', '취소', '중단', '아님',
40
+ ];
41
+ /** Keywords that suggest one memory uses/depends-on another. */
42
+ const DEPENDENCY_SIGNALS = [
43
+ 'uses', 'using', 'depends on', 'requires', 'needs', 'via', 'through',
44
+ 'built on', 'extends', 'imports', 'calls', 'powered by',
45
+ '사용', '의존', '필요', '통해', '기반',
46
+ ];
47
+ /**
48
+ * Extract significant keywords from text — words longer than 3 characters,
49
+ * lowercased, de-duplicated, with common stop-words removed.
50
+ */
51
+ function extractKeywords(text) {
52
+ const STOP_WORDS = new Set([
53
+ 'the', 'and', 'for', 'that', 'with', 'this', 'from', 'have', 'will',
54
+ 'been', 'when', 'then', 'than', 'into', 'also', 'some', 'more', 'each',
55
+ 'they', 'were', 'their', 'what', 'which', 'about',
56
+ ]);
57
+ const words = text
58
+ .toLowerCase()
59
+ .replace(/[^a-z0-9가-힣\s]/g, ' ')
60
+ .split(/\s+/)
61
+ .filter(w => w.length > 3 && !STOP_WORDS.has(w));
62
+ return new Set(words);
63
+ }
64
+ /**
65
+ * Compute the Jaccard-like overlap ratio between two keyword sets.
66
+ * Returns 0.0–1.0.
67
+ */
68
+ function keywordOverlap(a, b) {
69
+ if (a.size === 0 || b.size === 0)
70
+ return 0;
71
+ let shared = 0;
72
+ for (const w of a) {
73
+ if (b.has(w))
74
+ shared++;
75
+ }
76
+ const union = a.size + b.size - shared;
77
+ return union === 0 ? 0 : shared / union;
78
+ }
79
+ /**
80
+ * Return true if one content string contains contradiction signals near a
81
+ * keyword that the other string also contains.
82
+ */
83
+ function hasContradictionSignals(a, b) {
84
+ const aLow = a.toLowerCase();
85
+ const bLow = b.toLowerCase();
86
+ const keywordsA = extractKeywords(a);
87
+ const keywordsB = extractKeywords(b);
88
+ // Find shared keywords
89
+ const shared = [];
90
+ for (const w of keywordsA) {
91
+ if (keywordsB.has(w))
92
+ shared.push(w);
93
+ }
94
+ if (shared.length === 0)
95
+ return false;
96
+ // For each shared keyword, check if a contradiction signal appears nearby
97
+ // in either string (within a 60-character window around the keyword).
98
+ for (const keyword of shared) {
99
+ for (const text of [aLow, bLow]) {
100
+ const idx = text.indexOf(keyword);
101
+ if (idx === -1)
102
+ continue;
103
+ const window = text.slice(Math.max(0, idx - 60), idx + keyword.length + 60);
104
+ for (const signal of CONTRADICTION_SIGNALS) {
105
+ if (window.includes(signal))
106
+ return true;
107
+ }
108
+ }
109
+ }
110
+ return false;
111
+ }
112
+ /**
113
+ * Return true if `sourceContent` references key terms from `targetSummary`.
114
+ * This indicates a "uses" or "depends_on" relationship.
115
+ */
116
+ function contentReferences(sourceContent, targetSummary) {
117
+ const srcLow = sourceContent.toLowerCase();
118
+ const targetKeywords = extractKeywords(targetSummary);
119
+ // Must share at least 2 keywords AND have a dependency signal
120
+ const sharedCount = [...targetKeywords].filter(w => srcLow.includes(w)).length;
121
+ if (sharedCount < 2)
122
+ return false;
123
+ for (const signal of DEPENDENCY_SIGNALS) {
124
+ if (srcLow.includes(signal))
125
+ return true;
126
+ }
127
+ return false;
128
+ }
129
+ /**
130
+ * Return true if source and target have meaningful tag overlap (≥ 1 shared tag).
131
+ */
132
+ function hasSharedTags(source, target) {
133
+ if (source.tags.length === 0 || target.tags.length === 0)
134
+ return false;
135
+ const targetTags = new Set(target.tags.map(t => t.toLowerCase()));
136
+ return source.tags.some(t => targetTags.has(t.toLowerCase()));
137
+ }
138
+ /**
139
+ * Infer the most appropriate RelationType between a source and a target memory
140
+ * using type-based rules and keyword heuristics.
141
+ */
142
+ function inferRelationType(source, target) {
143
+ // ── Type-based structural rules ───────────────────────────────────────────
144
+ if (source.type === 'error' && target.type === 'decision')
145
+ return 'caused_by';
146
+ if (source.type === 'decision' && target.type === 'error')
147
+ return 'caused_by';
148
+ if (source.type === 'milestone' && target.type === 'task')
149
+ return 'derived_from';
150
+ if (source.type === 'task' && target.type === 'milestone')
151
+ return 'part_of';
152
+ if (source.type === 'decision' && target.type === 'decision') {
153
+ if (hasContradictionSignals(source.content, target.content))
154
+ return 'contradicts';
155
+ return 'related_to';
156
+ }
157
+ if (source.type === 'context' && target.type === 'decision')
158
+ return 'part_of';
159
+ // ── Content-based heuristics ──────────────────────────────────────────────
160
+ if (contentReferences(source.content, target.summary))
161
+ return 'uses';
162
+ if (contentReferences(target.content, source.summary))
163
+ return 'depends_on';
164
+ if (hasContradictionSignals(source.content, target.content))
165
+ return 'contradicts';
166
+ return 'related_to';
167
+ }
168
+ // ---------------------------------------------------------------------------
169
+ // extractRelationships — primary public function
170
+ // ---------------------------------------------------------------------------
171
+ /**
172
+ * Auto-extract relationships for a newly stored memory.
173
+ *
174
+ * Algorithm:
175
+ * 1. Find the top-K most similar existing memories using vector KNN if
176
+ * available, falling back to FTS5 keyword search.
177
+ * 2. For each candidate, compute a weight (cosine similarity or keyword
178
+ * overlap ratio).
179
+ * 3. Filter candidates below WEIGHT_THRESHOLD.
180
+ * 4. Infer the relationship type using keyword heuristics.
181
+ * 5. Persist edges via queries.createEdge().
182
+ *
183
+ * Returns the list of edges that were created.
184
+ */
185
+ export async function extractRelationships(newMemory, project) {
186
+ const created = [];
187
+ // ── 1. Candidate retrieval ────────────────────────────────────────────────
188
+ let candidates = [];
189
+ try {
190
+ const db = getDatabase();
191
+ const queryText = newMemory.content + ' ' + newMemory.summary;
192
+ const embedding = await generateEmbedding(queryText);
193
+ const vecResults = searchByVector(db, embedding, TOP_K + 1); // +1 to exclude self
194
+ const ids = vecResults
195
+ .map(r => r.memoryId)
196
+ .filter(id => id !== newMemory.id)
197
+ .slice(0, TOP_K);
198
+ if (ids.length > 0) {
199
+ const memories = getMemoryByIds(ids);
200
+ const idToDistance = new Map(vecResults.map(r => [r.memoryId, r.distance]));
201
+ for (const mem of memories) {
202
+ if (mem.id === newMemory.id)
203
+ continue;
204
+ // sqlite-vec returns L2 distance — convert to a 0–1 similarity score.
205
+ // L2 distance for unit vectors ranges 0–2; we rescale to [0,1].
206
+ const l2 = idToDistance.get(mem.id) ?? 2;
207
+ const similarity = Math.max(0, 1 - l2 / 2);
208
+ candidates.push({ memory: mem, weight: similarity });
209
+ }
210
+ }
211
+ }
212
+ catch {
213
+ // Vector search unavailable — fall back to FTS5
214
+ log.debug('Vector search unavailable, falling back to FTS5', { memoryId: newMemory.id });
215
+ }
216
+ // FTS5 fallback (or supplement when vector returns too few results)
217
+ if (candidates.length < TOP_K) {
218
+ const ftsQuery = newMemory.summary || newMemory.content.slice(0, 100);
219
+ const ftsResults = searchMemories(project, ftsQuery, TOP_K + 1);
220
+ const existingIds = new Set([newMemory.id, ...candidates.map(c => c.memory.id)]);
221
+ for (const mem of ftsResults) {
222
+ if (existingIds.has(mem.id))
223
+ continue;
224
+ const srcKw = extractKeywords(newMemory.content);
225
+ const tgtKw = extractKeywords(mem.content);
226
+ const weight = keywordOverlap(srcKw, tgtKw);
227
+ candidates.push({ memory: mem, weight });
228
+ existingIds.add(mem.id);
229
+ if (candidates.length >= TOP_K)
230
+ break;
231
+ }
232
+ }
233
+ // ── 2. Filter + deduplicate ───────────────────────────────────────────────
234
+ candidates = candidates
235
+ .filter(c => c.weight >= WEIGHT_THRESHOLD)
236
+ .sort((a, b) => b.weight - a.weight)
237
+ .slice(0, TOP_K);
238
+ // ── 3. Infer & persist edges ──────────────────────────────────────────────
239
+ const now = new Date().toISOString();
240
+ for (const { memory: target, weight } of candidates) {
241
+ const relation = inferRelationType(newMemory, target);
242
+ const edge = {
243
+ id: randomUUID(),
244
+ source_id: newMemory.id,
245
+ target_id: target.id,
246
+ relation,
247
+ weight: Math.round(weight * 1000) / 1000, // round to 3 decimal places
248
+ project,
249
+ created_at: now,
250
+ metadata: {},
251
+ };
252
+ try {
253
+ createEdge(edge);
254
+ created.push(edge);
255
+ log.debug('Constellation edge created', {
256
+ source: newMemory.id,
257
+ target: target.id,
258
+ relation,
259
+ weight: edge.weight,
260
+ });
261
+ }
262
+ catch (err) {
263
+ log.warn('Failed to create constellation edge', { err, source: newMemory.id, target: target.id });
264
+ }
265
+ }
266
+ return created;
267
+ }
268
+ // ---------------------------------------------------------------------------
269
+ // getConstellationGraph
270
+ // ---------------------------------------------------------------------------
271
+ /**
272
+ * Return the full constellation graph (nodes + edges) centred on a memory.
273
+ *
274
+ * Uses queries.getConstellation() which handles multi-depth BFS traversal
275
+ * and deduplication internally. Depth defaults to 1 (immediate neighbours).
276
+ */
277
+ export function getConstellationGraph(memoryId, project, depth = 1) {
278
+ return getConstellation(memoryId, project, depth);
279
+ }
280
+ // ---------------------------------------------------------------------------
281
+ // findRelatedMemories
282
+ // ---------------------------------------------------------------------------
283
+ /**
284
+ * Return the top N memories most strongly connected to the given memory,
285
+ * sorted by edge weight (descending).
286
+ *
287
+ * Useful for augmenting recall results with graph-traversal neighbours.
288
+ */
289
+ export function findRelatedMemories(memoryId, project, limit = 10) {
290
+ const edges = getEdges(memoryId, project);
291
+ if (edges.length === 0)
292
+ return [];
293
+ // Collect the IDs of connected memories (excluding memoryId itself)
294
+ const weightById = new Map();
295
+ for (const edge of edges) {
296
+ const connectedId = edge.source_id === memoryId ? edge.target_id : edge.source_id;
297
+ // Keep the highest weight if the same memory appears in multiple edges
298
+ const existing = weightById.get(connectedId) ?? 0;
299
+ if (edge.weight > existing) {
300
+ weightById.set(connectedId, edge.weight);
301
+ }
302
+ }
303
+ // Sort by weight descending, take top N
304
+ const sortedIds = [...weightById.entries()]
305
+ .sort((a, b) => b[1] - a[1])
306
+ .slice(0, limit)
307
+ .map(([id]) => id);
308
+ if (sortedIds.length === 0)
309
+ return [];
310
+ const memories = getMemoryByIds(sortedIds);
311
+ // Preserve the weight-sorted order
312
+ const idOrder = new Map(sortedIds.map((id, i) => [id, i]));
313
+ return memories.sort((a, b) => (idOrder.get(a.id) ?? 0) - (idOrder.get(b.id) ?? 0));
314
+ }
315
+ // ---------------------------------------------------------------------------
316
+ // suggestRelationships
317
+ // ---------------------------------------------------------------------------
318
+ /**
319
+ * Suggest potential relationships for an existing memory without persisting them.
320
+ * Useful for a "review" UI where a user can approve/reject suggestions.
321
+ *
322
+ * Returns candidates sorted by confidence (descending).
323
+ */
324
+ export function suggestRelationships(memoryId, project) {
325
+ // Get the source memory from the constellation graph (depth 0 = just the node)
326
+ const { nodes } = getConstellation(memoryId, project, 0);
327
+ const source = nodes.find(n => n.id === memoryId);
328
+ if (!source)
329
+ return [];
330
+ // Use FTS5 to find candidate memories to evaluate
331
+ const ftsQuery = source.summary || source.content.slice(0, 100);
332
+ const candidates = searchMemories(project, ftsQuery, 20);
333
+ // Get already-existing edge targets so we can exclude them
334
+ const existingEdges = getEdges(memoryId, project);
335
+ const alreadyLinked = new Set([
336
+ memoryId,
337
+ ...existingEdges.map(e => (e.source_id === memoryId ? e.target_id : e.source_id)),
338
+ ]);
339
+ const suggestions = [];
340
+ const srcKw = extractKeywords(source.content);
341
+ for (const candidate of candidates) {
342
+ if (alreadyLinked.has(candidate.id))
343
+ continue;
344
+ const tgtKw = extractKeywords(candidate.content);
345
+ const confidence = keywordOverlap(srcKw, tgtKw);
346
+ if (confidence < WEIGHT_THRESHOLD)
347
+ continue;
348
+ const suggestedRelation = inferRelationType(source, candidate);
349
+ suggestions.push({ target: candidate, suggestedRelation, confidence });
350
+ }
351
+ return suggestions
352
+ .sort((a, b) => b.confidence - a.confidence)
353
+ .slice(0, 10);
354
+ }
355
+ // ---------------------------------------------------------------------------
356
+ // cleanupEdges
357
+ // ---------------------------------------------------------------------------
358
+ /**
359
+ * Remove all constellation edges that reference the given memory ID.
360
+ * Should be called when a memory is deleted to prevent orphan edges.
361
+ */
362
+ export function cleanupEdges(memoryId) {
363
+ // getEdges returns all edges where memoryId is source OR target
364
+ // We need the project, but edges carry it — we can fetch edges without project filter.
365
+ // Since deleteEdge only needs the edge ID, we get all edges for this memory first.
366
+ // We don't have a project in scope here, so we query directly.
367
+ const db = getDatabase();
368
+ const rows = db.prepare(`
369
+ SELECT id FROM constellation_edges
370
+ WHERE source_id = ? OR target_id = ?
371
+ `).all(memoryId, memoryId);
372
+ for (const row of rows) {
373
+ try {
374
+ deleteEdge(row.id);
375
+ }
376
+ catch (err) {
377
+ log.warn('Failed to delete constellation edge during cleanup', { edgeId: row.id, err });
378
+ }
379
+ }
380
+ log.debug('Cleaned up constellation edges', { memoryId, count: rows.length });
381
+ }
382
+ //# sourceMappingURL=constellation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constellation.js","sourceRoot":"","sources":["../../src/engine/constellation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * corona.ts — In-memory cache layer (the Sun's corona)
3
+ *
4
+ * The corona is an in-memory cache of core + near zone memories that enables
5
+ * sub-millisecond recall for the most important memories — mimicking how
6
+ * humans instantly access their name, age, and profession (System 1).
7
+ *
8
+ * Architecture:
9
+ * - Holds up to MAX_CORONA_SIZE memories (sorted by distance ASC).
10
+ * - Maintains a reverse token index for O(1) keyword matching.
11
+ * - Warmed up on startup and after orbit recalculations.
12
+ * - Invalidated and re-warmed on project switch.
13
+ *
14
+ * The corona turns orbital distance from a visual metaphor into a real
15
+ * performance differentiator: closer memories are literally faster to find.
16
+ */
17
+ import type { Memory } from './types.js';
18
+ declare class Corona {
19
+ private cache;
20
+ private tokenIndex;
21
+ private project;
22
+ /** Load core + near zone memories from DB into the cache. */
23
+ warmup(project: string): void;
24
+ /** Invalidate cache and reload for a different project. */
25
+ switchProject(project: string): void;
26
+ /** Return memories in the core zone (distance < 1.0 AU). */
27
+ getCoreMemories(): Memory[];
28
+ /** Return memories in the near zone (1.0 <= distance < 5.0 AU). */
29
+ getNearMemories(): Memory[];
30
+ /** Token-based search across cached memories. Returns scored results. */
31
+ search(query: string, limit: number): Memory[];
32
+ /** Check if a memory is in the corona cache. */
33
+ has(id: string): boolean;
34
+ /** Add or update a memory in the cache (if it qualifies by distance). */
35
+ upsert(memory: Memory): void;
36
+ /** Remove a memory from the corona cache. */
37
+ evict(id: string): void;
38
+ /** Return the current project. */
39
+ getProject(): string;
40
+ /** Return cache statistics. */
41
+ stats(): {
42
+ total: number;
43
+ core: number;
44
+ near: number;
45
+ project: string;
46
+ };
47
+ private indexTokens;
48
+ private removeTokens;
49
+ }
50
+ /** Singleton corona instance. */
51
+ export declare const corona: Corona;
52
+ export {};
53
+ //# sourceMappingURL=corona.d.ts.map
@@ -0,0 +1,181 @@
1
+ /**
2
+ * corona.ts — In-memory cache layer (the Sun's corona)
3
+ *
4
+ * The corona is an in-memory cache of core + near zone memories that enables
5
+ * sub-millisecond recall for the most important memories — mimicking how
6
+ * humans instantly access their name, age, and profession (System 1).
7
+ *
8
+ * Architecture:
9
+ * - Holds up to MAX_CORONA_SIZE memories (sorted by distance ASC).
10
+ * - Maintains a reverse token index for O(1) keyword matching.
11
+ * - Warmed up on startup and after orbit recalculations.
12
+ * - Invalidated and re-warmed on project switch.
13
+ *
14
+ * The corona turns orbital distance from a visual metaphor into a real
15
+ * performance differentiator: closer memories are literally faster to find.
16
+ */
17
+ import { tokenize } from './gravity.js';
18
+ import { getMemoriesByProject } from '../storage/queries.js';
19
+ import { createLogger } from '../utils/logger.js';
20
+ const log = createLogger('corona');
21
+ const MAX_CORONA_SIZE = 200;
22
+ const CORE_THRESHOLD = 1.0; // distance < 1.0 AU
23
+ const NEAR_THRESHOLD = 5.0; // distance < 5.0 AU
24
+ class Corona {
25
+ cache = new Map();
26
+ tokenIndex = new Map();
27
+ project = '';
28
+ /** Load core + near zone memories from DB into the cache. */
29
+ warmup(project) {
30
+ this.project = project;
31
+ this.cache.clear();
32
+ this.tokenIndex.clear();
33
+ const memories = getMemoriesByProject(project);
34
+ // memories are already sorted by distance ASC from the query
35
+ // Filter out expired memories (valid_until in the past)
36
+ const now = new Date().toISOString();
37
+ const validMemories = memories.filter(m => !m.valid_until || m.valid_until > now);
38
+ const toCache = validMemories.slice(0, MAX_CORONA_SIZE);
39
+ for (const mem of toCache) {
40
+ this.cache.set(mem.id, mem);
41
+ this.indexTokens(mem);
42
+ }
43
+ log.debug('Corona warmed up', {
44
+ project,
45
+ total: toCache.length,
46
+ core: this.getCoreMemories().length,
47
+ near: this.getNearMemories().length,
48
+ });
49
+ }
50
+ /** Invalidate cache and reload for a different project. */
51
+ switchProject(project) {
52
+ this.warmup(project);
53
+ }
54
+ /** Return memories in the core zone (distance < 1.0 AU). */
55
+ getCoreMemories() {
56
+ const result = [];
57
+ for (const mem of this.cache.values()) {
58
+ if (mem.distance < CORE_THRESHOLD) {
59
+ result.push(mem);
60
+ }
61
+ }
62
+ return result.sort((a, b) => a.distance - b.distance);
63
+ }
64
+ /** Return memories in the near zone (1.0 <= distance < 5.0 AU). */
65
+ getNearMemories() {
66
+ const result = [];
67
+ for (const mem of this.cache.values()) {
68
+ if (mem.distance >= CORE_THRESHOLD && mem.distance < NEAR_THRESHOLD) {
69
+ result.push(mem);
70
+ }
71
+ }
72
+ return result.sort((a, b) => a.distance - b.distance);
73
+ }
74
+ /** Token-based search across cached memories. Returns scored results. */
75
+ search(query, limit) {
76
+ const queryTokens = tokenize(query);
77
+ if (queryTokens.length === 0 || this.cache.size === 0)
78
+ return [];
79
+ // Score each memory by counting matching tokens
80
+ const scores = new Map();
81
+ for (const token of queryTokens) {
82
+ const matchingIds = this.tokenIndex.get(token);
83
+ if (!matchingIds)
84
+ continue;
85
+ for (const id of matchingIds) {
86
+ scores.set(id, (scores.get(id) ?? 0) + 1);
87
+ }
88
+ }
89
+ if (scores.size === 0)
90
+ return [];
91
+ // Sort by score DESC, then by distance ASC for ties
92
+ return [...scores.entries()]
93
+ .sort((a, b) => {
94
+ if (b[1] !== a[1])
95
+ return b[1] - a[1];
96
+ const memA = this.cache.get(a[0]);
97
+ const memB = this.cache.get(b[0]);
98
+ return memA.distance - memB.distance;
99
+ })
100
+ .slice(0, limit)
101
+ .map(([id]) => this.cache.get(id))
102
+ .filter(Boolean);
103
+ }
104
+ /** Check if a memory is in the corona cache. */
105
+ has(id) {
106
+ return this.cache.has(id);
107
+ }
108
+ /** Add or update a memory in the cache (if it qualifies by distance). */
109
+ upsert(memory) {
110
+ if (memory.project !== this.project)
111
+ return;
112
+ // Remove old token entries if updating
113
+ if (this.cache.has(memory.id)) {
114
+ this.removeTokens(memory.id);
115
+ }
116
+ // Only cache if within corona range or if we have room
117
+ if (this.cache.size < MAX_CORONA_SIZE || this.cache.has(memory.id)) {
118
+ this.cache.set(memory.id, memory);
119
+ this.indexTokens(memory);
120
+ }
121
+ else {
122
+ // Check if this memory is closer than the farthest cached memory
123
+ let farthestId = '';
124
+ let farthestDist = 0;
125
+ for (const [id, m] of this.cache) {
126
+ if (m.distance > farthestDist) {
127
+ farthestDist = m.distance;
128
+ farthestId = id;
129
+ }
130
+ }
131
+ if (memory.distance < farthestDist) {
132
+ this.evict(farthestId);
133
+ this.cache.set(memory.id, memory);
134
+ this.indexTokens(memory);
135
+ }
136
+ }
137
+ }
138
+ /** Remove a memory from the corona cache. */
139
+ evict(id) {
140
+ this.removeTokens(id);
141
+ this.cache.delete(id);
142
+ }
143
+ /** Return the current project. */
144
+ getProject() {
145
+ return this.project;
146
+ }
147
+ /** Return cache statistics. */
148
+ stats() {
149
+ return {
150
+ total: this.cache.size,
151
+ core: this.getCoreMemories().length,
152
+ near: this.getNearMemories().length,
153
+ project: this.project,
154
+ };
155
+ }
156
+ // ── Private helpers ─────────────────────────────────────────────────────
157
+ indexTokens(memory) {
158
+ const text = [memory.content, memory.summary, ...memory.tags].join(' ');
159
+ const tokens = tokenize(text);
160
+ for (const token of tokens) {
161
+ let ids = this.tokenIndex.get(token);
162
+ if (!ids) {
163
+ ids = new Set();
164
+ this.tokenIndex.set(token, ids);
165
+ }
166
+ ids.add(memory.id);
167
+ }
168
+ }
169
+ removeTokens(id) {
170
+ // Remove id from all token sets
171
+ for (const [token, ids] of this.tokenIndex) {
172
+ ids.delete(id);
173
+ if (ids.size === 0) {
174
+ this.tokenIndex.delete(token);
175
+ }
176
+ }
177
+ }
178
+ }
179
+ /** Singleton corona instance. */
180
+ export const corona = new Corona();
181
+ //# sourceMappingURL=corona.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"corona.js","sourceRoot":"","sources":["../../src/engine/corona.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;AAEnC,MAAM,eAAe,GAAG,GAAG,CAAC;AAC5B,MAAM,cAAc,GAAG,GAAG,CAAC,CAAG,oBAAoB;AAClD,MAAM,cAAc,GAAG,GAAG,CAAC,CAAG,oBAAoB;AAElD,MAAM,MAAM;IACF,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IAClC,UAAU,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC5C,OAAO,GAAW,EAAE,CAAC;IAE7B,6DAA6D;IAC7D,MAAM,CAAC,OAAe;QACpB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QAExB,MAAM,QAAQ,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;QAC/C,6DAA6D;QAC7D,wDAAwD;QACxD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CACxC,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,WAAW,GAAG,GAAG,CACtC,CAAC;QACF,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC;QAExD,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YAC5B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;QAED,GAAG,CAAC,KAAK,CAAC,kBAAkB,EAAE;YAC5B,OAAO;YACP,KAAK,EAAE,OAAO,CAAC,MAAM;YACrB,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,MAAM;YACnC,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,MAAM;SACpC,CAAC,CAAC;IACL,CAAC;IAED,2DAA2D;IAC3D,aAAa,CAAC,OAAe;QAC3B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACvB,CAAC;IAED,4DAA4D;IAC5D,eAAe;QACb,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACtC,IAAI,GAAG,CAAC,QAAQ,GAAG,cAAc,EAAE,CAAC;gBAClC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;IACxD,CAAC;IAED,mEAAmE;IACnE,eAAe;QACb,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACtC,IAAI,GAAG,CAAC,QAAQ,IAAI,cAAc,IAAI,GAAG,CAAC,QAAQ,GAAG,cAAc,EAAE,CAAC;gBACpE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;IACxD,CAAC;IAED,yEAAyE;IACzE,MAAM,CAAC,KAAa,EAAE,KAAa;QACjC,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAEjE,gDAAgD;QAChD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;QAEzC,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;YAChC,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAC/C,IAAI,CAAC,WAAW;gBAAE,SAAS;YAC3B,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;gBAC7B,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;QAED,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAEjC,oDAAoD;QACpD,OAAO,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;aACzB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACb,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBAAE,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACtC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC;YACnC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC;YACnC,OAAO,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QACvC,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;aACf,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC;aAClC,MAAM,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC;IAED,gDAAgD;IAChD,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC;IAED,yEAAyE;IACzE,MAAM,CAAC,MAAc;QACnB,IAAI,MAAM,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO;YAAE,OAAO;QAE5C,uCAAuC;QACvC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC/B,CAAC;QAED,uDAAuD;QACvD,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,eAAe,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YACnE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;YAClC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,iEAAiE;YACjE,IAAI,UAAU,GAAG,EAAE,CAAC;YACpB,IAAI,YAAY,GAAG,CAAC,CAAC;YACrB,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACjC,IAAI,CAAC,CAAC,QAAQ,GAAG,YAAY,EAAE,CAAC;oBAC9B,YAAY,GAAG,CAAC,CAAC,QAAQ,CAAC;oBAC1B,UAAU,GAAG,EAAE,CAAC;gBAClB,CAAC;YACH,CAAC;YACD,IAAI,MAAM,CAAC,QAAQ,GAAG,YAAY,EAAE,CAAC;gBACnC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;gBACvB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;gBAClC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IAED,6CAA6C;IAC7C,KAAK,CAAC,EAAU;QACd,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACxB,CAAC;IAED,kCAAkC;IAClC,UAAU;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,+BAA+B;IAC/B,KAAK;QACH,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI;YACtB,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,MAAM;YACnC,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,MAAM;YACnC,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC;IACJ,CAAC;IAED,2EAA2E;IAEnE,WAAW,CAAC,MAAc;QAChC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxE,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC9B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACrC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;gBAChB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAClC,CAAC;YACD,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,EAAU;QAC7B,gCAAgC;QAChC,KAAK,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC3C,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACf,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;gBACnB,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAED,iCAAiC;AACjC,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC"}