cntx-ui 3.0.7 → 3.0.9

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 (36) hide show
  1. package/dist/bin/cntx-ui.js +70 -0
  2. package/dist/lib/agent-runtime.js +269 -0
  3. package/dist/lib/agent-tools.js +162 -0
  4. package/dist/lib/api-router.js +387 -0
  5. package/dist/lib/bundle-manager.js +236 -0
  6. package/dist/lib/configuration-manager.js +230 -0
  7. package/dist/lib/database-manager.js +277 -0
  8. package/dist/lib/file-system-manager.js +305 -0
  9. package/dist/lib/function-level-chunker.js +144 -0
  10. package/dist/lib/heuristics-manager.js +491 -0
  11. package/dist/lib/mcp-server.js +159 -0
  12. package/dist/lib/mcp-transport.js +10 -0
  13. package/dist/lib/semantic-splitter.js +335 -0
  14. package/dist/lib/simple-vector-store.js +98 -0
  15. package/dist/lib/treesitter-semantic-chunker.js +277 -0
  16. package/dist/lib/websocket-manager.js +268 -0
  17. package/dist/server.js +225 -0
  18. package/package.json +18 -8
  19. package/bin/cntx-ui-mcp.sh +0 -3
  20. package/bin/cntx-ui.js +0 -123
  21. package/lib/agent-runtime.js +0 -371
  22. package/lib/agent-tools.js +0 -370
  23. package/lib/api-router.js +0 -1026
  24. package/lib/bundle-manager.js +0 -326
  25. package/lib/configuration-manager.js +0 -760
  26. package/lib/database-manager.js +0 -397
  27. package/lib/file-system-manager.js +0 -489
  28. package/lib/function-level-chunker.js +0 -406
  29. package/lib/heuristics-manager.js +0 -529
  30. package/lib/mcp-server.js +0 -1380
  31. package/lib/mcp-transport.js +0 -97
  32. package/lib/semantic-splitter.js +0 -304
  33. package/lib/simple-vector-store.js +0 -108
  34. package/lib/treesitter-semantic-chunker.js +0 -1485
  35. package/lib/websocket-manager.js +0 -470
  36. package/server.js +0 -687
