@timmeck/brain-core 2.36.14 → 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.
@@ -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":"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"}
@@ -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