@timmeck/brain-core 2.36.12 → 2.36.15

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 (132) hide show
  1. package/command-center.html +955 -0
  2. package/dist/cross-brain/__tests__/borg-sync-engine.test.d.ts +1 -0
  3. package/dist/cross-brain/__tests__/borg-sync-engine.test.js +240 -0
  4. package/dist/cross-brain/__tests__/borg-sync-engine.test.js.map +1 -0
  5. package/dist/cross-brain/borg-sync-engine.d.ts +62 -0
  6. package/dist/cross-brain/borg-sync-engine.js +215 -0
  7. package/dist/cross-brain/borg-sync-engine.js.map +1 -0
  8. package/dist/cross-brain/borg-types.d.ts +37 -0
  9. package/dist/cross-brain/borg-types.js +9 -0
  10. package/dist/cross-brain/borg-types.js.map +1 -0
  11. package/dist/dashboard/__tests__/command-center-server.test.d.ts +1 -0
  12. package/dist/dashboard/__tests__/command-center-server.test.js +298 -0
  13. package/dist/dashboard/__tests__/command-center-server.test.js.map +1 -0
  14. package/dist/dashboard/command-center-server.d.ts +38 -0
  15. package/dist/dashboard/command-center-server.js +289 -0
  16. package/dist/dashboard/command-center-server.js.map +1 -0
  17. package/dist/embeddings/engine.js +2 -1
  18. package/dist/embeddings/engine.js.map +1 -1
  19. package/dist/index.d.ts +20 -1
  20. package/dist/index.js +15 -0
  21. package/dist/index.js.map +1 -1
  22. package/dist/llm/__tests__/anthropic-provider.test.d.ts +1 -0
  23. package/dist/llm/__tests__/anthropic-provider.test.js +121 -0
  24. package/dist/llm/__tests__/anthropic-provider.test.js.map +1 -0
  25. package/dist/llm/__tests__/llm-service.test.js +181 -40
  26. package/dist/llm/__tests__/llm-service.test.js.map +1 -1
  27. package/dist/llm/__tests__/ollama-embedding.test.d.ts +1 -0
  28. package/dist/llm/__tests__/ollama-embedding.test.js +128 -0
  29. package/dist/llm/__tests__/ollama-embedding.test.js.map +1 -0
  30. package/dist/llm/__tests__/ollama-provider.test.d.ts +1 -0
  31. package/dist/llm/__tests__/ollama-provider.test.js +213 -0
  32. package/dist/llm/__tests__/ollama-provider.test.js.map +1 -0
  33. package/dist/llm/__tests__/provider.test.d.ts +1 -0
  34. package/dist/llm/__tests__/provider.test.js +126 -0
  35. package/dist/llm/__tests__/provider.test.js.map +1 -0
  36. package/dist/llm/anthropic-provider.d.ts +41 -0
  37. package/dist/llm/anthropic-provider.js +86 -0
  38. package/dist/llm/anthropic-provider.js.map +1 -0
  39. package/dist/llm/index.d.ts +9 -1
  40. package/dist/llm/index.js +4 -0
  41. package/dist/llm/index.js.map +1 -1
  42. package/dist/llm/llm-service.d.ts +55 -7
  43. package/dist/llm/llm-service.js +184 -82
  44. package/dist/llm/llm-service.js.map +1 -1
  45. package/dist/llm/ollama-embedding.d.ts +46 -0
  46. package/dist/llm/ollama-embedding.js +93 -0
  47. package/dist/llm/ollama-embedding.js.map +1 -0
  48. package/dist/llm/ollama-provider.d.ts +80 -0
  49. package/dist/llm/ollama-provider.js +178 -0
  50. package/dist/llm/ollama-provider.js.map +1 -0
  51. package/dist/llm/provider.d.ts +120 -0
  52. package/dist/llm/provider.js +104 -0
  53. package/dist/llm/provider.js.map +1 -0
  54. package/dist/missions/mission-engine.d.ts +4 -0
  55. package/dist/missions/mission-engine.js +30 -8
  56. package/dist/missions/mission-engine.js.map +1 -1
  57. package/dist/notifications/__tests__/notification-service.test.d.ts +1 -0
  58. package/dist/notifications/__tests__/notification-service.test.js +176 -0
  59. package/dist/notifications/__tests__/notification-service.test.js.map +1 -0
  60. package/dist/notifications/discord-provider.d.ts +30 -0
  61. package/dist/notifications/discord-provider.js +89 -0
  62. package/dist/notifications/discord-provider.js.map +1 -0
  63. package/dist/notifications/email-provider.d.ts +41 -0
  64. package/dist/notifications/email-provider.js +101 -0
  65. package/dist/notifications/email-provider.js.map +1 -0
  66. package/dist/notifications/index.d.ts +8 -0
  67. package/dist/notifications/index.js +5 -0
  68. package/dist/notifications/index.js.map +1 -0
  69. package/dist/notifications/notification-provider.d.ts +75 -0
  70. package/dist/notifications/notification-provider.js +47 -0
  71. package/dist/notifications/notification-provider.js.map +1 -0
  72. package/dist/notifications/notification-service.d.ts +85 -0
  73. package/dist/notifications/notification-service.js +184 -0
  74. package/dist/notifications/notification-service.js.map +1 -0
  75. package/dist/notifications/telegram-provider.d.ts +30 -0
  76. package/dist/notifications/telegram-provider.js +78 -0
  77. package/dist/notifications/telegram-provider.js.map +1 -0
  78. package/dist/plugin/__tests__/plugin-registry.test.d.ts +1 -0
  79. package/dist/plugin/__tests__/plugin-registry.test.js +166 -0
  80. package/dist/plugin/__tests__/plugin-registry.test.js.map +1 -0
  81. package/dist/plugin/plugin-registry.d.ts +38 -0
  82. package/dist/plugin/plugin-registry.js +185 -0
  83. package/dist/plugin/plugin-registry.js.map +1 -0
  84. package/dist/plugin/types.d.ts +59 -0
  85. package/dist/plugin/types.js +2 -0
  86. package/dist/plugin/types.js.map +1 -0
  87. package/dist/research/adapters/__tests__/web-adapters.test.d.ts +1 -0
  88. package/dist/research/adapters/__tests__/web-adapters.test.js +106 -0
  89. package/dist/research/adapters/__tests__/web-adapters.test.js.map +1 -0
  90. package/dist/research/adapters/firecrawl-adapter.d.ts +57 -0
  91. package/dist/research/adapters/firecrawl-adapter.js +137 -0
  92. package/dist/research/adapters/firecrawl-adapter.js.map +1 -0
  93. package/dist/research/adapters/index.d.ts +3 -0
  94. package/dist/research/adapters/index.js +2 -0
  95. package/dist/research/adapters/index.js.map +1 -1
  96. package/dist/research/adapters/playwright-adapter.d.ts +54 -0
  97. package/dist/research/adapters/playwright-adapter.js +130 -0
  98. package/dist/research/adapters/playwright-adapter.js.map +1 -0
  99. package/dist/research/research-orchestrator.d.ts +3 -0
  100. package/dist/research/research-orchestrator.js +19 -1
  101. package/dist/research/research-orchestrator.js.map +1 -1
  102. package/dist/techradar/__tests__/techradar-engine.test.d.ts +1 -0
  103. package/dist/techradar/__tests__/techradar-engine.test.js +246 -0
  104. package/dist/techradar/__tests__/techradar-engine.test.js.map +1 -0
  105. package/dist/techradar/daily-digest.d.ts +18 -0
  106. package/dist/techradar/daily-digest.js +100 -0
  107. package/dist/techradar/daily-digest.js.map +1 -0
  108. package/dist/techradar/index.d.ts +5 -0
  109. package/dist/techradar/index.js +5 -0
  110. package/dist/techradar/index.js.map +1 -0
  111. package/dist/techradar/relevance-scorer.d.ts +29 -0
  112. package/dist/techradar/relevance-scorer.js +139 -0
  113. package/dist/techradar/relevance-scorer.js.map +1 -0
  114. package/dist/techradar/repo-watcher.d.ts +24 -0
  115. package/dist/techradar/repo-watcher.js +87 -0
  116. package/dist/techradar/repo-watcher.js.map +1 -0
  117. package/dist/techradar/techradar-engine.d.ts +69 -0
  118. package/dist/techradar/techradar-engine.js +382 -0
  119. package/dist/techradar/techradar-engine.js.map +1 -0
  120. package/dist/techradar/types.d.ts +87 -0
  121. package/dist/techradar/types.js +5 -0
  122. package/dist/techradar/types.js.map +1 -0
  123. package/dist/watchdog/__tests__/watchdog-service.test.d.ts +1 -0
  124. package/dist/watchdog/__tests__/watchdog-service.test.js +113 -0
  125. package/dist/watchdog/__tests__/watchdog-service.test.js.map +1 -0
  126. package/dist/watchdog/watchdog-service.d.ts +60 -0
  127. package/dist/watchdog/watchdog-service.js +275 -0
  128. package/dist/watchdog/watchdog-service.js.map +1 -0
  129. package/dist/watchdog/windows-service.d.ts +39 -0
  130. package/dist/watchdog/windows-service.js +179 -0
  131. package/dist/watchdog/windows-service.js.map +1 -0
  132. package/package.json +20 -2
