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.
Files changed (49) hide show
  1. package/README.md +51 -339
  2. package/VISION.md +110 -0
  3. package/bin/cntx-ui-mcp.sh +3 -0
  4. package/bin/cntx-ui.js +138 -55
  5. package/lib/agent-runtime.js +301 -0
  6. package/lib/agent-tools.js +370 -0
  7. package/lib/api-router.js +1161 -0
  8. package/lib/bundle-manager.js +236 -0
  9. package/lib/configuration-manager.js +760 -0
  10. package/lib/database-manager.js +397 -0
  11. package/lib/file-system-manager.js +489 -0
  12. package/lib/heuristics-manager.js +527 -0
  13. package/lib/mcp-server.js +1125 -2
  14. package/lib/semantic-splitter.js +225 -491
  15. package/lib/simple-vector-store.js +98 -0
  16. package/lib/websocket-manager.js +470 -0
  17. package/package.json +19 -25
  18. package/server.js +742 -1935
  19. package/templates/TOOLS.md +41 -0
  20. package/templates/activities/README.md +67 -0
  21. package/templates/activities/activities/create-project-bundles/README.md +84 -0
  22. package/templates/activities/activities/create-project-bundles/notes.md +98 -0
  23. package/templates/activities/activities/create-project-bundles/progress.md +63 -0
  24. package/templates/activities/activities/create-project-bundles/tasks.md +39 -0
  25. package/templates/activities/activities.json +219 -0
  26. package/templates/activities/lib/.markdownlint.jsonc +18 -0
  27. package/templates/activities/lib/create-activity.mdc +63 -0
  28. package/templates/activities/lib/generate-tasks.mdc +64 -0
  29. package/templates/activities/lib/process-task-list.mdc +52 -0
  30. package/templates/agent-config.yaml +65 -0
  31. package/templates/agent-instructions.md +234 -0
  32. package/templates/agent-rules/capabilities/activities-system.md +147 -0
  33. package/templates/agent-rules/capabilities/bundle-system.md +131 -0
  34. package/templates/agent-rules/capabilities/vector-search.md +135 -0
  35. package/templates/agent-rules/core/codebase-navigation.md +91 -0
  36. package/templates/agent-rules/core/performance-hierarchy.md +48 -0
  37. package/templates/agent-rules/core/response-formatting.md +120 -0
  38. package/templates/agent-rules/project-specific/architecture.md +145 -0
  39. package/templates/config.json +76 -0
  40. package/templates/hidden-files.json +14 -0
  41. package/web/dist/assets/index-B2OdTzzI.css +1 -0
  42. package/web/dist/assets/index-D0tBsKiR.js +2016 -0
  43. package/web/dist/cntx-ui.svg +18 -0
  44. package/web/dist/index.html +25 -8
  45. package/lib/semantic-integration.js +0 -441
  46. package/mcp-config-example.json +0 -9
  47. package/web/dist/assets/index-Ci1Q-YrQ.js +0 -611
  48. package/web/dist/assets/index-IUp4q_fr.css +0 -1
  49. package/web/dist/vite.svg +0 -21
package/bin/cntx-ui.js CHANGED
@@ -1,9 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import { readFileSync } from 'fs';
4
+ import { dirname, join } from 'path';
5
+ import { fileURLToPath } from 'url';
3
6
  import { startServer, startMCPServer, generateBundle, initConfig, getStatus, setupMCP } from '../server.js';
4
7
 
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+ const packagePath = join(__dirname, '..', 'package.json');
10
+ const packageJson = JSON.parse(readFileSync(packagePath, 'utf8'));
11
+
5
12
  const args = process.argv.slice(2);
6
- const command = args[0] || 'watch';
13
+ const command = args[0] || 'help';
14
+ const isVerbose = args.includes('--verbose');
7
15
 
8
16
  // Graceful shutdown
