cntx-ui 2.0.12 → 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 (45) 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/function-level-chunker.js +406 -0
  9. package/lib/heuristics-manager.js +425 -0
  10. package/lib/mcp-server.js +1054 -1
  11. package/lib/semantic-splitter.js +588 -0
  12. package/lib/simple-vector-store.js +329 -0
  13. package/lib/treesitter-semantic-chunker.js +1485 -0
  14. package/lib/websocket-manager.js +470 -0
  15. package/package.json +14 -3
  16. package/server.js +673 -1704
  17. package/templates/activities/README.md +67 -0
  18. package/templates/activities/activities/create-project-bundles/README.md +83 -0
  19. package/templates/activities/activities/create-project-bundles/notes.md +102 -0
  20. package/templates/activities/activities/create-project-bundles/progress.md +63 -0
  21. package/templates/activities/activities/create-project-bundles/tasks.md +39 -0
  22. package/templates/activities/activities.json +219 -0
  23. package/templates/activities/lib/.markdownlint.jsonc +18 -0
  24. package/templates/activities/lib/create-activity.mdc +63 -0
  25. package/templates/activities/lib/generate-tasks.mdc +64 -0
  26. package/templates/activities/lib/process-task-list.mdc +52 -0
  27. package/templates/agent-config.yaml +78 -0
  28. package/templates/agent-instructions.md +218 -0
  29. package/templates/agent-rules/capabilities/activities-system.md +147 -0
  30. package/templates/agent-rules/capabilities/bundle-system.md +131 -0
  31. package/templates/agent-rules/capabilities/vector-search.md +135 -0
  32. package/templates/agent-rules/core/codebase-navigation.md +91 -0
  33. package/templates/agent-rules/core/performance-hierarchy.md +48 -0
  34. package/templates/agent-rules/core/response-formatting.md +120 -0
  35. package/templates/agent-rules/project-specific/architecture.md +145 -0
  36. package/templates/config.json +76 -0
  37. package/templates/hidden-files.json +14 -0
  38. package/web/dist/assets/heuristics-manager-browser-DfonOP5I.js +1 -0
  39. package/web/dist/assets/index-dF3qg-y_.js +2486 -0
  40. package/web/dist/assets/index-h5FGSg_P.css +1 -0
  41. package/web/dist/cntx-ui.svg +18 -0
  42. package/web/dist/index.html +25 -8
  43. package/web/dist/assets/index-8Kli5657.js +0 -541
  44. package/web/dist/assets/index-C-Ldi33E.css +0 -1
  45. package/web/dist/vite.svg +0 -1
