cntx-ui 2.0.13 → 3.0.0
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/README.md +51 -339
- package/VISION.md +110 -0
- package/bin/cntx-ui-mcp.sh +3 -0
- package/bin/cntx-ui.js +138 -55
- package/lib/agent-runtime.js +301 -0
- package/lib/agent-tools.js +370 -0
- package/lib/api-router.js +1161 -0
- package/lib/bundle-manager.js +236 -0
- package/lib/configuration-manager.js +760 -0
- package/lib/database-manager.js +397 -0
- package/lib/file-system-manager.js +489 -0
- package/lib/heuristics-manager.js +527 -0
- package/lib/mcp-server.js +1125 -2
- package/lib/semantic-splitter.js +225 -491
- package/lib/simple-vector-store.js +98 -0
- package/lib/websocket-manager.js +470 -0
- package/package.json +19 -25
- package/server.js +742 -1935
- package/templates/TOOLS.md +41 -0
- package/templates/activities/README.md +67 -0
- package/templates/activities/activities/create-project-bundles/README.md +84 -0
- package/templates/activities/activities/create-project-bundles/notes.md +98 -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 +65 -0
- package/templates/agent-instructions.md +234 -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/index-B2OdTzzI.css +1 -0
- package/web/dist/assets/index-D0tBsKiR.js +2016 -0
- package/web/dist/cntx-ui.svg +18 -0
- package/web/dist/index.html +25 -8
- package/lib/semantic-integration.js +0 -441
- package/mcp-config-example.json +0 -9
- package/web/dist/assets/index-Ci1Q-YrQ.js +0 -611
- package/web/dist/assets/index-IUp4q_fr.css +0 -1
- package/web/dist/vite.svg +0 -21
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heuristics Manager - Centralized service for loading and applying heuristics
|
|
3
|
+
* Manages configuration-based code categorization logic
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readFileSync, existsSync, watchFile } from 'fs'
|
|
7
|
+
import { join } from 'path'
|
|
8
|
+
|
|
9
|
+
export default class HeuristicsManager {
|
|
10
|
+
constructor(configPath = './heuristics-config.json') {
|
|
11
|
+
this.configPath = configPath
|
|
12
|
+
this.config = null
|
|
13
|
+
this.cache = new Map()
|
|
14
|
+
this.isWatching = false
|
|
15
|
+
this.lastLoaded = null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Load heuristics configuration from file
|
|
20
|
+
*/
|
|
21
|
+
loadConfig() {
|
|
22
|
+
try {
|
|
23
|
+
if (!existsSync(this.configPath)) {
|
|
24
|
+
console.warn(`Heuristics config not found at ${this.configPath}, using fallback`)
|
|
25
|
+
this.config = this.getFallbackConfig()
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const configContent = readFileSync(this.configPath, 'utf8')
|
|
30
|
+
const newConfig = JSON.parse(configContent)
|
|
31
|
+
|
|
32
|
+
// Validate config structure
|
|
33
|
+
this.validateConfig(newConfig)
|
|
34
|
+
|
|
35
|
+
this.config = newConfig
|
|
36
|
+
this.lastLoaded = Date.now()
|
|
37
|
+
this.cache.clear() // Clear cache when config changes
|
|
38
|
+
|
|
39
|
+
// Set up file watching if not already watching
|
|
40
|
+
if (!this.isWatching) {
|
|
41
|
+
this.setupFileWatcher()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
console.log('✅ Heuristics configuration loaded successfully')
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error('❌ Failed to load heuristics config:', error.message)
|
|
47
|
+
console.log('📦 Falling back to hardcoded heuristics')
|
|
48
|
+
this.config = this.getFallbackConfig()
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Validate heuristics configuration structure
|
|
54
|
+
*/
|
|
55
|
+
validateConfig(config) {
|
|
56
|
+
const required = ['purposeHeuristics', 'bundleHeuristics', 'semanticTypeMapping']
|
|
57
|
+
|
|
58
|
+
for (const field of required) {
|
|
59
|
+
if (!config[field]) {
|
|
60
|
+
throw new Error(`Missing required field: ${field}`)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Validate purpose heuristics structure
|
|
65
|
+
if (!config.purposeHeuristics.patterns || !config.purposeHeuristics.fallback) {
|
|
66
|
+
throw new Error('Invalid purposeHeuristics structure')
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Validate bundle heuristics structure
|
|
70
|
+
if (!config.bundleHeuristics.patterns || !config.bundleHeuristics.fallback) {
|
|
71
|
+
throw new Error('Invalid bundleHeuristics structure')
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Set up file watcher for config changes
|
|
77
|
+
*/
|
|
78
|
+
setupFileWatcher() {
|
|
79
|
+
if (!existsSync(this.configPath)) return
|
|
80
|
+
|
|
81
|
+
watchFile(this.configPath, (curr, prev) => {
|
|
82
|
+
if (curr.mtime !== prev.mtime) {
|
|
83
|
+
console.log('📝 Heuristics config file changed, reloading...')
|
|
84
|
+
this.loadConfig()
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
this.isWatching = true
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get configuration, loading if necessary
|
|
93
|
+
*/
|
|
94
|
+
getConfig() {
|
|
95
|
+
if (!this.config) {
|
|
96
|
+
this.loadConfig()
|
|
97
|
+
}
|
|
98
|
+
return this.config
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Determine function purpose using configured heuristics
|
|
103
|
+
*/
|
|
104
|
+
determinePurpose(func) {
|
|
105
|
+
const config = this.getConfig();
|
|
106
|
+
const name = func.name.toLowerCase();
|
|
107
|
+
const pathParts = func.pathParts || [];
|
|
108
|
+
|
|
109
|
+
// console.log(`🔍 Determining purpose for: ${func.name} in ${pathParts.join('/')}`);
|
|
110
|
+
|
|
111
|
+
// Check each purpose pattern
|
|
112
|
+
for (const [patternName, pattern] of Object.entries(config.purposeHeuristics.patterns)) {
|
|
113
|
+
if (this.evaluateConditions(pattern.conditions, { func, name, pathParts })) {
|
|
114
|
+
// console.log(` ✅ Matched pattern: ${patternName} -> ${pattern.purpose}`);
|
|
115
|
+
return pattern.purpose;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Return fallback
|
|
120
|
+
return config.purposeHeuristics.fallback.purpose;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Infer business domains (e.g. auth, editing, file-mgmt)
|
|
125
|
+
*/
|
|
126
|
+
inferBusinessDomains(func) {
|
|
127
|
+
const domains = new Set();
|
|
128
|
+
const name = func.name.toLowerCase();
|
|
129
|
+
const path = (func.pathParts || []).join('/').toLowerCase();
|
|
130
|
+
const imports = func.includes?.imports || [];
|
|
131
|
+
|
|
132
|
+
// Path-based domains
|
|
133
|
+
if (path.includes('auth')) domains.add('authentication');
|
|
134
|
+
if (path.includes('component') || path.includes('ui')) domains.add('ui-layer');
|
|
135
|
+
if (path.includes('service') || path.includes('api')) domains.add('api-integration');
|
|
136
|
+
if (path.includes('test') || path.includes('spec')) domains.add('testing');
|
|
137
|
+
|
|
138
|
+
// Import-based domains
|
|
139
|
+
if (imports.some(i => i.includes('tauri'))) domains.add('desktop-runtime');
|
|
140
|
+
if (imports.some(i => i.includes('tiptap') || i.includes('prosemirror'))) domains.add('text-editing');
|
|
141
|
+
if (imports.some(i => i.includes('react'))) domains.add('frontend-ui');
|
|
142
|
+
|
|
143
|
+
// Name-based domains
|
|
144
|
+
if (/file|save|export|read|write/i.test(name)) domains.add('file-management');
|
|
145
|
+
if (/login|user|session/i.test(name)) domains.add('authentication');
|
|
146
|
+
|
|
147
|
+
return Array.from(domains);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Infer technical patterns (e.g. hooks, async-io, event-handlers)
|
|
152
|
+
*/
|
|
153
|
+
inferTechnicalPatterns(func) {
|
|
154
|
+
const patterns = new Set();
|
|
155
|
+
const name = func.name.toLowerCase();
|
|
156
|
+
const code = func.code || '';
|
|
157
|
+
|
|
158
|
+
if (name.startsWith('use')) patterns.add('react-hooks');
|
|
159
|
+
if (code.includes('async') || code.includes('await')) patterns.add('async-io');
|
|
160
|
+
if (code.includes('on(') || code.includes('addListener') || name.startsWith('handle')) patterns.add('event-driven');
|
|
161
|
+
if (code.includes('new ') || code.includes('class ')) patterns.add('object-oriented');
|
|
162
|
+
if (func.isExported) patterns.add('public-api');
|
|
163
|
+
|
|
164
|
+
return Array.from(patterns);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Suggest bundles for file using configured heuristics
|
|
169
|
+
*/
|
|
170
|
+
suggestBundlesForFile(filePath) {
|
|
171
|
+
const config = this.getConfig()
|
|
172
|
+
const fileName = filePath.toLowerCase()
|
|
173
|
+
const pathParts = fileName.split('/')
|
|
174
|
+
const suggestions = []
|
|
175
|
+
|
|
176
|
+
// Check each bundle pattern
|
|
177
|
+
for (const [patternName, pattern] of Object.entries(config.bundleHeuristics.patterns)) {
|
|
178
|
+
if (this.evaluateConditions(pattern.conditions, { fileName, filePath, pathParts })) {
|
|
179
|
+
suggestions.push(pattern.bundle)
|
|
180
|
+
|
|
181
|
+
// Check sub-patterns
|
|
182
|
+
if (pattern.subPatterns) {
|
|
183
|
+
for (const [subName, subPattern] of Object.entries(pattern.subPatterns)) {
|
|
184
|
+
if (this.evaluateConditions(subPattern.conditions, { fileName, filePath, pathParts })) {
|
|
185
|
+
suggestions.push(subPattern.bundle)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Apply fallback logic if no suggestions
|
|
193
|
+
if (suggestions.length === 0) {
|
|
194
|
+
const fallback = config.bundleHeuristics.fallback
|
|
195
|
+
|
|
196
|
+
if (fallback.webFallback && this.evaluateConditions(fallback.webFallback.conditions, { fileName, filePath, pathParts })) {
|
|
197
|
+
suggestions.push(fallback.webFallback.bundle)
|
|
198
|
+
} else if (fallback.defaultFallback) {
|
|
199
|
+
suggestions.push(...fallback.defaultFallback.bundles)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return [...new Set(suggestions)] // Remove duplicates
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Get semantic type cluster mapping
|
|
208
|
+
*/
|
|
209
|
+
getSemanticTypeMapping() {
|
|
210
|
+
const config = this.getConfig()
|
|
211
|
+
const mapping = {}
|
|
212
|
+
|
|
213
|
+
for (const [clusterName, cluster] of Object.entries(config.semanticTypeMapping.clusters)) {
|
|
214
|
+
for (const type of cluster.types) {
|
|
215
|
+
mapping[type] = cluster.clusterId
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return mapping
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Evaluate condition strings against context
|
|
224
|
+
*/
|
|
225
|
+
evaluateConditions(conditions, context) {
|
|
226
|
+
if (!Array.isArray(conditions)) {
|
|
227
|
+
conditions = [conditions]
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// For purpose heuristics, we generally want high precision, so use AND logic
|
|
231
|
+
// if there are multiple conditions
|
|
232
|
+
const needsAndLogic = conditions.length > 1 || this.requiresAndLogic(conditions)
|
|
233
|
+
|
|
234
|
+
if (needsAndLogic) {
|
|
235
|
+
return conditions.every(condition => {
|
|
236
|
+
try {
|
|
237
|
+
return this.evaluateCondition(condition, context)
|
|
238
|
+
} catch (error) {
|
|
239
|
+
console.warn(`Failed to evaluate condition: ${condition}`, error)
|
|
240
|
+
return false
|
|
241
|
+
}
|
|
242
|
+
})
|
|
243
|
+
} else {
|
|
244
|
+
return conditions.some(condition => {
|
|
245
|
+
try {
|
|
246
|
+
return this.evaluateCondition(condition, context)
|
|
247
|
+
} catch (error) {
|
|
248
|
+
console.warn(`Failed to evaluate condition: ${condition}`, error)
|
|
249
|
+
return false
|
|
250
|
+
}
|
|
251
|
+
})
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Determine if conditions require AND logic vs OR logic
|
|
257
|
+
*/
|
|
258
|
+
requiresAndLogic(conditions) {
|
|
259
|
+
// React hook pattern specifically needs AND logic
|
|
260
|
+
if (conditions.length === 2 &&
|
|
261
|
+
conditions.some(c => c.includes('name.startsWith')) &&
|
|
262
|
+
conditions.some(c => c.includes('func.type'))) {
|
|
263
|
+
return true
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Frontend pattern needs AND logic for web + src
|
|
267
|
+
if (conditions.length === 2 &&
|
|
268
|
+
conditions.some(c => c.includes("pathParts.includes('web')")) &&
|
|
269
|
+
conditions.some(c => c.includes("pathParts.includes('src')"))) {
|
|
270
|
+
return true
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Default to OR logic for other patterns
|
|
274
|
+
return false
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Evaluate a single condition
|
|
279
|
+
*/
|
|
280
|
+
evaluateCondition(condition, context) {
|
|
281
|
+
const { func, name, fileName, filePath, pathParts } = context
|
|
282
|
+
|
|
283
|
+
// Handle function type conditions
|
|
284
|
+
if (condition.includes('func.type ===')) {
|
|
285
|
+
const typeMatch = condition.match(/func\.type === ['"]([^'"]+)['"]/)
|
|
286
|
+
if (typeMatch && func) {
|
|
287
|
+
return func.type === typeMatch[1]
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Handle name-based conditions
|
|
292
|
+
if (condition.includes('name.startsWith(')) {
|
|
293
|
+
const prefixMatch = condition.match(/name\.startsWith\(['"]([^'"]+)['"]\)/)
|
|
294
|
+
if (prefixMatch && name) {
|
|
295
|
+
return name.startsWith(prefixMatch[1])
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (condition.includes('name.includes(')) {
|
|
300
|
+
const includesMatch = condition.match(/name\.includes\(['"]([^'"]+)['"]\)/)
|
|
301
|
+
if (includesMatch && name) {
|
|
302
|
+
return name.includes(includesMatch[1])
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Handle fileName conditions
|
|
307
|
+
if (condition.includes('fileName.includes(')) {
|
|
308
|
+
const includesMatch = condition.match(/fileName\.includes\(['"]([^'"]+)['"]\)/)
|
|
309
|
+
if (includesMatch && fileName) {
|
|
310
|
+
return fileName.includes(includesMatch[1])
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (condition.includes('fileName.endsWith(')) {
|
|
315
|
+
const endsWithMatch = condition.match(/fileName\.endsWith\(['"]([^'"]+)['"]\)/)
|
|
316
|
+
if (endsWithMatch && fileName) {
|
|
317
|
+
return fileName.endsWith(endsWithMatch[1])
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Handle pathParts conditions
|
|
322
|
+
if (condition.includes('pathParts.includes(')) {
|
|
323
|
+
const includesMatch = condition.match(/pathParts\.includes\(['"]([^'"]+)['"]\)/)
|
|
324
|
+
if (includesMatch && pathParts) {
|
|
325
|
+
return pathParts.includes(includesMatch[1])
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// New: Check imports in the chunk context
|
|
330
|
+
if (condition.includes('chunk.imports.includes(')) {
|
|
331
|
+
const importMatch = condition.match(/chunk\.imports\.includes\(['"]([^'"]+)['"]\)/)
|
|
332
|
+
if (importMatch && func.includes?.imports) {
|
|
333
|
+
return func.includes.imports.some(imp => imp.includes(importMatch[1]))
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// New: Check for specific naming patterns (case-insensitive)
|
|
338
|
+
if (condition.includes('name.matches(')) {
|
|
339
|
+
const regexMatch = condition.match(/name\.matches\(['"]([^'"]+)['"]\)/)
|
|
340
|
+
if (regexMatch && name) {
|
|
341
|
+
return new RegExp(regexMatch[1], 'i').test(name)
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return false
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Fallback configuration for when config file is unavailable
|
|
350
|
+
*/
|
|
351
|
+
getFallbackConfig() {
|
|
352
|
+
return {
|
|
353
|
+
version: "1.0.0",
|
|
354
|
+
purposeHeuristics: {
|
|
355
|
+
patterns: {
|
|
356
|
+
reactComponent: {
|
|
357
|
+
conditions: ["func.type === 'react_component'"],
|
|
358
|
+
purpose: "React component",
|
|
359
|
+
confidence: 0.95
|
|
360
|
+
},
|
|
361
|
+
reactHook: {
|
|
362
|
+
conditions: ["name.startsWith('use')", "func.type === 'function'"],
|
|
363
|
+
purpose: "React hook",
|
|
364
|
+
confidence: 0.9
|
|
365
|
+
},
|
|
366
|
+
serviceLayer: {
|
|
367
|
+
conditions: ["pathParts.includes('services')"],
|
|
368
|
+
purpose: "Service layer logic",
|
|
369
|
+
confidence: 0.7
|
|
370
|
+
},
|
|
371
|
+
componentLayer: {
|
|
372
|
+
conditions: ["pathParts.includes('components')"],
|
|
373
|
+
purpose: "UI component logic",
|
|
374
|
+
confidence: 0.7
|
|
375
|
+
},
|
|
376
|
+
tauriCommand: {
|
|
377
|
+
conditions: ["name.matches('command')", "chunk.imports.includes('tauri')"],
|
|
378
|
+
purpose: "Tauri backend command",
|
|
379
|
+
confidence: 0.9
|
|
380
|
+
},
|
|
381
|
+
textEditing: {
|
|
382
|
+
conditions: ["chunk.imports.includes('tiptap')", "chunk.imports.includes('prosemirror')"],
|
|
383
|
+
purpose: "Rich text editing logic",
|
|
384
|
+
confidence: 0.95
|
|
385
|
+
},
|
|
386
|
+
fileManagement: {
|
|
387
|
+
conditions: ["pathParts.includes('services')", "name.matches('file|export|save')"],
|
|
388
|
+
purpose: "File system service",
|
|
389
|
+
confidence: 0.85
|
|
390
|
+
},
|
|
391
|
+
uiComponent: {
|
|
392
|
+
conditions: ["pathParts.includes('components')", "name.matches('modal|button|menu|bar')"],
|
|
393
|
+
purpose: "UI component logic",
|
|
394
|
+
confidence: 0.85
|
|
395
|
+
},
|
|
396
|
+
apiHandler: {
|
|
397
|
+
conditions: ["name.includes('api')", "name.includes('endpoint')"],
|
|
398
|
+
purpose: "API handler",
|
|
399
|
+
confidence: 0.85
|
|
400
|
+
},
|
|
401
|
+
dataRetrieval: {
|
|
402
|
+
conditions: ["name.includes('get')", "name.includes('fetch')"],
|
|
403
|
+
purpose: "Data retrieval",
|
|
404
|
+
confidence: 0.8
|
|
405
|
+
},
|
|
406
|
+
dataCreation: {
|
|
407
|
+
conditions: ["name.includes('create')", "name.includes('add')"],
|
|
408
|
+
purpose: "Data creation",
|
|
409
|
+
confidence: 0.8
|
|
410
|
+
},
|
|
411
|
+
dataModification: {
|
|
412
|
+
conditions: ["name.includes('update')", "name.includes('edit')"],
|
|
413
|
+
purpose: "Data modification",
|
|
414
|
+
confidence: 0.8
|
|
415
|
+
},
|
|
416
|
+
dataDeletion: {
|
|
417
|
+
conditions: ["name.includes('delete')", "name.includes('remove')"],
|
|
418
|
+
purpose: "Data deletion",
|
|
419
|
+
confidence: 0.8
|
|
420
|
+
},
|
|
421
|
+
validation: {
|
|
422
|
+
conditions: ["name.includes('validate')", "name.includes('check')"],
|
|
423
|
+
purpose: "Validation",
|
|
424
|
+
confidence: 0.75
|
|
425
|
+
},
|
|
426
|
+
dataProcessing: {
|
|
427
|
+
conditions: ["name.includes('parse')", "name.includes('format')"],
|
|
428
|
+
purpose: "Data processing",
|
|
429
|
+
confidence: 0.75
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
fallback: {
|
|
433
|
+
purpose: "Utility function",
|
|
434
|
+
confidence: 0.5
|
|
435
|
+
}
|
|
436
|
+
},
|
|
437
|
+
bundleHeuristics: {
|
|
438
|
+
patterns: {
|
|
439
|
+
frontend: {
|
|
440
|
+
conditions: ["pathParts.includes('web')", "pathParts.includes('src')"],
|
|
441
|
+
bundle: "frontend",
|
|
442
|
+
confidence: 0.8,
|
|
443
|
+
subPatterns: {
|
|
444
|
+
uiComponents: {
|
|
445
|
+
conditions: ["pathParts.includes('components')"],
|
|
446
|
+
bundle: "ui-components",
|
|
447
|
+
confidence: 0.9
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
server: {
|
|
452
|
+
conditions: ["fileName.includes('server')", "fileName.includes('api')", "pathParts.includes('bin')"],
|
|
453
|
+
bundle: "server",
|
|
454
|
+
confidence: 0.85
|
|
455
|
+
},
|
|
456
|
+
configuration: {
|
|
457
|
+
conditions: ["fileName.includes('config')", "fileName.includes('setup')", "fileName.endsWith('.json')", "fileName.endsWith('.sh')", "fileName.includes('package')"],
|
|
458
|
+
bundle: "config",
|
|
459
|
+
confidence: 0.9
|
|
460
|
+
},
|
|
461
|
+
documentation: {
|
|
462
|
+
conditions: ["fileName.endsWith('.md')", "fileName.includes('doc')", "fileName.includes('readme')"],
|
|
463
|
+
bundle: "docs",
|
|
464
|
+
confidence: 0.95
|
|
465
|
+
}
|
|
466
|
+
},
|
|
467
|
+
fallback: {
|
|
468
|
+
webFallback: {
|
|
469
|
+
conditions: ["pathParts.includes('web')"],
|
|
470
|
+
bundle: "frontend",
|
|
471
|
+
confidence: 0.6
|
|
472
|
+
},
|
|
473
|
+
defaultFallback: {
|
|
474
|
+
bundles: ["server", "config"],
|
|
475
|
+
confidence: 0.4
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
},
|
|
479
|
+
semanticTypeMapping: {
|
|
480
|
+
clusters: {
|
|
481
|
+
businessLogic: { types: ["business_logic", "algorithm"], clusterId: 0 },
|
|
482
|
+
dataLayer: { types: ["data_processing", "database"], clusterId: 1 },
|
|
483
|
+
apiLayer: { types: ["api_integration", "middleware", "routing"], clusterId: 2 },
|
|
484
|
+
uiLayer: { types: ["ui_component", "page_component", "layout_component", "hook"], clusterId: 3 },
|
|
485
|
+
utilities: { types: ["utility", "configuration", "function", "type_definition"], clusterId: 4 },
|
|
486
|
+
testing: { types: ["testing", "documentation", "monitoring"], clusterId: 5 },
|
|
487
|
+
infrastructure: { types: ["error_handling", "performance", "security"], clusterId: 6 },
|
|
488
|
+
unknown: { types: ["unknown"], clusterId: 7 }
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Update configuration (for API endpoints) and persist to disk
|
|
496
|
+
*/
|
|
497
|
+
async updateConfig(newConfig) {
|
|
498
|
+
try {
|
|
499
|
+
this.validateConfig(newConfig)
|
|
500
|
+
|
|
501
|
+
// Write to disk
|
|
502
|
+
writeFileSync(this.configPath, JSON.stringify(newConfig, null, 2), 'utf8')
|
|
503
|
+
|
|
504
|
+
this.config = newConfig
|
|
505
|
+
this.cache.clear()
|
|
506
|
+
this.lastLoaded = Date.now()
|
|
507
|
+
|
|
508
|
+
console.log('📝 Heuristics configuration updated and saved to disk')
|
|
509
|
+
return true
|
|
510
|
+
} catch (error) {
|
|
511
|
+
console.error('❌ Failed to update heuristics config:', error.message)
|
|
512
|
+
throw error
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Get performance metrics
|
|
518
|
+
*/
|
|
519
|
+
getPerformanceMetrics() {
|
|
520
|
+
// TODO: Implement performance tracking
|
|
521
|
+
return {
|
|
522
|
+
totalEvaluations: 0,
|
|
523
|
+
accuracyScore: 0.0,
|
|
524
|
+
lastUpdated: this.lastLoaded
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|