cntx-ui 3.0.4 → 3.0.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/bin/cntx-ui.js +16 -49
- package/lib/agent-runtime.js +70 -0
- package/lib/api-router.js +1 -136
- package/lib/bundle-manager.js +118 -28
- package/lib/mcp-server.js +0 -146
- package/package.json +1 -1
- package/server.js +85 -373
- package/templates/TOOLS.md +0 -6
- package/templates/agent-config.yaml +0 -5
- package/templates/agent-instructions.md +2 -15
- package/templates/agent-rules/project-specific/architecture.md +0 -1
- package/templates/hidden-files.json +0 -1
- package/web/dist/assets/index-D2RTcdqV.js +1968 -0
- package/web/dist/assets/index-DJi03HLz.css +1 -0
- package/web/dist/index.html +2 -2
- package/templates/activities/README.md +0 -67
- package/templates/activities/activities/create-project-bundles/README.md +0 -84
- package/templates/activities/activities/create-project-bundles/notes.md +0 -98
- package/templates/activities/activities/create-project-bundles/progress.md +0 -63
- package/templates/activities/activities/create-project-bundles/tasks.md +0 -39
- package/templates/activities/activities.json +0 -219
- package/templates/activities/lib/.markdownlint.jsonc +0 -18
- package/templates/activities/lib/create-activity.mdc +0 -63
- package/templates/activities/lib/generate-tasks.mdc +0 -64
- package/templates/activities/lib/process-task-list.mdc +0 -52
- package/templates/agent-rules/capabilities/activities-system.md +0 -147
- package/web/dist/assets/index-4p3KJ0jf.js +0 -2016
- package/web/dist/assets/index-BPIipM25.css +0 -1
package/server.js
CHANGED
|
@@ -6,9 +6,7 @@
|
|
|
6
6
|
import { createServer } from 'http';
|
|
7
7
|
import { join, dirname, relative, extname } from 'path';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync
|
|
10
|
-
import * as fs from 'fs';
|
|
11
|
-
import { homedir } from 'os';
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
12
10
|
|
|
13
11
|
// Import our modular components
|
|
14
12
|
import ConfigurationManager from './lib/configuration-manager.js';
|
|
@@ -17,7 +15,6 @@ import FileSystemManager from './lib/file-system-manager.js';
|
|
|
17
15
|
import BundleManager from './lib/bundle-manager.js';
|
|
18
16
|
import APIRouter from './lib/api-router.js';
|
|
19
17
|
import WebSocketManager from './lib/websocket-manager.js';
|
|
20
|
-
import { AgentRuntime } from './lib/agent-runtime.js';
|
|
21
18
|
|
|
22
19
|
// Import existing lib modules
|
|
23
20
|
import { startMCPTransport } from './lib/mcp-transport.js';
|
|
@@ -51,7 +48,6 @@ export class CntxServer {
|
|
|
51
48
|
this.verbose = options.verbose || false;
|
|
52
49
|
this.mcpServerStarted = false;
|
|
53
50
|
this.mcpServer = null;
|
|
54
|
-
this.initMessages = []; // Track initialization messages
|
|
55
51
|
|
|
56
52
|
// Ensure directory exists early
|
|
57
53
|
if (!existsSync(this.CNTX_DIR)) mkdirSync(this.CNTX_DIR, { recursive: true });
|
|
@@ -78,9 +74,6 @@ export class CntxServer {
|
|
|
78
74
|
this.lastSemanticAnalysis = null;
|
|
79
75
|
this.vectorStoreInitialized = false;
|
|
80
76
|
|
|
81
|
-
// Initialize Agent Runtime
|
|
82
|
-
this.agentRuntime = new AgentRuntime(this);
|
|
83
|
-
|
|
84
77
|
// Create semantic analysis manager object for API router
|
|
85
78
|
this.semanticAnalysisManager = {
|
|
86
79
|
getSemanticAnalysis: () => this.getSemanticAnalysis(),
|
|
@@ -89,13 +82,6 @@ export class CntxServer {
|
|
|
89
82
|
lastSemanticAnalysis: this.lastSemanticAnalysis
|
|
90
83
|
};
|
|
91
84
|
|
|
92
|
-
// Create activity manager placeholder
|
|
93
|
-
this.activityManager = {
|
|
94
|
-
loadActivities: () => this.loadActivities(),
|
|
95
|
-
executeActivity: (id) => this.executeActivity(id),
|
|
96
|
-
stopActivity: (id) => this.stopActivity(id)
|
|
97
|
-
};
|
|
98
|
-
|
|
99
85
|
// Initialize API router with all managers
|
|
100
86
|
this.apiRouter = new APIRouter(
|
|
101
87
|
this,
|
|
@@ -103,8 +89,7 @@ export class CntxServer {
|
|
|
103
89
|
this.bundleManager,
|
|
104
90
|
this.fileSystemManager,
|
|
105
91
|
this.semanticAnalysisManager,
|
|
106
|
-
this.vectorStore
|
|
107
|
-
this.activityManager
|
|
92
|
+
this.vectorStore
|
|
108
93
|
);
|
|
109
94
|
|
|
110
95
|
// Add references for cross-module communication
|
|
@@ -112,87 +97,35 @@ export class CntxServer {
|
|
|
112
97
|
this.bundleManager.webSocketManager = this.webSocketManager;
|
|
113
98
|
}
|
|
114
99
|
|
|
115
|
-
//
|
|
116
|
-
async showProgressBar(message, minTime = 500) {
|
|
117
|
-
const startTime = Date.now();
|
|
118
|
-
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
119
|
-
let frameIndex = 0;
|
|
120
|
-
|
|
121
|
-
const interval = setInterval(() => {
|
|
122
|
-
process.stdout.write(`\r${frames[frameIndex]} ${message}`);
|
|
123
|
-
frameIndex = (frameIndex + 1) % frames.length;
|
|
124
|
-
}, 80);
|
|
100
|
+
// === Proxy methods for MCP compatibility ===
|
|
125
101
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const remaining = Math.max(0, minTime - elapsed);
|
|
102
|
+
get bundles() {
|
|
103
|
+
return this.configManager.getBundles();
|
|
104
|
+
}
|
|
130
105
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
return Promise.resolve();
|
|
135
|
-
};
|
|
106
|
+
getAllFiles() {
|
|
107
|
+
return this.fileSystemManager.getAllFiles();
|
|
136
108
|
}
|
|
137
109
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
let currentStep = 0;
|
|
110
|
+
getFileTree() {
|
|
111
|
+
return this.fileSystemManager.getFileTree();
|
|
112
|
+
}
|
|
142
113
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const filledLength = Math.round((progress / 100) * barLength);
|
|
147
|
-
const bar = '█'.repeat(filledLength) + '░'.repeat(barLength - filledLength);
|
|
114
|
+
generateBundle(name) {
|
|
115
|
+
return this.bundleManager.regenerateBundle(name);
|
|
116
|
+
}
|
|
148
117
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
118
|
+
generateAllBundles() {
|
|
119
|
+
return this.bundleManager.generateAllBundles();
|
|
120
|
+
}
|
|
152
121
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
return {
|
|
157
|
-
next: (stepName, minTime = 800) => {
|
|
158
|
-
return new Promise(async (resolve) => {
|
|
159
|
-
const startTime = Date.now();
|
|
160
|
-
|
|
161
|
-
// Move to next step
|
|
162
|
-
currentStep++;
|
|
163
|
-
|
|
164
|
-
if (currentStep < totalSteps) {
|
|
165
|
-
updateProgress(steps[currentStep]);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Add random delay between 200-800ms on top of minimum time
|
|
169
|
-
const randomDelay = Math.floor(Math.random() * 600) + 200;
|
|
170
|
-
const totalDelay = minTime + randomDelay;
|
|
171
|
-
|
|
172
|
-
// Wait minimum time + random delay
|
|
173
|
-
const elapsed = Date.now() - startTime;
|
|
174
|
-
const remaining = Math.max(0, totalDelay - elapsed);
|
|
175
|
-
if (remaining > 0) {
|
|
176
|
-
await new Promise(resolve => setTimeout(resolve, remaining));
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
resolve();
|
|
180
|
-
});
|
|
181
|
-
},
|
|
182
|
-
complete: () => {
|
|
183
|
-
const progress = 100;
|
|
184
|
-
const barLength = 30;
|
|
185
|
-
const bar = '█'.repeat(barLength);
|
|
186
|
-
process.stdout.write(`\r[${bar}] ${progress}% - Complete${' '.repeat(20)}\n`);
|
|
187
|
-
}
|
|
188
|
-
};
|
|
122
|
+
saveBundleStates() {
|
|
123
|
+
return this.configManager.saveBundleStates();
|
|
189
124
|
}
|
|
190
125
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
this.initMessages.push(message);
|
|
195
|
-
}
|
|
126
|
+
loadIgnorePatterns() {
|
|
127
|
+
this.configManager.loadIgnorePatterns();
|
|
128
|
+
this.fileSystemManager.setIgnorePatterns(this.configManager.getIgnorePatterns());
|
|
196
129
|
}
|
|
197
130
|
|
|
198
131
|
// === Initialization ===
|
|
@@ -202,55 +135,45 @@ export class CntxServer {
|
|
|
202
135
|
|
|
203
136
|
const { skipFileWatcher = false, skipBundleGeneration = false } = options;
|
|
204
137
|
|
|
205
|
-
|
|
206
|
-
? ['Loading configuration', 'Loading semantic cache']
|
|
207
|
-
: ['Loading configuration', 'Setting up file watcher', 'Loading semantic cache', 'Starting file watcher', 'Generating bundles'];
|
|
208
|
-
|
|
209
|
-
const progress = await this.showInitProgress(steps);
|
|
210
|
-
|
|
211
|
-
// Step 1: Loading configuration
|
|
138
|
+
// Step 1: Load configuration
|
|
212
139
|
this.configManager.loadConfig();
|
|
213
140
|
this.configManager.loadHiddenFilesConfig();
|
|
214
141
|
this.configManager.loadIgnorePatterns();
|
|
215
142
|
this.configManager.loadBundleStates();
|
|
216
|
-
|
|
143
|
+
console.log(' Configuration loaded');
|
|
217
144
|
|
|
218
145
|
if (!skipFileWatcher) {
|
|
219
|
-
// Step 2:
|
|
146
|
+
// Step 2: Set up file watcher
|
|
220
147
|
this.fileSystemManager.setIgnorePatterns(this.configManager.getIgnorePatterns());
|
|
221
|
-
|
|
148
|
+
console.log(' File watcher configured');
|
|
222
149
|
}
|
|
223
150
|
|
|
224
|
-
// Step 3:
|
|
151
|
+
// Step 3: Load semantic cache
|
|
225
152
|
const cacheData = this.configManager.loadSemanticCache();
|
|
226
153
|
if (cacheData) {
|
|
227
154
|
this.semanticCache = cacheData.analysis;
|
|
228
155
|
this.lastSemanticAnalysis = cacheData.timestamp;
|
|
156
|
+
console.log(` Semantic cache loaded (${this.semanticCache.chunks.length} chunks)`);
|
|
157
|
+
} else {
|
|
158
|
+
console.log(' No semantic cache found (will analyze on first request)');
|
|
229
159
|
}
|
|
230
|
-
await progress.next(skipFileWatcher ? steps[1] : steps[2], 800);
|
|
231
160
|
|
|
232
161
|
if (!skipFileWatcher) {
|
|
233
|
-
// Step 4:
|
|
162
|
+
// Step 4: Start file watcher
|
|
234
163
|
this.startWatching();
|
|
235
|
-
|
|
164
|
+
console.log(' File watcher started');
|
|
236
165
|
|
|
237
166
|
// Trigger initial semantic analysis in background if no cache
|
|
238
167
|
if (!this.semanticCache) {
|
|
239
168
|
this.getSemanticAnalysis().catch(err => console.error('Initial semantic analysis failed:', err.message));
|
|
240
169
|
}
|
|
241
170
|
|
|
242
|
-
// Step 5:
|
|
171
|
+
// Step 5: Generate bundles (awaited to prevent race conditions)
|
|
243
172
|
if (!skipBundleGeneration) {
|
|
244
|
-
this.bundleManager.generateAllBundles();
|
|
245
|
-
|
|
173
|
+
await this.bundleManager.generateAllBundles();
|
|
174
|
+
console.log(' Bundles generated');
|
|
246
175
|
}
|
|
247
176
|
}
|
|
248
|
-
|
|
249
|
-
// Complete progress bar
|
|
250
|
-
progress.complete();
|
|
251
|
-
|
|
252
|
-
// Generate Agent Manifest
|
|
253
|
-
await this.agentRuntime.generateAgentManifest();
|
|
254
177
|
}
|
|
255
178
|
|
|
256
179
|
// Display initialization summary
|
|
@@ -281,7 +204,7 @@ export class CntxServer {
|
|
|
281
204
|
// Display summary
|
|
282
205
|
if (summary.length > 0) {
|
|
283
206
|
console.log('Initialization complete:');
|
|
284
|
-
summary.forEach(msg => console.log(`
|
|
207
|
+
summary.forEach(msg => console.log(` - ${msg}`));
|
|
285
208
|
console.log('');
|
|
286
209
|
}
|
|
287
210
|
}
|
|
@@ -291,13 +214,13 @@ export class CntxServer {
|
|
|
291
214
|
startWatching() {
|
|
292
215
|
this.fileSystemManager.startWatching(async (eventType, filename) => {
|
|
293
216
|
if (this.verbose) {
|
|
294
|
-
console.log(
|
|
217
|
+
console.log(`File ${eventType}: ${filename}`);
|
|
295
218
|
}
|
|
296
219
|
|
|
297
220
|
// Skip processing files in .cntx directory to prevent infinite loops
|
|
298
221
|
if (filename.startsWith('.cntx/')) {
|
|
299
222
|
if (this.verbose) {
|
|
300
|
-
console.log(
|
|
223
|
+
console.log(`Skipping .cntx file: ${filename}`);
|
|
301
224
|
}
|
|
302
225
|
return;
|
|
303
226
|
}
|
|
@@ -337,7 +260,7 @@ export class CntxServer {
|
|
|
337
260
|
// Regenerate each affected bundle
|
|
338
261
|
for (const bundleName of affectedBundles) {
|
|
339
262
|
if (this.verbose) {
|
|
340
|
-
console.log(
|
|
263
|
+
console.log(`Auto-regenerating bundle: ${bundleName}`);
|
|
341
264
|
}
|
|
342
265
|
await this.bundleManager.regenerateBundle(bundleName);
|
|
343
266
|
}
|
|
@@ -439,7 +362,7 @@ export class CntxServer {
|
|
|
439
362
|
const files = this.fileSystemManager.getAllFiles()
|
|
440
363
|
.filter(f => supportedExtensions.includes(extname(f).toLowerCase()))
|
|
441
364
|
.map(f => relative(this.CWD, f));
|
|
442
|
-
|
|
365
|
+
|
|
443
366
|
let bundleConfig = null;
|
|
444
367
|
if (existsSync(this.configManager.CONFIG_FILE)) {
|
|
445
368
|
bundleConfig = JSON.parse(readFileSync(this.configManager.CONFIG_FILE, 'utf8'));
|
|
@@ -454,7 +377,9 @@ export class CntxServer {
|
|
|
454
377
|
}
|
|
455
378
|
|
|
456
379
|
// 4. Trigger background embedding enhancement
|
|
457
|
-
this.enhanceSemanticChunksIfNeeded(this.semanticCache)
|
|
380
|
+
this.enhanceSemanticChunksIfNeeded(this.semanticCache).catch(err => {
|
|
381
|
+
console.error('Background embedding enhancement failed:', err.message);
|
|
382
|
+
});
|
|
458
383
|
|
|
459
384
|
return this.semanticCache;
|
|
460
385
|
} catch (error) {
|
|
@@ -464,12 +389,12 @@ export class CntxServer {
|
|
|
464
389
|
}
|
|
465
390
|
|
|
466
391
|
async refreshSemanticAnalysis() {
|
|
467
|
-
console.log('
|
|
468
|
-
|
|
392
|
+
console.log('Refreshing semantic analysis and database...');
|
|
393
|
+
|
|
469
394
|
// Clear the database table but keep other data
|
|
470
395
|
this.databaseManager.db.prepare('DELETE FROM semantic_chunks').run();
|
|
471
396
|
this.databaseManager.db.prepare('DELETE FROM vector_embeddings').run();
|
|
472
|
-
|
|
397
|
+
|
|
473
398
|
this.semanticCache = null;
|
|
474
399
|
this.lastSemanticAnalysis = null;
|
|
475
400
|
|
|
@@ -488,11 +413,11 @@ export class CntxServer {
|
|
|
488
413
|
}
|
|
489
414
|
|
|
490
415
|
if (chunksNeedingEmbeddings.length === 0) {
|
|
491
|
-
console.log('
|
|
416
|
+
console.log('All chunks already have persistent embeddings');
|
|
492
417
|
return;
|
|
493
418
|
}
|
|
494
419
|
|
|
495
|
-
console.log(
|
|
420
|
+
console.log(`Enhancing ${chunksNeedingEmbeddings.length} chunks with persistent embeddings...`);
|
|
496
421
|
|
|
497
422
|
// Initialize vector store if needed
|
|
498
423
|
if (!this.vectorStoreInitialized) {
|
|
@@ -508,7 +433,7 @@ export class CntxServer {
|
|
|
508
433
|
console.error(`Failed to generate/persist embedding for chunk ${chunk.id}:`, error.message);
|
|
509
434
|
}
|
|
510
435
|
}
|
|
511
|
-
console.log('
|
|
436
|
+
console.log('Background embedding enhancement complete');
|
|
512
437
|
}
|
|
513
438
|
|
|
514
439
|
invalidateSemanticCache() {
|
|
@@ -527,121 +452,6 @@ export class CntxServer {
|
|
|
527
452
|
return this.bundleManager.generateFileXML(chunk.filePath);
|
|
528
453
|
}
|
|
529
454
|
|
|
530
|
-
invalidateSemanticCache() {
|
|
531
|
-
this.semanticCache = null;
|
|
532
|
-
this.lastSemanticAnalysis = null;
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
// === Activity Management (Placeholder) ===
|
|
536
|
-
|
|
537
|
-
async loadActivities() {
|
|
538
|
-
try {
|
|
539
|
-
const activitiesPath = join(this.CWD, '.cntx', 'activities');
|
|
540
|
-
const activitiesJsonPath = join(activitiesPath, 'activities.json');
|
|
541
|
-
|
|
542
|
-
console.log('DEBUG: Looking for activities at:', activitiesJsonPath);
|
|
543
|
-
console.log('DEBUG: File exists:', fs.existsSync(activitiesJsonPath));
|
|
544
|
-
console.log('DEBUG: CWD is:', this.CWD);
|
|
545
|
-
|
|
546
|
-
if (!fs.existsSync(activitiesJsonPath)) {
|
|
547
|
-
console.log('Activities file not found, returning empty array');
|
|
548
|
-
return [];
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
const activitiesData = JSON.parse(fs.readFileSync(activitiesJsonPath, 'utf8'));
|
|
552
|
-
|
|
553
|
-
return activitiesData.map((activity, index) => {
|
|
554
|
-
// Extract the actual directory name from the references field
|
|
555
|
-
let activityId = activity.title.toLowerCase().replace(/[^a-z0-9]/g, '-');
|
|
556
|
-
if (activity.references && activity.references.length > 0) {
|
|
557
|
-
// Extract directory name from path like ".cntx/activities/activities/refactor-js-to-ts/README.md"
|
|
558
|
-
const refPath = activity.references[0];
|
|
559
|
-
const pathParts = refPath.split('/');
|
|
560
|
-
if (pathParts.length >= 4) {
|
|
561
|
-
activityId = pathParts[3]; // activities/activities/{this-part}/README.md
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
const activityDir = join(activitiesPath, 'activities', activityId);
|
|
565
|
-
|
|
566
|
-
// Load markdown files
|
|
567
|
-
const files = {
|
|
568
|
-
readme: this.loadMarkdownFile(join(activityDir, 'README.md')),
|
|
569
|
-
progress: this.loadMarkdownFile(join(activityDir, 'progress.md')),
|
|
570
|
-
tasks: this.loadMarkdownFile(join(activityDir, 'tasks.md')),
|
|
571
|
-
notes: this.loadMarkdownFile(join(activityDir, 'notes.md'))
|
|
572
|
-
};
|
|
573
|
-
|
|
574
|
-
// Calculate progress from progress.md file
|
|
575
|
-
const progress = this.parseProgressFromMarkdown(files.progress);
|
|
576
|
-
|
|
577
|
-
return {
|
|
578
|
-
id: activityId,
|
|
579
|
-
name: activity.title,
|
|
580
|
-
description: activity.description,
|
|
581
|
-
status: activity.status === 'todo' ? 'pending' : activity.status,
|
|
582
|
-
priority: activity.tags?.includes('high') ? 'high' : activity.tags?.includes('low') ? 'low' : 'medium',
|
|
583
|
-
progress,
|
|
584
|
-
updatedAt: new Date().toISOString(),
|
|
585
|
-
category: activity.tags?.[0] || 'general',
|
|
586
|
-
files,
|
|
587
|
-
tags: activity.tags
|
|
588
|
-
};
|
|
589
|
-
});
|
|
590
|
-
} catch (error) {
|
|
591
|
-
console.error('Failed to load activities:', error);
|
|
592
|
-
return [];
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
loadMarkdownFile(filePath) {
|
|
597
|
-
try {
|
|
598
|
-
if (fs.existsSync(filePath)) {
|
|
599
|
-
return fs.readFileSync(filePath, 'utf8');
|
|
600
|
-
}
|
|
601
|
-
return 'No content available';
|
|
602
|
-
} catch (error) {
|
|
603
|
-
return `Error loading file: ${error.message}`;
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
parseProgressFromMarkdown(progressContent) {
|
|
608
|
-
try {
|
|
609
|
-
if (!progressContent || progressContent === 'No content available') {
|
|
610
|
-
return 0;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
// Look for "Overall Completion: XX%" pattern
|
|
614
|
-
const overallMatch = progressContent.match(/(?:Overall Completion|Progress):\s*(\d+)%/i);
|
|
615
|
-
if (overallMatch) {
|
|
616
|
-
return parseInt(overallMatch[1], 10);
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
// Fallback: count completed tasks vs total tasks in checkbox format
|
|
620
|
-
const taskMatches = progressContent.match(/- \[([x✓✅\s])\]/gi);
|
|
621
|
-
if (taskMatches && taskMatches.length > 0) {
|
|
622
|
-
const completedTasks = taskMatches.filter(match =>
|
|
623
|
-
match.includes('[x]') || match.includes('[✓]') || match.includes('[✅]')
|
|
624
|
-
).length;
|
|
625
|
-
return Math.round((completedTasks / taskMatches.length) * 100);
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
return 0;
|
|
629
|
-
} catch (error) {
|
|
630
|
-
console.error('Error parsing progress:', error);
|
|
631
|
-
return 0;
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
async executeActivity(activityId) {
|
|
636
|
-
// Placeholder - would execute specific activity
|
|
637
|
-
return { success: false, message: 'Activity execution not implemented' };
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
async stopActivity(activityId) {
|
|
641
|
-
// Placeholder - would stop running activity
|
|
642
|
-
return { success: false, message: 'Activity stopping not implemented' };
|
|
643
|
-
}
|
|
644
|
-
|
|
645
455
|
// === MCP Server Integration ===
|
|
646
456
|
|
|
647
457
|
startMCPServer() {
|
|
@@ -650,7 +460,7 @@ export class CntxServer {
|
|
|
650
460
|
this.mcpServerStarted = true;
|
|
651
461
|
|
|
652
462
|
if (this.verbose) {
|
|
653
|
-
console.log('
|
|
463
|
+
console.log('MCP server started');
|
|
654
464
|
}
|
|
655
465
|
}
|
|
656
466
|
}
|
|
@@ -668,8 +478,8 @@ export class CntxServer {
|
|
|
668
478
|
// Start server and show progress
|
|
669
479
|
server.listen(port, host, () => {
|
|
670
480
|
console.log('');
|
|
671
|
-
console.log(
|
|
672
|
-
console.log(
|
|
481
|
+
console.log(`Server running at http://${host}:${port}`);
|
|
482
|
+
console.log(`Serving ${this.bundleManager.getAllBundleInfo().length} bundles from your project`);
|
|
673
483
|
console.log('');
|
|
674
484
|
|
|
675
485
|
// Display initialization summary
|
|
@@ -678,11 +488,11 @@ export class CntxServer {
|
|
|
678
488
|
|
|
679
489
|
// Handle graceful shutdown
|
|
680
490
|
process.on('SIGINT', () => {
|
|
681
|
-
console.log('\
|
|
491
|
+
console.log('\nShutting down server...');
|
|
682
492
|
this.webSocketManager.close();
|
|
683
493
|
this.fileSystemManager.destroy();
|
|
684
494
|
server.close(() => {
|
|
685
|
-
console.log('
|
|
495
|
+
console.log('Server stopped');
|
|
686
496
|
process.exit(0);
|
|
687
497
|
});
|
|
688
498
|
});
|
|
@@ -691,11 +501,25 @@ export class CntxServer {
|
|
|
691
501
|
}
|
|
692
502
|
}
|
|
693
503
|
|
|
504
|
+
// Auto-init and start: checks for .cntx/, runs initConfig() if missing, then starts server
|
|
505
|
+
export async function autoInitAndStart(options = {}) {
|
|
506
|
+
const cwd = options.cwd || process.cwd();
|
|
507
|
+
const cntxDir = join(cwd, '.cntx');
|
|
508
|
+
|
|
509
|
+
if (!existsSync(cntxDir)) {
|
|
510
|
+
console.log('No .cntx directory found, initializing...');
|
|
511
|
+
console.log('');
|
|
512
|
+
await initConfig(cwd);
|
|
513
|
+
console.log('');
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
return startServer(options);
|
|
517
|
+
}
|
|
518
|
+
|
|
694
519
|
// Export function for CLI compatibility
|
|
695
520
|
export async function startServer(options = {}) {
|
|
696
521
|
const server = new CntxServer(options.cwd, { verbose: options.verbose });
|
|
697
522
|
|
|
698
|
-
// Show ASCII art first
|
|
699
523
|
const asciiArt = `
|
|
700
524
|
██████ ███ ██ ████████ ██ ██ ██ ██ ██
|
|
701
525
|
██ ████ ██ ██ ██ ██ ██ ██ ██
|
|
@@ -704,12 +528,13 @@ export async function startServer(options = {}) {
|
|
|
704
528
|
██████ ██ ████ ██ ██ ██ ██████ ██
|
|
705
529
|
`;
|
|
706
530
|
console.log(asciiArt);
|
|
707
|
-
console.log(''); // Add blank line after art
|
|
708
531
|
|
|
709
|
-
// Now start initialization
|
|
532
|
+
// Now start initialization
|
|
710
533
|
await server.init();
|
|
711
534
|
|
|
712
|
-
|
|
535
|
+
// Enable MCP status tracking by default
|
|
536
|
+
const withMcp = options.withMcp !== false;
|
|
537
|
+
if (withMcp) {
|
|
713
538
|
server.startMCPServer();
|
|
714
539
|
}
|
|
715
540
|
|
|
@@ -723,7 +548,7 @@ export async function startMCPServer(options = {}) {
|
|
|
723
548
|
server.startMCPServer();
|
|
724
549
|
|
|
725
550
|
// For MCP mode, we don't start the web server, just keep the process alive
|
|
726
|
-
console.log('
|
|
551
|
+
console.log('MCP server running on stdio...');
|
|
727
552
|
}
|
|
728
553
|
|
|
729
554
|
export async function generateBundle(bundleName = 'master') {
|
|
@@ -743,11 +568,11 @@ export async function generateBundle(bundleName = 'master') {
|
|
|
743
568
|
// Initialize project configuration
|
|
744
569
|
export async function initConfig(cwd = process.cwd()) {
|
|
745
570
|
const server = new CntxServer(cwd);
|
|
746
|
-
|
|
571
|
+
|
|
747
572
|
// 1. Initialize directory structure
|
|
748
573
|
if (!existsSync(server.CNTX_DIR)) {
|
|
749
574
|
mkdirSync(server.CNTX_DIR, { recursive: true });
|
|
750
|
-
console.log('
|
|
575
|
+
console.log('Created .cntx directory');
|
|
751
576
|
}
|
|
752
577
|
|
|
753
578
|
// 2. Create .mcp.json for Claude Code discovery
|
|
@@ -762,11 +587,11 @@ export async function initConfig(cwd = process.cwd()) {
|
|
|
762
587
|
}
|
|
763
588
|
};
|
|
764
589
|
writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), 'utf8');
|
|
765
|
-
console.log('
|
|
590
|
+
console.log('Created .mcp.json for MCP auto-discovery');
|
|
766
591
|
|
|
767
592
|
// 3. Initialize basic configuration with better defaults and auto-suggestions
|
|
768
593
|
server.configManager.loadConfig();
|
|
769
|
-
|
|
594
|
+
|
|
770
595
|
const suggestedBundles = {
|
|
771
596
|
master: ['**/*']
|
|
772
597
|
};
|
|
@@ -784,7 +609,7 @@ export async function initConfig(cwd = process.cwd()) {
|
|
|
784
609
|
commonDirs.forEach(d => {
|
|
785
610
|
if (existsSync(join(cwd, d.dir))) {
|
|
786
611
|
suggestedBundles[d.name] = [`${d.dir}/**`];
|
|
787
|
-
console.log(
|
|
612
|
+
console.log(` Suggested bundle: ${d.name} (${d.dir}/**)`);
|
|
788
613
|
}
|
|
789
614
|
});
|
|
790
615
|
|
|
@@ -820,89 +645,12 @@ export async function initConfig(cwd = process.cwd()) {
|
|
|
820
645
|
.mcp.json
|
|
821
646
|
`;
|
|
822
647
|
writeFileSync(ignorePath, defaultIgnore, 'utf8');
|
|
823
|
-
console.log('
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
console.log('⚙️ Basic configuration initialized');
|
|
827
|
-
|
|
828
|
-
// ... (rest of the file remains same)
|
|
829
|
-
const templateDir = join(__dirname, 'templates');
|
|
830
|
-
|
|
831
|
-
// Copy agent configuration files
|
|
832
|
-
const agentFiles = [
|
|
833
|
-
'agent-config.yaml',
|
|
834
|
-
'agent-instructions.md'
|
|
835
|
-
];
|
|
836
|
-
|
|
837
|
-
for (const file of agentFiles) {
|
|
838
|
-
const sourcePath = join(templateDir, file);
|
|
839
|
-
const destPath = join(server.CNTX_DIR, file);
|
|
840
|
-
|
|
841
|
-
if (existsSync(sourcePath) && !existsSync(destPath)) {
|
|
842
|
-
copyFileSync(sourcePath, destPath);
|
|
843
|
-
console.log(`📄 Created ${file}`);
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
// Copy agent-rules directory structure
|
|
848
|
-
const agentRulesSource = join(templateDir, 'agent-rules');
|
|
849
|
-
const agentRulesDest = join(server.CNTX_DIR, 'agent-rules');
|
|
850
|
-
|
|
851
|
-
if (existsSync(agentRulesSource) && !existsSync(agentRulesDest)) {
|
|
852
|
-
cpSync(agentRulesSource, agentRulesDest, { recursive: true });
|
|
853
|
-
console.log('📁 Created agent-rules directory with templates');
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
// Copy activities framework
|
|
857
|
-
const activitiesDir = join(server.CNTX_DIR, 'activities');
|
|
858
|
-
if (!existsSync(activitiesDir)) {
|
|
859
|
-
mkdirSync(activitiesDir, { recursive: true });
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
// Copy activities README
|
|
863
|
-
const activitiesReadmeSource = join(templateDir, 'activities', 'README.md');
|
|
864
|
-
const activitiesReadmeDest = join(activitiesDir, 'README.md');
|
|
865
|
-
|
|
866
|
-
if (existsSync(activitiesReadmeSource) && !existsSync(activitiesReadmeDest)) {
|
|
867
|
-
copyFileSync(activitiesReadmeSource, activitiesReadmeDest);
|
|
868
|
-
console.log('📄 Created activities/README.md');
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
// Copy activities lib directory (MDC templates)
|
|
872
|
-
const activitiesLibSource = join(templateDir, 'activities', 'lib');
|
|
873
|
-
const activitiesLibDest = join(activitiesDir, 'lib');
|
|
874
|
-
|
|
875
|
-
if (existsSync(activitiesLibSource) && !existsSync(activitiesLibDest)) {
|
|
876
|
-
cpSync(activitiesLibSource, activitiesLibDest, { recursive: true });
|
|
877
|
-
console.log('📁 Created activities/lib with MDC templates');
|
|
648
|
+
console.log('Created .cntxignore with smart defaults');
|
|
878
649
|
}
|
|
879
650
|
|
|
880
|
-
|
|
881
|
-
const activitiesJsonPath = join(activitiesDir, 'activities.json');
|
|
882
|
-
const templateActivitiesJsonPath = join(templateDir, 'activities', 'activities.json');
|
|
883
|
-
if (!existsSync(activitiesJsonPath) && existsSync(templateActivitiesJsonPath)) {
|
|
884
|
-
copyFileSync(templateActivitiesJsonPath, activitiesJsonPath);
|
|
885
|
-
console.log('📄 Created activities.json with bundle example activity');
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
// Copy example activity from templates
|
|
889
|
-
const activitiesDestDir = join(activitiesDir, 'activities');
|
|
890
|
-
const templateActivitiesDir = join(templateDir, 'activities', 'activities');
|
|
891
|
-
if (!existsSync(activitiesDestDir) && existsSync(templateActivitiesDir)) {
|
|
892
|
-
cpSync(templateActivitiesDir, activitiesDestDir, { recursive: true });
|
|
893
|
-
console.log('📁 Created example activity with templates');
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
console.log('');
|
|
897
|
-
console.log('🎉 cntx-ui initialized with full scaffolding!');
|
|
898
|
-
console.log('');
|
|
899
|
-
console.log('Next steps:');
|
|
900
|
-
console.log(' 1️⃣ Start the server: cntx-ui watch');
|
|
901
|
-
console.log(' 2️⃣ Open web UI: http://localhost:3333');
|
|
902
|
-
console.log(' 3️⃣ Read .cntx/agent-instructions.md for AI integration');
|
|
903
|
-
console.log(' 4️⃣ Explore .cntx/activities/README.md for project management');
|
|
651
|
+
console.log('Configuration initialized');
|
|
904
652
|
console.log('');
|
|
905
|
-
console.log('
|
|
653
|
+
console.log('Run cntx-ui to start the server, then open http://localhost:3333');
|
|
906
654
|
}
|
|
907
655
|
|
|
908
656
|
export async function getStatus() {
|
|
@@ -912,13 +660,13 @@ export async function getStatus() {
|
|
|
912
660
|
const bundles = server.bundleManager.getAllBundleInfo();
|
|
913
661
|
const totalFiles = server.fileSystemManager.getAllFiles().length;
|
|
914
662
|
|
|
915
|
-
console.log('
|
|
663
|
+
console.log('cntx-ui Status');
|
|
916
664
|
console.log('================');
|
|
917
665
|
console.log(`Total files: ${totalFiles}`);
|
|
918
666
|
console.log(`Bundles: ${bundles.length}`);
|
|
919
667
|
|
|
920
668
|
bundles.forEach(bundle => {
|
|
921
|
-
console.log(`
|
|
669
|
+
console.log(` - ${bundle.name}: ${bundle.fileCount} files (${Math.round(bundle.size / 1024)}KB)`);
|
|
922
670
|
});
|
|
923
671
|
|
|
924
672
|
return {
|
|
@@ -928,46 +676,10 @@ export async function getStatus() {
|
|
|
928
676
|
};
|
|
929
677
|
}
|
|
930
678
|
|
|
931
|
-
export function setupMCP() {
|
|
932
|
-
const configPath = join(homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
|
|
933
|
-
const projectPath = process.cwd();
|
|
934
|
-
|
|
935
|
-
console.log('🔧 Setting up MCP integration...');
|
|
936
|
-
console.log(`Project: ${projectPath}`);
|
|
937
|
-
console.log(`Claude config: ${configPath}`);
|
|
938
|
-
|
|
939
|
-
try {
|
|
940
|
-
let config = {};
|
|
941
|
-
if (existsSync(configPath)) {
|
|
942
|
-
config = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
if (!config.mcpServers) {
|
|
946
|
-
config.mcpServers = {};
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
config.mcpServers['cntx-ui'] = {
|
|
950
|
-
command: 'node',
|
|
951
|
-
args: [join(projectPath, 'bin', 'cntx-ui.js'), 'mcp'],
|
|
952
|
-
env: {}
|
|
953
|
-
};
|
|
954
|
-
|
|
955
|
-
// Ensure directory exists
|
|
956
|
-
mkdirSync(dirname(configPath), { recursive: true });
|
|
957
|
-
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
958
|
-
|
|
959
|
-
console.log('✅ MCP integration configured');
|
|
960
|
-
console.log('💡 Restart Claude Desktop to apply changes');
|
|
961
|
-
} catch (error) {
|
|
962
|
-
console.error('❌ Failed to setup MCP:', error.message);
|
|
963
|
-
console.log('💡 You may need to manually add the configuration to Claude Desktop');
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
|
|
967
679
|
// Auto-start server when run directly
|
|
968
680
|
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
969
681
|
if (isMainModule) {
|
|
970
|
-
console.log('
|
|
682
|
+
console.log('Starting cntx-ui server...');
|
|
971
683
|
const server = new CntxServer();
|
|
972
684
|
server.init();
|
|
973
685
|
server.listen(3333, 'localhost');
|