@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.
- package/CHANGELOG.md +8 -0
- package/dist/src/dsl/index.d.ts +28 -0
- package/dist/src/dsl/index.d.ts.map +1 -0
- package/dist/src/dsl/index.js +113 -0
- package/dist/src/dsl/index.js.map +1 -0
- package/dist/src/dsl/types.d.ts +19 -0
- package/dist/src/dsl/types.d.ts.map +1 -0
- package/dist/src/dsl/types.js +2 -0
- package/dist/src/dsl/types.js.map +1 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +60 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/plugin-loader.d.ts +2 -0
- package/dist/src/plugin-loader.d.ts.map +1 -1
- package/dist/src/plugin-loader.js +11 -2
- package/dist/src/plugin-loader.js.map +1 -1
- package/dist/src/server/config-loader.d.ts +40 -0
- package/dist/src/server/config-loader.d.ts.map +1 -0
- package/dist/src/server/config-loader.js +141 -0
- package/dist/src/server/config-loader.js.map +1 -0
- package/dist/src/server/dashboard copy.html +1187 -0
- package/dist/src/server/dashboard-old.html +1187 -0
- package/dist/src/server/dashboard.html +1480 -0
- package/dist/src/server/file-syncer.d.ts +21 -0
- package/dist/src/server/file-syncer.d.ts.map +1 -0
- package/dist/src/server/file-syncer.js +101 -0
- package/dist/src/server/file-syncer.js.map +1 -0
- package/dist/src/server/logo-dark.svg +1 -0
- package/dist/src/server/logo-light.svg +24 -0
- package/dist/src/server/server.d.ts +88 -0
- package/dist/src/server/server.d.ts.map +1 -0
- package/dist/src/server/server.js +411 -0
- package/dist/src/server/server.js.map +1 -0
- package/dist/src/server/state-manager.d.ts +24 -0
- package/dist/src/server/state-manager.d.ts.map +1 -0
- package/dist/src/server/state-manager.js +56 -0
- package/dist/src/server/state-manager.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- 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
|