cntx-ui 3.0.7 → 3.0.9

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 (36) hide show
  1. package/dist/bin/cntx-ui.js +70 -0
  2. package/dist/lib/agent-runtime.js +269 -0
  3. package/dist/lib/agent-tools.js +162 -0
  4. package/dist/lib/api-router.js +387 -0
  5. package/dist/lib/bundle-manager.js +236 -0
  6. package/dist/lib/configuration-manager.js +230 -0
  7. package/dist/lib/database-manager.js +277 -0
  8. package/dist/lib/file-system-manager.js +305 -0
  9. package/dist/lib/function-level-chunker.js +144 -0
  10. package/dist/lib/heuristics-manager.js +491 -0
  11. package/dist/lib/mcp-server.js +159 -0
  12. package/dist/lib/mcp-transport.js +10 -0
  13. package/dist/lib/semantic-splitter.js +335 -0
  14. package/dist/lib/simple-vector-store.js +98 -0
  15. package/dist/lib/treesitter-semantic-chunker.js +277 -0
  16. package/dist/lib/websocket-manager.js +268 -0
  17. package/dist/server.js +225 -0
  18. package/package.json +18 -8
  19. package/bin/cntx-ui-mcp.sh +0 -3
  20. package/bin/cntx-ui.js +0 -123
  21. package/lib/agent-runtime.js +0 -371
  22. package/lib/agent-tools.js +0 -370
  23. package/lib/api-router.js +0 -1026
  24. package/lib/bundle-manager.js +0 -326
  25. package/lib/configuration-manager.js +0 -760
  26. package/lib/database-manager.js +0 -397
  27. package/lib/file-system-manager.js +0 -489
  28. package/lib/function-level-chunker.js +0 -406
  29. package/lib/heuristics-manager.js +0 -529
  30. package/lib/mcp-server.js +0 -1380
  31. package/lib/mcp-transport.js +0 -97
  32. package/lib/semantic-splitter.js +0 -304
  33. package/lib/simple-vector-store.js +0 -108
  34. package/lib/treesitter-semantic-chunker.js +0 -1485
  35. package/lib/websocket-manager.js +0 -470
  36. package/server.js +0 -687
