cntx-ui 2.0.13 → 2.0.15

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 (44) hide show
  1. package/bin/cntx-ui.js +137 -55
  2. package/lib/agent-runtime.js +1480 -0
  3. package/lib/agent-tools.js +368 -0
  4. package/lib/api-router.js +978 -0
  5. package/lib/bundle-manager.js +471 -0
  6. package/lib/configuration-manager.js +725 -0
  7. package/lib/file-system-manager.js +472 -0
  8. package/lib/heuristics-manager.js +425 -0
  9. package/lib/mcp-server.js +1054 -1
  10. package/lib/semantic-splitter.js +7 -14
  11. package/lib/simple-vector-store.js +329 -0
  12. package/lib/websocket-manager.js +470 -0
  13. package/package.json +10 -3
  14. package/server.js +662 -1933
  15. package/templates/activities/README.md +67 -0
  16. package/templates/activities/activities/create-project-bundles/README.md +83 -0
  17. package/templates/activities/activities/create-project-bundles/notes.md +102 -0
  18. package/templates/activities/activities/create-project-bundles/progress.md +63 -0
  19. package/templates/activities/activities/create-project-bundles/tasks.md +39 -0
  20. package/templates/activities/activities.json +219 -0
  21. package/templates/activities/lib/.markdownlint.jsonc +18 -0
  22. package/templates/activities/lib/create-activity.mdc +63 -0
  23. package/templates/activities/lib/generate-tasks.mdc +64 -0
  24. package/templates/activities/lib/process-task-list.mdc +52 -0
  25. package/templates/agent-config.yaml +78 -0
  26. package/templates/agent-instructions.md +218 -0
  27. package/templates/agent-rules/capabilities/activities-system.md +147 -0
  28. package/templates/agent-rules/capabilities/bundle-system.md +131 -0
  29. package/templates/agent-rules/capabilities/vector-search.md +135 -0
  30. package/templates/agent-rules/core/codebase-navigation.md +91 -0
  31. package/templates/agent-rules/core/performance-hierarchy.md +48 -0
  32. package/templates/agent-rules/core/response-formatting.md +120 -0
  33. package/templates/agent-rules/project-specific/architecture.md +145 -0
  34. package/templates/config.json +76 -0
  35. package/templates/hidden-files.json +14 -0
  36. package/web/dist/assets/heuristics-manager-browser-DfonOP5I.js +1 -0
  37. package/web/dist/assets/index-dF3qg-y_.js +2486 -0
  38. package/web/dist/assets/index-h5FGSg_P.css +1 -0
  39. package/web/dist/cntx-ui.svg +18 -0
  40. package/web/dist/index.html +25 -8
  41. package/lib/semantic-integration.js +0 -441
  42. package/web/dist/assets/index-Ci1Q-YrQ.js +0 -611
  43. package/web/dist/assets/index-IUp4q_fr.css +0 -1
  44. package/web/dist/vite.svg +0 -21
