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.
- package/bin/cntx-ui.js +137 -55
- package/lib/agent-runtime.js +1480 -0
- package/lib/agent-tools.js +368 -0
- package/lib/api-router.js +978 -0
- package/lib/bundle-manager.js +471 -0
- package/lib/configuration-manager.js +725 -0
- package/lib/file-system-manager.js +472 -0
- package/lib/function-level-chunker.js +406 -0
- package/lib/heuristics-manager.js +425 -0
- package/lib/mcp-server.js +1054 -1
- package/lib/semantic-splitter.js +588 -0
- package/lib/simple-vector-store.js +329 -0
- package/lib/treesitter-semantic-chunker.js +1485 -0
- package/lib/websocket-manager.js +470 -0
- package/package.json +14 -3
- package/server.js +673 -1704
- package/templates/activities/README.md +67 -0
- package/templates/activities/activities/create-project-bundles/README.md +83 -0
- package/templates/activities/activities/create-project-bundles/notes.md +102 -0
- package/templates/activities/activities/create-project-bundles/progress.md +63 -0
- package/templates/activities/activities/create-project-bundles/tasks.md +39 -0
- package/templates/activities/activities.json +219 -0
- package/templates/activities/lib/.markdownlint.jsonc +18 -0
- package/templates/activities/lib/create-activity.mdc +63 -0
- package/templates/activities/lib/generate-tasks.mdc +64 -0
- package/templates/activities/lib/process-task-list.mdc +52 -0
- package/templates/agent-config.yaml +78 -0
- package/templates/agent-instructions.md +218 -0
- package/templates/agent-rules/capabilities/activities-system.md +147 -0
- package/templates/agent-rules/capabilities/bundle-system.md +131 -0
- package/templates/agent-rules/capabilities/vector-search.md +135 -0
- package/templates/agent-rules/core/codebase-navigation.md +91 -0
- package/templates/agent-rules/core/performance-hierarchy.md +48 -0
- package/templates/agent-rules/core/response-formatting.md +120 -0
- package/templates/agent-rules/project-specific/architecture.md +145 -0
- package/templates/config.json +76 -0
- package/templates/hidden-files.json +14 -0
- package/web/dist/assets/heuristics-manager-browser-DfonOP5I.js +1 -0
- package/web/dist/assets/index-dF3qg-y_.js +2486 -0
- package/web/dist/assets/index-h5FGSg_P.css +1 -0
- package/web/dist/cntx-ui.svg +18 -0
- package/web/dist/index.html +25 -8
- package/web/dist/assets/index-8Kli5657.js +0 -541
- package/web/dist/assets/index-C-Ldi33E.css +0 -1
- 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
|