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/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, copyFileSync, cpSync } from 'fs';
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
- // Progress bar utility
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
- return () => {
127
- clearInterval(interval);
128
- const elapsed = Date.now() - startTime;
129
- const remaining = Math.max(0, minTime - elapsed);
102
+ get bundles() {
103
+ return this.configManager.getBundles();
104
+ }
130
105
 
131
- if (remaining > 0) {
132
- return new Promise(resolve => setTimeout(resolve, remaining));
133
- }
134
- return Promise.resolve();
135
- };
106
+ getAllFiles() {
107
+ return this.fileSystemManager.getAllFiles();
136
108
  }
137
109
 
138
- // Single progress bar for initialization
139
- async showInitProgress(steps) {
140
- const totalSteps = steps.length;
141
- let currentStep = 0;
110
+ getFileTree() {
111
+ return this.fileSystemManager.getFileTree();
112
+ }
142
113
 
143
- const updateProgress = (stepName, completed = false) => {
144
- const progress = Math.round((currentStep / totalSteps) * 100);
145
- const barLength = 30;
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
- // Clear the line and show progress
150
- process.stdout.write(`\r[${bar}] ${progress}% - ${stepName}${' '.repeat(20)}`);
151
- };
118
+ generateAllBundles() {
119
+ return this.bundleManager.generateAllBundles();
120
+ }
152
121
 
153
- // Initialize progress bar
154
- updateProgress(steps[0]);
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
- // Helper method to add initialization messages
192
- addInitMessage(message) {
193
- if (this.verbose) {
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
- const steps = skipFileWatcher
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
- await progress.next(steps[0], 800);
143
+ console.log(' Configuration loaded');
217
144
 
218
145
  if (!skipFileWatcher) {
219
- // Step 2: Setting up file watcher
146
+ // Step 2: Set up file watcher
220
147
  this.fileSystemManager.setIgnorePatterns(this.configManager.getIgnorePatterns());
221
- await progress.next(steps[1], 400);
148
+ console.log(' File watcher configured');
222
149
  }
223
150
 
224
- // Step 3: Loading semantic cache
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: Starting file watcher
162
+ // Step 4: Start file watcher
234
163
  this.startWatching();
235
- await progress.next(steps[3], 600);
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: Generating bundles
171
+ // Step 5: Generate bundles (awaited to prevent race conditions)
243
172
  if (!skipBundleGeneration) {
244
- this.bundleManager.generateAllBundles();
245
- await progress.next(steps[4], 1200);
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(` ${msg}`));
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(`📁 File ${eventType}: ${filename}`);
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(`📁 Skipping .cntx file: ${filename}`);
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(`🔄 Auto-regenerating bundle: ${bundleName}`);
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('🔄 Refreshing semantic analysis and database...');
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('All chunks already have persistent embeddings');
416
+ console.log('All chunks already have persistent embeddings');
492
417
  return;
493
418
  }
494
419
 
495
- console.log(`🔧 Enhancing ${chunksNeedingEmbeddings.length} chunks with persistent embeddings...`);
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('Background embedding enhancement complete');
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('🔗 MCP server started');
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(`🌐 Server running at http://${host}:${port}`);
672
- console.log(`📊 Serving ${this.bundleManager.getAllBundleInfo().length} bundles from your project`);
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('\n🛑 Shutting down server...');
491
+ console.log('\nShutting down server...');
682
492
  this.webSocketManager.close();
683
493
  this.fileSystemManager.destroy();
684
494
  server.close(() => {
685
- console.log('Server stopped');
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 with progress bar
532
+ // Now start initialization
710
533
  await server.init();
711
534
 
712
- if (options.withMcp) {
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('🔗 MCP server running on stdio...');
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('📁 Created .cntx directory');
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('📄 Created .mcp.json for agent auto-discovery');
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(`💡 Suggested bundle: ${d.name} (${d.dir}/**)`);
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('📄 Created .cntxignore with smart defaults');
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
- // Copy activities.json from templates
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('💡 Pro tip: Use "cntx-ui status" to see your project overview');
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('📊 cntx-ui Status');
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(` ${bundle.name}: ${bundle.fileCount} files (${Math.round(bundle.size / 1024)}KB)`);
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('🚀 Starting cntx-ui server...');
682
+ console.log('Starting cntx-ui server...');
971
683
  const server = new CntxServer();
972
684
  server.init();
973
685
  server.listen(3333, 'localhost');