@@ -0,0 +1,1480 @@
1
+ /**
2
+ * Agent Runtime for Codebase Exploration and Development
3
+ * Implements the four behavior modes: Discovery, Query, Feature Investigation, Passive
4
+ */
5
+
6
+ import AgentTools from './agent-tools.js';
7
+
8
+ export class AgentRuntime {
9
+ constructor(cntxServer) {
10
+ this.cntxServer = cntxServer;
11
+ this.tools = new AgentTools(cntxServer);
12
+ }
13
+
14
+ /**
15
+ * Discovery Mode: "Tell me about this codebase"
16
+ * Summarize bundles, architectural patterns, and code organization
17
+ */
18
+ async discoverCodebase(options = {}) {
19
+ const { scope = 'all', includeDetails = true } = options;
20
+
21
+ try {
22
+ const discovery = {
23
+ overview: await this.getCodebaseOverview(),
24
+ bundles: await this.analyzeBundles(scope),
25
+ architecture: await this.analyzeArchitecture(),
26
+ patterns: await this.identifyPatterns(),
27
+ recommendations: []
28
+ };
29
+
30
+ if (includeDetails) {
31
+ discovery.semanticSummary = await this.getSemanticSummary();
32
+ discovery.fileTypes = await this.analyzeFileTypes();
33
+ discovery.complexity = await this.analyzeComplexity();
34
+ }
35
+
36
+ // Generate recommendations
37
+ discovery.recommendations = await this.generateDiscoveryRecommendations(discovery);
38
+
39
+ return discovery;
40
+ } catch (error) {
41
+ throw new Error(`Discovery failed: ${error.message}`);
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Query Mode: "Where is the user authentication handled?"
47
+ * Use semantic search and AST analysis for precise answers
48
+ */
49
+ async answerQuery(question, options = {}) {
50
+ const { scope = null, maxResults = 10, includeCode = false } = options;
51
+
52
+ try {
53
+ // Extract key terms from question
54
+ const searchTerms = this.extractSearchTerms(question);
55
+
56
+ // Perform semantic search
57
+ const semanticResults = await this.tools.searchSemanticChunks(searchTerms.primary, {
58
+ bundle: scope,
59
+ maxResults: maxResults * 2
60
+ });
61
+
62
+ // Perform bundle-aware file search if needed
63
+ const fileResults = await this.searchInFiles(searchTerms, scope);
64
+
65
+ // Combine and rank results
66
+ const combinedResults = this.combineSearchResults(semanticResults, fileResults, question);
67
+
68
+ // Generate contextual answer
69
+ const answer = await this.generateContextualAnswer(question, combinedResults, includeCode);
70
+
71
+ return {
72
+ question,
73
+ answer: answer.response,
74
+ evidence: answer.evidence,
75
+ confidence: answer.confidence,
76
+ suggestions: answer.suggestions,
77
+ relatedFiles: combinedResults.files.slice(0, 5),
78
+ totalMatches: combinedResults.totalMatches
79
+ };
80
+ } catch (error) {
81
+ throw new Error(`Query failed: ${error.message}`);
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Feature Investigation Mode: "I want to add dark mode—what already exists?"
87
+ * Search for existing implementations and identify integration points
88
+ */
89
+ async investigateFeature(featureDescription, options = {}) {
90
+ const { includeRecommendations = true } = options;
91
+
92
+ try {
93
+ const investigation = {
94
+ feature: featureDescription,
95
+ existing: await this.findExistingImplementations(featureDescription),
96
+ related: await this.findRelatedCode(featureDescription),
97
+ dependencies: await this.analyzeDependencies(featureDescription),
98
+ integration: await this.findIntegrationPoints(featureDescription),
99
+ patterns: await this.identifyImplementationPatterns(featureDescription)
100
+ };
101
+
102
+ if (includeRecommendations) {
103
+ investigation.recommendations = await this.generateImplementationRecommendations(investigation);
104
+ investigation.approach = await this.suggestImplementationApproach(investigation);
105
+ }
106
+
107
+ return investigation;
108
+ } catch (error) {
109
+ throw new Error(`Feature investigation failed: ${error.message}`);
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Passive Mode: "Let's discuss the architecture before I make changes"
115
+ * Engage in conversation about design decisions and patterns
116
+ */
117
+ async discussAndPlan(userInput, context = {}) {
118
+ try {
119
+ const discussion = {
120
+ userInput,
121
+ context: await this.analyzeDiscussionContext(userInput, context),
122
+ insights: await this.generateInsights(userInput),
123
+ considerations: await this.identifyConsiderations(userInput),
124
+ alternatives: await this.suggestAlternatives(userInput),
125
+ questions: await this.generateClarifyingQuestions(userInput)
126
+ };
127
+
128
+ return discussion;
129
+ } catch (error) {
130
+ throw new Error(`Discussion planning failed: ${error.message}`);
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Project Organizer Mode: Setup and maintenance of project organization
136
+ * Adapts to project maturity - setup for fresh projects, optimization for established ones
137
+ */
138
+ async organizeProject(options = {}) {
139
+ const { activity = 'detect', autoDetect = true, force = false } = options;
140
+
141
+ try {
142
+ const organization = {
143
+ projectState: await this.detectProjectState(),
144
+ currentActivity: activity,
145
+ timestamp: new Date().toISOString()
146
+ };
147
+
148
+ // Auto-detect appropriate activity if requested
149
+ if (autoDetect && activity === 'detect') {
150
+ organization.suggestedActivity = this.suggestActivity(organization.projectState);
151
+ organization.workflow = this.generateWorkflow(organization.projectState);
152
+ }
153
+
154
+ // Execute the requested activity
155
+ switch (activity) {
156
+ case 'detect':
157
+ organization.analysis = await this.analyzeProjectMaturity();
158
+ organization.recommendations = await this.generateSetupRecommendations(organization.projectState);
159
+ break;
160
+
161
+ case 'analyze':
162
+ organization.semanticAnalysis = await this.performSemanticAnalysis();
163
+ organization.readiness = this.assessBundlingReadiness(organization.semanticAnalysis);
164
+ break;
165
+
166
+ case 'bundle':
167
+ organization.bundleSuggestions = await this.generateIntelligentBundles();
168
+ organization.preview = await this.previewBundleChanges(organization.bundleSuggestions);
169
+ break;
170
+
171
+ case 'create':
172
+ organization.bundleSuggestions = await this.generateIntelligentBundles();
173
+ organization.creation = await this.createSuggestedBundles(organization.bundleSuggestions);
174
+ break;
175
+
176
+ case 'optimize':
177
+ organization.optimizations = await this.analyzeOptimizationOpportunities();
178
+ organization.recommendations = await this.generateOptimizationPlan();
179
+ break;
180
+
181
+ case 'audit':
182
+ organization.audit = await this.auditCurrentOrganization();
183
+ organization.issues = await this.identifyOrganizationalIssues();
184
+ break;
185
+
186
+ case 'cleanup':
187
+ organization.cleanup = await this.suggestCleanupActions();
188
+ organization.impact = await this.assessCleanupImpact();
189
+ break;
190
+
191
+ case 'validate':
192
+ organization.validation = await this.validateCurrentOrganization();
193
+ organization.health = await this.calculateOrganizationHealth();
194
+ break;
195
+
196
+ default:
197
+ throw new Error(`Unknown activity: ${activity}`);
198
+ }
199
+
200
+ // Add next steps
201
+ organization.nextSteps = this.generateNextSteps(organization, activity);
202
+
203
+ return organization;
204
+ } catch (error) {
205
+ throw new Error(`Project organization failed: ${error.message}`);
206
+ }
207
+ }
208
+
209
+ // Helper methods for Discovery Mode
210
+
211
+ async getCodebaseOverview() {
212
+ const bundles = Array.from(this.cntxServer.bundles.entries());
213
+ const totalFiles = bundles.reduce((sum, [_, bundle]) => sum + bundle.files.length, 0);
214
+ const totalSize = bundles.reduce((sum, [_, bundle]) => sum + bundle.size, 0);
215
+
216
+ return {
217
+ projectPath: this.cntxServer.CWD,
218
+ totalBundles: bundles.length,
219
+ totalFiles,
220
+ totalSize,
221
+ formattedSize: this.formatBytes(totalSize),
222
+ bundleNames: bundles.map(([name]) => name)
223
+ };
224
+ }
225
+
226
+ async analyzeBundles(scope) {
227
+ const bundlesToAnalyze = scope === 'all'
228
+ ? Array.from(this.cntxServer.bundles.entries())
229
+ : [[scope, this.cntxServer.bundles.get(scope)]].filter(([_, b]) => b);
230
+
231
+ return Promise.all(bundlesToAnalyze.map(async ([name, bundle]) => {
232
+ const fileTypes = this.categorizeFiles(bundle.files);
233
+ return {
234
+ name,
235
+ fileCount: bundle.files.length,
236
+ size: bundle.size,
237
+ formattedSize: this.formatBytes(bundle.size),
238
+ patterns: bundle.patterns,
239
+ fileTypes,
240
+ lastGenerated: bundle.lastGenerated,
241
+ changed: bundle.changed,
242
+ purpose: this.inferBundlePurpose(name, bundle.files, fileTypes)
243
+ };
244
+ }));
245
+ }
246
+
247
+ async analyzeArchitecture() {
248
+ const analysis = await this.tools.getSemanticAnalysis({ maxChunks: 100 });
249
+
250
+ if (!analysis.chunks) {
251
+ return { message: 'No semantic analysis available for architecture detection' };
252
+ }
253
+
254
+ const patterns = {
255
+ frontend: this.detectFrontendPatterns(analysis.chunks),
256
+ backend: this.detectBackendPatterns(analysis.chunks),
257
+ testing: this.detectTestingPatterns(analysis.chunks),
258
+ configuration: this.detectConfigPatterns(analysis.chunks)
259
+ };
260
+
261
+ return {
262
+ type: this.determineArchitectureType(patterns),
263
+ patterns,
264
+ frameworks: this.identifyFrameworks(analysis.chunks),
265
+ languages: this.identifyLanguages(analysis.chunks)
266
+ };
267
+ }
268
+
269
+ async identifyPatterns() {
270
+ const files = await this.tools.listFiles({ limit: 200 });
271
+ const analysis = await this.tools.getSemanticAnalysis({ maxChunks: 50 });
272
+
273
+ return {
274
+ organizational: this.identifyOrganizationalPatterns(files),
275
+ coding: this.identifyCodingPatterns(analysis.chunks || []),
276
+ naming: this.identifyNamingPatterns(files),
277
+ structural: this.identifyStructuralPatterns(files)
278
+ };
279
+ }
280
+
281
+ // Helper methods for Query Mode
282
+
283
+ extractSearchTerms(question) {
284
+ // Simple keyword extraction - could be enhanced with NLP
285
+ const stopWords = ['the', 'is', 'at', 'which', 'on', 'how', 'where', 'what', 'when', 'why'];
286
+ const words = question.toLowerCase()
287
+ .replace(/[^\w\s]/g, ' ')
288
+ .split(/\s+/)
289
+ .filter(word => word.length > 2 && !stopWords.includes(word));
290
+
291
+ return {
292
+ primary: words.join(' '),
293
+ keywords: words,
294
+ original: question
295
+ };
296
+ }
297
+
298
+ async searchInFiles(searchTerms, scope) {
299
+ const files = await this.tools.listFiles({
300
+ bundle: scope,
301
+ pattern: searchTerms.keywords.join('|'),
302
+ limit: 50
303
+ });
304
+
305
+ return {
306
+ files: files.map(f => ({
307
+ path: f.path,
308
+ bundles: f.bundles,
309
+ relevance: this.calculateFileRelevance(f.path, searchTerms.keywords)
310
+ })),
311
+ totalFiles: files.length
312
+ };
313
+ }
314
+
315
+ combineSearchResults(semanticResults, fileResults, question) {
316
+ const allFiles = new Set();
317
+ const chunks = semanticResults.chunks || [];
318
+
319
+ // Add files from semantic chunks
320
+ chunks.forEach(chunk => {
321
+ if (chunk.filePath) allFiles.add(chunk.filePath);
322
+ });
323
+
324
+ // Add files from direct search
325
+ fileResults.files.forEach(f => allFiles.add(f.path));
326
+
327
+ return {
328
+ chunks,
329
+ files: Array.from(allFiles),
330
+ totalMatches: chunks.length + fileResults.totalFiles,
331
+ semanticMatches: semanticResults.totalResults || 0,
332
+ fileMatches: fileResults.totalFiles
333
+ };
334
+ }
335
+
336
+ async generateContextualAnswer(question, results, includeCode) {
337
+ const evidence = [];
338
+ const suggestions = [];
339
+ let confidence = 0;
340
+
341
+ if (results.chunks.length > 0) {
342
+ confidence += 0.6;
343
+ evidence.push({
344
+ type: 'semantic',
345
+ count: results.chunks.length,
346
+ message: `Found ${results.chunks.length} relevant code chunks`
347
+ });
348
+
349
+ if (includeCode) {
350
+ evidence.push({
351
+ type: 'code',
352
+ samples: results.chunks.slice(0, 3).map(chunk => ({
353
+ file: chunk.filePath,
354
+ name: chunk.name,
355
+ purpose: chunk.purpose,
356
+ code: chunk.code
357
+ }))
358
+ });
359
+ }
360
+ }
361
+
362
+ if (results.files.length > 0) {
363
+ confidence += 0.3;
364
+ evidence.push({
365
+ type: 'files',
366
+ count: results.files.length,
367
+ files: results.files.slice(0, 5)
368
+ });
369
+ }
370
+
371
+ // Generate response based on evidence
372
+ let response = `Based on the analysis of your codebase:\n\n`;
373
+
374
+ if (results.chunks.length > 0) {
375
+ const topChunk = results.chunks[0];
376
+ response += `The most relevant code is in \`${topChunk.filePath}\` where `;
377
+ response += `${topChunk.purpose || topChunk.name} is implemented`;
378
+
379
+ if (topChunk.startLine) {
380
+ response += ` (lines ${topChunk.startLine}-${topChunk.endLine})`;
381
+ }
382
+ response += '.\n\n';
383
+
384
+ if (results.chunks.length > 1) {
385
+ response += `Additionally, found ${results.chunks.length - 1} other related implementations.\n\n`;
386
+ }
387
+ }
388
+
389
+ if (results.files.length > 0) {
390
+ response += `Key files to examine: ${results.files.slice(0, 3).join(', ')}\n\n`;
391
+ }
392
+
393
+ if (confidence < 0.5) {
394
+ suggestions.push('Consider running semantic analysis if not already done');
395
+ suggestions.push('Try rephrasing the question with more specific terms');
396
+ }
397
+
398
+ return {
399
+ response: response.trim(),
400
+ evidence,
401
+ confidence: Math.min(confidence, 1.0),
402
+ suggestions
403
+ };
404
+ }
405
+
406
+ // Helper methods for Feature Investigation Mode
407
+
408
+ async findExistingImplementations(featureDescription) {
409
+ const searchTerms = this.extractSearchTerms(featureDescription);
410
+ const results = await this.tools.searchSemanticChunks(searchTerms.primary, { maxResults: 20 });
411
+
412
+ return {
413
+ found: results.chunks.length > 0,
414
+ implementations: results.chunks.map(chunk => ({
415
+ file: chunk.filePath,
416
+ name: chunk.name,
417
+ purpose: chunk.purpose,
418
+ type: chunk.subtype,
419
+ bundles: chunk.bundles,
420
+ confidence: chunk.relevanceScore || 0
421
+ })),
422
+ summary: `Found ${results.chunks.length} potentially related implementations`
423
+ };
424
+ }
425
+
426
+ async findRelatedCode(featureDescription) {
427
+ // Look for related patterns in bundle organization
428
+ const bundles = await this.analyzeBundles('all');
429
+ const relatedBundles = bundles.filter(bundle =>
430
+ this.isFeatureRelated(featureDescription, bundle.name, bundle.purpose)
431
+ );
432
+
433
+ return {
434
+ bundles: relatedBundles,
435
+ patterns: this.identifyRelatedPatterns(featureDescription, relatedBundles)
436
+ };
437
+ }
438
+
439
+ async generateImplementationRecommendations(investigation) {
440
+ const recommendations = [];
441
+
442
+ if (investigation.existing.found) {
443
+ recommendations.push({
444
+ type: 'extend',
445
+ message: 'Extend existing implementation rather than creating new one',
446
+ files: investigation.existing.implementations.slice(0, 3).map(impl => impl.file)
447
+ });
448
+ } else {
449
+ recommendations.push({
450
+ type: 'create',
451
+ message: 'No existing implementation found - create new feature',
452
+ suggestedLocation: this.suggestImplementationLocation(investigation.feature)
453
+ });
454
+ }
455
+
456
+ if (investigation.related.bundles.length > 0) {
457
+ recommendations.push({
458
+ type: 'organize',
459
+ message: 'Consider organizing in existing bundle structure',
460
+ bundles: investigation.related.bundles.map(b => b.name)
461
+ });
462
+ }
463
+
464
+ return recommendations;
465
+ }
466
+
467
+ // Utility methods
468
+
469
+ formatBytes(bytes) {
470
+ if (bytes === 0) return '0 Bytes';
471
+ const k = 1024;
472
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
473
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
474
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
475
+ }
476
+
477
+ categorizeFiles(files) {
478
+ const categories = {};
479
+ files.forEach(file => {
480
+ const ext = require('path').extname(file).toLowerCase();
481
+ categories[ext] = (categories[ext] || 0) + 1;
482
+ });
483
+ return categories;
484
+ }
485
+
486
+ inferBundlePurpose(name, files, fileTypes) {
487
+ if (name.includes('component') || name.includes('ui')) return 'UI Components';
488
+ if (name.includes('api') || name.includes('server')) return 'Backend API';
489
+ if (name.includes('test')) return 'Testing';
490
+ if (name.includes('config')) return 'Configuration';
491
+ if (files.some(f => f.includes('hook'))) return 'React Hooks';
492
+ if (Object.keys(fileTypes).includes('.ts') || Object.keys(fileTypes).includes('.tsx')) return 'TypeScript Application';
493
+ return 'General Purpose';
494
+ }
495
+
496
+ detectFrontendPatterns(chunks) {
497
+ return {
498
+ react: chunks.filter(c => c.subtype === 'react_component').length,
499
+ hooks: chunks.filter(c => c.name && c.name.startsWith('use')).length,
500
+ components: chunks.filter(c => c.purpose && c.purpose.includes('component')).length
501
+ };
502
+ }
503
+
504
+ detectBackendPatterns(chunks) {
505
+ return {
506
+ apis: chunks.filter(c => c.purpose && c.purpose.includes('API')).length,
507
+ middleware: chunks.filter(c => c.purpose && c.purpose.includes('middleware')).length,
508
+ routes: chunks.filter(c => c.purpose && c.purpose.includes('route')).length
509
+ };
510
+ }
511
+
512
+ detectTestingPatterns(chunks) {
513
+ return {
514
+ tests: chunks.filter(c => c.filePath && c.filePath.includes('test')).length,
515
+ specs: chunks.filter(c => c.filePath && c.filePath.includes('spec')).length
516
+ };
517
+ }
518
+
519
+ detectConfigPatterns(chunks) {
520
+ return {
521
+ configs: chunks.filter(c => c.purpose && c.purpose.includes('config')).length
522
+ };
523
+ }
524
+
525
+ determineArchitectureType(patterns) {
526
+ if (patterns.frontend.react > 0) return 'React Application';
527
+ if (patterns.backend.apis > 0) return 'Backend API';
528
+ return 'Mixed/Utility';
529
+ }
530
+
531
+ identifyFrameworks(chunks) {
532
+ const frameworks = new Set();
533
+ chunks.forEach(chunk => {
534
+ if (chunk.includes?.imports) {
535
+ chunk.includes.imports.forEach(imp => {
536
+ if (imp.includes('react')) frameworks.add('React');
537
+ if (imp.includes('express')) frameworks.add('Express');
538
+ if (imp.includes('next')) frameworks.add('Next.js');
539
+ if (imp.includes('vue')) frameworks.add('Vue');
540
+ });
541
+ }
542
+ });
543
+ return Array.from(frameworks);
544
+ }
545
+
546
+ identifyLanguages(chunks) {
547
+ const languages = new Set();
548
+ chunks.forEach(chunk => {
549
+ if (chunk.filePath?.endsWith('.ts') || chunk.filePath?.endsWith('.tsx')) {
550
+ languages.add('TypeScript');
551
+ } else if (chunk.filePath?.endsWith('.js') || chunk.filePath?.endsWith('.jsx')) {
552
+ languages.add('JavaScript');
553
+ }
554
+ });
555
+ return Array.from(languages);
556
+ }
557
+
558
+ calculateFileRelevance(filePath, keywords) {
559
+ let score = 0;
560
+ const fileName = require('path').basename(filePath).toLowerCase();
561
+ keywords.forEach(keyword => {
562
+ if (fileName.includes(keyword.toLowerCase())) {
563
+ score += 1;
564
+ }
565
+ });
566
+ return score;
567
+ }
568
+
569
+ isFeatureRelated(featureDescription, bundleName, bundlePurpose) {
570
+ const feature = featureDescription.toLowerCase();
571
+ const name = bundleName.toLowerCase();
572
+ const purpose = (bundlePurpose || '').toLowerCase();
573
+
574
+ return name.includes(feature) || purpose.includes(feature) ||
575
+ (feature.includes('ui') && (name.includes('component') || name.includes('ui'))) ||
576
+ (feature.includes('api') && (name.includes('api') || name.includes('server')));
577
+ }
578
+
579
+ identifyRelatedPatterns(featureDescription, relatedBundles) {
580
+ return relatedBundles.map(bundle => ({
581
+ bundle: bundle.name,
582
+ pattern: bundle.patterns,
583
+ reason: `Similar naming/purpose pattern to ${featureDescription}`
584
+ }));
585
+ }
586
+
587
+ suggestImplementationLocation(featureDescription) {
588
+ const feature = featureDescription.toLowerCase();
589
+
590
+ if (feature.includes('component') || feature.includes('ui')) {
591
+ return 'web/src/components/';
592
+ }
593
+ if (feature.includes('hook')) {
594
+ return 'web/src/hooks/';
595
+ }
596
+ if (feature.includes('api')) {
597
+ return 'lib/';
598
+ }
599
+ if (feature.includes('util')) {
600
+ return 'web/src/utils/';
601
+ }
602
+
603
+ return 'web/src/';
604
+ }
605
+
606
+ identifyOrganizationalPatterns(files) {
607
+ const patterns = {
608
+ directoryBased: files.some(f => f.path.includes('components/') || f.path.includes('utils/')),
609
+ featureBased: files.some(f => f.path.split('/').length > 3),
610
+ flatStructure: files.every(f => f.path.split('/').length <= 2)
611
+ };
612
+ return patterns;
613
+ }
614
+
615
+ identifyCodingPatterns(chunks) {
616
+ return {
617
+ functionalComponents: chunks.filter(c => c.subtype === 'react_component').length,
618
+ hooks: chunks.filter(c => c.name && c.name.startsWith('use')).length,
619
+ asyncFunctions: chunks.filter(c => c.isAsync).length,
620
+ exportedFunctions: chunks.filter(c => c.isExported).length
621
+ };
622
+ }
623
+
624
+ identifyNamingPatterns(files) {
625
+ const patterns = {
626
+ camelCase: files.filter(f => /[a-z][A-Z]/.test(require('path').basename(f.path, require('path').extname(f.path)))).length,
627
+ kebabCase: files.filter(f => /-/.test(require('path').basename(f.path, require('path').extname(f.path)))).length,
628
+ pascalCase: files.filter(f => /^[A-Z]/.test(require('path').basename(f.path, require('path').extname(f.path)))).length
629
+ };
630
+ return patterns;
631
+ }
632
+
633
+ identifyStructuralPatterns(files) {
634
+ return {
635
+ hasTests: files.some(f => f.path.includes('test') || f.path.includes('spec')),
636
+ hasConfig: files.some(f => f.path.includes('config') || f.path.endsWith('.config.js')),
637
+ hasDocumentation: files.some(f => f.path.endsWith('.md')),
638
+ hasTypeDefinitions: files.some(f => f.path.endsWith('.d.ts'))
639
+ };
640
+ }
641
+
642
+ async getSemanticSummary() {
643
+ const analysis = await this.tools.getSemanticAnalysis({ maxChunks: 100 });
644
+ return analysis.summary || { message: 'No semantic summary available' };
645
+ }
646
+
647
+ async analyzeFileTypes() {
648
+ const files = await this.tools.listFiles({ limit: 500 });
649
+ return this.categorizeFiles(files.map(f => f.path));
650
+ }
651
+
652
+ async analyzeComplexity() {
653
+ const analysis = await this.tools.getSemanticAnalysis({ maxChunks: 100 });
654
+ if (!analysis.chunks) return { message: 'No complexity data available' };
655
+
656
+ const complexity = { low: 0, medium: 0, high: 0 };
657
+ analysis.chunks.forEach(chunk => {
658
+ const level = chunk.complexity?.level || 'low';
659
+ complexity[level]++;
660
+ });
661
+
662
+ return complexity;
663
+ }
664
+
665
+ async generateDiscoveryRecommendations(discovery) {
666
+ const recommendations = [];
667
+
668
+ if (discovery.bundles.length > 10) {
669
+ recommendations.push({
670
+ type: 'organization',
671
+ message: 'Consider consolidating similar bundles for better organization'
672
+ });
673
+ }
674
+
675
+ if (discovery.semanticSummary?.totalChunks > 100) {
676
+ recommendations.push({
677
+ type: 'performance',
678
+ message: 'Large codebase detected - consider using bundle-scoped queries for better performance'
679
+ });
680
+ }
681
+
682
+ return recommendations;
683
+ }
684
+
685
+ async analyzeDependencies(featureDescription) {
686
+ // Simple dependency analysis based on imports in semantic chunks
687
+ const analysis = await this.tools.getSemanticAnalysis({ maxChunks: 50 });
688
+ const allImports = new Set();
689
+
690
+ if (analysis.chunks) {
691
+ analysis.chunks.forEach(chunk => {
692
+ if (chunk.includes?.imports) {
693
+ chunk.includes.imports.forEach(imp => allImports.add(imp));
694
+ }
695
+ });
696
+ }
697
+
698
+ return Array.from(allImports);
699
+ }
700
+
701
+ async findIntegrationPoints(featureDescription) {
702
+ const searchResults = await this.tools.searchSemanticChunks(featureDescription, { maxResults: 10 });
703
+
704
+ return searchResults.chunks.map(chunk => ({
705
+ file: chunk.filePath,
706
+ function: chunk.name,
707
+ reason: `Potential integration point based on ${chunk.purpose}`
708
+ }));
709
+ }
710
+
711
+ async identifyImplementationPatterns(featureDescription) {
712
+ const bundles = await this.analyzeBundles('all');
713
+ const patterns = [];
714
+
715
+ bundles.forEach(bundle => {
716
+ if (this.isFeatureRelated(featureDescription, bundle.name, bundle.purpose)) {
717
+ patterns.push({
718
+ bundle: bundle.name,
719
+ fileTypes: bundle.fileTypes,
720
+ organizationPattern: bundle.patterns
721
+ });
722
+ }
723
+ });
724
+
725
+ return patterns;
726
+ }
727
+
728
+ async suggestImplementationApproach(investigation) {
729
+ if (investigation.existing.found) {
730
+ return {
731
+ strategy: 'extend',
732
+ description: 'Build upon existing implementation',
733
+ files: investigation.existing.implementations.slice(0, 2).map(impl => impl.file)
734
+ };
735
+ }
736
+
737
+ return {
738
+ strategy: 'create',
739
+ description: 'Create new implementation following project patterns',
740
+ location: this.suggestImplementationLocation(investigation.feature)
741
+ };
742
+ }
743
+
744
+ async analyzeDiscussionContext(userInput, context) {
745
+ return {
746
+ intent: this.classifyIntent(userInput),
747
+ scope: context.scope || 'general',
748
+ complexity: this.assessComplexity(userInput)
749
+ };
750
+ }
751
+
752
+ async generateInsights(userInput) {
753
+ return [
754
+ 'Consider the existing bundle organization when planning changes',
755
+ 'Use semantic search to find similar implementations',
756
+ 'Check for related patterns in the codebase before implementing'
757
+ ];
758
+ }
759
+
760
+ async identifyConsiderations(userInput) {
761
+ return [
762
+ 'Impact on existing bundles and organization',
763
+ 'Compatibility with current architecture patterns',
764
+ 'Testing strategy for new implementations'
765
+ ];
766
+ }
767
+
768
+ async suggestAlternatives(userInput) {
769
+ return [
770
+ 'Extend existing functionality instead of creating new',
771
+ 'Consider configuration-based approach for flexibility',
772
+ 'Evaluate third-party solutions before custom implementation'
773
+ ];
774
+ }
775
+
776
+ async generateClarifyingQuestions(userInput) {
777
+ return [
778
+ 'Which bundle or area of the codebase is most relevant?',
779
+ 'Are there existing implementations we should build upon?',
780
+ 'What are the specific requirements or constraints?'
781
+ ];
782
+ }
783
+
784
+ classifyIntent(userInput) {
785
+ const input = userInput.toLowerCase();
786
+ if (input.includes('implement') || input.includes('add') || input.includes('create')) {
787
+ return 'implementation';
788
+ }
789
+ if (input.includes('refactor') || input.includes('improve') || input.includes('optimize')) {
790
+ return 'optimization';
791
+ }
792
+ if (input.includes('understand') || input.includes('explain') || input.includes('how')) {
793
+ return 'understanding';
794
+ }
795
+ return 'discussion';
796
+ }
797
+
798
+ assessComplexity(userInput) {
799
+ const words = userInput.split(' ').length;
800
+ if (words > 20) return 'high';
801
+ if (words > 10) return 'medium';
802
+ return 'low';
803
+ }
804
+
805
+ // Project Organizer Mode Helper Methods
806
+
807
+ async detectProjectState() {
808
+ const bundles = await this.analyzeBundles('all');
809
+ const analysis = await this.tools.getSemanticAnalysis({ maxChunks: 10 });
810
+
811
+ // Determine project maturity
812
+ const state = {
813
+ bundleCount: bundles.length,
814
+ hasOnlyMaster: bundles.length === 1 && bundles[0].name === 'master',
815
+ hasSemanticAnalysis: analysis && analysis.chunks && analysis.chunks.length > 0,
816
+ totalFiles: bundles.reduce((sum, b) => sum + b.fileCount, 0),
817
+ maturityLevel: 'unknown'
818
+ };
819
+
820
+ // Classify maturity
821
+ if (state.hasOnlyMaster && !state.hasSemanticAnalysis) {
822
+ state.maturityLevel = 'fresh'; // Brand new project
823
+ } else if (state.hasOnlyMaster && state.hasSemanticAnalysis) {
824
+ state.maturityLevel = 'analyzed'; // Ready for bundling
825
+ } else if (state.bundleCount > 1 && state.bundleCount < 5) {
826
+ state.maturityLevel = 'organized'; // Basic organization
827
+ } else if (state.bundleCount >= 5) {
828
+ state.maturityLevel = 'mature'; // Well-organized
829
+ }
830
+
831
+ return state;
832
+ }
833
+
834
+ suggestActivity(projectState) {
835
+ switch (projectState.maturityLevel) {
836
+ case 'fresh':
837
+ return 'analyze'; // Need semantic analysis first
838
+ case 'analyzed':
839
+ return 'bundle'; // Ready to plan bundles
840
+ case 'organized':
841
+ return 'optimize'; // Can optimize existing organization
842
+ case 'mature':
843
+ return 'audit'; // Regular maintenance
844
+ default:
845
+ return 'detect';
846
+ }
847
+ }
848
+
849
+ generateWorkflow(projectState) {
850
+ const workflows = {
851
+ fresh: [
852
+ { step: 'analyze', description: 'Generate semantic analysis', required: true },
853
+ { step: 'bundle', description: 'Plan intelligent bundles', required: true },
854
+ { step: 'create', description: 'Create the planned bundles', required: true },
855
+ { step: 'validate', description: 'Verify organization', required: false }
856
+ ],
857
+ analyzed: [
858
+ { step: 'bundle', description: 'Plan intelligent bundles', required: true },
859
+ { step: 'create', description: 'Create the planned bundles', required: true },
860
+ { step: 'validate', description: 'Verify organization', required: false }
861
+ ],
862
+ organized: [
863
+ { step: 'audit', description: 'Review current organization', required: false },
864
+ { step: 'optimize', description: 'Improve bundle structure', required: false },
865
+ { step: 'validate', description: 'Verify improvements', required: false }
866
+ ],
867
+ mature: [
868
+ { step: 'audit', description: 'Regular maintenance check', required: false },
869
+ { step: 'cleanup', description: 'Remove obsolete patterns', required: false }
870
+ ]
871
+ };
872
+
873
+ return workflows[projectState.maturityLevel] || workflows.fresh;
874
+ }
875
+
876
+ async analyzeProjectMaturity() {
877
+ const bundles = await this.analyzeBundles('all');
878
+ const analysis = await this.tools.getSemanticAnalysis({ maxChunks: 50 });
879
+
880
+ return {
881
+ bundles: {
882
+ count: bundles.length,
883
+ types: bundles.map(b => ({ name: b.name, purpose: b.purpose, files: b.fileCount })),
884
+ coverage: this.calculateBundleCoverage(bundles)
885
+ },
886
+ codebase: {
887
+ hasSemanticAnalysis: analysis && analysis.chunks && analysis.chunks.length > 0,
888
+ chunkCount: analysis?.chunks?.length || 0,
889
+ complexity: analysis?.summary?.complexity || this.assessDefaultComplexity(bundles)
890
+ },
891
+ recommendations: this.generateMaturityRecommendations(bundles, analysis)
892
+ };
893
+ }
894
+
895
+ async generateSetupRecommendations(projectState) {
896
+ const recommendations = [];
897
+
898
+ if (projectState.maturityLevel === 'fresh') {
899
+ recommendations.push({
900
+ priority: 'high',
901
+ action: 'Generate semantic analysis',
902
+ reason: 'Required before intelligent bundle creation',
903
+ command: 'Use activity "analyze" to generate code analysis'
904
+ });
905
+ }
906
+
907
+ if (projectState.hasOnlyMaster) {
908
+ recommendations.push({
909
+ priority: 'high',
910
+ action: 'Create logical bundles',
911
+ reason: 'Only master bundle exists - organize code by purpose',
912
+ command: 'Use activity "bundle" after semantic analysis'
913
+ });
914
+ }
915
+
916
+ if (projectState.totalFiles > 50) {
917
+ recommendations.push({
918
+ priority: 'medium',
919
+ action: 'Consider bundle size limits',
920
+ reason: 'Large codebase may benefit from smaller, focused bundles'
921
+ });
922
+ }
923
+
924
+ return recommendations;
925
+ }
926
+
927
+ async performSemanticAnalysis() {
928
+ try {
929
+ // Trigger semantic analysis if not available
930
+ const existingAnalysis = await this.tools.getSemanticAnalysis({ maxChunks: 10 });
931
+
932
+ if (!existingAnalysis.chunks || existingAnalysis.chunks.length === 0) {
933
+ // Need to trigger analysis - this would typically call the cntx server's analysis
934
+ return {
935
+ status: 'analysis_needed',
936
+ message: 'Semantic analysis needs to be generated first',
937
+ instruction: 'Run semantic analysis before bundling'
938
+ };
939
+ }
940
+
941
+ return {
942
+ status: 'ready',
943
+ chunkCount: existingAnalysis.totalChunks,
944
+ summary: existingAnalysis.summary,
945
+ readyForBundling: true
946
+ };
947
+ } catch (error) {
948
+ return {
949
+ status: 'error',
950
+ message: error.message,
951
+ readyForBundling: false
952
+ };
953
+ }
954
+ }
955
+
956
+ assessBundlingReadiness(semanticAnalysis) {
957
+ if (semanticAnalysis.status === 'ready') {
958
+ return {
959
+ ready: true,
960
+ confidence: 'high',
961
+ reason: `${semanticAnalysis.chunkCount} semantic chunks available for intelligent bundling`
962
+ };
963
+ }
964
+
965
+ return {
966
+ ready: false,
967
+ confidence: 'none',
968
+ reason: semanticAnalysis.message || 'Semantic analysis required'
969
+ };
970
+ }
971
+
972
+ async generateIntelligentBundles() {
973
+ const analysis = await this.tools.getSemanticAnalysis({ maxChunks: 100 });
974
+
975
+ if (!analysis.chunks) {
976
+ return {
977
+ status: 'error',
978
+ message: 'Semantic analysis required before bundle generation'
979
+ };
980
+ }
981
+
982
+ const suggestions = {
983
+ recommended: {},
984
+ reasoning: [],
985
+ stats: {
986
+ totalChunks: analysis.chunks.length,
987
+ totalFiles: new Set(analysis.chunks.map(c => c.filePath)).size
988
+ }
989
+ };
990
+
991
+ // Group by semantic purpose
992
+ const purposeGroups = this.groupChunksByPurpose(analysis.chunks);
993
+
994
+ Object.entries(purposeGroups).forEach(([purpose, chunks]) => {
995
+ if (chunks.length >= 3) { // Only suggest if substantial
996
+ const bundleName = this.purposeToBundleName(purpose);
997
+ const patterns = this.generatePatternsForChunks(chunks);
998
+
999
+ suggestions.recommended[bundleName] = {
1000
+ patterns,
1001
+ chunkCount: chunks.length,
1002
+ files: [...new Set(chunks.map(c => c.filePath))],
1003
+ purpose: purpose
1004
+ };
1005
+
1006
+ suggestions.reasoning.push({
1007
+ bundle: bundleName,
1008
+ reason: `${chunks.length} functions with purpose: ${purpose}`,
1009
+ confidence: chunks.length > 5 ? 'high' : 'medium'
1010
+ });
1011
+ }
1012
+ });
1013
+
1014
+ // Add standard bundles
1015
+ this.addStandardBundles(suggestions, analysis.chunks);
1016
+
1017
+ return suggestions;
1018
+ }
1019
+
1020
+ async previewBundleChanges(bundleSuggestions) {
1021
+ const currentBundles = await this.analyzeBundles('all');
1022
+
1023
+ return {
1024
+ current: {
1025
+ count: currentBundles.length,
1026
+ bundles: currentBundles.map(b => ({ name: b.name, files: b.fileCount }))
1027
+ },
1028
+ proposed: {
1029
+ count: Object.keys(bundleSuggestions.recommended).length,
1030
+ bundles: Object.entries(bundleSuggestions.recommended).map(([name, bundle]) => ({
1031
+ name,
1032
+ files: bundle.files.length,
1033
+ purpose: bundle.purpose
1034
+ }))
1035
+ },
1036
+ impact: {
1037
+ filesReorganized: bundleSuggestions.stats?.totalFiles || 0,
1038
+ newBundles: Object.keys(bundleSuggestions.recommended).length,
1039
+ recommendation: 'Review and approve bundle organization before applying'
1040
+ }
1041
+ };
1042
+ }
1043
+
1044
+ async createSuggestedBundles(bundleSuggestions) {
1045
+ if (!bundleSuggestions || !bundleSuggestions.recommended) {
1046
+ return {
1047
+ status: 'error',
1048
+ message: 'No bundle suggestions available'
1049
+ };
1050
+ }
1051
+
1052
+ const results = {
1053
+ status: 'success',
1054
+ created: [],
1055
+ failed: [],
1056
+ total: Object.keys(bundleSuggestions.recommended).length
1057
+ };
1058
+
1059
+ // Create each suggested bundle
1060
+ for (const [bundleName, bundleConfig] of Object.entries(bundleSuggestions.recommended)) {
1061
+ try {
1062
+ // Use the agent tools to create bundle via MCP
1063
+ const createResult = await this.createBundleViaMCP(bundleName, bundleConfig.patterns, bundleConfig.purpose);
1064
+
1065
+ if (createResult.success) {
1066
+ results.created.push({
1067
+ name: bundleName,
1068
+ patterns: bundleConfig.patterns,
1069
+ files: bundleConfig.files?.length || 0,
1070
+ purpose: bundleConfig.purpose
1071
+ });
1072
+ } else {
1073
+ results.failed.push({
1074
+ name: bundleName,
1075
+ error: createResult.error || 'Unknown error'
1076
+ });
1077
+ }
1078
+ } catch (error) {
1079
+ results.failed.push({
1080
+ name: bundleName,
1081
+ error: error.message
1082
+ });
1083
+ }
1084
+ }
1085
+
1086
+ // Update status based on results
1087
+ if (results.failed.length > 0) {
1088
+ results.status = results.created.length > 0 ? 'partial' : 'failed';
1089
+ }
1090
+
1091
+ results.summary = `Created ${results.created.length}/${results.total} bundles successfully`;
1092
+
1093
+ if (results.failed.length > 0) {
1094
+ results.summary += `. Failed to create ${results.failed.length} bundles.`;
1095
+ }
1096
+
1097
+ return results;
1098
+ }
1099
+
1100
+ async createBundleViaMCP(name, patterns, description) {
1101
+ try {
1102
+ // Check if bundle already exists
1103
+ const existingBundles = await this.analyzeBundles('all');
1104
+ if (existingBundles.some(b => b.name === name)) {
1105
+ return {
1106
+ success: false,
1107
+ error: `Bundle '${name}' already exists`
1108
+ };
1109
+ }
1110
+
1111
+ // Don't allow creating or overwriting master bundle
1112
+ if (name === 'master') {
1113
+ return {
1114
+ success: false,
1115
+ error: 'Cannot create or overwrite master bundle'
1116
+ };
1117
+ }
1118
+
1119
+ // Use the existing bundle creation functionality through the server
1120
+ // This simulates what the MCP create_bundle tool does
1121
+ const { join } = await import('path');
1122
+ const { existsSync, readFileSync, writeFileSync } = await import('fs');
1123
+
1124
+ const configPath = join(this.cntxServer.CNTX_DIR, 'config.json');
1125
+ let config = { bundles: {} };
1126
+
1127
+ if (existsSync(configPath)) {
1128
+ config = JSON.parse(readFileSync(configPath, 'utf8'));
1129
+ }
1130
+
1131
+ // Add new bundle
1132
+ config.bundles[name] = patterns;
1133
+
1134
+ // Save config
1135
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
1136
+
1137
+ // Reload server config and regenerate bundles
1138
+ this.cntxServer.loadConfig();
1139
+ this.cntxServer.generateAllBundles();
1140
+
1141
+ return {
1142
+ success: true,
1143
+ bundle: {
1144
+ name,
1145
+ patterns,
1146
+ description,
1147
+ created: new Date().toISOString()
1148
+ }
1149
+ };
1150
+ } catch (error) {
1151
+ return {
1152
+ success: false,
1153
+ error: error.message
1154
+ };
1155
+ }
1156
+ }
1157
+
1158
+ async analyzeOptimizationOpportunities() {
1159
+ const bundles = await this.analyzeBundles('all');
1160
+ const analysis = await this.tools.getSemanticAnalysis({ maxChunks: 50 });
1161
+
1162
+ const opportunities = [];
1163
+
1164
+ // Check for oversized bundles
1165
+ bundles.forEach(bundle => {
1166
+ if (bundle.fileCount > 50) {
1167
+ opportunities.push({
1168
+ type: 'split',
1169
+ bundle: bundle.name,
1170
+ issue: `Large bundle with ${bundle.fileCount} files`,
1171
+ suggestion: 'Consider splitting by functionality'
1172
+ });
1173
+ }
1174
+ });
1175
+
1176
+ // Check for undersized bundles
1177
+ bundles.forEach(bundle => {
1178
+ if (bundle.fileCount < 3 && bundle.name !== 'master') {
1179
+ opportunities.push({
1180
+ type: 'merge',
1181
+ bundle: bundle.name,
1182
+ issue: `Small bundle with only ${bundle.fileCount} files`,
1183
+ suggestion: 'Consider merging with related bundle'
1184
+ });
1185
+ }
1186
+ });
1187
+
1188
+ // Check for misaligned purposes
1189
+ if (analysis.chunks) {
1190
+ const misaligned = this.findMisalignedFiles(bundles, analysis.chunks);
1191
+ misaligned.forEach(item => {
1192
+ opportunities.push({
1193
+ type: 'realign',
1194
+ file: item.file,
1195
+ issue: `File purpose '${item.purpose}' doesn't match bundle '${item.currentBundle}'`,
1196
+ suggestion: `Consider moving to '${item.suggestedBundle}' bundle`
1197
+ });
1198
+ });
1199
+ }
1200
+
1201
+ return opportunities;
1202
+ }
1203
+
1204
+ async generateOptimizationPlan() {
1205
+ const opportunities = await this.analyzeOptimizationOpportunities();
1206
+
1207
+ const plan = {
1208
+ priority_1: opportunities.filter(o => o.type === 'split'),
1209
+ priority_2: opportunities.filter(o => o.type === 'realign'),
1210
+ priority_3: opportunities.filter(o => o.type === 'merge'),
1211
+ summary: `Found ${opportunities.length} optimization opportunities`
1212
+ };
1213
+
1214
+ return plan;
1215
+ }
1216
+
1217
+ async auditCurrentOrganization() {
1218
+ const bundles = await this.analyzeBundles('all');
1219
+ const analysis = await this.tools.getSemanticAnalysis({ maxChunks: 50 });
1220
+
1221
+ return {
1222
+ bundleHealth: this.assessBundleHealth(bundles),
1223
+ coverage: this.calculateBundleCoverage(bundles),
1224
+ alignment: this.assessSemanticAlignment(bundles, analysis),
1225
+ recommendations: this.generateAuditRecommendations(bundles, analysis)
1226
+ };
1227
+ }
1228
+
1229
+ async identifyOrganizationalIssues() {
1230
+ const bundles = await this.analyzeBundles('all');
1231
+ const issues = [];
1232
+
1233
+ // Check for naming inconsistencies
1234
+ const namingPatterns = this.analyzeNamingPatterns(bundles);
1235
+ if (namingPatterns.inconsistent) {
1236
+ issues.push({
1237
+ type: 'naming',
1238
+ severity: 'medium',
1239
+ description: 'Inconsistent bundle naming patterns detected'
1240
+ });
1241
+ }
1242
+
1243
+ // Check for duplicate patterns
1244
+ const duplicates = this.findDuplicatePatterns(bundles);
1245
+ duplicates.forEach(dup => {
1246
+ issues.push({
1247
+ type: 'duplication',
1248
+ severity: 'high',
1249
+ description: `Pattern '${dup.pattern}' used in multiple bundles: ${dup.bundles.join(', ')}`
1250
+ });
1251
+ });
1252
+
1253
+ return issues;
1254
+ }
1255
+
1256
+ generateNextSteps(organization, currentActivity) {
1257
+ const state = organization.projectState;
1258
+ const steps = [];
1259
+
1260
+ switch (currentActivity) {
1261
+ case 'detect':
1262
+ if (state.maturityLevel === 'fresh') {
1263
+ steps.push('Run activity "analyze" to generate semantic analysis');
1264
+ } else if (state.maturityLevel === 'analyzed') {
1265
+ steps.push('Run activity "bundle" to create intelligent bundles');
1266
+ }
1267
+ break;
1268
+
1269
+ case 'analyze':
1270
+ if (organization.semanticAnalysis?.readyForBundling) {
1271
+ steps.push('Run activity "bundle" to create logical bundle organization');
1272
+ }
1273
+ break;
1274
+
1275
+ case 'bundle':
1276
+ if (organization.bundleSuggestions?.recommended) {
1277
+ steps.push('Review suggested bundles and run activity "create" to implement them');
1278
+ steps.push('After creation, run activity "validate" to verify organization');
1279
+ }
1280
+ break;
1281
+
1282
+ case 'create':
1283
+ if (organization.creation?.status === 'success') {
1284
+ steps.push('Bundle creation completed successfully! Run activity "validate" to verify organization');
1285
+ } else if (organization.creation?.failed?.length > 0) {
1286
+ steps.push('Some bundles failed to create. Review errors and retry if needed');
1287
+ }
1288
+ break;
1289
+
1290
+ case 'optimize':
1291
+ if (organization.optimizations?.length > 0) {
1292
+ steps.push('Review optimization opportunities and implement highest priority items');
1293
+ }
1294
+ break;
1295
+ }
1296
+
1297
+ if (steps.length === 0) {
1298
+ steps.push('Project organization is up to date - consider periodic audits');
1299
+ }
1300
+
1301
+ return steps;
1302
+ }
1303
+
1304
+ // Additional helper methods
1305
+
1306
+ purposeToBundleName(purpose) {
1307
+ const purposeMap = {
1308
+ 'React component': 'ui-components',
1309
+ 'API endpoint': 'api-endpoints',
1310
+ 'Utility function': 'utilities',
1311
+ 'Configuration': 'configuration',
1312
+ 'Type definition': 'types',
1313
+ 'Test': 'tests'
1314
+ };
1315
+
1316
+ return purposeMap[purpose] || purpose.toLowerCase().replace(/\s+/g, '-');
1317
+ }
1318
+
1319
+ addStandardBundles(suggestions, chunks) {
1320
+ // Add configuration bundle
1321
+ suggestions.recommended.configuration = {
1322
+ patterns: ['*.config.*', 'package.json', 'tsconfig*.json', '.env*'],
1323
+ chunkCount: 0,
1324
+ files: [],
1325
+ purpose: 'Build and environment configuration'
1326
+ };
1327
+
1328
+ // Add tests bundle if test files exist
1329
+ const testFiles = chunks.filter(c => c.filePath && (c.filePath.includes('test') || c.filePath.includes('spec')));
1330
+ if (testFiles.length > 0) {
1331
+ suggestions.recommended.tests = {
1332
+ patterns: ['**/*.test.*', '**/*.spec.*', '**/__tests__/**'],
1333
+ chunkCount: testFiles.length,
1334
+ files: testFiles.map(c => c.filePath),
1335
+ purpose: 'Test files and test utilities'
1336
+ };
1337
+ }
1338
+ }
1339
+
1340
+ calculateBundleCoverage(bundles) {
1341
+ const totalFiles = bundles.reduce((sum, b) => sum + b.fileCount, 0);
1342
+ const masterBundle = bundles.find(b => b.name === 'master');
1343
+
1344
+ if (masterBundle && bundles.length === 1) {
1345
+ return { coverage: 100, organized: false, recommendation: 'Create specific bundles for better organization' };
1346
+ }
1347
+
1348
+ return { coverage: 100, organized: true, recommendation: 'Bundle organization looks good' };
1349
+ }
1350
+
1351
+ assessBundleHealth(bundles) {
1352
+ const health = {
1353
+ score: 0,
1354
+ issues: [],
1355
+ strengths: []
1356
+ };
1357
+
1358
+ // Check bundle count
1359
+ if (bundles.length === 1) {
1360
+ health.issues.push('Only master bundle - needs organization');
1361
+ health.score += 20;
1362
+ } else if (bundles.length > 1 && bundles.length <= 8) {
1363
+ health.strengths.push('Good bundle organization');
1364
+ health.score += 80;
1365
+ } else {
1366
+ health.issues.push('Too many bundles - consider consolidation');
1367
+ health.score += 60;
1368
+ }
1369
+
1370
+ return health;
1371
+ }
1372
+
1373
+ assessDefaultComplexity(bundles) {
1374
+ const totalFiles = bundles.reduce((sum, b) => sum + b.fileCount, 0);
1375
+
1376
+ if (totalFiles < 20) return { level: 'low', score: 1 };
1377
+ if (totalFiles < 100) return { level: 'medium', score: 2 };
1378
+ return { level: 'high', score: 3 };
1379
+ }
1380
+
1381
+ generateMaturityRecommendations(bundles, analysis) {
1382
+ const recommendations = [];
1383
+
1384
+ if (bundles.length === 1) {
1385
+ recommendations.push('Create semantic bundles for better code organization');
1386
+ }
1387
+
1388
+ if (!analysis || !analysis.chunks) {
1389
+ recommendations.push('Generate semantic analysis for intelligent bundling');
1390
+ }
1391
+
1392
+ return recommendations;
1393
+ }
1394
+
1395
+ findMisalignedFiles(bundles, chunks) {
1396
+ // Simplified implementation - would need more sophisticated logic
1397
+ return [];
1398
+ }
1399
+
1400
+ analyzeNamingPatterns(bundles) {
1401
+ const patterns = bundles.map(b => b.name);
1402
+ const hasConsistentNaming = patterns.every(name =>
1403
+ name.includes('-') || name.toLowerCase() === name
1404
+ );
1405
+
1406
+ return { inconsistent: !hasConsistentNaming };
1407
+ }
1408
+
1409
+ findDuplicatePatterns(bundles) {
1410
+ const patternMap = new Map();
1411
+
1412
+ bundles.forEach(bundle => {
1413
+ bundle.patterns.forEach(pattern => {
1414
+ if (!patternMap.has(pattern)) {
1415
+ patternMap.set(pattern, []);
1416
+ }
1417
+ patternMap.get(pattern).push(bundle.name);
1418
+ });
1419
+ });
1420
+
1421
+ return Array.from(patternMap.entries())
1422
+ .filter(([pattern, bundleNames]) => bundleNames.length > 1)
1423
+ .map(([pattern, bundleNames]) => ({ pattern, bundles: bundleNames }));
1424
+ }
1425
+
1426
+ async suggestCleanupActions() {
1427
+ return [
1428
+ { action: 'Remove unused bundle patterns', impact: 'low', effort: 'low' },
1429
+ { action: 'Consolidate similar bundles', impact: 'medium', effort: 'medium' }
1430
+ ];
1431
+ }
1432
+
1433
+ async assessCleanupImpact() {
1434
+ return {
1435
+ estimatedTimeReduction: '10-15%',
1436
+ maintainabilityImprovement: 'medium',
1437
+ riskLevel: 'low'
1438
+ };
1439
+ }
1440
+
1441
+ async validateCurrentOrganization() {
1442
+ const bundles = await this.analyzeBundles('all');
1443
+ return {
1444
+ valid: bundles.length > 1,
1445
+ score: bundles.length === 1 ? 30 : 85,
1446
+ issues: bundles.length === 1 ? ['Only master bundle exists'] : []
1447
+ };
1448
+ }
1449
+
1450
+ async calculateOrganizationHealth() {
1451
+ const bundles = await this.analyzeBundles('all');
1452
+ const health = this.assessBundleHealth(bundles);
1453
+
1454
+ return {
1455
+ overall: health.score > 70 ? 'good' : health.score > 40 ? 'fair' : 'poor',
1456
+ score: health.score,
1457
+ recommendations: health.issues
1458
+ };
1459
+ }
1460
+
1461
+ assessSemanticAlignment(bundles, analysis) {
1462
+ // Simplified - would analyze if files are in semantically appropriate bundles
1463
+ return {
1464
+ aligned: bundles.length > 1,
1465
+ score: bundles.length > 1 ? 80 : 30
1466
+ };
1467
+ }
1468
+
1469
+ generateAuditRecommendations(bundles, analysis) {
1470
+ const recommendations = [];
1471
+
1472
+ if (bundles.length === 1) {
1473
+ recommendations.push('Create semantic bundles for better organization');
1474
+ }
1475
+
1476
+ return recommendations;
1477
+ }
1478
+ }
1479
+
1480
+ export default AgentRuntime;