9
17
  process.on('SIGINT', () => {
@@ -11,63 +19,138 @@ process.on('SIGINT', () => {
11
19
  process.exit(0);
12
20
  });
13
21
 
14
- switch (command) {
15
- case 'watch':
16
- const port = parseInt(args[1]) || 3333;
17
- const withMcp = args.includes('--with-mcp');
18
- startServer({ port, withMcp });
19
- break;
20
-
21
- case 'mcp':
22
- // MCP server mode - runs on stdio
23
- startMCPServer({ cwd: process.cwd() });
24
- break;
25
-
26
- case 'bundle':
27
- const bundleName = args[1] || 'master';
28
- try {
29
- generateBundle(bundleName);
30
- console.log(`✅ Bundle '${bundleName}' generated`);
31
- } catch (e) {
32
- console.error(`❌ Bundle '${bundleName}' not found`);
33
- }
34
- break;
22
+ function showHelp() {
23
+ console.log(`cntx-ui v${packageJson.version}
35
24
 
36
- case 'init':
37
- initConfig();
38
- break;
25
+ ${packageJson.description}
39
26
 
40
- case 'status':
41
- getStatus();
42
- break;
27
+ Usage:
28
+ cntx-ui <command> [options]
43
29
 
44
- case 'setup-mcp':
45
- setupMCP();
46
- break;
30
+ Commands:
31
+ init Initialize configuration in current directory
32
+ watch [port] Start web server (default port: 3333)
33
+ mcp Start MCP server (stdio transport)
34
+ bundle [name] Generate specific bundle (default: master)
35
+ status Show current project status
36
+ setup-mcp Add this project to Claude Desktop MCP config
37
+
38
+ Options:
39
+ --verbose Enable detailed logging
40
+ --with-mcp Start web server with MCP status tracking
41
+ --version, -v Show version number
42
+ --help, -h Show this help message
47
43
 
48
- default:
49
- console.log(`cntx-ui v2.0.8
50
-
51
- Usage:
52
- cntx-ui init Initialize configuration
53
- cntx-ui watch [port] Start web server (default port: 3333)
54
- cntx-ui watch --with-mcp Start web server with MCP status tracking
55
- cntx-ui mcp Start MCP server (stdio transport)
56
- cntx-ui setup-mcp Add this project to Claude Desktop MCP config
57
- cntx-ui bundle [name] Generate specific bundle (default: master)
58
- cntx-ui status Show current status
59
-
60
44
  Examples:
61
- cntx-ui init
62
- cntx-ui watch 8080
63
- cntx-ui watch --with-mcp
64
- cntx-ui setup-mcp
65
- cntx-ui mcp
66
- cntx-ui bundle api
67
-
68
- MCP Usage:
69
- The MCP server provides AI-accessible bundle management:
70
- - Resources: Access bundles and files via cntx:// URIs
71
- - Tools: List bundles, generate bundles, get project status
72
- - Integration: Use with Claude Desktop, Cursor, or other MCP clients`);
45
+ cntx-ui init Initialize a new project
46
+ cntx-ui watch Start web server on port 3333
47
+ cntx-ui watch 8080 Start web server on port 8080
48
+ cntx-ui watch --verbose Start with detailed logs
49
+ cntx-ui watch --with-mcp Start with MCP integration
50
+ cntx-ui bundle api Generate 'api' bundle
51
+ cntx-ui status Show project status
52
+ cntx-ui setup-mcp Configure Claude Desktop integration
53
+
54
+ MCP Integration:
55
+ The MCP server provides AI-accessible bundle management for Claude Desktop
56
+ and other MCP-compatible clients. Use 'setup-mcp' to configure automatic
57
+ integration with Claude Desktop.
58
+
59
+ Agent Collaboration:
60
+ To get an external agent up to speed with your project, use this prompt:
61
+
62
+ "I'm working in a project that uses cntx-ui for file organization and AI
63
+ collaboration. Please read these files to understand the project structure
64
+ and help me with activities:
65
+
66
+ @.cntx/agent-instructions.md
67
+ @.cntx/activities/README.md
68
+ @.cntx/activities/activities.json
69
+
70
+ After reading those, please also examine:
71
+ @.cntx/activities/lib/create-activity.mdc
72
+ @.cntx/activities/lib/generate-tasks.mdc
73
+ @.cntx/activities/lib/process-task-list.mdc
74
+
75
+ These files contain the complete workflow for creating and managing
76
+ activities with agent assistance."
77
+
78
+ Repository: ${packageJson.repository.url}
79
+ Author: ${packageJson.author}
80
+ License: ${packageJson.license}`);
81
+ }
82
+
83
+ function showVersion() {
84
+ console.log(`cntx-ui v${packageJson.version}`);
73
85
  }
86
+
87
+ async function main() {
88
+ // Handle version flags
89
+ if (args.includes('--version') || args.includes('-v')) {
90
+ return showVersion();
91
+ }
92
+
93
+ // Handle help flags
94
+ if (args.includes('--help') || args.includes('-h') || command === 'help') {
95
+ return showHelp();
96
+ }
97
+
98
+ // Handle default command (watch if no command provided and no flags)
99
+ const actualCommand = command === 'help' ? 'watch' : command;
100
+
101
+ try {
102
+ switch (actualCommand) {
103
+ case 'watch':
104
+ case 'w':
105
+ const port = parseInt(args[1]) || 3333;
106
+ // Enable MCP status tracking by default for the web dashboard
107
+ const withMcp = !args.includes('--no-mcp');
108
+ await startServer({ port, withMcp, verbose: isVerbose });
109
+ break;
110
+
111
+ case 'mcp':
112
+ // MCP server mode - runs on stdio
113
+ await startMCPServer({ cwd: process.cwd(), verbose: isVerbose });
114
+ break;
115
+
116
+ case 'bundle':
117
+ case 'b':
118
+ const bundleName = args[1] || 'master';
119
+ try {
120
+ await generateBundle(bundleName);
121
+ console.log(`✅ Bundle '${bundleName}' generated successfully`);
122
+ } catch (error) {
123
+ console.error(`❌ Failed to generate bundle '${bundleName}': ${error.message}`);
124
+ process.exit(1);
125
+ }
126
+ break;
127
+
128
+ case 'init':
129
+ case 'i':
130
+ await initConfig();
131
+ break;
132
+
133
+ case 'status':
134
+ case 's':
135
+ await getStatus();
136
+ break;
137
+
138
+ case 'setup-mcp':
139
+ setupMCP();
140
+ break;
141
+
142
+ default:
143
+ console.error(`❌ Unknown command: ${command}`);
144
+ console.log('Run "cntx-ui --help" for usage information.');
145
+ process.exit(1);
146
+ }
147
+ } catch (error) {
148
+ console.error(`❌ Error: ${error.message}`);
149
+ if (isVerbose) {
150
+ console.error(error.stack);
151
+ }
152
+ process.exit(1);
153
+ }
154
+ }
155
+
156
+ main().catch(console.error);
@@ -0,0 +1,301 @@
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
+ async generateContextualAnswer(question, results, includeCode) {
285
+ let response = `Based on the codebase analysis:\n\n`;
286
+ if (results.chunks.length > 0) {
287
+ const top = results.chunks[0];
288
+ response += `The most relevant implementation found is \`${top.name}\` in \`${top.filePath}\` (Purpose: ${top.purpose}).\n\n`;
289
+ } else {
290
+ response += `No direct semantic matches found. Try refining your query.`;
291
+ }
292
+
293
+ return {
294
+ response,
295
+ evidence: results.chunks.slice(0, 3),
296
+ confidence: results.chunks.length > 0 ? 0.8 : 0.2
297
+ };
298
+ }
299
+ }
300
+
301
+ export default AgentRuntime;