@esotech/contextuate 2.0.0 → 2.1.1

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 (103) hide show
  1. package/README.md +169 -1
  2. package/dist/commands/claude.d.ts +21 -0
  3. package/dist/commands/claude.js +213 -0
  4. package/dist/commands/context.d.ts +1 -0
  5. package/dist/commands/create.d.ts +3 -0
  6. package/dist/commands/index.d.ts +4 -0
  7. package/dist/commands/init.d.ts +7 -0
  8. package/dist/commands/init.js +67 -6
  9. package/dist/commands/install.d.ts +28 -0
  10. package/dist/commands/install.js +100 -11
  11. package/dist/commands/monitor.d.ts +55 -0
  12. package/dist/commands/monitor.js +1007 -0
  13. package/dist/commands/remove.d.ts +3 -0
  14. package/dist/commands/run.d.ts +6 -0
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.js +113 -1
  17. package/dist/monitor/daemon/circuit-breaker.d.ts +121 -0
  18. package/dist/monitor/daemon/circuit-breaker.js +552 -0
  19. package/dist/monitor/daemon/cli.d.ts +8 -0
  20. package/dist/monitor/daemon/cli.js +82 -0
  21. package/dist/monitor/daemon/index.d.ts +137 -0
  22. package/dist/monitor/daemon/index.js +695 -0
  23. package/dist/monitor/daemon/notifier.d.ts +25 -0
  24. package/dist/monitor/daemon/notifier.js +98 -0
  25. package/dist/monitor/daemon/processor.d.ts +89 -0
  26. package/dist/monitor/daemon/processor.js +455 -0
  27. package/dist/monitor/daemon/state.d.ts +80 -0
  28. package/dist/monitor/daemon/state.js +162 -0
  29. package/dist/monitor/daemon/watcher.d.ts +47 -0
  30. package/dist/monitor/daemon/watcher.js +171 -0
  31. package/dist/monitor/daemon/wrapper-manager.d.ts +106 -0
  32. package/dist/monitor/daemon/wrapper-manager.js +374 -0
  33. package/dist/monitor/hooks/emit-event.js +652 -0
  34. package/dist/monitor/persistence/file-store.d.ts +88 -0
  35. package/dist/monitor/persistence/file-store.js +335 -0
  36. package/dist/monitor/persistence/index.d.ts +7 -0
  37. package/dist/monitor/persistence/index.js +10 -0
  38. package/dist/monitor/server/adapters/redis.d.ts +38 -0
  39. package/dist/monitor/server/adapters/redis.js +213 -0
  40. package/dist/monitor/server/adapters/unix-socket.d.ts +33 -0
  41. package/dist/monitor/server/adapters/unix-socket.js +182 -0
  42. package/dist/monitor/server/broker.d.ts +135 -0
  43. package/dist/monitor/server/broker.js +475 -0
  44. package/dist/monitor/server/cli.d.ts +8 -0
  45. package/dist/monitor/server/cli.js +98 -0
  46. package/dist/monitor/server/fastify.d.ts +16 -0
  47. package/dist/monitor/server/fastify.js +184 -0
  48. package/dist/monitor/server/index.d.ts +36 -0
  49. package/dist/monitor/server/index.js +153 -0
  50. package/dist/monitor/server/websocket.d.ts +80 -0
  51. package/dist/monitor/server/websocket.js +453 -0
  52. package/dist/monitor/ui/assets/index-4IssW9On.js +59 -0
  53. package/dist/monitor/ui/assets/index-vo9hLe5R.css +32 -0
  54. package/dist/monitor/ui/favicon.png +0 -0
  55. package/dist/monitor/ui/index.html +14 -0
  56. package/dist/monitor/ui/logo.png +0 -0
  57. package/dist/monitor/ui/logo.svg +1 -0
  58. package/dist/runtime/driver.d.ts +16 -0
  59. package/dist/runtime/tools.d.ts +10 -0
  60. package/dist/templates/README.md +33 -7
  61. package/dist/templates/agents/aegis.md +4 -0
  62. package/dist/templates/agents/archon.md +13 -22
  63. package/dist/templates/agents/atlas.md +4 -0
  64. package/dist/templates/agents/canvas.md +4 -0
  65. package/dist/templates/agents/chronicle.md +4 -0
  66. package/dist/templates/agents/chronos.md +4 -0
  67. package/dist/templates/agents/cipher.md +4 -0
  68. package/dist/templates/agents/crucible.md +4 -0
  69. package/dist/templates/agents/echo.md +4 -0
  70. package/dist/templates/agents/forge.md +4 -0
  71. package/dist/templates/agents/ledger.md +4 -0
  72. package/dist/templates/agents/meridian.md +4 -0
  73. package/dist/templates/agents/nexus.md +4 -0
  74. package/dist/templates/agents/pythia.md +217 -0
  75. package/dist/templates/agents/scribe.md +4 -0
  76. package/dist/templates/agents/sentinel.md +4 -0
  77. package/dist/templates/agents/{oracle.md → thoth.md} +11 -7
  78. package/dist/templates/agents/unity.md +4 -0
  79. package/dist/templates/agents/vox.md +4 -0
  80. package/dist/templates/agents/weaver.md +4 -0
  81. package/dist/templates/commands/consult.md +138 -0
  82. package/dist/templates/commands/orchestrate.md +173 -0
  83. package/dist/templates/framework-agents/documentation-expert.md +3 -3
  84. package/dist/templates/framework-agents/tools-expert.md +8 -8
  85. package/dist/templates/standards/agent-roles.md +68 -21
  86. package/dist/templates/standards/coding-standards.md +9 -26
  87. package/dist/templates/templates/context.md +17 -2
  88. package/dist/templates/templates/contextuate.md +21 -28
  89. package/dist/templates/tools/{agent-creator.tool.md → agent-creator.md} +3 -3
  90. package/dist/types/monitor.d.ts +660 -0
  91. package/dist/types/monitor.js +75 -0
  92. package/dist/utils/git.d.ts +9 -0
  93. package/dist/utils/tokens.d.ts +10 -0
  94. package/package.json +18 -5
  95. package/dist/templates/version.json +0 -8
  96. /package/dist/templates/templates/standards/{go.standards.md → go.md} +0 -0
  97. /package/dist/templates/templates/standards/{java.standards.md → java.md} +0 -0
  98. /package/dist/templates/templates/standards/{javascript.standards.md → javascript.md} +0 -0
  99. /package/dist/templates/templates/standards/{php.standards.md → php.md} +0 -0
  100. /package/dist/templates/templates/standards/{python.standards.md → python.md} +0 -0
  101. /package/dist/templates/tools/{quickref.tool.md → quickref.md} +0 -0
  102. /package/dist/templates/tools/{spawn.tool.md → spawn.md} +0 -0
  103. /package/dist/templates/tools/{standards-detector.tool.md → standards-detector.md} +0 -0
