@auto-engineer/cli 0.7.5 → 0.7.6

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 (40) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/src/dsl/index.d.ts +28 -0
  3. package/dist/src/dsl/index.d.ts.map +1 -0
  4. package/dist/src/dsl/index.js +113 -0
  5. package/dist/src/dsl/index.js.map +1 -0
  6. package/dist/src/dsl/types.d.ts +19 -0
  7. package/dist/src/dsl/types.d.ts.map +1 -0
  8. package/dist/src/dsl/types.js +2 -0
  9. package/dist/src/dsl/types.js.map +1 -0
  10. package/dist/src/index.d.ts +1 -1
  11. package/dist/src/index.d.ts.map +1 -1
  12. package/dist/src/index.js +60 -0
  13. package/dist/src/index.js.map +1 -1
  14. package/dist/src/plugin-loader.d.ts +2 -0
  15. package/dist/src/plugin-loader.d.ts.map +1 -1
  16. package/dist/src/plugin-loader.js +11 -2
  17. package/dist/src/plugin-loader.js.map +1 -1
  18. package/dist/src/server/config-loader.d.ts +40 -0
  19. package/dist/src/server/config-loader.d.ts.map +1 -0
  20. package/dist/src/server/config-loader.js +141 -0
  21. package/dist/src/server/config-loader.js.map +1 -0
  22. package/dist/src/server/dashboard copy.html +1187 -0
  23. package/dist/src/server/dashboard-old.html +1187 -0
  24. package/dist/src/server/dashboard.html +1480 -0
  25. package/dist/src/server/file-syncer.d.ts +21 -0
  26. package/dist/src/server/file-syncer.d.ts.map +1 -0
  27. package/dist/src/server/file-syncer.js +101 -0
  28. package/dist/src/server/file-syncer.js.map +1 -0
  29. package/dist/src/server/logo-dark.svg +1 -0
  30. package/dist/src/server/logo-light.svg +24 -0
  31. package/dist/src/server/server.d.ts +88 -0
  32. package/dist/src/server/server.d.ts.map +1 -0
  33. package/dist/src/server/server.js +411 -0
  34. package/dist/src/server/server.js.map +1 -0
  35. package/dist/src/server/state-manager.d.ts +24 -0
  36. package/dist/src/server/state-manager.d.ts.map +1 -0
  37. package/dist/src/server/state-manager.js +56 -0
  38. package/dist/src/server/state-manager.js.map +1 -0
  39. package/dist/tsconfig.tsbuildinfo +1 -1
  40. package/package.json +15 -7
