@timmeck/brain-core 2.36.32 → 2.36.34

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.
@@ -0,0 +1,428 @@
1
+ import { getLogger } from '../utils/logger.js';
2
+ // ── Need detection patterns ──────────────────────────────
3
+ /** Analyze error patterns, knowledge gaps, and existing code to detect needs */
4
+ const NEED_DETECTORS = [
5
+ {
6
+ need: 'retry mechanism',
7
+ reason: 'Repeated errors of the same type suggest missing retry/backoff logic',
8
+ priority: 0.8,
9
+ detectQuery: `SELECT COUNT(*) as c FROM errors WHERE occurrence_count >= 3`,
10
+ matchKeywords: ['retry', 'backoff', 'retryWithBackoff', 'retryable', 'exponential'],
11
+ },
12
+ {
13
+ need: 'rate limiter',
14
+ reason: 'API rate limit errors detected — need throttling/rate limiting',
15
+ priority: 0.75,
16
+ detectQuery: `SELECT COUNT(*) as c FROM errors WHERE fingerprint LIKE '%rate%limit%' OR fingerprint LIKE '%429%' OR fingerprint LIKE '%throttl%'`,
17
+ matchKeywords: ['rateLimit', 'throttle', 'RateLimiter', 'Throttle', 'limiter'],
18
+ },
19
+ {
20
+ need: 'cache layer',
21
+ reason: 'Repeated identical queries could benefit from caching',
22
+ priority: 0.7,
23
+ detectQuery: `SELECT COUNT(*) as c FROM rag_vectors WHERE collection = 'errors' AND id > 10`,
24
+ matchKeywords: ['cache', 'Cache', 'LRU', 'memoize', 'TTL', 'CacheStore', 'CacheManager'],
25
+ },
26
+ {
27
+ need: 'better error classes',
28
+ reason: 'Many UnknownError types — custom error hierarchy would improve error handling',
29
+ priority: 0.65,
30
+ detectQuery: `SELECT COUNT(*) as c FROM errors WHERE fingerprint LIKE '%UnknownError%'`,
31
+ matchKeywords: ['Error', 'AppError', 'HttpError', 'CustomError', 'BaseError', 'error_handling'],
32
+ },
33
+ {
34
+ need: 'queue/batch processing',
35
+ reason: 'Multiple sequential operations could be batched for efficiency',
36
+ priority: 0.6,
37
+ detectQuery: `SELECT COUNT(*) as c FROM tool_usage WHERE duration_ms > 5000`,
38
+ matchKeywords: ['queue', 'Queue', 'batch', 'Batch', 'pool', 'Pool', 'worker', 'Worker'],
39
+ },
40
+ {
41
+ need: 'validation layer',
42
+ reason: 'Input validation errors suggest need for schema validation',
43
+ priority: 0.55,
44
+ detectQuery: `SELECT COUNT(*) as c FROM errors WHERE fingerprint LIKE '%validat%' OR fingerprint LIKE '%schema%' OR fingerprint LIKE '%TypeError%'`,
45
+ matchKeywords: ['validate', 'Validator', 'schema', 'Schema', 'zod', 'joi', 'sanitize'],
46
+ },
47
+ {
48
+ need: 'streaming/pipeline pattern',
49
+ reason: 'Large data processing could benefit from streaming',
50
+ priority: 0.5,
51
+ detectQuery: `SELECT COUNT(*) as c FROM rag_vectors WHERE collection = 'insights'`,
52
+ matchKeywords: ['stream', 'Stream', 'pipe', 'Pipeline', 'Transform', 'readable', 'writable'],
53
+ },
54
+ {
55
+ need: 'middleware pattern',
56
+ reason: 'Request processing chains could use middleware architecture',
57
+ priority: 0.45,
58
+ detectQuery: `SELECT COUNT(*) as c FROM tool_usage WHERE tool_name LIKE '%.%' GROUP BY tool_name HAVING COUNT(*) > 5 LIMIT 1`,
59
+ matchKeywords: ['middleware', 'Middleware', 'plugin', 'Plugin', 'hook', 'Hook', 'interceptor'],
60
+ },
61
+ {
62
+ need: 'monitoring/metrics',
63
+ reason: 'System observability would improve debugging and optimization',
64
+ priority: 0.5,
65
+ detectQuery: `SELECT 1 as c`,
66
+ matchKeywords: ['monitor', 'Monitor', 'metric', 'Metric', 'health', 'HealthCheck', 'observe'],
67
+ },
68
+ {
69
+ need: 'concurrency control',
70
+ reason: 'Parallel operations need proper concurrency management',
71
+ priority: 0.6,
72
+ detectQuery: `SELECT COUNT(*) as c FROM tool_usage WHERE outcome = 'failure' AND tool_name LIKE '%parallel%' OR tool_name LIKE '%concurrent%'`,
73
+ matchKeywords: ['concurrent', 'parallel', 'Semaphore', 'Mutex', 'lock', 'throttledQueue', 'Pool'],
74
+ },
75
+ ];
76
+ // ── Tag-based connection rules ───────────────────────────
77
+ const CONNECTION_RULES = [
78
+ { tagA: 'caching', tagB: 'retry', relationship: 'complementary', strength: 0.8, reason: 'Caching reduces load, retry handles failures — together they make systems resilient' },
79
+ { tagA: 'caching', tagB: 'validation', relationship: 'complementary', strength: 0.6, reason: 'Validate before caching to avoid storing invalid data' },
80
+ { tagA: 'retry', tagB: 'logging', relationship: 'complementary', strength: 0.7, reason: 'Retry attempts should be logged for debugging' },
81
+ { tagA: 'streaming', tagB: 'batching', relationship: 'complementary', strength: 0.8, reason: 'Stream processing and batch processing are complementary data patterns' },
82
+ { tagA: 'async', tagB: 'concurrency', relationship: 'enhances', strength: 0.7, reason: 'Async operations benefit from concurrency control' },
83
+ { tagA: 'events', tagB: 'logging', relationship: 'complementary', strength: 0.6, reason: 'Event systems should emit logs for observability' },
84
+ { tagA: 'extensible', tagB: 'events', relationship: 'enhances', strength: 0.7, reason: 'Plugin/middleware systems often use events for hooks' },
85
+ { tagA: 'testing', tagB: 'validation', relationship: 'complementary', strength: 0.5, reason: 'Test utilities and validation share assertion patterns' },
86
+ { tagA: 'parsing', tagB: 'validation', relationship: 'prerequisite', strength: 0.7, reason: 'Parse first, then validate — they go hand in hand' },
87
+ { tagA: 'concurrency', tagB: 'batching', relationship: 'enhances', strength: 0.7, reason: 'Batch operations with concurrency limits for optimal throughput' },
88
+ ];
89
+ // ── FeatureRecommender ───────────────────────────────────
90
+ export class FeatureRecommender {
91
+ db;
92
+ log = getLogger();
93
+ featureExtractor = null;
94
+ ragEngine = null;
95
+ knowledgeGraph = null;
96
+ thoughtStream = null;
97
+ lastScanAt = null;
98
+ constructor(db) {
99
+ this.db = db;
100
+ this.ensureTables();
101
+ }
102
+ setFeatureExtractor(fe) { this.featureExtractor = fe; }
103
+ setRAGEngine(rag) { this.ragEngine = rag; }
104
+ setKnowledgeGraph(kg) { this.knowledgeGraph = kg; }
105
+ setThoughtStream(ts) { this.thoughtStream = ts; }
106
+ ensureTables() {
107
+ this.db.exec(`
108
+ CREATE TABLE IF NOT EXISTS feature_wishes (
109
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
110
+ need TEXT NOT NULL,
111
+ reason TEXT NOT NULL DEFAULT '',
112
+ priority REAL DEFAULT 0.5,
113
+ matched_feature_id INTEGER,
114
+ matched_feature_name TEXT,
115
+ match_score REAL DEFAULT 0,
116
+ status TEXT DEFAULT 'open',
117
+ created_at TEXT DEFAULT (datetime('now')),
118
+ updated_at TEXT DEFAULT (datetime('now')),
119
+ UNIQUE(need)
120
+ );
121
+ CREATE INDEX IF NOT EXISTS idx_wishes_status ON feature_wishes(status);
122
+ CREATE INDEX IF NOT EXISTS idx_wishes_priority ON feature_wishes(priority DESC);
123
+
124
+ CREATE TABLE IF NOT EXISTS feature_connections (
125
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
126
+ feature_id_a INTEGER NOT NULL,
127
+ feature_id_b INTEGER NOT NULL,
128
+ name_a TEXT NOT NULL,
129
+ name_b TEXT NOT NULL,
130
+ relationship TEXT NOT NULL DEFAULT 'complementary',
131
+ strength REAL DEFAULT 0.5,
132
+ reason TEXT DEFAULT '',
133
+ created_at TEXT DEFAULT (datetime('now')),
134
+ UNIQUE(feature_id_a, feature_id_b)
135
+ );
136
+ CREATE INDEX IF NOT EXISTS idx_connections_feature ON feature_connections(feature_id_a);
137
+ `);
138
+ }
139
+ /**
140
+ * Full recommendation cycle: detect needs → match features → build connections.
141
+ * Called periodically by ResearchOrchestrator.
142
+ */
143
+ async runCycle() {
144
+ const start = Date.now();
145
+ let wishesCreated = 0;
146
+ let connectionsFound = 0;
147
+ let matchesFound = 0;
148
+ this.thoughtStream?.emit('feature_recommender', 'analyzing', 'Scanning for feature needs and connections...', 'routine');
149
+ // 1. Detect needs from Brain's own data
150
+ wishesCreated = this.detectNeeds();
151
+ // 2. Match wishes against extracted features
152
+ matchesFound = this.matchWishesToFeatures();
153
+ // 3. Build connections between features
154
+ connectionsFound = this.buildConnections();
155
+ this.lastScanAt = new Date().toISOString();
156
+ if (wishesCreated > 0 || matchesFound > 0) {
157
+ this.thoughtStream?.emit('feature_recommender', 'discovering', `Feature scan: ${wishesCreated} needs detected, ${matchesFound} matches found, ${connectionsFound} connections built`, matchesFound > 0 ? 'notable' : 'routine');
158
+ }
159
+ this.log.info(`[FeatureRecommender] Cycle complete: ${wishesCreated} wishes, ${matchesFound} matches, ${connectionsFound} connections (${Date.now() - start}ms)`);
160
+ return {
161
+ wishesCreated,
162
+ connectionsFound,
163
+ matchesFound,
164
+ durationMs: Date.now() - start,
165
+ };
166
+ }
167
+ /**
168
+ * Detect needs by analyzing Brain's own data (errors, tool usage, knowledge gaps).
169
+ */
170
+ detectNeeds() {
171
+ let created = 0;
172
+ for (const detector of NEED_DETECTORS) {
173
+ try {
174
+ const result = this.db.prepare(detector.detectQuery).get();
175
+ if (result && result.c > 0) {
176
+ const inserted = this.db.prepare(`
177
+ INSERT OR IGNORE INTO feature_wishes (need, reason, priority)
178
+ VALUES (?, ?, ?)
179
+ `).run(detector.need, detector.reason, detector.priority);
180
+ if (inserted.changes > 0)
181
+ created++;
182
+ }
183
+ }
184
+ catch {
185
+ // Query may reference tables that don't exist — that's fine
186
+ }
187
+ }
188
+ // Also detect needs from knowledge graph gaps
189
+ if (this.knowledgeGraph) {
190
+ try {
191
+ const contradictions = this.knowledgeGraph.contradictions();
192
+ if (contradictions.length > 3) {
193
+ const inserted = this.db.prepare(`
194
+ INSERT OR IGNORE INTO feature_wishes (need, reason, priority)
195
+ VALUES (?, ?, ?)
196
+ `).run('contradiction resolver', `${contradictions.length} contradictions in knowledge graph need resolution`, 0.55);
197
+ if (inserted.changes > 0)
198
+ created++;
199
+ }
200
+ }
201
+ catch { /* KG may not be ready */ }
202
+ }
203
+ return created;
204
+ }
205
+ /**
206
+ * Match open wishes against extracted features.
207
+ */
208
+ matchWishesToFeatures() {
209
+ if (!this.featureExtractor)
210
+ return 0;
211
+ const openWishes = this.db.prepare(`SELECT id, need FROM feature_wishes WHERE status = 'open'`).all();
212
+ let matched = 0;
213
+ for (const wish of openWishes) {
214
+ // Find the detector keywords for this need
215
+ const detector = NEED_DETECTORS.find(d => d.need === wish.need);
216
+ if (!detector)
217
+ continue;
218
+ // Search features matching any keyword
219
+ let bestMatch = null;
220
+ for (const keyword of detector.matchKeywords) {
221
+ const features = this.featureExtractor.search({
222
+ query: keyword,
223
+ minUsefulness: 0.4,
224
+ limit: 3,
225
+ });
226
+ for (const f of features) {
227
+ const score = this.calculateMatchScore(wish.need, f, detector.matchKeywords);
228
+ if (score > (bestMatch?.score ?? 0)) {
229
+ bestMatch = { id: f.id, name: f.name, score };
230
+ }
231
+ }
232
+ }
233
+ if (bestMatch && bestMatch.score >= 0.3) {
234
+ this.db.prepare(`
235
+ UPDATE feature_wishes
236
+ SET matched_feature_id = ?, matched_feature_name = ?, match_score = ?,
237
+ status = 'matched', updated_at = datetime('now')
238
+ WHERE id = ?
239
+ `).run(bestMatch.id, bestMatch.name, bestMatch.score, wish.id);
240
+ matched++;
241
+ }
242
+ }
243
+ return matched;
244
+ }
245
+ /**
246
+ * Build connections between extracted features based on tags and co-occurrence.
247
+ */
248
+ buildConnections() {
249
+ if (!this.featureExtractor)
250
+ return 0;
251
+ const allFeatures = this.featureExtractor.search({ minUsefulness: 0.4, limit: 100 });
252
+ let created = 0;
253
+ // Parse tags for each feature
254
+ const featureTags = new Map();
255
+ for (const f of allFeatures) {
256
+ const tags = typeof f.tags === 'string' ? JSON.parse(f.tags) : (f.tags ?? []);
257
+ featureTags.set(f.id, { feature: f, tags });
258
+ }
259
+ // Apply connection rules
260
+ for (const rule of CONNECTION_RULES) {
261
+ const withTagA = [...featureTags.entries()].filter(([, v]) => v.tags.includes(rule.tagA));
262
+ const withTagB = [...featureTags.entries()].filter(([, v]) => v.tags.includes(rule.tagB));
263
+ for (const [idA, a] of withTagA) {
264
+ for (const [idB, b] of withTagB) {
265
+ if (idA === idB)
266
+ continue;
267
+ // Ensure consistent ordering (lower ID first)
268
+ const [first, second] = idA < idB ? [idA, idB] : [idB, idA];
269
+ const [nameFirst, nameSecond] = idA < idB
270
+ ? [a.feature.name, b.feature.name]
271
+ : [b.feature.name, a.feature.name];
272
+ try {
273
+ const inserted = this.db.prepare(`
274
+ INSERT OR IGNORE INTO feature_connections
275
+ (feature_id_a, feature_id_b, name_a, name_b, relationship, strength, reason)
276
+ VALUES (?, ?, ?, ?, ?, ?, ?)
277
+ `).run(first, second, nameFirst, nameSecond, rule.relationship, rule.strength, rule.reason);
278
+ if (inserted.changes > 0)
279
+ created++;
280
+ }
281
+ catch { /* duplicate */ }
282
+ }
283
+ }
284
+ }
285
+ // Also connect features from the same repo that share categories
286
+ const byRepo = new Map();
287
+ for (const f of allFeatures) {
288
+ const list = byRepo.get(f.repo) ?? [];
289
+ list.push(f);
290
+ byRepo.set(f.repo, list);
291
+ }
292
+ for (const features of byRepo.values()) {
293
+ if (features.length < 2)
294
+ continue;
295
+ // Connect top features within same repo as "complementary"
296
+ const top = features.sort((a, b) => b.usefulness - a.usefulness).slice(0, 5);
297
+ for (let i = 0; i < top.length; i++) {
298
+ for (let j = i + 1; j < top.length; j++) {
299
+ const a = top[i];
300
+ const b = top[j];
301
+ if (a.category === b.category)
302
+ continue; // same category = less interesting
303
+ try {
304
+ this.db.prepare(`
305
+ INSERT OR IGNORE INTO feature_connections
306
+ (feature_id_a, feature_id_b, name_a, name_b, relationship, strength, reason)
307
+ VALUES (?, ?, ?, ?, ?, ?, ?)
308
+ `).run(Math.min(a.id, b.id), Math.max(a.id, b.id), a.id < b.id ? a.name : b.name, a.id < b.id ? b.name : a.name, 'complementary', 0.4, `Both from ${a.repo} — different roles (${a.category} + ${b.category})`);
309
+ created++;
310
+ }
311
+ catch { /* duplicate */ }
312
+ }
313
+ }
314
+ }
315
+ return created;
316
+ }
317
+ /**
318
+ * Calculate how well a feature matches a need.
319
+ */
320
+ calculateMatchScore(need, feature, keywords) {
321
+ let score = 0;
322
+ const lowerName = feature.name.toLowerCase();
323
+ const lowerSnippet = (feature.codeSnippet ?? '').toLowerCase();
324
+ const lowerNeed = need.toLowerCase();
325
+ // Direct name match
326
+ for (const kw of keywords) {
327
+ if (lowerName.includes(kw.toLowerCase()))
328
+ score += 0.3;
329
+ if (lowerSnippet.includes(kw.toLowerCase()))
330
+ score += 0.1;
331
+ }
332
+ // Need words in feature name
333
+ for (const word of lowerNeed.split(/\s+/)) {
334
+ if (word.length > 3 && lowerName.includes(word))
335
+ score += 0.2;
336
+ }
337
+ // Usefulness boost
338
+ score += feature.usefulness * 0.2;
339
+ return Math.min(1, score);
340
+ }
341
+ // ── Query methods ──────────────────────────────────────
342
+ /**
343
+ * Get the feature wishlist (what Brain wants).
344
+ */
345
+ getWishlist(status) {
346
+ const condition = status ? `WHERE status = ?` : '';
347
+ const params = status ? [status] : [];
348
+ return this.db.prepare(`
349
+ SELECT id, need, reason, priority, matched_feature_id as matchedFeatureId,
350
+ matched_feature_name as matchedFeatureName, match_score as matchScore,
351
+ status, created_at as createdAt, updated_at as updatedAt
352
+ FROM feature_wishes
353
+ ${condition}
354
+ ORDER BY priority DESC
355
+ `).all(...params);
356
+ }
357
+ /**
358
+ * Get connections for a specific feature (what goes well with it).
359
+ */
360
+ getConnections(featureId) {
361
+ if (featureId) {
362
+ return this.db.prepare(`
363
+ SELECT id, feature_id_a as featureIdA, feature_id_b as featureIdB,
364
+ name_a as nameA, name_b as nameB, relationship, strength, reason
365
+ FROM feature_connections
366
+ WHERE feature_id_a = ? OR feature_id_b = ?
367
+ ORDER BY strength DESC
368
+ `).all(featureId, featureId);
369
+ }
370
+ return this.db.prepare(`
371
+ SELECT id, feature_id_a as featureIdA, feature_id_b as featureIdB,
372
+ name_a as nameA, name_b as nameB, relationship, strength, reason
373
+ FROM feature_connections
374
+ ORDER BY strength DESC
375
+ LIMIT 50
376
+ `).all();
377
+ }
378
+ /**
379
+ * Get "if you have X, you could also use Y" suggestions.
380
+ */
381
+ getRelatedSuggestions(featureName) {
382
+ const connections = this.db.prepare(`
383
+ SELECT name_a as nameA, name_b as nameB, relationship, strength, reason
384
+ FROM feature_connections
385
+ WHERE name_a = ? OR name_b = ?
386
+ ORDER BY strength DESC
387
+ LIMIT 10
388
+ `).all(featureName, featureName);
389
+ return connections.map(c => ({
390
+ feature: c.nameA === featureName ? c.nameB : c.nameA,
391
+ relationship: c.relationship,
392
+ reason: c.reason,
393
+ strength: c.strength,
394
+ }));
395
+ }
396
+ /**
397
+ * Adopt a feature (mark wish as fulfilled).
398
+ */
399
+ adoptFeature(wishId) {
400
+ this.db.prepare(`
401
+ UPDATE feature_wishes SET status = 'adopted', updated_at = datetime('now') WHERE id = ?
402
+ `).run(wishId);
403
+ }
404
+ /**
405
+ * Dismiss a wish (not needed).
406
+ */
407
+ dismissWish(wishId) {
408
+ this.db.prepare(`
409
+ UPDATE feature_wishes SET status = 'dismissed', updated_at = datetime('now') WHERE id = ?
410
+ `).run(wishId);
411
+ }
412
+ getStatus() {
413
+ const total = this.db.prepare('SELECT COUNT(*) as c FROM feature_wishes').get();
414
+ const open = this.db.prepare(`SELECT COUNT(*) as c FROM feature_wishes WHERE status = 'open'`).get();
415
+ const matched = this.db.prepare(`SELECT COUNT(*) as c FROM feature_wishes WHERE status = 'matched'`).get();
416
+ const adopted = this.db.prepare(`SELECT COUNT(*) as c FROM feature_wishes WHERE status = 'adopted'`).get();
417
+ const connections = this.db.prepare('SELECT COUNT(*) as c FROM feature_connections').get();
418
+ return {
419
+ totalWishes: total.c,
420
+ openWishes: open.c,
421
+ matchedWishes: matched.c,
422
+ adoptedWishes: adopted.c,
423
+ totalConnections: connections.c,
424
+ lastScanAt: this.lastScanAt,
425
+ };
426
+ }
427
+ }
428
+ //# sourceMappingURL=feature-recommender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-recommender.js","sourceRoot":"","sources":["../../src/codegen/feature-recommender.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAgD/C,4DAA4D;AAE5D,gFAAgF;AAChF,MAAM,cAAc,GAQf;IACH;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,sEAAsE;QAC9E,QAAQ,EAAE,GAAG;QACb,WAAW,EAAE,8DAA8D;QAC3E,aAAa,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,WAAW,EAAE,aAAa,CAAC;KACpF;IACD;QACE,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,gEAAgE;QACxE,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,oIAAoI;QACjJ,aAAa,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,CAAC;KAC/E;IACD;QACE,IAAI,EAAE,aAAa;QACnB,MAAM,EAAE,uDAAuD;QAC/D,QAAQ,EAAE,GAAG;QACb,WAAW,EAAE,+EAA+E;QAC5F,aAAa,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,cAAc,CAAC;KACzF;IACD;QACE,IAAI,EAAE,sBAAsB;QAC5B,MAAM,EAAE,+EAA+E;QACvF,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,0EAA0E;QACvF,aAAa,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,gBAAgB,CAAC;KAChG;IACD;QACE,IAAI,EAAE,wBAAwB;QAC9B,MAAM,EAAE,gEAAgE;QACxE,QAAQ,EAAE,GAAG;QACb,WAAW,EAAE,+DAA+D;QAC5E,aAAa,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC;KACxF;IACD;QACE,IAAI,EAAE,kBAAkB;QACxB,MAAM,EAAE,4DAA4D;QACpE,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,sIAAsI;QACnJ,aAAa,EAAE,CAAC,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC;KACvF;IACD;QACE,IAAI,EAAE,4BAA4B;QAClC,MAAM,EAAE,oDAAoD;QAC5D,QAAQ,EAAE,GAAG;QACb,WAAW,EAAE,qEAAqE;QAClF,aAAa,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,CAAC;KAC7F;IACD;QACE,IAAI,EAAE,oBAAoB;QAC1B,MAAM,EAAE,6DAA6D;QACrE,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,gHAAgH;QAC7H,aAAa,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC;KAC/F;IACD;QACE,IAAI,EAAE,oBAAoB;QAC1B,MAAM,EAAE,+DAA+D;QACvE,QAAQ,EAAE,GAAG;QACb,WAAW,EAAE,eAAe;QAC5B,aAAa,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,CAAC;KAC9F;IACD;QACE,IAAI,EAAE,qBAAqB;QAC3B,MAAM,EAAE,wDAAwD;QAChE,QAAQ,EAAE,GAAG;QACb,WAAW,EAAE,iIAAiI;QAC9I,aAAa,EAAE,CAAC,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,CAAC;KAClG;CACF,CAAC;AAEF,4DAA4D;AAE5D,MAAM,gBAAgB,GAMjB;IACH,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,qFAAqF,EAAE;IAC/K,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,uDAAuD,EAAE;IACtJ,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,+CAA+C,EAAE;IACzI,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,wEAAwE,EAAE;IACvK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,mDAAmD,EAAE;IAC5I,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,kDAAkD,EAAE;IAC7I,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,sDAAsD,EAAE;IAC/I,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,wDAAwD,EAAE;IACvJ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,mDAAmD,EAAE;IACjJ,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,iEAAiE,EAAE;CAC9J,CAAC;AAEF,4DAA4D;AAE5D,MAAM,OAAO,kBAAkB;IACZ,EAAE,CAAoB;IACtB,GAAG,GAAG,SAAS,EAAE,CAAC;IAC3B,gBAAgB,GAA4B,IAAI,CAAC;IACjD,SAAS,GAAqB,IAAI,CAAC;IACnC,cAAc,GAAgC,IAAI,CAAC;IACnD,aAAa,GAAyB,IAAI,CAAC;IAC3C,UAAU,GAAkB,IAAI,CAAC;IAEzC,YAAY,EAAqB;QAC/B,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,YAAY,EAAE,CAAC;IACtB,CAAC;IAED,mBAAmB,CAAC,EAAoB,IAAU,IAAI,CAAC,gBAAgB,GAAG,EAAE,CAAC,CAAC,CAAC;IAC/E,YAAY,CAAC,GAAc,IAAU,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC;IAC5D,iBAAiB,CAAC,EAAwB,IAAU,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC,CAAC,CAAC;IAC/E,gBAAgB,CAAC,EAAiB,IAAU,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC,CAAC,CAAC;IAE9D,YAAY;QAClB,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA8BZ,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,QAAQ;QACZ,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,IAAI,aAAa,GAAG,CAAC,CAAC;QACtB,IAAI,gBAAgB,GAAG,CAAC,CAAC;QACzB,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,qBAAqB,EAAE,WAAW,EACzD,+CAA+C,EAAE,SAAS,CAAC,CAAC;QAE9D,wCAAwC;QACxC,aAAa,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAEnC,6CAA6C;QAC7C,YAAY,GAAG,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAE5C,wCAAwC;QACxC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAE3C,IAAI,CAAC,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAE3C,IAAI,aAAa,GAAG,CAAC,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YAC1C,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,qBAAqB,EAAE,aAAa,EAC3D,iBAAiB,aAAa,oBAAoB,YAAY,mBAAmB,gBAAgB,oBAAoB,EACrH,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAC9C,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,wCAAwC,aAAa,YAAY,YAAY,aAAa,gBAAgB,iBAAiB,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,KAAK,CAAC,CAAC;QAElK,OAAO;YACL,aAAa;YACb,gBAAgB;YAChB,YAAY;YACZ,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SAC/B,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,WAAW;QACjB,IAAI,OAAO,GAAG,CAAC,CAAC;QAEhB,KAAK,MAAM,QAAQ,IAAI,cAAc,EAAE,CAAC;YACtC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,GAAG,EAA+B,CAAC;gBACxF,IAAI,MAAM,IAAI,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;WAGhC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;oBAC1D,IAAI,QAAQ,CAAC,OAAO,GAAG,CAAC;wBAAE,OAAO,EAAE,CAAC;gBACtC,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,4DAA4D;YAC9D,CAAC;QACH,CAAC;QAED,8CAA8C;QAC9C,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,IAAI,CAAC;gBACH,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,EAAE,CAAC;gBAC5D,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;WAGhC,CAAC,CAAC,GAAG,CACJ,wBAAwB,EACxB,GAAG,cAAc,CAAC,MAAM,oDAAoD,EAC5E,IAAI,CACL,CAAC;oBACF,IAAI,QAAQ,CAAC,OAAO,GAAG,CAAC;wBAAE,OAAO,EAAE,CAAC;gBACtC,CAAC;YACH,CAAC;YAAC,MAAM,CAAC,CAAC,yBAAyB,CAAC,CAAC;QACvC,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACK,qBAAqB;QAC3B,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAAE,OAAO,CAAC,CAAC;QAErC,MAAM,UAAU,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAChC,2DAA2D,CAC5D,CAAC,GAAG,EAAyC,CAAC;QAE/C,IAAI,OAAO,GAAG,CAAC,CAAC;QAEhB,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,2CAA2C;YAC3C,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC;YAChE,IAAI,CAAC,QAAQ;gBAAE,SAAS;YAExB,uCAAuC;YACvC,IAAI,SAAS,GAAuD,IAAI,CAAC;YAEzE,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC;gBAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC;oBAC5C,KAAK,EAAE,OAAO;oBACd,aAAa,EAAE,GAAG;oBAClB,KAAK,EAAE,CAAC;iBACT,CAAC,CAAC;gBAEH,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;oBACzB,MAAM,KAAK,GAAG,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC;oBAC7E,IAAI,KAAK,GAAG,CAAC,SAAS,EAAE,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC;wBACpC,SAAS,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;oBAChD,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,SAAS,IAAI,SAAS,CAAC,KAAK,IAAI,GAAG,EAAE,CAAC;gBACxC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;SAKf,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC/D,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACK,gBAAgB;QACtB,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAAE,OAAO,CAAC,CAAC;QAErC,MAAM,WAAW,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,aAAa,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACrF,IAAI,OAAO,GAAG,CAAC,CAAC;QAEhB,8BAA8B;QAC9B,MAAM,WAAW,GAA+D,IAAI,GAAG,EAAE,CAAC;QAC1F,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;YAC9E,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,CAAC;QAED,yBAAyB;QACzB,KAAK,MAAM,IAAI,IAAI,gBAAgB,EAAE,CAAC;YACpC,MAAM,QAAQ,GAAG,CAAC,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAC1F,MAAM,QAAQ,GAAG,CAAC,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAE1F,KAAK,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,QAAQ,EAAE,CAAC;gBAChC,KAAK,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,QAAQ,EAAE,CAAC;oBAChC,IAAI,GAAG,KAAK,GAAG;wBAAE,SAAS;oBAC1B,8CAA8C;oBAC9C,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;oBAC5D,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,GAAG,GAAG,GAAG,GAAG;wBACvC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;wBAClC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;oBAErC,IAAI,CAAC;wBACH,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;aAIhC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;wBAC5F,IAAI,QAAQ,CAAC,OAAO,GAAG,CAAC;4BAAE,OAAO,EAAE,CAAC;oBACtC,CAAC;oBAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC;gBAC7B,CAAC;YACH,CAAC;QACH,CAAC;QAED,iEAAiE;QACjE,MAAM,MAAM,GAAG,IAAI,GAAG,EAA8B,CAAC;QACrD,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACtC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACb,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC3B,CAAC;QAED,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;YACvC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;gBAAE,SAAS;YAClC,2DAA2D;YAC3D,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAC7E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACpC,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBACxC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAE,CAAC;oBAClB,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAE,CAAC;oBAClB,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ;wBAAE,SAAS,CAAC,mCAAmC;oBAC5E,IAAI,CAAC;wBACH,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;aAIf,CAAC,CAAC,GAAG,CACJ,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAC1C,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAC7B,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAC7B,eAAe,EAAE,GAAG,EACpB,aAAa,CAAC,CAAC,IAAI,uBAAuB,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC,QAAQ,GAAG,CACxE,CAAC;wBACF,OAAO,EAAE,CAAC;oBACZ,CAAC;oBAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC;gBAC7B,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACK,mBAAmB,CAAC,IAAY,EAAE,OAAyB,EAAE,QAAkB;QACrF,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QAC7C,MAAM,YAAY,GAAG,CAAC,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAC/D,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAErC,oBAAoB;QACpB,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;YAC1B,IAAI,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC;gBAAE,KAAK,IAAI,GAAG,CAAC;YACvD,IAAI,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC;gBAAE,KAAK,IAAI,GAAG,CAAC;QAC5D,CAAC;QAED,6BAA6B;QAC7B,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1C,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,KAAK,IAAI,GAAG,CAAC;QAChE,CAAC;QAED,mBAAmB;QACnB,KAAK,IAAI,OAAO,CAAC,UAAU,GAAG,GAAG,CAAC;QAElC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,0DAA0D;IAE1D;;OAEG;IACH,WAAW,CAAC,MAAe;QACzB,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAEtC,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;QAKnB,SAAS;;KAEZ,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAkB,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,SAAkB;QAC/B,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;;OAMtB,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAwB,CAAC;QACtD,CAAC;QAED,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;;KAMtB,CAAC,CAAC,GAAG,EAAyB,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,qBAAqB,CAAC,WAAmB;QACvC,MAAM,WAAW,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;;KAMnC,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,WAAW,CAAoG,CAAC;QAEpI,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC3B,OAAO,EAAE,CAAC,CAAC,KAAK,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK;YACpD,YAAY,EAAE,CAAC,CAAC,YAAY;YAC5B,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,QAAQ,EAAE,CAAC,CAAC,QAAQ;SACrB,CAAC,CAAC,CAAC;IACN,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,MAAc;QACzB,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;KAEf,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,MAAc;QACxB,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;KAEf,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjB,CAAC;IAED,SAAS;QACP,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,0CAA0C,CAAC,CAAC,GAAG,EAAmB,CAAC;QACjG,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,gEAAgE,CAAC,CAAC,GAAG,EAAmB,CAAC;QACtH,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,mEAAmE,CAAC,CAAC,GAAG,EAAmB,CAAC;QAC5H,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,mEAAmE,CAAC,CAAC,GAAG,EAAmB,CAAC;QAC5H,MAAM,WAAW,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,+CAA+C,CAAC,CAAC,GAAG,EAAmB,CAAC;QAE5G,OAAO;YACL,WAAW,EAAE,KAAK,CAAC,CAAC;YACpB,UAAU,EAAE,IAAI,CAAC,CAAC;YAClB,aAAa,EAAE,OAAO,CAAC,CAAC;YACxB,aAAa,EAAE,OAAO,CAAC,CAAC;YACxB,gBAAgB,EAAE,WAAW,CAAC,CAAC;YAC/B,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAC;IACJ,CAAC;CACF"}
@@ -9,4 +9,6 @@ export { RepoAbsorber } from './repo-absorber.js';
9
9
  export type { AbsorbResult, RepoAbsorberStatus } from './repo-absorber.js';
