cntx-ui 3.0.5 → 3.0.7
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 +16 -49
- package/lib/agent-runtime.js +70 -0
- package/lib/api-router.js +1 -136
- package/lib/mcp-server.js +0 -146
- package/package.json +1 -1
- package/server.js +93 -380
- package/templates/TOOLS.md +0 -6
- package/templates/agent-config.yaml +0 -5
- package/templates/agent-instructions.md +2 -15
- package/templates/agent-rules/project-specific/architecture.md +0 -1
- package/templates/hidden-files.json +0 -1
- package/web/dist/assets/index-D2RTcdqV.js +1968 -0
- package/web/dist/assets/index-DJi03HLz.css +1 -0
- package/web/dist/index.html +2 -2
- package/templates/activities/README.md +0 -67
- package/templates/activities/activities/create-project-bundles/README.md +0 -84
- package/templates/activities/activities/create-project-bundles/notes.md +0 -98
- package/templates/activities/activities/create-project-bundles/progress.md +0 -63
- package/templates/activities/activities/create-project-bundles/tasks.md +0 -39
- package/templates/activities/activities.json +0 -219
- package/templates/activities/lib/.markdownlint.jsonc +0 -18
- package/templates/activities/lib/create-activity.mdc +0 -63
- package/templates/activities/lib/generate-tasks.mdc +0 -64
- package/templates/activities/lib/process-task-list.mdc +0 -52
- package/templates/agent-rules/capabilities/activities-system.md +0 -147
- package/web/dist/assets/index-4p3KJ0jf.js +0 -2016
- package/web/dist/assets/index-BPIipM25.css +0 -1
package/bin/cntx-ui.js
CHANGED
|
@@ -3,19 +3,19 @@
|
|
|
3
3
|
import { readFileSync } from 'fs';
|
|
4
4
|
import { dirname, join } from 'path';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
|
-
import {
|
|
6
|
+
import { autoInitAndStart, startMCPServer, generateBundle, initConfig, getStatus } from '../server.js';
|
|
7
7
|
|
|
8
8
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
9
|
const packagePath = join(__dirname, '..', 'package.json');
|
|
10
10
|
const packageJson = JSON.parse(readFileSync(packagePath, 'utf8'));
|
|
11
11
|
|
|
12
12
|
const args = process.argv.slice(2);
|
|
13
|
-
const command = args[0] || '
|
|
13
|
+
const command = args[0] || 'start';
|
|
14
14
|
const isVerbose = args.includes('--verbose');
|
|
15
15
|
|
|
16
16
|
// Graceful shutdown
|
|
17
17
|
process.on('SIGINT', () => {
|
|
18
|
-
console.log('\n
|
|
18
|
+
console.log('\n Shutting down cntx-ui...');
|
|
19
19
|
process.exit(0);
|
|
20
20
|
});
|
|
21
21
|
|
|
@@ -25,55 +25,30 @@ function showHelp() {
|
|
|
25
25
|
${packageJson.description}
|
|
26
26
|
|
|
27
27
|
Usage:
|
|
28
|
-
cntx-ui
|
|
28
|
+
cntx-ui [command] [options]
|
|
29
29
|
|
|
30
30
|
Commands:
|
|
31
|
+
(default) Auto-init if needed, then start web server
|
|
31
32
|
init Initialize configuration in current directory
|
|
32
|
-
watch [port] Start web server (default port: 3333)
|
|
33
33
|
mcp Start MCP server (stdio transport)
|
|
34
34
|
bundle [name] Generate specific bundle (default: master)
|
|
35
35
|
status Show current project status
|
|
36
|
-
setup-mcp Add this project to Claude Desktop MCP config
|
|
37
36
|
|
|
38
37
|
Options:
|
|
39
38
|
--verbose Enable detailed logging
|
|
40
|
-
--with-mcp Start web server with MCP status tracking
|
|
41
39
|
--version, -v Show version number
|
|
42
40
|
--help, -h Show this help message
|
|
43
41
|
|
|
44
42
|
Examples:
|
|
43
|
+
cntx-ui Start server (auto-inits if needed)
|
|
45
44
|
cntx-ui init Initialize a new project
|
|
46
|
-
cntx-ui
|
|
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
|
|
45
|
+
cntx-ui mcp Start MCP server on stdio
|
|
50
46
|
cntx-ui bundle api Generate 'api' bundle
|
|
51
47
|
cntx-ui status Show project status
|
|
52
|
-
cntx-ui setup-mcp Configure Claude Desktop integration
|
|
53
48
|
|
|
54
49
|
MCP Integration:
|
|
55
|
-
|
|
56
|
-
|
|
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."
|
|
50
|
+
Running 'cntx-ui init' creates a .mcp.json file so Claude Code
|
|
51
|
+
can auto-discover the MCP server. Run 'cntx-ui mcp' for stdio mode.
|
|
77
52
|
|
|
78
53
|
Repository: ${packageJson.repository.url}
|
|
79
54
|
Author: ${packageJson.author}
|
|
@@ -95,17 +70,13 @@ async function main() {
|
|
|
95
70
|
return showHelp();
|
|
96
71
|
}
|
|
97
72
|
|
|
98
|
-
// Handle default command (watch if no command provided and no flags)
|
|
99
|
-
const actualCommand = command === 'help' ? 'watch' : command;
|
|
100
|
-
|
|
101
73
|
try {
|
|
102
|
-
switch (
|
|
74
|
+
switch (command) {
|
|
75
|
+
case 'start':
|
|
103
76
|
case 'watch':
|
|
104
77
|
case 'w':
|
|
105
78
|
const port = parseInt(args[1]) || 3333;
|
|
106
|
-
|
|
107
|
-
const withMcp = !args.includes('--no-mcp');
|
|
108
|
-
await startServer({ port, withMcp, verbose: isVerbose });
|
|
79
|
+
await autoInitAndStart({ port, verbose: isVerbose });
|
|
109
80
|
break;
|
|
110
81
|
|
|
111
82
|
case 'mcp':
|
|
@@ -118,9 +89,9 @@ async function main() {
|
|
|
118
89
|
const bundleName = args[1] || 'master';
|
|
119
90
|
try {
|
|
120
91
|
await generateBundle(bundleName);
|
|
121
|
-
console.log(
|
|
92
|
+
console.log(`Bundle '${bundleName}' generated successfully`);
|
|
122
93
|
} catch (error) {
|
|
123
|
-
console.error(
|
|
94
|
+
console.error(`Failed to generate bundle '${bundleName}': ${error.message}`);
|
|
124
95
|
process.exit(1);
|
|
125
96
|
}
|
|
126
97
|
break;
|
|
@@ -135,17 +106,13 @@ async function main() {
|
|
|
135
106
|
await getStatus();
|
|
136
107
|
break;
|
|
137
108
|
|
|
138
|
-
case 'setup-mcp':
|
|
139
|
-
setupMCP();
|
|
140
|
-
break;
|
|
141
|
-
|
|
142
109
|
default:
|
|
143
|
-
console.error(
|
|
110
|
+
console.error(`Unknown command: ${command}`);
|
|
144
111
|
console.log('Run "cntx-ui --help" for usage information.');
|
|
145
112
|
process.exit(1);
|
|
146
113
|
}
|
|
147
114
|
} catch (error) {
|
|
148
|
-
console.error(
|
|
115
|
+
console.error(`Error: ${error.message}`);
|
|
149
116
|
if (isVerbose) {
|
|
150
117
|
console.error(error.stack);
|
|
151
118
|
}
|
package/lib/agent-runtime.js
CHANGED
|
@@ -281,6 +281,76 @@ This agent is **stateful**. All interactions in this directory are logged to a p
|
|
|
281
281
|
return { strategy: 'TBD', description: 'Ready to plan' };
|
|
282
282
|
}
|
|
283
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
|
+
|
|
284
354
|
async generateContextualAnswer(question, results, includeCode) {
|
|
285
355
|
let response = `Based on the codebase analysis:\n\n`;
|
|
286
356
|
if (results.chunks.length > 0) {
|
package/lib/api-router.js
CHANGED
|
@@ -8,26 +8,19 @@ import fs from 'fs';
|
|
|
8
8
|
import path from 'path';
|
|
9
9
|
|
|
10
10
|
export default class APIRouter {
|
|
11
|
-
constructor(cntxServer, configManager, bundleManager, fileSystemManager, semanticAnalysisManager, vectorStore
|
|
11
|
+
constructor(cntxServer, configManager, bundleManager, fileSystemManager, semanticAnalysisManager, vectorStore) {
|
|
12
12
|
this.cntxServer = cntxServer;
|
|
13
13
|
this.configManager = configManager;
|
|
14
14
|
this.bundleManager = bundleManager;
|
|
15
15
|
this.fileSystemManager = fileSystemManager;
|
|
16
16
|
this.semanticAnalysisManager = semanticAnalysisManager;
|
|
17
17
|
this.vectorStore = vectorStore;
|
|
18
|
-
this.activityManager = activityManager;
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
async handleRequest(req, res, url) {
|
|
22
21
|
const method = req.method;
|
|
23
22
|
const pathname = url.pathname;
|
|
24
23
|
|
|
25
|
-
// DEBUG: Log all incoming API requests
|
|
26
|
-
console.log('[API REQUEST]', method, pathname);
|
|
27
|
-
if (pathname.includes('database')) {
|
|
28
|
-
console.log('[DATABASE] Route requested:', pathname, method);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
24
|
try {
|
|
32
25
|
// Route to appropriate handler
|
|
33
26
|
if (pathname === '/api/bundles' && method === 'GET') {
|
|
@@ -73,26 +66,6 @@ export default class APIRouter {
|
|
|
73
66
|
return await this.handleGetFiles(req, res);
|
|
74
67
|
}
|
|
75
68
|
|
|
76
|
-
if (pathname === '/api/cursor-rules' && method === 'GET') {
|
|
77
|
-
return await this.handleGetCursorRules(req, res);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (pathname === '/api/cursor-rules' && method === 'POST') {
|
|
81
|
-
return await this.handlePostCursorRules(req, res);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (pathname === '/api/cursor-rules/templates' && method === 'GET') {
|
|
85
|
-
return await this.handleGetCursorRulesTemplates(req, res);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (pathname === '/api/claude-md' && method === 'GET') {
|
|
89
|
-
return await this.handleGetClaudeMd(req, res);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (pathname === '/api/claude-md' && method === 'POST') {
|
|
93
|
-
return await this.handlePostClaudeMd(req, res);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
69
|
if (pathname === '/api/heuristics/config' && method === 'GET') {
|
|
97
70
|
return await this.handleGetHeuristicsConfig(req, res);
|
|
98
71
|
}
|
|
@@ -190,25 +163,6 @@ export default class APIRouter {
|
|
|
190
163
|
return await this.handlePostVectorDbSearchByDomain(req, res);
|
|
191
164
|
}
|
|
192
165
|
|
|
193
|
-
if (pathname === '/api/activities' && method === 'GET') {
|
|
194
|
-
return await this.handleGetActivities(req, res);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if (pathname.startsWith('/api/activities/') && pathname.endsWith('/reasoning') && method === 'GET') {
|
|
198
|
-
const activityId = pathname.split('/')[3];
|
|
199
|
-
return await this.handleGetActivityReasoning(req, res, activityId);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (pathname.startsWith('/api/activities/') && pathname.endsWith('/execute') && method === 'POST') {
|
|
203
|
-
const activityId = pathname.split('/')[3];
|
|
204
|
-
return await this.handlePostActivityExecute(req, res, activityId);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (pathname.startsWith('/api/activities/') && pathname.endsWith('/stop') && method === 'POST') {
|
|
208
|
-
const activityId = pathname.split('/')[3];
|
|
209
|
-
return await this.handlePostActivityStop(req, res, activityId);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
166
|
if (pathname === '/api/open-file' && method === 'POST') {
|
|
213
167
|
return await this.handleOpenFile(req, res);
|
|
214
168
|
}
|
|
@@ -429,49 +383,6 @@ export default class APIRouter {
|
|
|
429
383
|
res.end(JSON.stringify({ success: true }));
|
|
430
384
|
}
|
|
431
385
|
|
|
432
|
-
async handleGetCursorRules(req, res) {
|
|
433
|
-
const content = this.configManager.loadCursorRules();
|
|
434
|
-
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
435
|
-
res.end(content);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
async handlePostCursorRules(req, res) {
|
|
439
|
-
const body = await this.getRequestBody(req);
|
|
440
|
-
const { content } = JSON.parse(body);
|
|
441
|
-
|
|
442
|
-
this.configManager.saveCursorRules(content);
|
|
443
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
444
|
-
res.end(JSON.stringify({ success: true }));
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
async handleGetCursorRulesTemplates(req, res) {
|
|
448
|
-
const templates = {
|
|
449
|
-
react: this.configManager.generateCursorRulesTemplate({ projectType: 'react', name: 'React Project' }),
|
|
450
|
-
vue: this.configManager.generateCursorRulesTemplate({ projectType: 'vue', name: 'Vue Project' }),
|
|
451
|
-
angular: this.configManager.generateCursorRulesTemplate({ projectType: 'angular', name: 'Angular Project' }),
|
|
452
|
-
'node-backend': this.configManager.generateCursorRulesTemplate({ projectType: 'node-backend', name: 'Node.js Backend' }),
|
|
453
|
-
javascript: this.configManager.generateCursorRulesTemplate({ projectType: 'javascript', name: 'JavaScript Project' })
|
|
454
|
-
};
|
|
455
|
-
|
|
456
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
457
|
-
res.end(JSON.stringify(templates));
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
async handleGetClaudeMd(req, res) {
|
|
461
|
-
const content = this.configManager.loadClaudeMd();
|
|
462
|
-
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
463
|
-
res.end(content);
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
async handlePostClaudeMd(req, res) {
|
|
467
|
-
const body = await this.getRequestBody(req);
|
|
468
|
-
const { content } = JSON.parse(body);
|
|
469
|
-
|
|
470
|
-
this.configManager.saveClaudeMd(content);
|
|
471
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
472
|
-
res.end(JSON.stringify({ success: true }));
|
|
473
|
-
}
|
|
474
|
-
|
|
475
386
|
async handleGetHeuristicsConfig(req, res) {
|
|
476
387
|
const config = this.configManager.loadHeuristicsConfig();
|
|
477
388
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
@@ -907,52 +818,6 @@ export default class APIRouter {
|
|
|
907
818
|
}
|
|
908
819
|
}
|
|
909
820
|
|
|
910
|
-
// === Activities ===
|
|
911
|
-
|
|
912
|
-
async handleGetActivities(req, res) {
|
|
913
|
-
try {
|
|
914
|
-
const activities = await this.activityManager.loadActivities();
|
|
915
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
916
|
-
res.end(JSON.stringify(activities));
|
|
917
|
-
} catch (error) {
|
|
918
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
919
|
-
res.end(JSON.stringify({ error: error.message }));
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
async handleGetActivityReasoning(req, res, activityId) {
|
|
924
|
-
try {
|
|
925
|
-
const history = this.configManager.dbManager.getSessionHistory(activityId);
|
|
926
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
927
|
-
res.end(JSON.stringify({ history }));
|
|
928
|
-
} catch (error) {
|
|
929
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
930
|
-
res.end(JSON.stringify({ error: error.message }));
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
async handlePostActivityExecute(req, res, activityId) {
|
|
935
|
-
try {
|
|
936
|
-
const result = await this.activityManager.executeActivity(activityId);
|
|
937
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
938
|
-
res.end(JSON.stringify(result));
|
|
939
|
-
} catch (error) {
|
|
940
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
941
|
-
res.end(JSON.stringify({ error: error.message }));
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
async handlePostActivityStop(req, res, activityId) {
|
|
946
|
-
try {
|
|
947
|
-
const result = await this.activityManager.stopActivity(activityId);
|
|
948
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
949
|
-
res.end(JSON.stringify(result));
|
|
950
|
-
} catch (error) {
|
|
951
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
952
|
-
res.end(JSON.stringify({ error: error.message }));
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
|
|
956
821
|
async handleOpenFile(req, res) {
|
|
957
822
|
try {
|
|
958
823
|
const body = await this.getRequestBody(req);
|
package/lib/mcp-server.js
CHANGED
|
@@ -578,36 +578,6 @@ export class MCPServer {
|
|
|
578
578
|
required: ['path', 'content']
|
|
579
579
|
}
|
|
580
580
|
},
|
|
581
|
-
{
|
|
582
|
-
name: 'manage_activities',
|
|
583
|
-
description: 'CRUD operations for project activities',
|
|
584
|
-
inputSchema: {
|
|
585
|
-
type: 'object',
|
|
586
|
-
properties: {
|
|
587
|
-
action: {
|
|
588
|
-
type: 'string',
|
|
589
|
-
enum: ['list', 'get', 'create', 'update', 'delete'],
|
|
590
|
-
description: 'Action to perform on activities'
|
|
591
|
-
},
|
|
592
|
-
activityId: {
|
|
593
|
-
type: 'string',
|
|
594
|
-
description: 'Activity ID (required for get, update, delete)'
|
|
595
|
-
},
|
|
596
|
-
activity: {
|
|
597
|
-
type: 'object',
|
|
598
|
-
description: 'Activity data (required for create, update)',
|
|
599
|
-
properties: {
|
|
600
|
-
title: { type: 'string' },
|
|
601
|
-
description: { type: 'string' },
|
|
602
|
-
status: { type: 'string', enum: ['todo', 'in_progress', 'completed', 'blocked'] },
|
|
603
|
-
tags: { type: 'array', items: { type: 'string' } },
|
|
604
|
-
tasks: { type: 'array', items: { type: 'object' } }
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
},
|
|
608
|
-
required: ['action']
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
581
|
];
|
|
612
582
|
|
|
613
583
|
return this.createSuccessResponse(id, { tools });
|
|
@@ -676,9 +646,6 @@ export class MCPServer {
|
|
|
676
646
|
case 'write_file':
|
|
677
647
|
return this.toolWriteFile(args, id);
|
|
678
648
|
|
|
679
|
-
case 'manage_activities':
|
|
680
|
-
return this.toolManageActivities(args, id);
|
|
681
|
-
|
|
682
649
|
default:
|
|
683
650
|
return this.createErrorResponse(id, -32602, 'Unknown tool');
|
|
684
651
|
}
|
|
@@ -1369,119 +1336,6 @@ ${Array.from(this.cntxServer.bundles.entries()).map(([name, bundle]) =>
|
|
|
1369
1336
|
}
|
|
1370
1337
|
}
|
|
1371
1338
|
|
|
1372
|
-
async toolManageActivities(args, id) {
|
|
1373
|
-
const { action, activityId, activity } = args;
|
|
1374
|
-
|
|
1375
|
-
if (!action) {
|
|
1376
|
-
return this.createErrorResponse(id, -32602, 'Action is required');
|
|
1377
|
-
}
|
|
1378
|
-
|
|
1379
|
-
try {
|
|
1380
|
-
const activitiesPath = join(this.cntxServer.CWD, '.cntx', 'activities');
|
|
1381
|
-
const activitiesJsonPath = join(activitiesPath, 'activities.json');
|
|
1382
|
-
|
|
1383
|
-
let activities = [];
|
|
1384
|
-
if (existsSync(activitiesJsonPath)) {
|
|
1385
|
-
activities = JSON.parse(readFileSync(activitiesJsonPath, 'utf8'));
|
|
1386
|
-
}
|
|
1387
|
-
|
|
1388
|
-
let result;
|
|
1389
|
-
|
|
1390
|
-
switch (action) {
|
|
1391
|
-
case 'list':
|
|
1392
|
-
result = { activities: activities.map(a => ({
|
|
1393
|
-
id: a.title.toLowerCase().replace(/[^a-z0-9]/g, '-'),
|
|
1394
|
-
title: a.title,
|
|
1395
|
-
description: a.description,
|
|
1396
|
-
status: a.status,
|
|
1397
|
-
tags: a.tags
|
|
1398
|
-
})) };
|
|
1399
|
-
break;
|
|
1400
|
-
|
|
1401
|
-
case 'get':
|
|
1402
|
-
if (!activityId) {
|
|
1403
|
-
return this.createErrorResponse(id, -32602, 'Activity ID is required for get action');
|
|
1404
|
-
}
|
|
1405
|
-
const found = activities.find(a =>
|
|
1406
|
-
a.title.toLowerCase().replace(/[^a-z0-9]/g, '-') === activityId
|
|
1407
|
-
);
|
|
1408
|
-
if (!found) {
|
|
1409
|
-
return this.createErrorResponse(id, -32602, `Activity not found: ${activityId}`);
|
|
1410
|
-
}
|
|
1411
|
-
|
|
1412
|
-
// Load markdown files
|
|
1413
|
-
const activityDir = join(activitiesPath, 'activities', activityId);
|
|
1414
|
-
const files = {};
|
|
1415
|
-
['README.md', 'progress.md', 'tasks.md', 'notes.md'].forEach(file => {
|
|
1416
|
-
const filePath = join(activityDir, file);
|
|
1417
|
-
files[file.replace('.md', '')] = existsSync(filePath)
|
|
1418
|
-
? readFileSync(filePath, 'utf8')
|
|
1419
|
-
: 'No content available';
|
|
1420
|
-
});
|
|
1421
|
-
|
|
1422
|
-
result = { ...found, files };
|
|
1423
|
-
break;
|
|
1424
|
-
|
|
1425
|
-
case 'create':
|
|
1426
|
-
if (!activity || !activity.title) {
|
|
1427
|
-
return this.createErrorResponse(id, -32602, 'Activity with title is required for create action');
|
|
1428
|
-
}
|
|
1429
|
-
activities.push({
|
|
1430
|
-
title: activity.title,
|
|
1431
|
-
description: activity.description || '',
|
|
1432
|
-
status: activity.status || 'todo',
|
|
1433
|
-
tags: activity.tags || ['general'],
|
|
1434
|
-
tasks: activity.tasks || []
|
|
1435
|
-
});
|
|
1436
|
-
writeFileSync(activitiesJsonPath, JSON.stringify(activities, null, 2));
|
|
1437
|
-
result = { created: true, activityId: activity.title.toLowerCase().replace(/[^a-z0-9]/g, '-') };
|
|
1438
|
-
break;
|
|
1439
|
-
|
|
1440
|
-
case 'update':
|
|
1441
|
-
if (!activityId || !activity) {
|
|
1442
|
-
return this.createErrorResponse(id, -32602, 'Activity ID and activity data are required for update action');
|
|
1443
|
-
}
|
|
1444
|
-
const updateIndex = activities.findIndex(a =>
|
|
1445
|
-
a.title.toLowerCase().replace(/[^a-z0-9]/g, '-') === activityId
|
|
1446
|
-
);
|
|
1447
|
-
if (updateIndex === -1) {
|
|
1448
|
-
return this.createErrorResponse(id, -32602, `Activity not found: ${activityId}`);
|
|
1449
|
-
}
|
|
1450
|
-
activities[updateIndex] = { ...activities[updateIndex], ...activity };
|
|
1451
|
-
writeFileSync(activitiesJsonPath, JSON.stringify(activities, null, 2));
|
|
1452
|
-
result = { updated: true };
|
|
1453
|
-
break;
|
|
1454
|
-
|
|
1455
|
-
case 'delete':
|
|
1456
|
-
if (!activityId) {
|
|
1457
|
-
return this.createErrorResponse(id, -32602, 'Activity ID is required for delete action');
|
|
1458
|
-
}
|
|
1459
|
-
const deleteIndex = activities.findIndex(a =>
|
|
1460
|
-
a.title.toLowerCase().replace(/[^a-z0-9]/g, '-') === activityId
|
|
1461
|
-
);
|
|
1462
|
-
if (deleteIndex === -1) {
|
|
1463
|
-
return this.createErrorResponse(id, -32602, `Activity not found: ${activityId}`);
|
|
1464
|
-
}
|
|
1465
|
-
activities.splice(deleteIndex, 1);
|
|
1466
|
-
writeFileSync(activitiesJsonPath, JSON.stringify(activities, null, 2));
|
|
1467
|
-
result = { deleted: true };
|
|
1468
|
-
break;
|
|
1469
|
-
|
|
1470
|
-
default:
|
|
1471
|
-
return this.createErrorResponse(id, -32602, `Unknown action: ${action}`);
|
|
1472
|
-
}
|
|
1473
|
-
|
|
1474
|
-
return this.createSuccessResponse(id, {
|
|
1475
|
-
content: [{
|
|
1476
|
-
type: 'text',
|
|
1477
|
-
text: JSON.stringify(result, null, 2)
|
|
1478
|
-
}]
|
|
1479
|
-
});
|
|
1480
|
-
} catch (error) {
|
|
1481
|
-
return this.createErrorResponse(id, -32603, 'Failed to manage activities', error.message);
|
|
1482
|
-
}
|
|
1483
|
-
}
|
|
1484
|
-
|
|
1485
1339
|
// Helper methods
|
|
1486
1340
|
getMimeType(filePath) {
|
|
1487
1341
|
const ext = filePath.split('.').pop()?.toLowerCase();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cntx-ui",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.0.
|
|
4
|
+
"version": "3.0.7",
|
|
5
5
|
"description": "Autonomous Repository Intelligence engine with web UI and MCP server. Unified semantic code understanding, local RAG, and agent working memory.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"repository-intelligence",
|