@@ -1,371 +0,0 @@
1
- /**
2
- * Agent Runtime for Codebase Exploration and Development
3
- * Now stateful with SQLite-based working memory
4
- */
5
-
6
- import AgentTools from './agent-tools.js';
7
- import crypto from 'crypto';
8
- import fs from 'fs';
9
- import path from 'path';
10
- import { fileURLToPath } from 'url';
11
-
12
- export class AgentRuntime {
13
- constructor(cntxServer) {
14
- this.cntxServer = cntxServer;
15
- this.db = cntxServer.databaseManager;
16
- this.tools = new AgentTools(cntxServer);
17
- this.currentSessionId = null;
18
- }
19
-
20
- /**
21
- * Initialize or resume a session
22
- */
23
- async startSession(id = null, title = 'New Exploration') {
24
- this.currentSessionId = id || crypto.randomUUID();
25
- this.db.createSession(this.currentSessionId, title);
26
- // Refresh manifest when a new session starts
27
- await this.generateAgentManifest();
28
- return this.currentSessionId;
29
- }
30
-
31
- /**
32
- * Generates a .cntx/AGENT.md manifest for machine consumption
33
- */
34
- async generateAgentManifest() {
35
- const overview = await this.getCodebaseOverview();
36
- const summary = await this.getSemanticSummary();
37
- const bundles = await this.analyzeBundles('all');
38
-
39
- // Auto-generate tool reference from MCP server
40
- let toolsReference = '';
41
- if (this.cntxServer.mcpServer) {
42
- const tools = this.cntxServer.mcpServer.getToolDefinitions();
43
- toolsReference = tools.map(t => {
44
- let params = [];
45
- if (t.inputSchema?.properties) {
46
- params = Object.entries(t.inputSchema.properties).map(([name, prop]) => {
47
- const isReq = t.inputSchema.required?.includes(name) ? 'required' : 'optional';
48
- return `\`${name}\` (${prop.type}, ${isReq}): ${prop.description}`;
49
- });
50
- }
51
- return `### \`${t.name}\`\n${t.description}\n${params.length > 0 ? '**Parameters:**\n- ' + params.join('\n- ') : '*No parameters required*'}\n`;
52
- }).join('\n');
53
- }
54
-
55
- const manifest = `# 🤖 Agent Handshake: ${overview.projectPath.split('/').pop()}
56
-
57
- ## Project Overview
58
- - **Path:** \`${overview.projectPath}\`
59
- - **Total Files:** ${overview.totalFiles}
60
- - **Semantic Intelligence:** ${summary.totalChunks} persistent chunks indexed.
61
-
62
- ## Codebase Organization (Bundles)
63
- ${bundles.map(b => `- **${b.name}**: ${b.purpose} (${b.fileCount} files)`).join('\n')}
64
-
65
- ## Intelligence Interface (MCP Tools)
66
- You have access to a specialized "Repository Intelligence" engine. Use these tools for high-signal exploration:
67
-
68
- ${toolsReference || '*(MCP Server not yet initialized, tools will appear here)*'}
69
-
70
- ---
71
-
72
- ## 🛠 Complete Tool & API Reference
73
- Refer to the dynamic reference below for full parameter schemas and HTTP fallback endpoints.
74
-
75
- ${fs.readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), '../templates/TOOLS.md'), 'utf8')}
76
-
77
- ## Working Memory
78
- This agent is **stateful**. All interactions in this directory are logged to a persistent SQLite database (\`.cntx/bundles.db\`), allowing for context retention across sessions.
79
-
80
- ---
81
- *Generated automatically by cntx-ui. Optimized for LLM consumption.*
82
- `;
83
-
84
- const manifestPath = path.join(this.cntxServer.CNTX_DIR, 'AGENT.md');
85
- fs.writeFileSync(manifestPath, manifest, 'utf8');
86
- if (this.cntxServer.verbose) console.log('📄 Agent manifest updated: .cntx/AGENT.md');
87
- }
88
-
89
- /**
90
- * Log an interaction to the agent's memory
91
- */
92
- async logInteraction(role, content, metadata = {}) {
93
- if (!this.currentSessionId) await this.startSession();
94
- this.db.addMessage(this.currentSessionId, role, content, metadata);
95
- }
96
-
97
- /**
98
- * Discovery Mode: "Tell me about this codebase"
99
- * Now logs the discovery process to memory
100
- */
101
- async discoverCodebase(options = {}) {
102
- const { scope = 'all', includeDetails = true } = options;
103
-
104
- try {
105
- await this.logInteraction('agent', `Starting codebase discovery for scope: ${scope}`);
106
-
107
- const discovery = {
108
- overview: await this.getCodebaseOverview(),
109
- bundles: await this.analyzeBundles(scope),
110
- architecture: await this.analyzeArchitecture(),
111
- patterns: await this.identifyPatterns(),
112
- recommendations: []
113
- };
114
-
115
- if (includeDetails) {
116
- discovery.semanticSummary = await this.getSemanticSummary();
117
- discovery.fileTypes = await this.analyzeFileTypes();
118
- discovery.complexity = await this.analyzeComplexity();
119
- }
120
-
121
- discovery.recommendations = await this.generateDiscoveryRecommendations(discovery);
122
-
123
- await this.logInteraction('agent', `Discovery complete. Found ${discovery.overview.totalFiles} files.`, { discovery });
124
-
125
- return discovery;
126
- } catch (error) {
127
- await this.logInteraction('agent', `Discovery failed: ${error.message}`);
128
- throw new Error(`Discovery failed: ${error.message}`);
129
- }
130
- }
131
-
132
- /**
133
- * Query Mode: "Where is the user authentication handled?"
134
- * Now recalls previous context from SQLite
135
- */
136
- async answerQuery(question, options = {}) {
137
- const { scope = null, maxResults = 10, includeCode = false } = options;
138
-
139
- try {
140
- await this.logInteraction('user', question);
141
-
142
- // Perform semantic search via Vector Store
143
- const combinedResults = await this.cntxServer.vectorStore.search(question, { limit: maxResults });
144
-
145
- // Generate contextual answer
146
- const answer = await this.generateContextualAnswer(question, { chunks: combinedResults, files: [] }, includeCode);
147
-
148
- const response = {
149
- question,
150
- answer: answer.response,
151
- evidence: answer.evidence,
152
- confidence: answer.confidence,
153
- relatedFiles: [...new Set(combinedResults.map(c => c.filePath))].slice(0, 5)
154
- };
155
-
156
- await this.logInteraction('agent', response.answer, { response });
157
-
158
- return response;
159
- } catch (error) {
160
- throw new Error(`Query failed: ${error.message}`);
161
- }
162
- }
163
-
164
- /**
165
- * Feature Investigation Mode: Now persists the investigation approach
166
- */
167
- async investigateFeature(featureDescription, options = {}) {
168
- const { includeRecommendations = true } = options;
169
-
170
- try {
171
- await this.logInteraction('user', `Investigating feature: ${featureDescription}`);
172
-
173
- const investigation = {
174
- feature: featureDescription,
175
- existing: await this.findExistingImplementations(featureDescription),
176
- related: await this.findRelatedCode(featureDescription),
177
- integration: await this.findIntegrationPoints(featureDescription)
178
- };
179
-
180
- if (includeRecommendations) {
181
- investigation.approach = await this.suggestImplementationApproach(investigation);
182
- }
183
-
184
- await this.logInteraction('agent', `Investigation complete for ${featureDescription}`, { investigation });
185
-
186
- return investigation;
187
- } catch (error) {
188
- throw new Error(`Feature investigation failed: ${error.message}`);
189
- }
190
- }
191
-
192
- // --- Helper Methods (reusing your existing logic but streamlined) ---
193
-
194
- async getCodebaseOverview() {
195
- const bundles = Array.from(this.cntxServer.bundleManager.getAllBundleInfo());
196
- const totalFiles = bundles.reduce((sum, b) => sum + b.fileCount, 0);
197
- const totalSize = bundles.reduce((sum, b) => sum + b.size, 0);
198
-
199
- return {
200
- projectPath: this.cntxServer.CWD,
201
- totalBundles: bundles.length,
202
- totalFiles,
203
- totalSize,
204
- bundleNames: bundles.map(b => b.name)
205
- };
206
- }
207
-
208
- async analyzeBundles(scope) {
209
- const bundles = this.cntxServer.bundleManager.getAllBundleInfo();
210
- const filtered = scope === 'all' ? bundles : bundles.filter(b => b.name === scope);
211
-
212
- return filtered.map(b => ({
213
- ...b,
214
- purpose: this.inferBundlePurpose(b.name, b.files)
215
- }));
216
- }
217
-
218
- inferBundlePurpose(name, files) {
219
- if (name.includes('component') || name.includes('ui')) return 'UI Components';
220
- if (name.includes('api') || name.includes('server')) return 'Backend API';
221
- return 'General Module';
222
- }
223
-
224
- async analyzeArchitecture() {
225
- return {
226
- type: 'Dynamic Architecture',
227
- timestamp: new Date().toISOString()
228
- };
229
- }
230
-
231
- async identifyPatterns() {
232
- return {
233
- coding: 'Modern Node.js',
234
- style: 'Functional / Modular'
235
- };
236
- }
237
-
238
- async getSemanticSummary() {
239
- const chunks = this.db.db.prepare('SELECT COUNT(*) as count FROM semantic_chunks').get();
240
- return { totalChunks: chunks.count };
241
- }
242
-
243
- async analyzeFileTypes() {
244
- const rows = this.db.db.prepare('SELECT file_path FROM semantic_chunks').all();
245
- const exts = {};
246
- rows.forEach(r => {
247
- const ext = r.file_path.split('.').pop();
248
- exts[ext] = (exts[ext] || 0) + 1;
249
- });
250
- return exts;
251
- }
252
-
253
- async analyzeComplexity() {
254
- const rows = this.db.db.prepare('SELECT complexity_score FROM semantic_chunks').all();
255
- const scores = { low: 0, medium: 0, high: 0 };
256
- rows.forEach(r => {
257
- if (r.complexity_score < 5) scores.low++;
258
- else if (r.complexity_score < 15) scores.medium++;
259
- else scores.high++;
260
- });
261
- return scores;
262
- }
263
-
264
- async generateDiscoveryRecommendations() {
265
- return [{ type: 'info', message: 'Continue organizing by semantic purpose.' }];
266
- }
267
-
268
- async findExistingImplementations(featureDescription) {
269
- return await this.cntxServer.vectorStore.search(featureDescription, { limit: 5 });
270
- }
271
-
272
- async findRelatedCode(featureDescription) {
273
- return [];
274
- }
275
-
276
- async findIntegrationPoints(featureDescription) {
277
- return [];
278
- }
279
-
280
- async suggestImplementationApproach(investigation) {
281
- return { strategy: 'TBD', description: 'Ready to plan' };
282
- }
283
-
284
- /**
285
- * Discussion Mode: Engage in architectural discussion about the codebase
286
- */
287
- async discussAndPlan(userInput, context = {}) {
288
- try {
289
- await this.logInteraction('user', userInput);
290
-
291
- const overview = await this.getCodebaseOverview();
292
- const searchResults = await this.cntxServer.vectorStore.search(userInput, { limit: 5 });
293
-
294
- const response = {
295
- input: userInput,
296
- context,
297
- overview,
298
- relevantCode: searchResults.map(r => ({
299
- name: r.name,
300
- filePath: r.filePath,
301
- purpose: r.purpose,
302
- type: r.type
303
- })),
304
- suggestions: [
305
- 'Review the relevant code sections listed above.',
306
- 'Consider how changes would affect dependent bundles.',
307
- 'Use semantic search to explore related patterns.'
308
- ]
309
- };
310
-
311
- await this.logInteraction('agent', `Discussion: ${userInput}`, { response });
312
-
313
- return response;
314
- } catch (error) {
315
- throw new Error(`Discussion failed: ${error.message}`);
316
- }
317
- }
318
-
319
- /**
320
- * Organize Mode: Setup and maintenance of project organization
321
- */
322
- async organizeProject(options = {}) {
323
- const { activity = 'detect', autoDetect = true, force = false } = options;
324
-
325
- try {
326
- await this.logInteraction('agent', `Organizing project: ${activity}`);
327
-
328
- const overview = await this.getCodebaseOverview();
329
- const bundles = await this.analyzeBundles('all');
330
-
331
- const response = {
332
- activity,
333
- overview,
334
- bundles: bundles.map(b => ({
335
- name: b.name,
336
- fileCount: b.fileCount,
337
- purpose: b.purpose
338
- })),
339
- recommendations: [
340
- 'Review bundle organization for coverage gaps.',
341
- 'Check .cntxignore for missing exclusion patterns.',
342
- 'Run semantic analysis to identify uncategorized code.'
343
- ]
344
- };
345
-
346
- await this.logInteraction('agent', `Organization complete for activity: ${activity}`, { response });
347
-
348
- return response;
349
- } catch (error) {
350
- throw new Error(`Organization failed: ${error.message}`);
351
- }
352
- }
353
-
354
- async generateContextualAnswer(question, results, includeCode) {
355
- let response = `Based on the codebase analysis:\n\n`;
356
- if (results.chunks.length > 0) {
357
- const top = results.chunks[0];
358
- response += `The most relevant implementation found is \`${top.name}\` in \`${top.filePath}\` (Purpose: ${top.purpose}).\n\n`;
359
- } else {
360
- response += `No direct semantic matches found. Try refining your query.`;
361
- }
362
-
363
- return {
364
- response,
365
- evidence: results.chunks.slice(0, 3),
366
- confidence: results.chunks.length > 0 ? 0.8 : 0.2
367
- };
368
- }
369
- }
370
-
371
- export default AgentRuntime;