10
10
  export { FeatureExtractor } from './feature-extractor.js';
11
11
  export type { ExtractedFeature, FeatureCategory, FeatureExtractionResult, FeatureSearchOptions, FeatureStats } from './feature-extractor.js';
12
+ export { FeatureRecommender } from './feature-recommender.js';
13
+ export type { FeatureWish, FeatureConnection, RecommendationResult, FeatureRecommenderStatus } from './feature-recommender.js';
12
14
  export type { CodeMinerConfig, RepoContent, CodeMinerSummary, ExtractedPattern, DependencyPattern, TechStack, ProjectStructure, ReadmePattern, ContextBuilderConfig, BuiltContext, CodeGeneratorConfig, GenerationTrigger, GenerationStatus, GenerationRequest, GenerationResult, GenerationRecord, CodeGeneratorSummary, } from './types.js';
@@ -5,4 +5,5 @@ export { CodeGenerator, runCodeGeneratorMigration } from './code-generator.js';
5
5
  export { CodegenServer } from './codegen-server.js';
6
6
  export { RepoAbsorber } from './repo-absorber.js';
7
7
  export { FeatureExtractor } from './feature-extractor.js';
8
+ export { FeatureRecommender } from './feature-recommender.js';
8
9
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/codegen/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAE/E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/codegen/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAE/E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -5,7 +5,10 @@ export interface BrainPeer {
5
5
  export declare class CrossBrainClient {
6
6
  private selfName;
7
7
  private peers;
8
+ private localHandler;
8
9
  constructor(selfName: string, peers?: BrainPeer[]);
10
+ /** Set a local handler so queries to self are routed locally instead of over IPC. */
11
+ setLocalHandler(handler: (method: string, params?: unknown) => unknown | Promise<unknown>): void;
9
12
  /**
10
13
  * Query a specific peer brain by name.
11
14
  * Returns null if the peer is not available.
@@ -13,7 +16,7 @@ export declare class CrossBrainClient {
13
16
  query(peerName: string, method: string, params?: unknown): Promise<unknown | null>;
14
17
  /**
15
18
  * Broadcast a query to all available peer brains.
16
- * Returns results from all peers that responded.
19
+ * Returns results from all peers that responded (+ self if local handler set).
17
20
  */
18
21
  broadcast(method: string, params?: unknown): Promise<{
19
22
  name: string;
@@ -8,15 +8,29 @@ const DEFAULT_PEERS = [
8
8
  export class CrossBrainClient {
9
9
  selfName;
10
10
  peers;
11
+ localHandler = null;
11
12
  constructor(selfName, peers) {
12
13
  this.selfName = selfName;
13
14
  this.peers = (peers ?? DEFAULT_PEERS).filter(p => p.name !== selfName);
14
15
  }
16
+ /** Set a local handler so queries to self are routed locally instead of over IPC. */
17
+ setLocalHandler(handler) {
18
+ this.localHandler = handler;
19
+ }
15
20
  /**
16
21
  * Query a specific peer brain by name.
17
22
  * Returns null if the peer is not available.
18
23
  */
19
24
  async query(peerName, method, params) {
25
+ // Self-query → use local handler if available
26
+ if (peerName === this.selfName && this.localHandler) {
27
+ try {
28
+ return await this.localHandler(method, params);
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ }
20
34
  const peer = this.peers.find(p => p.name === peerName);
21
35
  if (!peer)
22
36
  return null;
@@ -35,10 +49,18 @@ export class CrossBrainClient {
35
49
  }
36
50
  /**
37
51
  * Broadcast a query to all available peer brains.
38
- * Returns results from all peers that responded.
52
+ * Returns results from all peers that responded (+ self if local handler set).
39
53
  */
40
54
  async broadcast(method, params) {
41
55
  const results = [];
56
+ // Include self via local handler
57
+ if (this.localHandler) {
58
+ try {
59
+ const result = await this.localHandler(method, params);
60
+ results.push({ name: this.selfName, result });
61
+ }
62
+ catch { /* skip */ }
63
+ }
42
64
  const promises = this.peers.map(async (peer) => {
43
65
  const client = new IpcClient(peer.pipeName, 3000);
44
66
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/cross-brain/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/cross-brain/client.ts"],"names":[],"mappings":"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"}
@@ -33,6 +33,7 @@ export interface CommandCenterOptions {
33
33
  getRepoAbsorberStatus?: () => unknown;
34
34
  getRepoAbsorberHistory?: (limit?: number) => unknown;
35
35
  getIntelligenceStats?: () => unknown;
36
+ getEmotionalStatus?: () => unknown;
36
37
  triggerAction?: (action: string, params?: unknown) => Promise<unknown>;
37
38
  }
38
39
  export declare class CommandCenterServer {
@@ -44,6 +45,7 @@ export declare class CommandCenterServer {
44
45
  private dashboardHtml;
45
46
  private logger;
46
47
  constructor(options: CommandCenterOptions);
48
+ getClientCount(): number;
47
49
  start(): void;
48
50
  stop(): void;
49
51
  /** Ensure the brain running this server appears in the brains list. */
@@ -14,6 +14,7 @@ export class CommandCenterServer {
14
14
  constructor(options) {
15
15
  this.options = options;
16
16
  }
17
+ getClientCount() { return this.clients.size; }
17
18
  start() {
18
19
  const { port } = this.options;
19
20
  // Load HTML
@@ -280,6 +281,17 @@ export class CommandCenterServer {
280
281
  }
281
282
  catch { /* ignore */ }
282
283
  }, 30_000));
284
+ // Emotional (5s — for entity animation)
285
+ this.timers.push(setInterval(() => {
286
+ if (this.clients.size === 0)
287
+ return;
288
+ if (!this.options.getEmotionalStatus)
289
+ return;
290
+ try {
291
+ this.broadcast('emotional', this.options.getEmotionalStatus());
292
+ }
293
+ catch { /* ignore */ }
294
+ }, 5_000));
283
295
  // Heartbeat (30s)
284
296
  this.timers.push(setInterval(() => {
285
297
  if (this.clients.size > 0) {
@@ -377,7 +389,8 @@ export class CommandCenterServer {
377
389
  status: this.options.getRepoAbsorberStatus(),
378
390
  history: this.options.getRepoAbsorberHistory?.(10) ?? [],
379
391
  } : null;
380
- this.json(res, { ecosystem, engines: engineResults, watchdog, plugins, borg, analytics, llm, thoughts, errors, selfmod, missions, knowledge, debates, intelligence, repoAbsorber });
392
+ const emotional = this.options.getEmotionalStatus?.() ?? null;
393
+ this.json(res, { ecosystem, engines: engineResults, watchdog, plugins, borg, analytics, llm, thoughts, errors, selfmod, missions, knowledge, debates, intelligence, repoAbsorber, emotional });
381
394
  }
382
395
  catch (err) {
383
396
  this.json(res, { error: err.message }, 500);