@@ -1,470 +0,0 @@
1
- /**
2
- * WebSocket Manager for cntx-ui
3
- * Handles real-time client communication and updates
4
- */
5
-
6
- import { WebSocketServer } from 'ws';
7
-
8
- export default class WebSocketManager {
9
- constructor(bundleManager, configManager, options = {}) {
10
- this.bundleManager = bundleManager;
11
- this.configManager = configManager;
12
- this.verbose = options.verbose || false;
13
- this.clients = new Set();
14
- this.wss = null;
15
- }
16
-
17
- // === WebSocket Server Setup ===
18
-
19
- initialize(httpServer) {
20
- this.wss = new WebSocketServer({ server: httpServer });
21
-
22
- this.wss.on('connection', (ws) => {
23
- this.handleConnection(ws);
24
- });
25
-
26
- if (this.verbose) {
27
- console.log('🔌 WebSocket server initialized');
28
- }
29
- }
30
-
31
- handleConnection(ws) {
32
- // Add client to our set
33
- this.clients.add(ws);
34
- if (this.verbose) {
35
- console.log(`📱 WebSocket client connected (${this.clients.size} total clients)`);
36
- }
37
-
38
- // Send initial update to the new client
39
- this.sendUpdate(ws);
40
-
41
- // Handle client disconnect
42
- ws.on('close', () => {
43
- this.clients.delete(ws);
44
- if (this.verbose) {
45
- console.log(`📱 WebSocket client disconnected (${this.clients.size} total clients)`);
46
- }
47
- });
48
-
49
- // Handle client errors
50
- ws.on('error', (error) => {
51
- if (this.verbose) {
52
- console.error('WebSocket client error:', error.message);
53
- }
54
- this.clients.delete(ws);
55
- });
56
-
57
- // Optional: Handle incoming messages from clients
58
- ws.on('message', (message) => {
59
- try {
60
- const data = JSON.parse(message.toString());
61
- this.handleClientMessage(ws, data);
62
- } catch (error) {
63
- if (this.verbose) {
64
- console.error('Invalid WebSocket message:', error.message);
65
- }
66
- }
67
- });
68
- }
69
-
70
- handleClientMessage(ws, data) {
71
- // Handle different types of client messages
72
- switch (data.type) {
73
- case 'ping':
74
- ws.send(JSON.stringify({ type: 'pong', timestamp: Date.now() }));
75
- break;
76
-
77
- case 'request-update':
78
- this.sendUpdate(ws);
79
- break;
80
-
81
- case 'subscribe':
82
- // Future: Handle subscription to specific bundle updates
83
- ws.subscriptions = data.bundles || [];
84
- break;
85
-
86
- default:
87
- if (this.verbose) {
88
- console.warn('Unknown WebSocket message type:', data.type);
89
- }
90
- }
91
- }
92
-
93
- // === Client Management ===
94
-
95
- getClientCount() {
96
- return this.clients.size;
97
- }
98
-
99
- getActiveClients() {
100
- // Filter out clients that might be in a closed state
101
- const activeClients = new Set();
102
-
103
- this.clients.forEach(client => {
104
- if (client.readyState === 1) { // WebSocket.OPEN
105
- activeClients.add(client);
106
- } else {
107
- // Remove dead connections
108
- this.clients.delete(client);
109
- }
110
- });
111
-
112
- return activeClients;
113
- }
114
-
115
- // === Broadcasting Updates ===
116
-
117
- broadcastUpdate() {
118
- const activeClients = this.getActiveClients();
119
-
120
- if (activeClients.size === 0) {
121
- return; // No clients to update
122
- }
123
-
124
- if (this.verbose) {
125
- console.log(`📡 Broadcasting update to ${activeClients.size} client(s)`);
126
- }
127
-
128
- activeClients.forEach(client => {
129
- this.sendUpdate(client);
130
- });
131
- }
132
-
133
- sendUpdate(client) {
134
- if (client.readyState !== 1) { // Not WebSocket.OPEN
135
- return;
136
- }
137
-
138
- try {
139
- const updateData = this.prepareUpdateData();
140
- client.send(JSON.stringify(updateData));
141
- } catch (error) {
142
- if (this.verbose) {
143
- console.error('Failed to send WebSocket update:', error.message);
144
- }
145
- this.clients.delete(client);
146
- }
147
- }
148
-
149
- prepareUpdateData() {
150
- const bundles = this.configManager.getBundles();
151
-
152
- const bundleData = Array.from(bundles.entries()).map(([name, bundle]) => ({
153
- name,
154
- changed: bundle.changed,
155
- fileCount: bundle.files.length,
156
- content: bundle.content.substring(0, 2000) + (bundle.content.length > 2000 ? '...' : ''),
157
- files: bundle.files,
158
- lastGenerated: bundle.generated,
159
- size: bundle.size,
160
- patterns: bundle.patterns
161
- }));
162
-
163
- return {
164
- type: 'bundle-update',
165
- timestamp: new Date().toISOString(),
166
- bundles: bundleData,
167
- serverStatus: {
168
- uptime: process.uptime(),
169
- scanning: this.bundleManager._isScanning || false,
170
- totalFiles: this.bundleManager.fileSystemManager?.getAllFiles()?.length || 0
171
- }
172
- };
173
- }
174
-
175
- // === Targeted Updates ===
176
-
177
- broadcastBundleUpdate(bundleName) {
178
- const activeClients = this.getActiveClients();
179
-
180
- if (activeClients.size === 0) {
181
- return;
182
- }
183
-
184
- if (this.verbose) {
185
- console.log(`📡 Broadcasting ${bundleName} bundle update to ${activeClients.size} client(s)`);
186
- }
187
-
188
- const bundle = this.configManager.getBundles().get(bundleName);
189
- if (!bundle) {
190
- return;
191
- }
192
-
193
- const updateData = {
194
- type: 'bundle-specific-update',
195
- timestamp: new Date().toISOString(),
196
- bundleName,
197
- bundle: {
198
- name: bundleName,
199
- changed: bundle.changed,
200
- fileCount: bundle.files.length,
201
- content: bundle.content.substring(0, 2000) + (bundle.content.length > 2000 ? '...' : ''),
202
- files: bundle.files,
203
- lastGenerated: bundle.generated,
204
- size: bundle.size,
205
- patterns: bundle.patterns
206
- }
207
- };
208
-
209
- activeClients.forEach(client => {
210
- try {
211
- if (client.readyState === 1) {
212
- client.send(JSON.stringify(updateData));
213
- }
214
- } catch (error) {
215
- if (this.verbose) {
216
- console.error('Failed to send bundle update:', error.message);
217
- }
218
- this.clients.delete(client);
219
- }
220
- });
221
- }
222
-
223
- broadcastFileChange(filename, eventType) {
224
- const activeClients = this.getActiveClients();
225
-
226
- if (activeClients.size === 0) {
227
- return;
228
- }
229
-
230
- const updateData = {
231
- type: 'file-change',
232
- timestamp: new Date().toISOString(),
233
- filename,
234
- eventType,
235
- message: `File ${eventType}: ${filename}`
236
- };
237
-
238
- activeClients.forEach(client => {
239
- try {
240
- if (client.readyState === 1) {
241
- client.send(JSON.stringify(updateData));
242
- }
243
- } catch (error) {
244
- if (this.verbose) {
245
- console.error('Failed to send file change update:', error.message);
246
- }
247
- this.clients.delete(client);
248
- }
249
- });
250
- }
251
-
252
- broadcastStatusUpdate(status) {
253
- const activeClients = this.getActiveClients();
254
-
255
- if (activeClients.size === 0) {
256
- return;
257
- }
258
-
259
- const updateData = {
260
- type: 'status-update',
261
- timestamp: new Date().toISOString(),
262
- status
263
- };
264
-
265
- activeClients.forEach(client => {
266
- try {
267
- if (client.readyState === 1) {
268
- client.send(JSON.stringify(updateData));
269
- }
270
- } catch (error) {
271
- if (this.verbose) {
272
- console.error('Failed to send status update:', error.message);
273
- }
274
- this.clients.delete(client);
275
- }
276
- });
277
- }
278
-
279
- // === Utility Methods ===
280
-
281
- ping() {
282
- const activeClients = this.getActiveClients();
283
-
284
- const pingData = {
285
- type: 'ping',
286
- timestamp: new Date().toISOString(),
287
- serverTime: Date.now()
288
- };
289
-
290
- activeClients.forEach(client => {
291
- try {
292
- if (client.readyState === 1) {
293
- client.send(JSON.stringify(pingData));
294
- }
295
- } catch (error) {
296
- this.clients.delete(client);
297
- }
298
- });
299
- }
300
-
301
- // === Cleanup ===
302
-
303
- close() {
304
- if (this.wss) {
305
- if (this.verbose) {
306
- console.log('🔌 Closing WebSocket server...');
307
- }
308
-
309
- // Close all client connections
310
- this.clients.forEach(client => {
311
- try {
312
- if (client.readyState === 1) {
313
- client.close(1000, 'Server shutting down');
314
- }
315
- } catch (error) {
316
- if (this.verbose) {
317
- console.error('Error closing WebSocket client:', error.message);
318
- }
319
- }
320
- });
321
-
322
- // Close the WebSocket server
323
- this.wss.close(() => {
324
- if (this.verbose) {
325
- console.log('🔌 WebSocket server closed');
326
- }
327
- });
328
-
329
- this.clients.clear();
330
- }
331
- }
332
-
333
- // === Health Check ===
334
-
335
- getHealthStatus() {
336
- return {
337
- connected: this.clients.size,
338
- active: this.getActiveClients().size,
339
- server: this.wss ? 'running' : 'stopped'
340
- };
341
- }
342
-
343
- // === Event Handlers for Integration ===
344
-
345
- onBundleGenerated(bundleName) {
346
- this.broadcastBundleUpdate(bundleName);
347
- this.broadcastBundleSyncCompleted(bundleName);
348
- }
349
-
350
- onBundlesGenerated() {
351
- this.broadcastUpdate();
352
- }
353
-
354
- onConfigChanged() {
355
- this.broadcastUpdate();
356
- }
357
-
358
- onFileChanged(filename, eventType) {
359
- // Notify which bundles are affected by this file change
360
- const affectedBundles = this.getAffectedBundles(filename);
361
-
362
- affectedBundles.forEach(bundleName => {
363
- this.broadcastBundleFileChanged(bundleName, filename);
364
- });
365
-
366
- this.broadcastFileChange(filename, eventType);
367
-
368
- // Also broadcast bundle updates after a short delay to allow bundle regeneration
369
- setTimeout(() => {
370
- this.broadcastUpdate();
371
- }, 500);
372
- }
373
-
374
- // === New Bundle Sync Event Handlers ===
375
-
376
- onBundleSyncStarted(bundleName) {
377
- const updateData = {
378
- type: 'bundle-sync-started',
379
- bundleName,
380
- timestamp: new Date().toISOString()
381
- };
382
- this.broadcastToActiveClients(updateData);
383
- }
384
-
385
- onBundleSyncCompleted(bundleName) {
386
- const updateData = {
387
- type: 'bundle-sync-completed',
388
- bundleName,
389
- timestamp: new Date().toISOString()
390
- };
391
- this.broadcastToActiveClients(updateData);
392
- }
393
-
394
- onBundleSyncFailed(bundleName, error) {
395
- const updateData = {
396
- type: 'bundle-sync-failed',
397
- bundleName,
398
- error: error.message || error,
399
- timestamp: new Date().toISOString()
400
- };
401
- this.broadcastToActiveClients(updateData);
402
- }
403
-
404
- broadcastBundleFileChanged(bundleName, filename) {
405
- const updateData = {
406
- type: 'bundle-file-changed',
407
- bundleName,
408
- filename,
409
- timestamp: new Date().toISOString()
410
- };
411
- this.broadcastToActiveClients(updateData);
412
- }
413
-
414
- broadcastBundleSyncCompleted(bundleName) {
415
- const updateData = {
416
- type: 'bundle-sync-completed',
417
- bundleName,
418
- timestamp: new Date().toISOString()
419
- };
420
- this.broadcastToActiveClients(updateData);
421
- }
422
-
423
- // Helper method to broadcast to all active clients
424
- broadcastToActiveClients(data) {
425
- const activeClients = this.getActiveClients();
426
-
427
- if (activeClients.size === 0) {
428
- return;
429
- }
430
-
431
- activeClients.forEach(client => {
432
- try {
433
- if (client.readyState === 1) {
434
- client.send(JSON.stringify(data));
435
- }
436
- } catch (error) {
437
- if (this.verbose) {
438
- console.error('Failed to send WebSocket update:', error.message);
439
- }
440
- this.clients.delete(client);
441
- }
442
- });
443
- }
444
-
445
- // Helper to find which bundles are affected by a file change
446
- getAffectedBundles(filename) {
447
- const bundles = this.configManager.getBundles();
448
- const affectedBundles = [];
449
-
450
- bundles.forEach((bundle, name) => {
451
- const matchesBundle = bundle.patterns.some(pattern =>
452
- this.bundleManager.fileSystemManager.matchesPattern(filename, pattern)
453
- );
454
-
455
- if (matchesBundle) {
456
- affectedBundles.push(name);
457
- }
458
- });
459
-
460
- return affectedBundles;
461
- }
462
-
463
- onHiddenFilesChanged() {
464
- this.broadcastUpdate();
465
- }
466
-
467
- onIgnorePatternsChanged() {
468
- this.broadcastUpdate();
469
- }
470
- }