@@ -0,0 +1,475 @@
1
+ "use strict";
2
+ /**
3
+ * Event Broker
4
+ *
5
+ * Session management and WebSocket broadcast layer for the 3-layer architecture.
6
+ *
7
+ * Role:
8
+ * - Load sessions from disk on startup
9
+ * - Connect to daemon to receive processed events and session updates
10
+ * - Handle session management actions (rename, pin, hide, delete, set parent)
11
+ * - Broadcast updates to WebSocket clients
12
+ * - Subscribe to Redis for multi-machine UI aggregation (optional)
13
+ *
14
+ * Note: Event processing (correlation, parent linking, etc.) is handled by the daemon.
15
+ */
16
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ var desc = Object.getOwnPropertyDescriptor(m, k);
19
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
20
+ desc = { enumerable: true, get: function() { return m[k]; } };
21
+ }
22
+ Object.defineProperty(o, k2, desc);
23
+ }) : (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ o[k2] = m[k];
26
+ }));
27
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
28
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
29
+ }) : function(o, v) {
30
+ o["default"] = v;
31
+ });
32
+ var __importStar = (this && this.__importStar) || (function () {
33
+ var ownKeys = function(o) {
34
+ ownKeys = Object.getOwnPropertyNames || function (o) {
35
+ var ar = [];
36
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
37
+ return ar;
38
+ };
39
+ return ownKeys(o);
40
+ };
41
+ return function (mod) {
42
+ if (mod && mod.__esModule) return mod;
43
+ var result = {};
44
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
45
+ __setModuleDefault(result, mod);
46
+ return result;
47
+ };
48
+ })();
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.EventBroker = void 0;
51
+ const net = __importStar(require("net"));
52
+ class EventBroker {
53
+ constructor(config) {
54
+ this.daemonSocket = null;
55
+ this.persistence = null;
56
+ this.handlers = new Set();
57
+ this.sessions = new Map();
58
+ this.reconnectTimeout = null;
59
+ this.stopping = false;
60
+ this.connectionAttempts = 0;
61
+ this.config = config;
62
+ }
63
+ /**
64
+ * Start the event broker
65
+ */
66
+ async start() {
67
+ // Load sessions from disk
68
+ await this.loadSessions();
69
+ // Connect to daemon socket (optional - daemon may not be running)
70
+ this.connectToDaemon();
71
+ console.log('[Broker] Started - sessions loaded, daemon connection initiated');
72
+ }
73
+ /**
74
+ * Stop the event broker
75
+ */
76
+ async stop() {
77
+ // Set stopping flag BEFORE clearing timeout or destroying socket
78
+ // This prevents the close event from scheduling a new reconnection
79
+ this.stopping = true;
80
+ if (this.reconnectTimeout) {
81
+ clearTimeout(this.reconnectTimeout);
82
+ this.reconnectTimeout = null;
83
+ }
84
+ if (this.daemonSocket) {
85
+ this.daemonSocket.destroy();
86
+ this.daemonSocket = null;
87
+ }
88
+ console.log('[Broker] Stopped');
89
+ }
90
+ /**
91
+ * Connect to daemon socket to receive processed events
92
+ */
93
+ connectToDaemon() {
94
+ const socketPath = '/tmp/contextuate-daemon.sock';
95
+ this.daemonSocket = net.createConnection(socketPath);
96
+ let buffer = '';
97
+ this.daemonSocket.on('data', (data) => {
98
+ buffer += data.toString();
99
+ const lines = buffer.split('\n');
100
+ buffer = lines.pop() || '';
101
+ for (const line of lines) {
102
+ if (line.trim()) {
103
+ try {
104
+ const message = JSON.parse(line);
105
+ this.handleDaemonMessage(message);
106
+ }
107
+ catch (err) {
108
+ console.error('[Broker] Failed to parse daemon message:', err);
109
+ }
110
+ }
111
+ }
112
+ });
113
+ this.daemonSocket.on('connect', () => {
114
+ this.connectionAttempts = 0; // Reset on successful connection
115
+ console.log('[Broker] Connected to daemon');
116
+ });
117
+ this.daemonSocket.on('error', (err) => {
118
+ // Only log after a few attempts to avoid noise during startup
119
+ if (this.connectionAttempts >= 3) {
120
+ console.log('[Broker] Daemon connection error:', err.message);
121
+ }
122
+ this.scheduleDaemonReconnect();
123
+ });
124
+ this.daemonSocket.on('close', () => {
125
+ if (!this.stopping && this.connectionAttempts === 0) {
126
+ // Only log if we were previously connected
127
+ console.log('[Broker] Daemon connection closed, will retry...');
128
+ }
129
+ this.scheduleDaemonReconnect();
130
+ });
131
+ }
132
+ /**
133
+ * Schedule reconnection to daemon
134
+ */
135
+ scheduleDaemonReconnect() {
136
+ // Don't reconnect if we're stopping
137
+ if (this.stopping) {
138
+ return;
139
+ }
140
+ if (this.reconnectTimeout) {
141
+ return;
142
+ }
143
+ this.connectionAttempts++;
144
+ // Fast retries initially (500ms for first 5 attempts), then slow down
145
+ const delay = this.connectionAttempts <= 5 ? 500 : 5000;
146
+ this.reconnectTimeout = setTimeout(() => {
147
+ this.reconnectTimeout = null;
148
+ // Double-check stopping flag before reconnecting
149
+ if (!this.stopping) {
150
+ this.connectToDaemon();
151
+ }
152
+ }, delay);
153
+ }
154
+ /**
155
+ * Handle message from daemon
156
+ */
157
+ handleDaemonMessage(message) {
158
+ if (message.type === 'session_update') {
159
+ // Update local session cache
160
+ const session = message.session;
161
+ const isNew = !this.sessions.has(session.sessionId);
162
+ this.sessions.set(session.sessionId, session);
163
+ // Emit to WebSocket clients
164
+ if (isNew) {
165
+ this.emit('session_created', session);
166
+ }
167
+ else {
168
+ this.emit('session_updated', session);
169
+ }
170
+ }
171
+ else if (message.type === 'wrapper_connected') {
172
+ // Wrapper session connected
173
+ this.emit('wrapper_connected', {
174
+ wrapperId: message.wrapperId,
175
+ state: message.state,
176
+ });
177
+ }
178
+ else if (message.type === 'wrapper_disconnected') {
179
+ // Wrapper session disconnected
180
+ this.emit('wrapper_disconnected', {
181
+ wrapperId: message.wrapperId,
182
+ exitCode: message.exitCode,
183
+ });
184
+ }
185
+ else if (message.type === 'wrapper_state') {
186
+ // Wrapper state changed
187
+ this.emit('wrapper_state', {
188
+ wrapperId: message.wrapperId,
189
+ state: message.state,
190
+ claudeSessionId: message.claudeSessionId,
191
+ });
192
+ }
193
+ else if (message.type === 'wrapper_output') {
194
+ // Wrapper terminal output
195
+ this.emit('wrapper_output', {
196
+ wrapperId: message.wrapperId,
197
+ data: message.data,
198
+ timestamp: message.timestamp,
199
+ });
200
+ }
201
+ else if (message.type === 'wrapper_spawned') {
202
+ // Wrapper spawn response
203
+ this.emit('wrapper_spawned', {
204
+ wrapperId: message.wrapperId || '',
205
+ success: message.success,
206
+ error: message.error,
207
+ });
208
+ }
209
+ else if (message.type === 'wrappers_list') {
210
+ // List of active wrappers from daemon
211
+ this.emit('wrappers_list', {
212
+ wrappers: message.wrappers || [],
213
+ });
214
+ }
215
+ else if (message.eventType) {
216
+ // This is an event from the daemon
217
+ const event = message;
218
+ this.emit('event', event);
219
+ }
220
+ }
221
+ /**
222
+ * Send a message to the daemon
223
+ */
224
+ sendToDaemon(message) {
225
+ if (this.daemonSocket && this.daemonSocket.writable) {
226
+ this.daemonSocket.write(JSON.stringify(message) + '\n');
227
+ }
228
+ else {
229
+ console.error('[Broker] Cannot send to daemon - not connected');
230
+ }
231
+ }
232
+ /**
233
+ * Set the persistence store
234
+ */
235
+ setPersistence(store) {
236
+ this.persistence = store;
237
+ }
238
+ /**
239
+ * Register an event handler
240
+ */
241
+ onEvent(handler) {
242
+ this.handlers.add(handler);
243
+ return () => this.handlers.delete(handler);
244
+ }
245
+ /**
246
+ * Get all active sessions
247
+ */
248
+ getSessions(includeHidden = true) {
249
+ const sessions = Array.from(this.sessions.values());
250
+ if (includeHidden) {
251
+ return sessions;
252
+ }
253
+ return sessions.filter(session => !session.hidden);
254
+ }
255
+ /**
256
+ * Get a specific session
257
+ */
258
+ getSession(sessionId) {
259
+ return this.sessions.get(sessionId);
260
+ }
261
+ /**
262
+ * Persist session to storage
263
+ */
264
+ async persistSession(session) {
265
+ if (this.persistence) {
266
+ try {
267
+ await this.persistence.saveSession(session);
268
+ }
269
+ catch (err) {
270
+ console.error('[Broker] Failed to persist session:', err);
271
+ }
272
+ }
273
+ }
274
+ /**
275
+ * Emit event to all handlers
276
+ */
277
+ emit(type, data) {
278
+ this.handlers.forEach((handler) => {
279
+ try {
280
+ const result = handler(type, data);
281
+ if (result instanceof Promise) {
282
+ result.catch((err) => {
283
+ console.error('[Broker] Handler error:', err);
284
+ });
285
+ }
286
+ }
287
+ catch (err) {
288
+ console.error('[Broker] Handler error:', err);
289
+ }
290
+ });
291
+ }
292
+ /**
293
+ * Load existing sessions from persistence (disk)
294
+ */
295
+ async loadSessions() {
296
+ if (this.persistence) {
297
+ try {
298
+ const sessions = await this.persistence.getSessions();
299
+ for (const session of sessions) {
300
+ this.sessions.set(session.sessionId, session);
301
+ }
302
+ console.log(`[Broker] Loaded ${sessions.length} sessions from persistence`);
303
+ }
304
+ catch (err) {
305
+ console.error('[Broker] Failed to load sessions:', err);
306
+ }
307
+ }
308
+ }
309
+ /**
310
+ * Get configuration
311
+ */
312
+ getConfig() {
313
+ return this.config;
314
+ }
315
+ /**
316
+ * Hide a session (soft-hide, preserves data)
317
+ */
318
+ async hideSession(sessionId) {
319
+ const session = this.sessions.get(sessionId);
320
+ if (!session) {
321
+ throw new Error(`Session not found: ${sessionId}`);
322
+ }
323
+ session.hidden = true;
324
+ await this.persistSession(session);
325
+ this.emit('session_updated', session);
326
+ console.log(`[Broker] Session hidden: ${sessionId.slice(0, 8)}`);
327
+ }
328
+ /**
329
+ * Unhide a session
330
+ */
331
+ async unhideSession(sessionId) {
332
+ const session = this.sessions.get(sessionId);
333
+ if (!session) {
334
+ throw new Error(`Session not found: ${sessionId}`);
335
+ }
336
+ session.hidden = false;
337
+ await this.persistSession(session);
338
+ this.emit('session_updated', session);
339
+ console.log(`[Broker] Session unhidden: ${sessionId.slice(0, 8)}`);
340
+ }
341
+ /**
342
+ * Delete a session (permanent removal)
343
+ */
344
+ async deleteSession(sessionId) {
345
+ const session = this.sessions.get(sessionId);
346
+ if (!session) {
347
+ throw new Error(`Session not found: ${sessionId}`);
348
+ }
349
+ // Remove from parent's child list if applicable
350
+ if (session.parentSessionId) {
351
+ const parent = this.sessions.get(session.parentSessionId);
352
+ if (parent) {
353
+ parent.childSessionIds = parent.childSessionIds.filter(id => id !== sessionId);
354
+ await this.persistSession(parent);
355
+ this.emit('session_updated', parent);
356
+ }
357
+ }
358
+ // Remove from memory
359
+ this.sessions.delete(sessionId);
360
+ // Remove from persistence
361
+ if (this.persistence) {
362
+ try {
363
+ await this.persistence.deleteSession(sessionId);
364
+ }
365
+ catch (err) {
366
+ console.error('[Broker] Failed to delete session from persistence:', err);
367
+ }
368
+ }
369
+ console.log(`[Broker] Session deleted: ${sessionId.slice(0, 8)}`);
370
+ }
371
+ /**
372
+ * Hide all sessions
373
+ */
374
+ async hideAllSessions() {
375
+ const sessions = Array.from(this.sessions.values());
376
+ for (const session of sessions) {
377
+ session.hidden = true;
378
+ await this.persistSession(session);
379
+ }
380
+ console.log(`[Broker] All sessions hidden (${sessions.length} total)`);
381
+ }
382
+ /**
383
+ * Delete all sessions
384
+ */
385
+ async deleteAllSessions() {
386
+ const sessionIds = Array.from(this.sessions.keys());
387
+ // Clear memory
388
+ this.sessions.clear();
389
+ // Clear persistence
390
+ if (this.persistence) {
391
+ try {
392
+ await this.persistence.deleteAllSessions();
393
+ }
394
+ catch (err) {
395
+ console.error('[Broker] Failed to delete all sessions from persistence:', err);
396
+ }
397
+ }
398
+ console.log(`[Broker] All sessions deleted (${sessionIds.length} total)`);
399
+ }
400
+ /**
401
+ * Manually set parent session (user override for grouping)
402
+ */
403
+ async setParentSession(sessionId, parentSessionId) {
404
+ const session = this.sessions.get(sessionId);
405
+ if (!session) {
406
+ throw new Error(`Session not found: ${sessionId}`);
407
+ }
408
+ // Remove from old parent's child list
409
+ if (session.parentSessionId) {
410
+ const oldParent = this.sessions.get(session.parentSessionId);
411
+ if (oldParent) {
412
+ oldParent.childSessionIds = oldParent.childSessionIds.filter(id => id !== sessionId);
413
+ await this.persistSession(oldParent);
414
+ this.emit('session_updated', oldParent);
415
+ }
416
+ }
417
+ // Update session's parent
418
+ session.parentSessionId = parentSessionId || undefined;
419
+ session.manualParentSessionId = parentSessionId || undefined;
420
+ session.isUserInitiated = !parentSessionId; // No parent = user-initiated
421
+ // Add to new parent's child list
422
+ if (parentSessionId) {
423
+ const newParent = this.sessions.get(parentSessionId);
424
+ if (newParent && !newParent.childSessionIds.includes(sessionId)) {
425
+ newParent.childSessionIds.push(sessionId);
426
+ await this.persistSession(newParent);
427
+ this.emit('session_updated', newParent);
428
+ }
429
+ }
430
+ await this.persistSession(session);
431
+ this.emit('session_updated', session);
432
+ console.log(`[Broker] Session ${sessionId.slice(0, 8)} parent set to ${parentSessionId?.slice(0, 8) || 'none'}`);
433
+ }
434
+ /**
435
+ * Toggle session pinned state
436
+ */
437
+ async togglePin(sessionId) {
438
+ const session = this.sessions.get(sessionId);
439
+ if (!session) {
440
+ throw new Error(`Session not found: ${sessionId}`);
441
+ }
442
+ session.isPinned = !session.isPinned;
443
+ await this.persistSession(session);
444
+ this.emit('session_updated', session);
445
+ console.log(`[Broker] Session ${sessionId.slice(0, 8)} ${session.isPinned ? 'pinned' : 'unpinned'}`);
446
+ }
447
+ /**
448
+ * Set whether a session is user-initiated
449
+ */
450
+ async setUserInitiated(sessionId, isUserInitiated) {
451
+ const session = this.sessions.get(sessionId);
452
+ if (!session) {
453
+ throw new Error(`Session not found: ${sessionId}`);
454
+ }
455
+ session.isUserInitiated = isUserInitiated;
456
+ await this.persistSession(session);
457
+ this.emit('session_updated', session);
458
+ console.log(`[Broker] Session ${sessionId.slice(0, 8)} marked as ${isUserInitiated ? 'user-initiated' : 'sub-agent'}`);
459
+ }
460
+ /**
461
+ * Rename a session (set custom label)
462
+ */
463
+ async renameSession(sessionId, label) {
464
+ const session = this.sessions.get(sessionId);
465
+ if (!session) {
466
+ throw new Error(`Session not found: ${sessionId}`);
467
+ }
468
+ // Empty string clears the label
469
+ session.label = label.trim() || undefined;
470
+ await this.persistSession(session);
471
+ this.emit('session_updated', session);
472
+ console.log(`[Broker] Session ${sessionId.slice(0, 8)} renamed to "${session.label || '(cleared)'}"`);
473
+ }
474
+ }
475
+ exports.EventBroker = EventBroker;
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Server CLI Entry Point
4
+ *
5
+ * This is the entry point for running the UI server as a standalone process.
6
+ * Used when starting the server in detached mode.
7
+ */
8
+ export {};
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Server CLI Entry Point
5
+ *
6
+ * This is the entry point for running the UI server as a standalone process.
7
+ * Used when starting the server in detached mode.
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ const fs = __importStar(require("fs"));
44
+ const commander_1 = require("commander");
45
+ const index_js_1 = require("./index.js");
46
+ const monitor_js_1 = require("../../types/monitor.js");
47
+ const PATHS = (0, monitor_js_1.getDefaultMonitorPaths)();
48
+ const program = new commander_1.Command();
49
+ program
50
+ .name('contextuate-server')
51
+ .description('Contextuate Monitor UI Server')
52
+ .option('-c, --config <path>', 'Path to config file')
53
+ .option('-p, --port <port>', 'HTTP port override', parseInt)
54
+ .option('-w, --ws-port <port>', 'WebSocket port override', parseInt)
55
+ .parse(process.argv);
56
+ const options = program.opts();
57
+ async function main() {
58
+ if (!options.config) {
59
+ console.error('[Error] Config file path is required (--config)');
60
+ process.exit(1);
61
+ }
62
+ // Load configuration
63
+ let config;
64
+ try {
65
+ const configContent = await fs.promises.readFile(options.config, 'utf-8');
66
+ config = JSON.parse(configContent);
67
+ }
68
+ catch (err) {
69
+ console.error(`[Error] Failed to load config: ${err.message}`);
70
+ process.exit(1);
71
+ }
72
+ // Apply command-line overrides
73
+ if (options.port) {
74
+ config.server.port = options.port;
75
+ }
76
+ if (options.wsPort) {
77
+ config.server.wsPort = options.wsPort;
78
+ }
79
+ // Create and start server
80
+ const server = await (0, index_js_1.createMonitorServer)({
81
+ config,
82
+ dataDir: PATHS.baseDir
83
+ });
84
+ await server.start();
85
+ console.log(`[Server] UI server running on http://localhost:${config.server.port}`);
86
+ // Handle shutdown signals
87
+ const shutdown = async () => {
88
+ console.log('\n[Info] Shutting down server...');
89
+ await server.stop();
90
+ process.exit(0);
91
+ };
92
+ process.on('SIGINT', shutdown);
93
+ process.on('SIGTERM', shutdown);
94
+ }
95
+ main().catch((err) => {
96
+ console.error('[Error] Fatal error:', err);
97
+ process.exit(1);
98
+ });
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Fastify HTTP Server
3
+ *
4
+ * Serves the Vue UI and provides REST API endpoints
5
+ * for the monitor dashboard.
6
+ */
7
+ import { FastifyInstance } from 'fastify';
8
+ import type { EventBroker } from './broker';
9
+ import type { PersistenceStore } from '../../types/monitor';
10
+ export interface FastifyServerOptions {
11
+ host: string;
12
+ port: number;
13
+ broker: EventBroker;
14
+ persistence?: PersistenceStore;
15
+ }
16
+ export declare function createFastifyServer(options: FastifyServerOptions): Promise<FastifyInstance>;