@@ -0,0 +1,298 @@
1
+ import { describe, it, expect, vi, afterEach } from 'vitest';
2
+ import http from 'node:http';
3
+ vi.mock('../../utils/logger.js', () => ({
4
+ getLogger: () => ({
5
+ info: vi.fn(),
6
+ warn: vi.fn(),
7
+ error: vi.fn(),
8
+ debug: vi.fn(),
9
+ }),
10
+ }));
11
+ import { CommandCenterServer } from '../command-center-server.js';
12
+ // ── Helpers ─────────────────────────────────────────────────
13
+ function request(port, path, method = 'GET', body) {
14
+ return new Promise((resolve, reject) => {
15
+ const req = http.request({ hostname: '127.0.0.1', port, path, method, headers: body ? { 'Content-Type': 'application/json' } : {} }, (res) => {
16
+ let data = '';
17
+ res.on('data', (chunk) => (data += chunk));
18
+ res.on('end', () => resolve({ statusCode: res.statusCode, headers: res.headers, body: data }));
19
+ });
20
+ req.on('error', reject);
21
+ if (body)
22
+ req.write(body);
23
+ req.end();
24
+ });
25
+ }
26
+ function createMockOptions(overrides = {}) {
27
+ return {
28
+ port: 0,
29
+ selfName: 'brain',
30
+ crossBrain: {
31
+ broadcast: vi.fn().mockResolvedValue([]),
32
+ query: vi.fn().mockResolvedValue(null),
33
+ getPeerNames: vi.fn().mockReturnValue(['trading-brain', 'marketing-brain']),
34
+ getAvailablePeers: vi.fn().mockResolvedValue([]),
35
+ addPeer: vi.fn(),
36
+ removePeer: vi.fn(),
37
+ },
38
+ ecosystemService: {
39
+ getStatus: vi.fn().mockResolvedValue({
40
+ brains: [{ name: 'brain', available: true, version: '1.0.0', uptime: 100, pid: 1234, methods: 50 }],
41
+ health: { score: 85, status: 'healthy', activeBrains: 1, totalEvents: 10, correlations: 0, recentErrors: 0, recentTradeLosses: 0, alerts: [] },
42
+ correlations: [],
43
+ recentEvents: [],
44
+ }),
45
+ getAggregatedAnalytics: vi.fn().mockResolvedValue({
46
+ brain: { errors: 5, solutions: 3, modules: 10 },
47
+ }),
48
+ getCorrelations: vi.fn().mockReturnValue([]),
49
+ getTimeline: vi.fn().mockReturnValue([]),
50
+ getHealth: vi.fn().mockReturnValue({ score: 85, status: 'healthy' }),
51
+ },
52
+ correlator: {
53
+ getHealth: vi.fn().mockReturnValue({ score: 85, status: 'healthy' }),
54
+ getCorrelations: vi.fn().mockReturnValue([]),
55
+ getTimeline: vi.fn().mockReturnValue([]),
56
+ },
57
+ watchdog: null,
58
+ pluginRegistry: null,
59
+ borgSync: null,
60
+ ...overrides,
61
+ };
62
+ }
63
+ function startServer(overrides = {}) {
64
+ return new Promise((resolve) => {
65
+ const opts = createMockOptions(overrides);
66
+ const server = new CommandCenterServer(opts);
67
+ server.start();
68
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
+ const internal = server.server;
70
+ internal.on('listening', () => {
71
+ const addr = internal.address();
72
+ resolve({ server, port: addr.port });
73
+ });
74
+ });
75
+ }
76
+ // ── Tests ───────────────────────────────────────────────────
77
+ describe('CommandCenterServer', () => {
78
+ let server = null;
79
+ afterEach(() => {
80
+ server?.stop();
81
+ server = null;
82
+ });
83
+ it('GET / returns HTML', async () => {
84
+ const result = await startServer();
85
+ server = result.server;
86
+ const res = await request(result.port, '/');
87
+ expect(res.statusCode).toBe(200);
88
+ expect(res.headers['content-type']).toContain('text/html');
89
+ // Should contain the fallback or real HTML
90
+ expect(res.body).toContain('Command Center');
91
+ });
92
+ it('GET /api/state returns full state snapshot', async () => {
93
+ const result = await startServer();
94
+ server = result.server;
95
+ const res = await request(result.port, '/api/state');
96
+ expect(res.statusCode).toBe(200);
97
+ expect(res.headers['content-type']).toContain('application/json');
98
+ const data = JSON.parse(res.body);
99
+ expect(data).toHaveProperty('ecosystem');
100
+ expect(data).toHaveProperty('engines');
101
+ expect(data).toHaveProperty('watchdog');
102
+ expect(data).toHaveProperty('plugins');
103
+ expect(data).toHaveProperty('analytics');
104
+ expect(data.ecosystem.brains).toHaveLength(1);
105
+ expect(data.ecosystem.brains[0].name).toBe('brain');
106
+ });
107
+ it('GET /api/ecosystem returns ecosystem status', async () => {
108
+ const result = await startServer();
109
+ server = result.server;
110
+ const res = await request(result.port, '/api/ecosystem');
111
+ expect(res.statusCode).toBe(200);
112
+ const data = JSON.parse(res.body);
113
+ expect(data.brains).toBeInstanceOf(Array);
114
+ expect(data.health).toHaveProperty('score');
115
+ });
116
+ it('GET /api/engines broadcasts to peers', async () => {
117
+ const mockBroadcast = vi.fn().mockResolvedValue([
118
+ { name: 'brain', result: [{ engine: 'learning', thoughtCount: 5 }] },
119
+ ]);
120
+ const result = await startServer({
121
+ crossBrain: {
122
+ broadcast: mockBroadcast,
123
+ getPeerNames: vi.fn().mockReturnValue([]),
124
+ },
125
+ });
126
+ server = result.server;
127
+ const res = await request(result.port, '/api/engines');
128
+ expect(res.statusCode).toBe(200);
129
+ expect(mockBroadcast).toHaveBeenCalledWith('consciousness.engines');
130
+ const data = JSON.parse(res.body);
131
+ expect(data).toHaveLength(1);
132
+ expect(data[0].name).toBe('brain');
133
+ });
134
+ it('GET /api/watchdog returns empty array when no watchdog', async () => {
135
+ const result = await startServer({ watchdog: null });
136
+ server = result.server;
137
+ const res = await request(result.port, '/api/watchdog');
138
+ expect(res.statusCode).toBe(200);
139
+ const data = JSON.parse(res.body);
140
+ expect(data).toEqual([]);
141
+ });
142
+ it('GET /api/watchdog returns daemon status when available', async () => {
143
+ const mockWatchdog = {
144
+ getStatus: vi.fn().mockReturnValue([
145
+ { name: 'brain', pid: 1234, running: true, healthy: true, uptime: 5000, restarts: 0 },
146
+ ]),
147
+ };
148
+ const result = await startServer({ watchdog: mockWatchdog });
149
+ server = result.server;
150
+ const res = await request(result.port, '/api/watchdog');
151
+ expect(res.statusCode).toBe(200);
152
+ const data = JSON.parse(res.body);
153
+ expect(data).toHaveLength(1);
154
+ expect(data[0].name).toBe('brain');
155
+ expect(data[0].running).toBe(true);
156
+ });
157
+ it('GET /api/plugins returns empty array when no registry', async () => {
158
+ const result = await startServer({ pluginRegistry: null });
159
+ server = result.server;
160
+ const res = await request(result.port, '/api/plugins');
161
+ expect(res.statusCode).toBe(200);
162
+ expect(JSON.parse(res.body)).toEqual([]);
163
+ });
164
+ it('GET /api/plugins returns plugin list when available', async () => {
165
+ const mockPlugins = {
166
+ list: vi.fn().mockReturnValue([
167
+ { name: 'test-plugin', version: '1.0.0', description: 'A test' },
168
+ ]),
169
+ };
170
+ const result = await startServer({ pluginRegistry: mockPlugins });
171
+ server = result.server;
172
+ const res = await request(result.port, '/api/plugins');
173
+ expect(res.statusCode).toBe(200);
174
+ const data = JSON.parse(res.body);
175
+ expect(data).toHaveLength(1);
176
+ expect(data[0].name).toBe('test-plugin');
177
+ });
178
+ it('GET /api/borg returns not available when no borgSync', async () => {
179
+ const result = await startServer({ borgSync: null });
180
+ server = result.server;
181
+ const res = await request(result.port, '/api/borg');
182
+ expect(res.statusCode).toBe(200);
183
+ const data = JSON.parse(res.body);
184
+ expect(data.available).toBe(false);
185
+ });
186
+ it('GET /api/borg returns borg status when available', async () => {
187
+ const mockBorg = {
188
+ getStatus: vi.fn().mockReturnValue({ enabled: true, mode: 'full', totalSyncs: 5 }),
189
+ getConfig: vi.fn().mockReturnValue({ enabled: true, mode: 'full' }),
190
+ getHistory: vi.fn().mockReturnValue([]),
191
+ };
192
+ const result = await startServer({ borgSync: mockBorg });
193
+ server = result.server;
194
+ const res = await request(result.port, '/api/borg');
195
+ expect(res.statusCode).toBe(200);
196
+ const data = JSON.parse(res.body);
197
+ expect(data.status.enabled).toBe(true);
198
+ expect(data.config.mode).toBe('full');
199
+ });
200
+ it('GET /api/analytics returns aggregated analytics', async () => {
201
+ const result = await startServer();
202
+ server = result.server;
203
+ const res = await request(result.port, '/api/analytics');
204
+ expect(res.statusCode).toBe(200);
205
+ const data = JSON.parse(res.body);
206
+ expect(data.brain).toEqual({ errors: 5, solutions: 3, modules: 10 });
207
+ });
208
+ it('POST /api/borg/toggle toggles borg sync', async () => {
209
+ const mockBorg = {
210
+ getStatus: vi.fn().mockReturnValue({ enabled: false }),
211
+ getConfig: vi.fn().mockReturnValue({}),
212
+ getHistory: vi.fn().mockReturnValue([]),
213
+ setEnabled: vi.fn(),
214
+ };
215
+ const result = await startServer({ borgSync: mockBorg });
216
+ server = result.server;
217
+ const res = await request(result.port, '/api/borg/toggle', 'POST', JSON.stringify({ enabled: true }));
218
+ expect(res.statusCode).toBe(200);
219
+ const data = JSON.parse(res.body);
220
+ expect(data.toggled).toBe(true);
221
+ expect(mockBorg.setEnabled).toHaveBeenCalledWith(true);
222
+ });
223
+ it('POST /api/borg/toggle returns 501 when no borgSync', async () => {
224
+ const result = await startServer({ borgSync: null });
225
+ server = result.server;
226
+ const res = await request(result.port, '/api/borg/toggle', 'POST', JSON.stringify({ enabled: true }));
227
+ expect(res.statusCode).toBe(501);
228
+ });
229
+ it('POST /api/borg/toggle returns 400 on invalid body', async () => {
230
+ const mockBorg = {
231
+ getStatus: vi.fn().mockReturnValue({ enabled: false }),
232
+ getConfig: vi.fn().mockReturnValue({}),
233
+ getHistory: vi.fn().mockReturnValue([]),
234
+ setEnabled: vi.fn(),
235
+ };
236
+ const result = await startServer({ borgSync: mockBorg });
237
+ server = result.server;
238
+ const res = await request(result.port, '/api/borg/toggle', 'POST', JSON.stringify({ foo: 'bar' }));
239
+ expect(res.statusCode).toBe(400);
240
+ });
241
+ it('GET /events returns SSE stream', async () => {
242
+ const result = await startServer();
243
+ server = result.server;
244
+ const sseData = await new Promise((resolve, reject) => {
245
+ const req = http.request({ hostname: '127.0.0.1', port: result.port, path: '/events' }, (res) => {
246
+ expect(res.statusCode).toBe(200);
247
+ expect(res.headers['content-type']).toBe('text/event-stream');
248
+ let data = '';
249
+ res.on('data', (chunk) => {
250
+ data += chunk;
251
+ // After first event, resolve
252
+ if (data.includes('event: connected')) {
253
+ res.destroy();
254
+ resolve(data);
255
+ }
256
+ });
257
+ });
258
+ req.on('error', (err) => {
259
+ if (err.message.includes('socket hang up'))
260
+ return;
261
+ reject(err);
262
+ });
263
+ req.end();
264
+ });
265
+ expect(sseData).toContain('event: connected');
266
+ });
267
+ it('GET /nonexistent returns 404', async () => {
268
+ const result = await startServer();
269
+ server = result.server;
270
+ const res = await request(result.port, '/nonexistent');
271
+ expect(res.statusCode).toBe(404);
272
+ expect(res.body).toBe('Not Found');
273
+ });
274
+ it('OPTIONS returns 204 with CORS headers', async () => {
275
+ const result = await startServer();
276
+ server = result.server;
277
+ const res = await request(result.port, '/', 'OPTIONS');
278
+ expect(res.statusCode).toBe(204);
279
+ expect(res.headers['access-control-allow-origin']).toBe('*');
280
+ expect(res.headers['access-control-allow-methods']).toContain('GET');
281
+ });
282
+ it('sets CORS headers on all responses', async () => {
283
+ const result = await startServer();
284
+ server = result.server;
285
+ const res = await request(result.port, '/api/ecosystem');
286
+ expect(res.headers['access-control-allow-origin']).toBe('*');
287
+ });
288
+ it('stop() closes the server', async () => {
289
+ const result = await startServer();
290
+ server = result.server;
291
+ const resBefore = await request(result.port, '/api/watchdog');
292
+ expect(resBefore.statusCode).toBe(200);
293
+ server.stop();
294
+ server = null;
295
+ await expect(request(result.port, '/')).rejects.toThrow();
296
+ });
297
+ });
298
+ //# sourceMappingURL=command-center-server.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-center-server.test.js","sourceRoot":"","sources":["../../../src/dashboard/__tests__/command-center-server.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,EAAE,CAAC,IAAI,CAAC,uBAAuB,EAAE,GAAG,EAAE,CAAC,CAAC;IACtC,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;QAChB,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;QACb,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;QACb,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE;QACd,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE;KACf,CAAC;CACH,CAAC,CAAC,CAAC;AAEJ,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAGlE,+DAA+D;AAE/D,SAAS,OAAO,CACd,IAAY,EACZ,IAAY,EACZ,MAAM,GAAG,KAAK,EACd,IAAa;IAEb,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE;YAC3I,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC;YAC3C,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,UAAW,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAClG,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACxB,IAAI,IAAI;YAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,GAAG,CAAC,GAAG,EAAE,CAAC;IACZ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB,CAAC,YAA2C,EAAE;IACtE,OAAO;QACL,IAAI,EAAE,CAAC;QACP,QAAQ,EAAE,OAAO;QACjB,UAAU,EAAE;YACV,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACxC,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC;YACtC,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,eAAe,EAAE,iBAAiB,CAAC,CAAC;YAC3E,iBAAiB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;YAChD,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE;YAChB,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE;SAC6B;QAClD,gBAAgB,EAAE;YAChB,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;gBACnC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;gBACnG,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,iBAAiB,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE;gBAC9I,YAAY,EAAE,EAAE;gBAChB,YAAY,EAAE,EAAE;aACjB,CAAC;YACF,sBAAsB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;gBAChD,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE;aAChD,CAAC;YACF,eAAe,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;YAC5C,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;YACxC,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;SACd;QACxD,UAAU,EAAE;YACV,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YACpE,eAAe,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;YAC5C,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;SACQ;QAClD,QAAQ,EAAE,IAAI;QACd,cAAc,EAAE,IAAI;QACpB,QAAQ,EAAE,IAAI;QACd,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAClB,YAA2C,EAAE;IAE7C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,IAAI,mBAAmB,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,EAAE,CAAC;QAEf,8DAA8D;QAC9D,MAAM,QAAQ,GAAI,MAAc,CAAC,MAAqB,CAAC;QACvD,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE;YAC5B,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAsB,CAAC;YACpD,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,+DAA+D;AAE/D,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,IAAI,MAAM,GAA+B,IAAI,CAAC;IAE9C,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,EAAE,IAAI,EAAE,CAAC;QACf,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oBAAoB,EAAE,KAAK,IAAI,EAAE;QAClC,MAAM,MAAM,GAAG,MAAM,WAAW,EAAE,CAAC;QACnC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAC3D,2CAA2C;QAC3C,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,MAAM,GAAG,MAAM,WAAW,EAAE,CAAC;QACnC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QACrD,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;QAElE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,MAAM,GAAG,MAAM,WAAW,EAAE,CAAC;QACnC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;QACzD,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,aAAa,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;YAC9C,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,EAAE;SACrE,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC;YAC/B,UAAU,EAAE;gBACV,SAAS,EAAE,aAAa;gBACxB,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;aACO;SACnD,CAAC,CAAC;QACH,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QACvD,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,CAAC,aAAa,CAAC,CAAC,oBAAoB,CAAC,uBAAuB,CAAC,CAAC;QACpE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QACxD,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,MAAM,YAAY,GAAG;YACnB,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC;gBACjC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE;aACtF,CAAC;SACH,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,QAAQ,EAAE,YAA2D,EAAE,CAAC,CAAC;QAC5G,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QACxD,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QACvD,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,WAAW,GAAG;YAClB,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC;gBAC5B,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE;aACjE,CAAC;SACH,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,cAAc,EAAE,WAAgE,EAAE,CAAC,CAAC;QACvH,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QACvD,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QACpD,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,QAAQ,GAAG;YACf,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;YAClF,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YACnE,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;SACxC,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,QAAQ,EAAE,QAAuD,EAAE,CAAC,CAAC;QACxG,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QACpD,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,MAAM,GAAG,MAAM,WAAW,EAAE,CAAC;QACnC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;QACzD,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,QAAQ,GAAG;YACf,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YACtD,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;YACtC,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;YACvC,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE;SACpB,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,QAAQ,EAAE,QAAuD,EAAE,CAAC,CAAC;QACxG,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACtG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACtG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,QAAQ,GAAG;YACf,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YACtD,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;YACtC,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;YACvC,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE;SACpB,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,QAAQ,EAAE,QAAuD,EAAE,CAAC,CAAC;QACxG,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QACnG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,MAAM,GAAG,MAAM,WAAW,EAAE,CAAC;QACnC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,OAAO,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC9F,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACjC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;gBAC9D,IAAI,IAAI,GAAG,EAAE,CAAC;gBACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;oBACvB,IAAI,IAAI,KAAK,CAAC;oBACd,6BAA6B;oBAC7B,IAAI,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;wBACtC,GAAG,CAAC,OAAO,EAAE,CAAC;wBACd,OAAO,CAAC,IAAI,CAAC,CAAC;oBAChB,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACtB,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;oBAAE,OAAO;gBACnD,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC,CAAC,CAAC;YACH,GAAG,CAAC,GAAG,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;QAC5C,MAAM,MAAM,GAAG,MAAM,WAAW,EAAE,CAAC;QACnC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QACvD,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,MAAM,GAAG,MAAM,WAAW,EAAE,CAAC;QACnC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QACvD,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7D,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,8BAA8B,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,MAAM,GAAG,MAAM,WAAW,EAAE,CAAC;QACnC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;QACzD,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,MAAM,GAAG,MAAM,WAAW,EAAE,CAAC;QACnC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAEvB,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QAC9D,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEvC,MAAM,CAAC,IAAI,EAAE,CAAC;QACd,MAAM,GAAG,IAAI,CAAC;QAEd,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { CrossBrainClient } from '../cross-brain/client.js';
2
+ import type { EcosystemService } from '../ecosystem/service.js';
3
+ import type { CrossBrainCorrelator } from '../cross-brain/correlator.js';
4
+ import type { WatchdogService } from '../watchdog/watchdog-service.js';
5
+ import type { PluginRegistry } from '../plugin/plugin-registry.js';
6
+ import type { BorgSyncEngine } from '../cross-brain/borg-sync-engine.js';
7
+ export interface CommandCenterOptions {
8
+ port: number;
9
+ selfName: string;
10
+ crossBrain: CrossBrainClient;
11
+ ecosystemService: EcosystemService;
12
+ correlator: CrossBrainCorrelator;
13
+ watchdog?: WatchdogService | null;
14
+ pluginRegistry?: PluginRegistry | null;
15
+ borgSync?: BorgSyncEngine | null;
16
+ }
17
+ export declare class CommandCenterServer {
18
+ private options;
19
+ private server;
20
+ private clients;
21
+ private timers;
22
+ private dashboardHtml;
23
+ private logger;
24
+ constructor(options: CommandCenterOptions);
25
+ start(): void;
26
+ stop(): void;
27
+ private handleState;
28
+ private handleEcosystem;
29
+ private handleEngines;
30
+ private handleWatchdog;
31
+ private handlePlugins;
32
+ private handleBorg;
33
+ private handleAnalytics;
34
+ private handleBorgToggle;
35
+ private handleSSE;
36
+ private broadcast;
37
+ private json;
38
+ }
@@ -0,0 +1,289 @@
1
+ import http from 'node:http';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { getLogger } from '../utils/logger.js';
5
+ // ── Server ───────────────────────────────────────────────
6
+ export class CommandCenterServer {
7
+ options;
8
+ server = null;
9
+ clients = new Set();
10
+ timers = [];
11
+ dashboardHtml = null;
12
+ logger = getLogger();
13
+ constructor(options) {
14
+ this.options = options;
15
+ }
16
+ start() {
17
+ const { port } = this.options;
18
+ // Load HTML
19
+ const htmlPath = path.resolve(path.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Z]:)/, '$1')), '../../command-center.html');
20
+ try {
21
+ this.dashboardHtml = fs.readFileSync(htmlPath, 'utf-8');
22
+ }
23
+ catch {
24
+ this.dashboardHtml = '<html><body><h1>Command Center HTML not found</h1></body></html>';
25
+ }
26
+ this.server = http.createServer((req, res) => {
27
+ const url = new URL(req.url ?? '/', `http://localhost:${port}`);
28
+ // CORS + Security
29
+ res.setHeader('Access-Control-Allow-Origin', '*');
30
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
31
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
32
+ res.setHeader('X-Content-Type-Options', 'nosniff');
33
+ if (req.method === 'OPTIONS') {
34
+ res.writeHead(204);
35
+ res.end();
36
+ return;
37
+ }
38
+ // ── Routes ──────────────────────────────────────────
39
+ try {
40
+ if (url.pathname === '/' || url.pathname === '/dashboard') {
41
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
42
+ res.end(this.dashboardHtml);
43
+ return;
44
+ }
45
+ if (url.pathname === '/api/state') {
46
+ this.handleState(res);
47
+ return;
48
+ }
49
+ if (url.pathname === '/api/ecosystem') {
50
+ this.handleEcosystem(res);
51
+ return;
52
+ }
53
+ if (url.pathname === '/api/engines') {
54
+ this.handleEngines(res);
55
+ return;
56
+ }
57
+ if (url.pathname === '/api/watchdog') {
58
+ this.handleWatchdog(res);
59
+ return;
60
+ }
61
+ if (url.pathname === '/api/plugins') {
62
+ this.handlePlugins(res);
63
+ return;
64
+ }
65
+ if (url.pathname === '/api/borg') {
66
+ this.handleBorg(res);
67
+ return;
68
+ }
69
+ if (url.pathname === '/api/analytics') {
70
+ this.handleAnalytics(res);
71
+ return;
72
+ }
73
+ if (url.pathname === '/api/borg/toggle' && req.method === 'POST') {
74
+ this.handleBorgToggle(req, res);
75
+ return;
76
+ }
77
+ if (url.pathname === '/events') {
78
+ this.handleSSE(req, res);
79
+ return;
80
+ }
81
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
82
+ res.end('Not Found');
83
+ }
84
+ catch (err) {
85
+ this.logger.error(`Command Center route error: ${err.message}`);
86
+ if (!res.headersSent) {
87
+ res.writeHead(500, { 'Content-Type': 'application/json' });
88
+ res.end(JSON.stringify({ error: err.message }));
89
+ }
90
+ }
91
+ });
92
+ // ── SSE Timers ──────────────────────────────────────
93
+ // Ecosystem (10s)
94
+ this.timers.push(setInterval(() => {
95
+ if (this.clients.size === 0)
96
+ return;
97
+ this.options.ecosystemService.getStatus()
98
+ .then(status => this.broadcast('ecosystem', status))
99
+ .catch(() => { });
100
+ }, 10_000));
101
+ // Engines (15s)
102
+ this.timers.push(setInterval(() => {
103
+ if (this.clients.size === 0)
104
+ return;
105
+ this.options.crossBrain.broadcast('consciousness.engines')
106
+ .then(results => this.broadcast('engines', results))
107
+ .catch(() => { });
108
+ }, 15_000));
109
+ // Watchdog (30s)
110
+ this.timers.push(setInterval(() => {
111
+ if (this.clients.size === 0)
112
+ return;
113
+ const status = this.options.watchdog?.getStatus() ?? [];
114
+ this.broadcast('watchdog', status);
115
+ }, 30_000));
116
+ // Borg (30s)
117
+ this.timers.push(setInterval(() => {
118
+ if (this.clients.size === 0)
119
+ return;
120
+ if (!this.options.borgSync)
121
+ return;
122
+ this.broadcast('borg', {
123
+ status: this.options.borgSync.getStatus(),
124
+ config: this.options.borgSync.getConfig(),
125
+ history: this.options.borgSync.getHistory(20),
126
+ });
127
+ }, 30_000));
128
+ // Analytics (30s)
129
+ this.timers.push(setInterval(() => {
130
+ if (this.clients.size === 0)
131
+ return;
132
+ this.options.ecosystemService.getAggregatedAnalytics()
133
+ .then(analytics => this.broadcast('analytics', analytics))
134
+ .catch(() => { });
135
+ }, 30_000));
136
+ // Heartbeat (30s)
137
+ this.timers.push(setInterval(() => {
138
+ if (this.clients.size > 0) {
139
+ this.broadcast('heartbeat', { time: Date.now() });
140
+ }
141
+ }, 30_000));
142
+ // ── Error handling ──────────────────────────────────
143
+ this.server.on('error', (err) => {
144
+ if (err.code === 'EADDRINUSE') {
145
+ this.logger.warn(`Command Center port ${port} already in use — skipping`);
146
+ this.server?.close();
147
+ this.server = null;
148
+ }
149
+ else {
150
+ this.logger.error(`Command Center error: ${err.message}`);
151
+ }
152
+ });
153
+ this.server.listen(port, () => {
154
+ this.logger.info(`Command Center started on http://localhost:${port}`);
155
+ });
156
+ }
157
+ stop() {
158
+ for (const timer of this.timers)
159
+ clearInterval(timer);
160
+ this.timers = [];
161
+ for (const client of this.clients) {
162
+ try {
163
+ client.end();
164
+ }
165
+ catch { /* ignore */ }
166
+ }
167
+ this.clients.clear();
168
+ this.server?.close();
169
+ this.server = null;
170
+ this.logger.info('Command Center stopped');
171
+ }
172
+ // ── Route Handlers ──────────────────────────────────────
173
+ async handleState(res) {
174
+ try {
175
+ const [ecosystem, engineResults, analytics] = await Promise.all([
176
+ this.options.ecosystemService.getStatus(),
177
+ this.options.crossBrain.broadcast('consciousness.engines'),
178
+ this.options.ecosystemService.getAggregatedAnalytics(),
179
+ ]);
180
+ const watchdog = this.options.watchdog?.getStatus() ?? [];
181
+ const plugins = this.options.pluginRegistry?.list() ?? [];
182
+ const borg = this.options.borgSync ? {
183
+ status: this.options.borgSync.getStatus(),
184
+ config: this.options.borgSync.getConfig(),
185
+ history: this.options.borgSync.getHistory(20),
186
+ } : null;
187
+ this.json(res, { ecosystem, engines: engineResults, watchdog, plugins, borg, analytics });
188
+ }
189
+ catch (err) {
190
+ this.json(res, { error: err.message }, 500);
191
+ }
192
+ }
193
+ async handleEcosystem(res) {
194
+ try {
195
+ const status = await this.options.ecosystemService.getStatus();
196
+ this.json(res, status);
197
+ }
198
+ catch (err) {
199
+ this.json(res, { error: err.message }, 500);
200
+ }
201
+ }
202
+ async handleEngines(res) {
203
+ try {
204
+ const results = await this.options.crossBrain.broadcast('consciousness.engines');
205
+ // Also include self (the brain running this server)
206
+ this.json(res, results);
207
+ }
208
+ catch (err) {
209
+ this.json(res, { error: err.message }, 500);
210
+ }
211
+ }
212
+ handleWatchdog(res) {
213
+ const status = this.options.watchdog?.getStatus() ?? [];
214
+ this.json(res, status);
215
+ }
216
+ handlePlugins(res) {
217
+ const plugins = this.options.pluginRegistry?.list() ?? [];
218
+ this.json(res, plugins);
219
+ }
220
+ handleBorg(res) {
221
+ if (!this.options.borgSync) {
222
+ this.json(res, { enabled: false, available: false });
223
+ return;
224
+ }
225
+ this.json(res, {
226
+ status: this.options.borgSync.getStatus(),
227
+ config: this.options.borgSync.getConfig(),
228
+ history: this.options.borgSync.getHistory(50),
229
+ });
230
+ }
231
+ async handleAnalytics(res) {
232
+ try {
233
+ const analytics = await this.options.ecosystemService.getAggregatedAnalytics();
234
+ this.json(res, analytics);
235
+ }
236
+ catch (err) {
237
+ this.json(res, { error: err.message }, 500);
238
+ }
239
+ }
240
+ handleBorgToggle(req, res) {
241
+ if (!this.options.borgSync) {
242
+ this.json(res, { error: 'Borg sync not available' }, 501);
243
+ return;
244
+ }
245
+ let body = '';
246
+ req.on('data', (chunk) => { body += chunk.toString(); });
247
+ req.on('end', () => {
248
+ try {
249
+ const { enabled } = JSON.parse(body || '{}');
250
+ if (typeof enabled !== 'boolean') {
251
+ this.json(res, { error: 'Missing "enabled" boolean' }, 400);
252
+ return;
253
+ }
254
+ this.options.borgSync.setEnabled(enabled);
255
+ this.json(res, { enabled, toggled: true });
256
+ }
257
+ catch (err) {
258
+ this.json(res, { error: err.message }, 400);
259
+ }
260
+ });
261
+ }
262
+ handleSSE(req, res) {
263
+ res.writeHead(200, {
264
+ 'Content-Type': 'text/event-stream',
265
+ 'Cache-Control': 'no-cache',
266
+ 'Connection': 'keep-alive',
267
+ });
268
+ res.write(`event: connected\ndata: ${JSON.stringify({ clients: this.clients.size + 1 })}\n\n`);
269
+ this.clients.add(res);
270
+ req.on('close', () => this.clients.delete(res));
271
+ }
272
+ // ── Helpers ─────────────────────────────────────────────
273
+ broadcast(event, data) {
274
+ const msg = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
275
+ for (const client of this.clients) {
276
+ try {
277
+ client.write(msg);
278
+ }
279
+ catch {
280
+ this.clients.delete(client);
281
+ }
282
+ }
283
+ }
284
+ json(res, data, status = 200) {
285
+ res.writeHead(status, { 'Content-Type': 'application/json' });
286
+ res.end(JSON.stringify(data));
287
+ }
288
+ }
289
+ //# sourceMappingURL=command-center-server.js.map