@@ -0,0 +1,329 @@
1
+ /**
2
+ * Simple In-Memory Vector Store for cntx-ui
3
+ * Free, local embeddings without external dependencies
4
+ */
5
+
6
+ import { pipeline } from '@xenova/transformers'
7
+
8
+ class SimpleVectorStore {
9
+ constructor(options = {}) {
10
+ this.modelName = options.modelName || 'Xenova/all-MiniLM-L6-v2'
11
+ this.collectionName = options.collectionName || 'code-chunks'
12
+ this.embedder = null
13
+ this.vectors = new Map() // id -> { embedding, metadata }
14
+ }
15
+
16
+ /**
17
+ * Initialize the embedding model
18
+ */
19
+ async initialize() {
20
+ console.log('🔧 Initializing simple vector store...')
21
+
22
+ // Load the embedding model (downloads on first run)
23
+ this.embedder = await pipeline('feature-extraction', this.modelName)
24
+ console.log('✅ Embedding model loaded')
25
+ }
26
+
27
+ /**
28
+ * Alias for initialize() to match server expectations
29
+ */
30
+ async init() {
31
+ return this.initialize()
32
+ }
33
+
34
+ /**
35
+ * Generate embedding for a single text
36
+ */
37
+ async generateEmbedding(text) {
38
+ if (!this.embedder) {
39
+ await this.initialize()
40
+ }
41
+
42
+ try {
43
+ const result = await this.embedder(text, {
44
+ pooling: 'mean',
45
+ normalize: true
46
+ })
47
+
48
+ return Array.from(result.data)
49
+ } catch (error) {
50
+ console.error('❌ Failed to generate embedding:', error.message)
51
+ throw error
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Create embeddings for semantic chunks
57
+ */
58
+ async createEmbeddings(chunks) {
59
+ if (!this.embedder) {
60
+ await this.initialize()
61
+ }
62
+
63
+ console.log(`🔍 Creating embeddings for ${chunks.length} chunks...`)
64
+
65
+ const embeddings = []
66
+ const batchSize = 10 // Process in batches to avoid memory issues
67
+
68
+ for (let i = 0; i < chunks.length; i += batchSize) {
69
+ const batch = chunks.slice(i, i + batchSize)
70
+ console.log(`📦 Processing batch ${Math.floor(i / batchSize) + 1}/${Math.ceil(chunks.length / batchSize)}`)
71
+
72
+ for (const chunk of batch) {
73
+ try {
74
+ // Create searchable text from chunk data
75
+ const searchableText = this.createSearchableText(chunk)
76
+
77
+ // Generate embedding
78
+ const result = await this.embedder(searchableText, {
79
+ pooling: 'mean',
80
+ normalize: true
81
+ })
82
+
83
+ // Convert to array format
84
+ const embedding = Array.from(result.data)
85
+
86
+ embeddings.push({
87
+ id: chunk.name && chunk.filePath
88
+ ? `${chunk.name}:${chunk.filePath}:${chunk.startLine || ''}`
89
+ : `chunk-${i}`,
90
+ embedding: embedding,
91
+ metadata: {
92
+ content: chunk.code || '',
93
+ semanticType: chunk.semanticType || '',
94
+ businessDomain: chunk.businessDomain || [],
95
+ technicalPatterns: chunk.technicalPatterns || [],
96
+ purpose: chunk.purpose || '',
97
+ files: chunk.files || [],
98
+ size: chunk.size || 0,
99
+ complexity: chunk.complexity || 0
100
+ }
101
+ })
102
+ } catch (error) {
103
+ console.warn(`⚠️ Failed to embed chunk ${chunk.name}:`, error.message)
104
+ }
105
+ }
106
+ }
107
+
108
+ console.log(`✅ Created ${embeddings.length} embeddings`)
109
+ return embeddings
110
+ }
111
+
112
+ /**
113
+ * Create searchable text from semantic chunk
114
+ */
115
+ createSearchableText(chunk) {
116
+ const parts = []
117
+
118
+ // Add code content if available
119
+ if (chunk.code) {
120
+ parts.push(chunk.code)
121
+ }
122
+
123
+ // Add semantic type
124
+ if (chunk.semanticType) {
125
+ parts.push(`Type: ${chunk.semanticType}`)
126
+ }
127
+
128
+ // Add business domains
129
+ if (chunk.businessDomain && chunk.businessDomain.length > 0) {
130
+ parts.push(`Domain: ${chunk.businessDomain.join(', ')}`)
131
+ }
132
+
133
+ // Add technical patterns
134
+ if (chunk.technicalPatterns && chunk.technicalPatterns.length > 0) {
135
+ parts.push(`Patterns: ${chunk.technicalPatterns.join(', ')}`)
136
+ }
137
+
138
+ // Add purpose
139
+ if (chunk.purpose) {
140
+ parts.push(`Purpose: ${chunk.purpose}`)
141
+ }
142
+
143
+ // Add file names for context
144
+ if (chunk.files && chunk.files.length > 0) {
145
+ const fileNames = chunk.files.map(f => f.split('/').pop()).join(', ')
146
+ parts.push(`Files: ${fileNames}`)
147
+ }
148
+
149
+ return parts.join(' | ')
150
+ }
151
+
152
+ /**
153
+ * Store chunks in vector database
154
+ */
155
+ async storeChunks(chunks) {
156
+ const embeddings = await this.createEmbeddings(chunks)
157
+
158
+ if (embeddings.length === 0) {
159
+ console.warn('⚠️ No embeddings created, skipping storage')
160
+ return
161
+ }
162
+
163
+ // Store in memory
164
+ for (const embedding of embeddings) {
165
+ this.vectors.set(embedding.id, {
166
+ embedding: embedding.embedding,
167
+ metadata: embedding.metadata
168
+ })
169
+ }
170
+
171
+ console.log(`✅ Stored ${embeddings.length} chunks in memory vector store`)
172
+ }
173
+
174
+ /**
175
+ * Store chunks that already have embeddings (e.g., from cache)
176
+ */
177
+ async storePrecomputedChunks(chunks) {
178
+ if (!chunks || chunks.length === 0) {
179
+ console.warn('⚠️ No chunks provided for storage')
180
+ return
181
+ }
182
+
183
+ let storedCount = 0
184
+ for (const chunk of chunks) {
185
+ if (chunk.embedding && chunk.embedding.length > 0) {
186
+ this.vectors.set(chunk.id || chunk.name, {
187
+ embedding: chunk.embedding,
188
+ metadata: chunk.metadata || {
189
+ content: chunk.code || chunk.content || '',
190
+ semanticType: chunk.semanticType || 'unknown',
191
+ businessDomain: chunk.businessDomain || [],
192
+ technicalPatterns: chunk.technicalPatterns || [],
193
+ purpose: chunk.purpose || '',
194
+ files: chunk.files || [chunk.filePath].filter(Boolean),
195
+ size: chunk.size || 0,
196
+ complexity: chunk.complexity || 0
197
+ }
198
+ })
199
+ storedCount++
200
+ }
201
+ }
202
+
203
+ console.log(`✅ Stored ${storedCount} precomputed chunks in memory vector store`)
204
+ return storedCount
205
+ }
206
+
207
+ /**
208
+ * Calculate cosine similarity between two vectors
209
+ */
210
+ cosineSimilarity(vecA, vecB) {
211
+ let dotProduct = 0
212
+ let normA = 0
213
+ let normB = 0
214
+
215
+ for (let i = 0; i < vecA.length; i++) {
216
+ dotProduct += vecA[i] * vecB[i]
217
+ normA += vecA[i] * vecA[i]
218
+ normB += vecB[i] * vecB[i]
219
+ }
220
+
221
+ return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB))
222
+ }
223
+
224
+ /**
225
+ * Find similar code chunks
226
+ */
227
+ async findSimilar(query, options = {}) {
228
+ if (!this.embedder) {
229
+ await this.initialize()
230
+ }
231
+
232
+ const {
233
+ limit = 10,
234
+ minSimilarity = 0.5
235
+ } = options
236
+
237
+ try {
238
+ // Create embedding for the query
239
+ const queryEmbedding = await this.embedder(query, {
240
+ pooling: 'mean',
241
+ normalize: true
242
+ })
243
+
244
+ const queryVector = Array.from(queryEmbedding.data)
245
+
246
+ // Calculate similarities with all stored vectors
247
+ const similarities = []
248
+ for (const [id, vector] of this.vectors) {
249
+ const similarity = this.cosineSimilarity(queryVector, vector.embedding)
250
+ if (similarity >= minSimilarity) {
251
+ similarities.push({
252
+ id: id,
253
+ similarity: similarity,
254
+ metadata: vector.metadata
255
+ })
256
+ }
257
+ }
258
+
259
+ // Sort by similarity and return top results
260
+ return similarities
261
+ .sort((a, b) => b.similarity - a.similarity)
262
+ .slice(0, limit)
263
+ } catch (error) {
264
+ console.error('❌ Search failed:', error)
265
+ return []
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Find chunks by semantic type
271
+ */
272
+ async findByType(semanticType, limit = 10) {
273
+ return this.findSimilar(`Type: ${semanticType}`, {
274
+ limit,
275
+ minSimilarity: 0.7
276
+ })
277
+ }
278
+
279
+ /**
280
+ * Find chunks by business domain
281
+ */
282
+ async findByDomain(domain, limit = 10) {
283
+ return this.findSimilar(`Domain: ${domain}`, {
284
+ limit,
285
+ minSimilarity: 0.6
286
+ })
287
+ }
288
+
289
+ /**
290
+ * Find chunks by technical pattern
291
+ */
292
+ async findByPattern(pattern, limit = 10) {
293
+ return this.findSimilar(`Patterns: ${pattern}`, {
294
+ limit,
295
+ minSimilarity: 0.6
296
+ })
297
+ }
298
+
299
+ /**
300
+ * Get collection statistics
301
+ */
302
+ async getStats() {
303
+ return {
304
+ totalChunks: this.vectors.size,
305
+ collectionName: this.collectionName,
306
+ modelName: this.modelName
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Clear all stored chunks
312
+ */
313
+ async clear() {
314
+ this.vectors.clear()
315
+ console.log('✅ Cleared in-memory vector store')
316
+ }
317
+
318
+ /**
319
+ * Add/update a single chunk (legacy compatibility)
320
+ */
321
+ async upsert(id, embedding, metadata) {
322
+ this.vectors.set(id, {
323
+ embedding: embedding,
324
+ metadata: metadata
325
+ })
326
+ }
327
+ }
328
+
329
+ export default SimpleVectorStore