@@ -0,0 +1,21 @@
1
+ import type { Server as SocketIOServer } from 'socket.io';
2
+ export declare class FileSyncer {
3
+ private watcher?;
4
+ private io;
5
+ private watchDir;
6
+ private extensions;
7
+ constructor(io: SocketIOServer, watchDir?: string, extensions?: string[]);
8
+ /**
9
+ * Start watching files for changes
10
+ */
11
+ start(): void;
12
+ /**
13
+ * Get all initial files for syncing
14
+ */
15
+ private getInitialFiles;
16
+ /**
17
+ * Stop watching files
18
+ */
19
+ stop(): void;
20
+ }
21
+ //# sourceMappingURL=file-syncer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-syncer.d.ts","sourceRoot":"","sources":["../../../src/server/file-syncer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,IAAI,cAAc,EAAE,MAAM,WAAW,CAAC;AAa1D,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAC,CAAqB;IACrC,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAW;gBAEjB,EAAE,EAAE,cAAc,EAAE,QAAQ,SAAM,EAAE,UAAU,WAA2B;IAMrF;;OAEG;IACH,KAAK,IAAI,IAAI;IA4Db;;OAEG;YACW,eAAe;IAuB7B;;OAEG;IACH,IAAI,IAAI,IAAI;CAMb"}
@@ -0,0 +1,101 @@
1
+ import chokidar from 'chokidar';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import createDebug from 'debug';
5
+ const debug = createDebug('auto-engineer:server:file-syncer');
6
+ export class FileSyncer {
7
+ constructor(io, watchDir = '.', extensions = ['.js', '.html', '.css']) {
8
+ this.io = io;
9
+ this.watchDir = watchDir;
10
+ this.extensions = extensions;
11
+ }
12
+ /**
13
+ * Start watching files for changes
14
+ */
15
+ start() {
16
+ debug('Starting file syncer for directory:', this.watchDir);
17
+ debug('Watching extensions:', this.extensions);
18
+ // Set up file watcher
19
+ this.watcher = chokidar.watch(this.watchDir, {
20
+ ignored: /(^|[\\/\\])\./, // ignore dotfiles
21
+ persistent: true,
22
+ });
23
+ this.watcher.on('all', (event, filePath) => {
24
+ if (!this.extensions.some((ext) => filePath.endsWith(ext)))
25
+ return;
26
+ const relativePath = path.relative(this.watchDir, filePath);
27
+ debug('File event:', event, relativePath);
28
+ if (event === 'add' || event === 'change') {
29
+ const content = fs.readFileSync(filePath, 'base64');
30
+ this.io.emit('file-change', { event, path: relativePath, content });
31
+ }
32
+ else if (event === 'unlink') {
33
+ this.io.emit('file-change', { event: 'delete', path: relativePath });
34
+ }
35
+ });
36
+ // Handle client connections
37
+ this.io.on('connection', (socket) => {
38
+ debug('File sync client connected');
39
+ // Send initial file sync
40
+ this.getInitialFiles()
41
+ .then((files) => {
42
+ socket.emit('initial-sync', { files });
43
+ debug('Sent initial sync with', files.length, 'files');
44
+ })
45
+ .catch((err) => {
46
+ console.error('Initial sync failed:', err);
47
+ });
48
+ // Handle client file changes
49
+ socket.on('client-file-change', (data) => {
50
+ const fullPath = path.join(this.watchDir, data.path);
51
+ const dir = path.dirname(fullPath);
52
+ debug('Client file change:', data.event, data.path);
53
+ try {
54
+ if (data.event === 'delete') {
55
+ fs.unlinkSync(fullPath);
56
+ }
57
+ else {
58
+ fs.mkdirSync(dir, { recursive: true });
59
+ const content = Buffer.from(data.content ?? '', 'base64');
60
+ fs.writeFileSync(fullPath, content);
61
+ }
62
+ }
63
+ catch (error) {
64
+ console.error('Failed to handle client file change:', error);
65
+ }
66
+ });
67
+ });
68
+ }
69
+ /**
70
+ * Get all initial files for syncing
71
+ */
72
+ async getInitialFiles() {
73
+ const files = [];
74
+ const walk = async (dir) => {
75
+ const entries = await fs.promises.readdir(dir, { withFileTypes: true });
76
+ for (const entry of entries) {
77
+ const fullPath = path.join(dir, entry.name);
78
+ const relativePath = path.relative(this.watchDir, fullPath);
79
+ if (entry.isDirectory() && !entry.name.startsWith('.')) {
80
+ await walk(fullPath);
81
+ }
82
+ else if (entry.isFile() && this.extensions.some((ext) => relativePath.endsWith(ext))) {
83
+ const content = fs.readFileSync(fullPath, 'base64');
84
+ files.push({ path: relativePath, content });
85
+ }
86
+ }
87
+ };
88
+ await walk(this.watchDir);
89
+ return files;
90
+ }
91
+ /**
92
+ * Stop watching files
93
+ */
94
+ stop() {
95
+ if (this.watcher) {
96
+ debug('Stopping file syncer');
97
+ void this.watcher.close();
98
+ }
99
+ }
100
+ }
101
+ //# sourceMappingURL=file-syncer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-syncer.js","sourceRoot":"","sources":["../../../src/server/file-syncer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ <svg width="637" height="637" viewBox="0 0 637 637" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0_1042_512)"><rect width="637" height="637" fill="#1A1A1A"/><path d="M693.161 -427.743L-623.632 1532.31L-591.107 1552.06L725.686 -407.988L693.161 -427.743Z" fill="#EC3F4A"/><path d="M725.695 -407.962L-591.097 1552.09L-571.511 1563.98L745.281 -396.066L725.695 -407.962Z" fill="#1A1A1A"/><path d="M745.281 -396.071L-571.511 1563.98L-538.986 1583.73L777.807 -376.315L745.281 -396.071Z" fill="#FF8A1D"/><path d="M777.815 -376.302L-538.978 1583.75L-519.391 1595.64L797.402 -364.406L777.815 -376.302Z" fill="#1A1A1A"/><path d="M797.394 -364.425L-519.399 1595.62L-486.874 1615.38L829.919 -344.67L797.394 -364.425Z" fill="#5EC72D"/><path d="M829.913 -344.684L-486.879 1615.37L-467.293 1627.26L849.499 -332.787L829.913 -344.684Z" fill="#1A1A1A"/><path d="M849.467 -332.791L-467.326 1627.26L-434.801 1647.01L881.992 -313.035L849.467 -332.791Z" fill="#42C3F7"/><path d="M882 -313.038L-434.792 1647.01L-415.206 1658.91L901.587 -301.142L882 -313.038Z" fill="#1A1A1A"/><path d="M673.55 -439.635L-643.242 1520.42L-623.656 1532.31L693.136 -427.738L673.55 -439.635Z" fill="#1A1A1A"/><path d="M512.644 100H121.718C109.652 100 100 109.667 100 121.751V513.277C100 525.361 109.652 535.028 121.718 535.028H512.644C524.71 535.028 534.362 525.361 534.362 513.277V121.751C534.362 109.667 524.71 100 512.644 100Z" fill="white"/><path d="M413.706 481.86C451.11 481.86 481.274 451.649 481.274 414.189C481.274 376.728 451.11 346.518 413.706 346.518C376.303 346.518 346.139 376.728 346.139 414.189C346.139 451.649 376.303 481.86 413.706 481.86Z" fill="#1A1A1A"/><path d="M153.089 347.968C153.089 347.243 153.813 346.518 154.537 346.518H287.017C287.741 346.518 288.465 347.243 288.465 347.968V412.98C288.465 413.705 287.741 414.43 287.017 414.43H257.095C256.371 414.43 255.647 415.155 255.647 415.88V480.893C255.647 481.618 254.923 482.343 254.199 482.343H188.321C187.597 482.343 186.873 481.618 186.873 480.893V415.88C186.873 415.155 186.149 414.43 185.425 414.43H154.296C153.572 414.43 152.848 413.705 152.848 412.98V347.968H153.089Z" fill="#1A1A1A"/><path d="M347.587 153.17C346.863 153.17 346.139 153.895 346.139 154.621V223.017C346.139 259.269 376.303 288.513 413.706 288.513C451.11 288.513 481.274 259.269 481.274 223.017V154.621C481.274 153.895 480.55 153.17 479.826 153.17H347.345H347.587Z" fill="#1A1A1A"/><path d="M153.33 286.339C152.848 287.306 153.33 288.272 154.537 288.272H286.776C287.742 288.272 288.465 287.306 287.983 286.339L221.863 154.139C221.381 153.172 219.933 153.172 219.45 154.139L153.33 286.339Z" fill="#1A1A1A"/></g><defs><clipPath id="clip0_1042_512"><rect width="637" height="637" fill="white"/></clipPath></defs></svg>
@@ -0,0 +1,24 @@
1
+ <svg width="637" height="637" viewBox="0 0 637 637" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g clip-path="url(#clip0_1042_573)">
3
+ <rect width="637" height="637" fill="white"/>
4
+ <path d="M693.161 -427.743L-623.632 1532.31L-591.107 1552.06L725.686 -407.988L693.161 -427.743Z" fill="#EC3F4A"/>
5
+ <path d="M725.695 -407.962L-591.097 1552.09L-571.511 1563.98L745.281 -396.066L725.695 -407.962Z" fill="white"/>
6
+ <path d="M745.281 -396.071L-571.511 1563.98L-538.986 1583.73L777.807 -376.315L745.281 -396.071Z" fill="#FF8A1D"/>
7
+ <path d="M777.815 -376.302L-538.978 1583.75L-519.391 1595.64L797.402 -364.406L777.815 -376.302Z" fill="white"/>
8
+ <path d="M797.394 -364.425L-519.399 1595.62L-486.874 1615.38L829.919 -344.67L797.394 -364.425Z" fill="#5EC72D"/>
9
+ <path d="M829.913 -344.684L-486.879 1615.37L-467.293 1627.26L849.499 -332.787L829.913 -344.684Z" fill="white"/>
10
+ <path d="M849.467 -332.791L-467.326 1627.26L-434.801 1647.01L881.992 -313.035L849.467 -332.791Z" fill="#42C3F7"/>
11
+ <path d="M882 -313.038L-434.792 1647.01L-415.206 1658.91L901.587 -301.142L882 -313.038Z" fill="white"/>
12
+ <path d="M673.55 -439.635L-643.242 1520.42L-623.656 1532.31L693.136 -427.738L673.55 -439.635Z" fill="white"/>
13
+ <path d="M512.644 100H121.718C109.652 100 100 109.667 100 121.751V513.277C100 525.361 109.652 535.028 121.718 535.028H512.644C524.71 535.028 534.362 525.361 534.362 513.277V121.751C534.362 109.667 524.71 100 512.644 100Z" fill="#1A1A1A"/>
14
+ <path d="M413.706 481.86C451.11 481.86 481.274 451.649 481.274 414.189C481.274 376.728 451.11 346.518 413.706 346.518C376.303 346.518 346.139 376.728 346.139 414.189C346.139 451.649 376.303 481.86 413.706 481.86Z" fill="white"/>
15
+ <path d="M153.089 347.968C153.089 347.243 153.813 346.518 154.537 346.518H287.017C287.741 346.518 288.465 347.243 288.465 347.968V412.98C288.465 413.705 287.741 414.43 287.017 414.43H257.095C256.371 414.43 255.647 415.155 255.647 415.88V480.893C255.647 481.618 254.923 482.343 254.199 482.343H188.321C187.597 482.343 186.873 481.618 186.873 480.893V415.88C186.873 415.155 186.149 414.43 185.425 414.43H154.296C153.572 414.43 152.848 413.705 152.848 412.98V347.968H153.089Z" fill="white"/>
16
+ <path d="M347.587 153.17C346.863 153.17 346.139 153.895 346.139 154.621V223.017C346.139 259.269 376.303 288.513 413.706 288.513C451.11 288.513 481.274 259.269 481.274 223.017V154.621C481.274 153.895 480.55 153.17 479.826 153.17H347.345H347.587Z" fill="white"/>
17
+ <path d="M153.33 286.339C152.848 287.306 153.33 288.272 154.537 288.272H286.776C287.742 288.272 288.465 287.306 287.983 286.339L221.863 154.139C221.381 153.172 219.933 153.172 219.45 154.139L153.33 286.339Z" fill="white"/>
18
+ </g>
19
+ <defs>
20
+ <clipPath id="clip0_1042_573">
21
+ <rect width="637" height="637" fill="white"/>
22
+ </clipPath>
23
+ </defs>
24
+ </svg>
@@ -0,0 +1,88 @@
1
+ import { type MessageBus, type Event } from '@auto-engineer/message-bus';
2
+ import { StateManager } from './state-manager';
3
+ import type { EventRegistration, FoldRegistration } from '../dsl/types';
4
+ export interface MessageBusServerConfig {
5
+ port?: number;
6
+ wsPort?: number;
7
+ fileSyncDir?: string;
8
+ fileSyncExtensions?: string[];
9
+ enableFileSync?: boolean;
10
+ }
11
+ export declare class MessageBusServer {
12
+ private app;
13
+ private httpServer;
14
+ private io;
15
+ private messageBus;
16
+ private stateManager;
17
+ private fileSyncer?;
18
+ private config;
19
+ private eventHandlers;
20
+ private foldRegistry;
21
+ private commandHandlerNames;
22
+ private eventHistory;
23
+ private maxEventHistory;
24
+ constructor(config?: MessageBusServerConfig);
25
+ /**
26
+ * Set up global event listener for state management and event forwarding
27
+ */
28
+ private setupGlobalEventListener;
29
+ /**
30
+ * Set up HTTP routes
31
+ */
32
+ private setupRoutes;
33
+ /**
34
+ * Set up WebSocket handlers
35
+ */
36
+ private setupWebSocketHandlers;
37
+ /**
38
+ * Process handler result to reduce complexity
39
+ */
40
+ private processHandlerResult;
41
+ private processCommandArray;
42
+ private processActionOrCommand;
43
+ private processDispatchAction;
44
+ /**
45
+ * Register event handlers from DSL
46
+ */
47
+ registerEventHandler(registration: EventRegistration): void;
48
+ /**
49
+ * Register fold function from DSL
50
+ */
51
+ registerFold(registration: FoldRegistration): void;
52
+ /**
53
+ * Register command handlers directly with the message bus
54
+ */
55
+ registerCommandHandlers(handlers: unknown[]): void;
56
+ /**
57
+ * Initialize state
58
+ */
59
+ initializeState(state: unknown): void;
60
+ /**
61
+ * Start the server
62
+ */
63
+ start(): Promise<void>;
64
+ /**
65
+ * Stop the server
66
+ */
67
+ stop(): Promise<void>;
68
+ /**
69
+ * Get the message bus instance
70
+ */
71
+ getMessageBus(): MessageBus;
72
+ /**
73
+ * Get the state manager instance
74
+ */
75
+ getStateManager(): StateManager<Record<string, unknown>>;
76
+ /**
77
+ * Get the event history
78
+ */
79
+ getEventHistory(): Array<{
80
+ event: Event;
81
+ timestamp: string;
82
+ }>;
83
+ /**
84
+ * Clear event history
85
+ */
86
+ clearEventHistory(): void;
87
+ }
88
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/server/server.ts"],"names":[],"mappings":"AAIA,OAAO,EAAoB,KAAK,UAAU,EAAgB,KAAK,KAAK,EAAE,MAAM,4BAA4B,CAAC;AAEzG,OAAO,EAAE,YAAY,EAAqB,MAAM,iBAAiB,CAAC;AAElE,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAkB,MAAM,cAAc,CAAC;AASxF,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,GAAG,CAAsB;IACjC,OAAO,CAAC,UAAU,CAAkC;IACpD,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,UAAU,CAAC,CAAa;IAChC,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,aAAa,CAAyD;IAC9E,OAAO,CAAC,YAAY,CAAiE;IACrF,OAAO,CAAC,mBAAmB,CAAgB;IAC3C,OAAO,CAAC,YAAY,CAAkD;IACtE,OAAO,CAAC,eAAe,CAAQ;gBAEnB,MAAM,GAAE,sBAA2B;IAsC/C;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAqChC;;OAEG;IACH,OAAO,CAAC,WAAW;IAwGnB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA8C9B;;OAEG;YACW,oBAAoB;YAUpB,mBAAmB;YAgBnB,sBAAsB;YAWtB,qBAAqB;IAqBnC;;OAEG;IACH,oBAAoB,CAAC,YAAY,EAAE,iBAAiB,GAAG,IAAI;IAoB3D;;OAEG;IACH,YAAY,CAAC,YAAY,EAAE,gBAAgB,GAAG,IAAI;IAOlD;;OAEG;IACH,uBAAuB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI;IAiBlD;;OAEG;IACH,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IASrC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA+B5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB3B;;OAEG;IACH,aAAa,IAAI,UAAU;IAI3B;;OAEG;IACH,eAAe,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAIxD;;OAEG;IACH,eAAe,IAAI,KAAK,CAAC;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAI7D;;OAEG;IACH,iBAAiB,IAAI,IAAI;CAG1B"}
@@ -0,0 +1,411 @@
1
+ import express from 'express';
2
+ import cors from 'cors';
3
+ import { createServer } from 'http';
4
+ import { Server as SocketIOServer } from 'socket.io';
5
+ import { createMessageBus } from '@auto-engineer/message-bus';
6
+ import createDebug from 'debug';
7
+ import { StateManager } from './state-manager.js';
8
+ import { FileSyncer } from './file-syncer.js';
9
+ import { fileURLToPath } from 'url';
10
+ import { dirname, join } from 'path';
11
+ const debug = createDebug('auto-engineer:server');
12
+ const debugHttp = createDebug('auto-engineer:server:http');
13
+ const debugWs = createDebug('auto-engineer:server:ws');
14
+ const debugBus = createDebug('auto-engineer:server:bus');
15
+ export class MessageBusServer {
16
+ constructor(config = {}) {
17
+ this.eventHandlers = new Map();
18
+ this.foldRegistry = new Map();
19
+ this.commandHandlerNames = [];
20
+ this.eventHistory = [];
21
+ this.maxEventHistory = 1000; // Limit to prevent memory issues
22
+ this.config = {
23
+ port: config.port ?? 5555,
24
+ wsPort: config.wsPort ?? 5556,
25
+ fileSyncDir: config.fileSyncDir ?? '.',
26
+ fileSyncExtensions: config.fileSyncExtensions ?? ['.js', '.html', '.css'],
27
+ enableFileSync: config.enableFileSync !== false,
28
+ };
29
+ // Initialize Express app
30
+ this.app = express();
31
+ this.app.use(cors());
32
+ this.app.use(express.json());
33
+ // Create HTTP server
34
+ this.httpServer = createServer(this.app);
35
+ // Initialize Socket.IO on the same server
36
+ this.io = new SocketIOServer(this.httpServer, {
37
+ cors: { origin: '*' },
38
+ });
39
+ // Initialize message bus and state manager
40
+ this.messageBus = createMessageBus();
41
+ this.stateManager = new StateManager();
42
+ // Set up global event listener for state management
43
+ this.setupGlobalEventListener();
44
+ // Set up HTTP routes
45
+ this.setupRoutes();
46
+ // Set up WebSocket handlers
47
+ this.setupWebSocketHandlers();
48
+ debug('Message bus server initialized');
49
+ }
50
+ /**
51
+ * Set up global event listener for state management and event forwarding
52
+ */
53
+ setupGlobalEventListener() {
54
+ this.messageBus.subscribeAll({
55
+ name: 'ServerStateManager',
56
+ handle: async (event) => {
57
+ debugBus('Received event:', event.type);
58
+ // Store event in history
59
+ this.eventHistory.push({
60
+ event,
61
+ timestamp: new Date().toISOString(),
62
+ });
63
+ // Trim history if it exceeds max size
64
+ if (this.eventHistory.length > this.maxEventHistory) {
65
+ this.eventHistory = this.eventHistory.slice(-this.maxEventHistory);
66
+ }
67
+ // Apply event to state
68
+ this.stateManager.applyEvent(event);
69
+ // Trigger registered event handlers
70
+ const handlers = this.eventHandlers.get(event.type) || [];
71
+ for (const handler of handlers) {
72
+ try {
73
+ handler(event);
74
+ }
75
+ catch (error) {
76
+ console.error(`Error in event handler for ${event.type}:`, error);
77
+ }
78
+ }
79
+ // Broadcast event to WebSocket clients
80
+ this.io.emit('event', event);
81
+ debugWs('Broadcasted event to WebSocket clients:', event.type);
82
+ },
83
+ });
84
+ }
85
+ /**
86
+ * Set up HTTP routes
87
+ */
88
+ setupRoutes() {
89
+ // Health check endpoint
90
+ this.app.get('/health', (_req, res) => {
91
+ res.json({
92
+ status: 'healthy',
93
+ uptime: process.uptime(),
94
+ timestamp: new Date().toISOString(),
95
+ });
96
+ });
97
+ // Serve dashboard
98
+ this.app.get('/', (_req, res) => {
99
+ const __dirname = dirname(fileURLToPath(import.meta.url));
100
+ res.sendFile(join(__dirname, 'dashboard.html'));
101
+ });
102
+ // Get registry information
103
+ this.app.get('/registry', (_req, res) => {
104
+ res.json({
105
+ eventHandlers: Array.from(this.eventHandlers.keys()),
106
+ folds: Array.from(this.foldRegistry.keys()),
107
+ commandHandlers: this.commandHandlerNames,
108
+ });
109
+ });
110
+ // Get event history
111
+ this.app.get('/events', (_req, res) => {
112
+ res.json(this.eventHistory);
113
+ });
114
+ // Get current state
115
+ this.app.get('/state', (_req, res) => {
116
+ res.json(this.stateManager.getState());
117
+ });
118
+ // Command endpoint
119
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
120
+ this.app.post('/command', async (req, res) => {
121
+ try {
122
+ const command = req.body;
123
+ debugHttp('Received command:', command.type);
124
+ debugHttp('Command data:', command.data);
125
+ // Validate command structure
126
+ if (!command.type || !('data' in command)) {
127
+ return res.status(400).json({
128
+ status: 'nack',
129
+ error: 'Invalid command structure. Must have type and data fields.',
130
+ });
131
+ }
132
+ // Add request ID if not present
133
+ const hasRequestId = command.requestId !== null && command.requestId !== undefined && command.requestId !== '';
134
+ const cmdWithId = hasRequestId
135
+ ? command
136
+ : { ...command, requestId: `req-${Date.now()}-${Math.random().toString(36).substring(2, 11)}` };
137
+ // TODO: Add type validation based on command types
138
+ // validateCommand(command);
139
+ // Check if command handler exists
140
+ if (!this.commandHandlerNames.includes(cmdWithId.type)) {
141
+ return res.status(404).json({
142
+ status: 'nack',
143
+ error: `Command handler not found for command: ${cmdWithId.type}`,
144
+ availableCommands: this.commandHandlerNames,
145
+ });
146
+ }
147
+ // Send to message bus (non-blocking)
148
+ this.messageBus
149
+ .sendCommand(cmdWithId)
150
+ .then(() => {
151
+ debugHttp('Command processed successfully:', cmdWithId.type);
152
+ })
153
+ .catch((err) => {
154
+ console.error('Command failed:', err);
155
+ // Emit error event for UI to capture
156
+ this.io.emit('commandError', {
157
+ commandId: cmdWithId.requestId,
158
+ error: err instanceof Error ? err.message : String(err),
159
+ timestamp: new Date().toISOString(),
160
+ });
161
+ });
162
+ // Return acknowledgment immediately
163
+ res.json({
164
+ status: 'ack',
165
+ commandId: cmdWithId.requestId,
166
+ timestamp: new Date().toISOString(),
167
+ });
168
+ }
169
+ catch (error) {
170
+ debugHttp('Error processing command:', error);
171
+ res.status(400).json({
172
+ status: 'nack',
173
+ error: error instanceof Error ? error.message : 'Failed to process command',
174
+ });
175
+ }
176
+ });
177
+ debugHttp('HTTP routes configured');
178
+ }
179
+ /**
180
+ * Set up WebSocket handlers
181
+ */
182
+ setupWebSocketHandlers() {
183
+ this.io.on('connection', (socket) => {
184
+ debugWs('WebSocket client connected:', socket.id);
185
+ // Send current state to new client
186
+ socket.emit('state', this.stateManager.getState());
187
+ // Handle command from WebSocket
188
+ socket.on('command', async (command) => {
189
+ debugWs('Received command via WebSocket:', command.type);
190
+ try {
191
+ // Add request ID if not present
192
+ const hasRequestId = command.requestId !== null && command.requestId !== undefined && command.requestId !== '';
193
+ const cmdWithId = hasRequestId
194
+ ? command
195
+ : { ...command, requestId: `ws-${Date.now()}-${Math.random().toString(36).substring(2, 11)}` };
196
+ await this.messageBus.sendCommand(cmdWithId);
197
+ socket.emit('command-ack', {
198
+ status: 'ack',
199
+ commandId: cmdWithId.requestId,
200
+ });
201
+ }
202
+ catch (error) {
203
+ socket.emit('command-ack', {
204
+ status: 'nack',
205
+ error: error instanceof Error ? error.message : 'Unknown error',
206
+ });
207
+ }
208
+ });
209
+ // Handle state query
210
+ socket.on('get-state', () => {
211
+ socket.emit('state', this.stateManager.getState());
212
+ });
213
+ socket.on('disconnect', () => {
214
+ debugWs('WebSocket client disconnected:', socket.id);
215
+ });
216
+ });
217
+ debugWs('WebSocket handlers configured');
218
+ }
219
+ /**
220
+ * Process handler result to reduce complexity
221
+ */
222
+ async processHandlerResult(result) {
223
+ if (result === null || result === undefined)
224
+ return;
225
+ if (Array.isArray(result)) {
226
+ await this.processCommandArray(result);
227
+ }
228
+ else if (typeof result === 'object' && result !== null && 'type' in result) {
229
+ await this.processActionOrCommand(result);
230
+ }
231
+ }
232
+ async processCommandArray(commands) {
233
+ debugBus('Dispatching multiple commands from event handler');
234
+ for (const command of commands) {
235
+ if (command !== null &&
236
+ command !== undefined &&
237
+ typeof command === 'object' &&
238
+ 'type' in command &&
239
+ 'data' in command) {
240
+ debugBus('Dispatching command:', command.type);
241
+ await this.messageBus.sendCommand(command);
242
+ }
243
+ }
244
+ }
245
+ async processActionOrCommand(action) {
246
+ const actionObj = action;
247
+ if (actionObj !== null && typeof actionObj === 'object' && 'data' in actionObj) {
248
+ debugBus('Dispatching command from event handler:', action.type);
249
+ await this.messageBus.sendCommand(action);
250
+ }
251
+ else {
252
+ await this.processDispatchAction(action);
253
+ }
254
+ }
255
+ // eslint-disable-next-line complexity
256
+ async processDispatchAction(action) {
257
+ if (action.type === 'dispatch' && action.command) {
258
+ debugBus('Dispatching command from dispatch action:', action.command.type);
259
+ await this.messageBus.sendCommand(action.command);
260
+ }
261
+ else if (action.type === 'dispatch-parallel' && action.commands) {
262
+ debugBus('Dispatching parallel commands from event handler');
263
+ await Promise.all(action.commands.map((cmd) => this.messageBus.sendCommand(cmd)));
264
+ }
265
+ else if (action.type === 'dispatch-sequence' && action.commands) {
266
+ debugBus('Dispatching sequential commands from event handler');
267
+ for (const cmd of action.commands) {
268
+ await this.messageBus.sendCommand(cmd);
269
+ }
270
+ }
271
+ else if (action.type === 'dispatch-custom' && action.commandFactory) {
272
+ const cmds = action.commandFactory();
273
+ const commands = Array.isArray(cmds) ? cmds : [cmds];
274
+ for (const cmd of commands) {
275
+ await this.messageBus.sendCommand(cmd);
276
+ }
277
+ }
278
+ }
279
+ /**
280
+ * Register event handlers from DSL
281
+ */
282
+ registerEventHandler(registration) {
283
+ debug('Registering event handler for:', registration.eventType);
284
+ const handler = async (event) => {
285
+ try {
286
+ const result = registration.handler(event);
287
+ await this.processHandlerResult(result);
288
+ }
289
+ catch (error) {
290
+ console.error('Error in event handler:', error);
291
+ }
292
+ };
293
+ // Store handler for later execution
294
+ if (!this.eventHandlers.has(registration.eventType)) {
295
+ this.eventHandlers.set(registration.eventType, []);
296
+ }
297
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
298
+ this.eventHandlers.get(registration.eventType).push(handler);
299
+ }
300
+ /**
301
+ * Register fold function from DSL
302
+ */
303
+ registerFold(registration) {
304
+ debug('Registering fold for:', registration.eventType);
305
+ const foldFn = registration.reducer;
306
+ this.stateManager.registerFold(registration.eventType, foldFn);
307
+ this.foldRegistry.set(registration.eventType, foldFn);
308
+ }
309
+ /**
310
+ * Register command handlers directly with the message bus
311
+ */
312
+ registerCommandHandlers(handlers) {
313
+ for (const handler of handlers) {
314
+ if (handler !== null &&
315
+ handler !== undefined &&
316
+ typeof handler === 'object' &&
317
+ 'name' in handler &&
318
+ 'handle' in handler) {
319
+ const cmdHandler = handler;
320
+ debugBus('Registering command handler:', cmdHandler.name);
321
+ this.messageBus.registerCommandHandler(cmdHandler);
322
+ this.commandHandlerNames.push(cmdHandler.name);
323
+ }
324
+ }
325
+ }
326
+ /**
327
+ * Initialize state
328
+ */
329
+ initializeState(state) {
330
+ // Update the existing state manager's state rather than creating a new one
331
+ // This preserves registered folds
332
+ // Use type assertion through unknown to access private property
333
+ const sm = this.stateManager;
334
+ sm.state = state;
335
+ debug('State initialized:', state);
336
+ }
337
+ /**
338
+ * Start the server
339
+ */
340
+ async start() {
341
+ const { port, enableFileSync, fileSyncDir, fileSyncExtensions } = this.config;
342
+ // Start file syncer if enabled
343
+ if (enableFileSync === true) {
344
+ this.fileSyncer = new FileSyncer(this.io, fileSyncDir, fileSyncExtensions);
345
+ this.fileSyncer.start();
346
+ debug(`File syncer started for ${fileSyncDir} with extensions: ${fileSyncExtensions?.join(', ')}`);
347
+ }
348
+ // Start HTTP/WebSocket server
349
+ await new Promise((resolve) => {
350
+ this.httpServer.listen(port, () => {
351
+ console.log(`Message bus server running on port ${port}`);
352
+ console.log(`Dashboard available at http://localhost:${port}`);
353
+ console.log(`WebSocket server available on ws://localhost:${port}`);
354
+ if (enableFileSync === true) {
355
+ console.log(`File sync enabled for ${fileSyncDir} (extensions: ${fileSyncExtensions?.join(', ')})`);
356
+ }
357
+ resolve();
358
+ });
359
+ });
360
+ // TODO: Add event store integration here
361
+ // this.eventStore = new EventStore();
362
+ // this.messageBus.subscribeAll({
363
+ // name: 'EventStore',
364
+ // handle: event => this.eventStore.append(event)
365
+ // });
366
+ }
367
+ /**
368
+ * Stop the server
369
+ */
370
+ async stop() {
371
+ debug('Stopping message bus server');
372
+ // Stop file syncer
373
+ if (this.fileSyncer) {
374
+ this.fileSyncer.stop();
375
+ }
376
+ // Close WebSocket connections
377
+ await this.io.close();
378
+ // Close HTTP server
379
+ await new Promise((resolve) => {
380
+ this.httpServer.close(() => {
381
+ debug('Server stopped');
382
+ resolve();
383
+ });
384
+ });
385
+ }
386
+ /**
387
+ * Get the message bus instance
388
+ */
389
+ getMessageBus() {
390
+ return this.messageBus;
391
+ }
392
+ /**
393
+ * Get the state manager instance
394
+ */
395
+ getStateManager() {
396
+ return this.stateManager;
397
+ }
398
+ /**
399
+ * Get the event history
400
+ */
401
+ getEventHistory() {
402
+ return this.eventHistory;
403
+ }
404
+ /**
405
+ * Clear event history
406
+ */
407
+ clearEventHistory() {
408
+ this.eventHistory = [];
409
+ }
410
+ }
411
+ //# sourceMappingURL=server.js.map