dev-mcp-server 0.0.2 → 1.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 (58) hide show
  1. package/.env.example +23 -55
  2. package/README.md +609 -219
  3. package/cli.js +486 -160
  4. package/package.json +2 -2
  5. package/src/agents/BaseAgent.js +113 -0
  6. package/src/agents/dreamer.js +165 -0
  7. package/src/agents/improver.js +175 -0
  8. package/src/agents/specialists.js +202 -0
  9. package/src/agents/taskDecomposer.js +176 -0
  10. package/src/agents/teamCoordinator.js +153 -0
  11. package/src/api/routes/agents.js +172 -0
  12. package/src/api/routes/extras.js +115 -0
  13. package/src/api/routes/git.js +72 -0
  14. package/src/api/routes/ingest.js +60 -40
  15. package/src/api/routes/knowledge.js +59 -41
  16. package/src/api/routes/memory.js +41 -0
  17. package/src/api/routes/newRoutes.js +168 -0
  18. package/src/api/routes/pipelines.js +41 -0
  19. package/src/api/routes/planner.js +54 -0
  20. package/src/api/routes/query.js +24 -0
  21. package/src/api/routes/sessions.js +54 -0
  22. package/src/api/routes/tasks.js +67 -0
  23. package/src/api/routes/tools.js +85 -0
  24. package/src/api/routes/v5routes.js +196 -0
  25. package/src/api/server.js +133 -5
  26. package/src/context/compactor.js +151 -0
  27. package/src/context/contextEngineer.js +181 -0
  28. package/src/context/contextVisualizer.js +140 -0
  29. package/src/core/conversationEngine.js +231 -0
  30. package/src/core/indexer.js +169 -143
  31. package/src/core/ingester.js +141 -126
  32. package/src/core/queryEngine.js +286 -236
  33. package/src/cron/cronScheduler.js +260 -0
  34. package/src/dashboard/index.html +1181 -0
  35. package/src/lsp/symbolNavigator.js +220 -0
  36. package/src/memory/memoryManager.js +186 -0
  37. package/src/memory/teamMemory.js +111 -0
  38. package/src/messaging/messageBus.js +177 -0
  39. package/src/monitor/proactiveMonitor.js +337 -0
  40. package/src/pipelines/pipelineEngine.js +230 -0
  41. package/src/planner/plannerEngine.js +202 -0
  42. package/src/plugins/builtin/stats-plugin.js +29 -0
  43. package/src/plugins/pluginManager.js +144 -0
  44. package/src/prompts/promptEngineer.js +289 -0
  45. package/src/sessions/sessionManager.js +166 -0
  46. package/src/skills/skillsManager.js +263 -0
  47. package/src/storage/store.js +127 -105
  48. package/src/tasks/taskManager.js +151 -0
  49. package/src/tools/BashTool.js +154 -0
  50. package/src/tools/FileEditTool.js +280 -0
  51. package/src/tools/GitTool.js +212 -0
  52. package/src/tools/GrepTool.js +199 -0
  53. package/src/tools/registry.js +1380 -0
  54. package/src/utils/costTracker.js +69 -0
  55. package/src/utils/fileParser.js +176 -153
  56. package/src/utils/llmClient.js +355 -206
  57. package/src/watcher/fileWatcher.js +137 -0
  58. package/src/worktrees/worktreeManager.js +176 -0
@@ -3,6 +3,11 @@ const router = express.Router();
3
3
  const { QueryEngine, QUERY_MODES } = require('../../core/queryEngine');
4
4
  const logger = require('../../utils/logger');
5
5
 
6
+ /**
7
+ * POST /api/query
8
+ * General question — auto-detects mode
9
+ * Body: { question, topK?, filter? }
10
+ */
6
11
  router.post('/', async (req, res) => {
7
12
  const { question, topK, filter, mode } = req.body;
8
13
 
@@ -19,6 +24,11 @@ router.post('/', async (req, res) => {
19
24
  }
20
25
  });
21
26
 
27
+ /**
28
+ * POST /api/query/debug
29
+ * "Why is this failing?"
30
+ * Body: { error, stackTrace?, topK? }
31
+ */
22
32
  router.post('/debug', async (req, res) => {
23
33
  const { error, stackTrace, question, topK } = req.body;
24
34
 
@@ -40,6 +50,11 @@ router.post('/debug', async (req, res) => {
40
50
  }
41
51
  });
42
52
 
53
+ /**
54
+ * POST /api/query/usage
55
+ * "Where is this used?"
56
+ * Body: { symbol, topK? }
57
+ */
43
58
  router.post('/usage', async (req, res) => {
44
59
  const { symbol, topK } = req.body;
45
60
 
@@ -56,6 +71,11 @@ router.post('/usage', async (req, res) => {
56
71
  }
57
72
  });
58
73
 
74
+ /**
75
+ * POST /api/query/impact
76
+ * "If I change this, what breaks?"
77
+ * Body: { target, changeDescription?, topK? }
78
+ */
59
79
  router.post('/impact', async (req, res) => {
60
80
  const { target, changeDescription, topK } = req.body;
61
81
 
@@ -72,6 +92,10 @@ router.post('/impact', async (req, res) => {
72
92
  }
73
93
  });
74
94
 
95
+ /**
96
+ * POST /api/query/stream
97
+ * Streaming version of general query (Server-Sent Events)
98
+ */
75
99
  router.post('/stream', async (req, res) => {
76
100
  const { question, topK, mode } = req.body;
77
101
 
@@ -0,0 +1,54 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const sessionManager = require('../../sessions/sessionManager');
4
+
5
+ /** GET /api/sessions — list all sessions */
6
+ router.get('/', (req, res) => {
7
+ res.json({ sessions: sessionManager.list() });
8
+ });
9
+
10
+ /** POST /api/sessions — create a new session */
11
+ router.post('/', (req, res) => {
12
+ const session = sessionManager.create(req.body);
13
+ res.status(201).json({ success: true, session });
14
+ });
15
+
16
+ /** GET /api/sessions/:id — get / resume a session */
17
+ router.get('/:id', (req, res) => {
18
+ try {
19
+ const session = sessionManager.resume(req.params.id);
20
+ res.json(session);
21
+ } catch (err) {
22
+ res.status(404).json({ error: err.message });
23
+ }
24
+ });
25
+
26
+ /** POST /api/sessions/:id/messages — append a message */
27
+ router.post('/:id/messages', (req, res) => {
28
+ try {
29
+ const session = sessionManager.addMessage(req.params.id, req.body);
30
+ res.json({ success: true, messageCount: session.messages.length });
31
+ } catch (err) {
32
+ res.status(404).json({ error: err.message });
33
+ }
34
+ });
35
+
36
+ /** GET /api/sessions/:id/export — export as markdown */
37
+ router.get('/:id/export', (req, res) => {
38
+ try {
39
+ const md = sessionManager.exportMarkdown(req.params.id);
40
+ res.setHeader('Content-Type', 'text/markdown');
41
+ res.setHeader('Content-Disposition', `attachment; filename="session-${req.params.id}.md"`);
42
+ res.send(md);
43
+ } catch (err) {
44
+ res.status(404).json({ error: err.message });
45
+ }
46
+ });
47
+
48
+ /** DELETE /api/sessions/:id */
49
+ router.delete('/:id', (req, res) => {
50
+ const deleted = sessionManager.delete(req.params.id);
51
+ res.json({ success: deleted });
52
+ });
53
+
54
+ module.exports = router;
@@ -0,0 +1,67 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const { TaskManager, STATUS, PRIORITY } = require('../../tasks/taskManager');
4
+
5
+ /** GET /api/tasks */
6
+ router.get('/', (req, res) => {
7
+ const { status, priority, tags, assignee, includeDone } = req.query;
8
+ const tasks = TaskManager.list({
9
+ status, priority,
10
+ tags: tags ? tags.split(',') : undefined,
11
+ assignee,
12
+ includeDone: includeDone === 'true',
13
+ });
14
+ res.json({ tasks, stats: TaskManager.getStats() });
15
+ });
16
+
17
+ /** POST /api/tasks */
18
+ router.post('/', (req, res) => {
19
+ try {
20
+ const task = TaskManager.create(req.body);
21
+ res.status(201).json({ success: true, task });
22
+ } catch (err) {
23
+ res.status(400).json({ error: err.message });
24
+ }
25
+ });
26
+
27
+ /** GET /api/tasks/:id */
28
+ router.get('/:id', (req, res) => {
29
+ const task = TaskManager.get(parseInt(req.params.id));
30
+ if (!task) return res.status(404).json({ error: 'Task not found' });
31
+ res.json(task);
32
+ });
33
+
34
+ /** PATCH /api/tasks/:id */
35
+ router.patch('/:id', (req, res) => {
36
+ try {
37
+ const task = TaskManager.update(parseInt(req.params.id), req.body);
38
+ res.json({ success: true, task });
39
+ } catch (err) {
40
+ res.status(400).json({ error: err.message });
41
+ }
42
+ });
43
+
44
+ /** POST /api/tasks/:id/notes */
45
+ router.post('/:id/notes', (req, res) => {
46
+ const { note } = req.body;
47
+ if (!note) return res.status(400).json({ error: 'note is required' });
48
+ try {
49
+ const task = TaskManager.addNote(parseInt(req.params.id), note);
50
+ res.json({ success: true, task });
51
+ } catch (err) {
52
+ res.status(400).json({ error: err.message });
53
+ }
54
+ });
55
+
56
+ /** DELETE /api/tasks/:id */
57
+ router.delete('/:id', (req, res) => {
58
+ const deleted = TaskManager.delete(parseInt(req.params.id));
59
+ res.json({ success: deleted });
60
+ });
61
+
62
+ /** GET /api/tasks/meta/constants */
63
+ router.get('/meta/constants', (req, res) => {
64
+ res.json({ STATUS, PRIORITY });
65
+ });
66
+
67
+ module.exports = router;
@@ -0,0 +1,85 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const BashTool = require('../../tools/BashTool');
4
+ const GrepTool = require('../../tools/GrepTool');
5
+ const logger = require('../../utils/logger');
6
+
7
+ /** POST /api/tools/bash — execute a shell command */
8
+ router.post('/bash', async (req, res) => {
9
+ const { command, cwd, timeout, approved } = req.body;
10
+ if (!command) return res.status(400).json({ error: 'command is required' });
11
+
12
+ const permission = BashTool.checkPermission(command);
13
+ if (permission === 'dangerous') {
14
+ return res.status(403).json({ error: 'Command blocked: dangerous pattern detected', permission });
15
+ }
16
+ if (permission === 'needs-approval' && !approved) {
17
+ return res.status(202).json({ needsApproval: true, command, permission,
18
+ message: 'Set approved:true in body to execute, or grant permission via /api/tools/bash/permit' });
19
+ }
20
+
21
+ try {
22
+ const result = await BashTool.execute(command, { cwd, timeout, approved: true });
23
+ res.json(result);
24
+ } catch (err) {
25
+ res.status(500).json({ error: err.message });
26
+ }
27
+ });
28
+
29
+ /** POST /api/tools/bash/permit — grant permission for a command */
30
+ router.post('/bash/permit', (req, res) => {
31
+ const { command, level } = req.body;
32
+ if (!command) return res.status(400).json({ error: 'command is required' });
33
+ BashTool.grantPermission(command, level || 'session');
34
+ res.json({ success: true, command, level: level || 'session' });
35
+ });
36
+
37
+ /** GET /api/tools/grep — search codebase */
38
+ router.get('/grep', async (req, res) => {
39
+ const { pattern, cwd, glob, ignoreCase, maxResults, contextLines, literal } = req.query;
40
+ if (!pattern) return res.status(400).json({ error: 'pattern is required' });
41
+
42
+ try {
43
+ const result = await GrepTool.search(pattern, {
44
+ cwd, glob, ignoreCase: ignoreCase === 'true',
45
+ maxResults: parseInt(maxResults) || 50,
46
+ contextLines: parseInt(contextLines) || 2,
47
+ literal: literal === 'true',
48
+ });
49
+ res.json(result);
50
+ } catch (err) {
51
+ res.status(500).json({ error: err.message });
52
+ }
53
+ });
54
+
55
+ /** GET /api/tools/grep/definitions/:symbol — find symbol definitions */
56
+ router.get('/grep/definitions/:symbol', async (req, res) => {
57
+ try {
58
+ const matches = await GrepTool.findDefinitions(req.params.symbol, req.query.cwd);
59
+ res.json({ symbol: req.params.symbol, matches, count: matches.length });
60
+ } catch (err) {
61
+ res.status(500).json({ error: err.message });
62
+ }
63
+ });
64
+
65
+ /** GET /api/tools/grep/imports/:module — find all imports of a module */
66
+ router.get('/grep/imports/:module', async (req, res) => {
67
+ try {
68
+ const result = await GrepTool.findImports(req.params.module, req.query.cwd);
69
+ res.json(result);
70
+ } catch (err) {
71
+ res.status(500).json({ error: err.message });
72
+ }
73
+ });
74
+
75
+ /** GET /api/tools/grep/todos — find all TODO/FIXME comments */
76
+ router.get('/grep/todos', async (req, res) => {
77
+ try {
78
+ const result = await GrepTool.findTodos(req.query.cwd);
79
+ res.json(result);
80
+ } catch (err) {
81
+ res.status(500).json({ error: err.message });
82
+ }
83
+ });
84
+
85
+ module.exports = router;
@@ -0,0 +1,196 @@
1
+ 'use strict';
2
+ const express = require('express');
3
+ const logger = require('../../utils/logger');
4
+
5
+ // ── PLUGINS ───────────────────────────────────────────────────────────────────
6
+ const pluginsRouter = express.Router();
7
+ const pluginManager = require('../../plugins/pluginManager');
8
+
9
+ pluginsRouter.get('/', (req, res) => res.json({ plugins: pluginManager.list(), stats: pluginManager.getStats() }));
10
+ pluginsRouter.get('/:name', (req, res) => {
11
+ const p = pluginManager.get(req.params.name);
12
+ if (!p) return res.status(404).json({ error: 'Plugin not found' });
13
+ res.json(p);
14
+ });
15
+ pluginsRouter.post('/:name/enable', (req, res) => {
16
+ try { res.json(pluginManager.enable(req.params.name)); }
17
+ catch (e) { res.status(400).json({ error: e.message }); }
18
+ });
19
+ pluginsRouter.post('/:name/disable', (req, res) => {
20
+ try { res.json(pluginManager.disable(req.params.name)); }
21
+ catch (e) { res.status(400).json({ error: e.message }); }
22
+ });
23
+
24
+ module.exports.pluginsRouter = pluginsRouter;
25
+
26
+ // ── WORKTREES ─────────────────────────────────────────────────────────────────
27
+ const worktreesRouter = express.Router();
28
+ const wm = require('../../worktrees/worktreeManager');
29
+
30
+ worktreesRouter.get('/', async (req, res) => {
31
+ try { res.json({ worktrees: await wm.list(req.query.cwd), stats: wm.getStats() }); }
32
+ catch (e) { res.status(500).json({ error: e.message }); }
33
+ });
34
+ worktreesRouter.post('/', async (req, res) => {
35
+ const { name, branch, cwd, createBranch } = req.body;
36
+ if (!name || !branch) return res.status(400).json({ error: 'name and branch required' });
37
+ try { res.status(201).json(await wm.create(name, branch, { cwd, createBranch })); }
38
+ catch (e) { res.status(500).json({ error: e.message }); }
39
+ });
40
+ worktreesRouter.get('/:name', (req, res) => {
41
+ const wt = wm.get(req.params.name);
42
+ if (!wt) return res.status(404).json({ error: 'Worktree not found' });
43
+ res.json(wt);
44
+ });
45
+ worktreesRouter.get('/:name/diff', async (req, res) => {
46
+ try { res.json(await wm.diff(req.params.name)); }
47
+ catch (e) { res.status(500).json({ error: e.message }); }
48
+ });
49
+ worktreesRouter.get('/:name/log', async (req, res) => {
50
+ try { res.json({ log: await wm.log(req.params.name, req.query.limit) }); }
51
+ catch (e) { res.status(500).json({ error: e.message }); }
52
+ });
53
+ worktreesRouter.post('/:name/commit', async (req, res) => {
54
+ try { res.json(await wm.commit(req.params.name, req.body.message)); }
55
+ catch (e) { res.status(500).json({ error: e.message }); }
56
+ });
57
+ worktreesRouter.delete('/:name', async (req, res) => {
58
+ try { res.json(await wm.remove(req.params.name, { force: req.query.force === 'true' })); }
59
+ catch (e) { res.status(500).json({ error: e.message }); }
60
+ });
61
+
62
+ module.exports.worktreesRouter = worktreesRouter;
63
+
64
+ // ── CRON ──────────────────────────────────────────────────────────────────────
65
+ const cronRouter = express.Router();
66
+ const cron = require('../../cron/cronScheduler');
67
+
68
+ cronRouter.get('/', (req, res) => res.json({ jobs: cron.list(), stats: cron.getStats() }));
69
+ cronRouter.post('/', (req, res) => {
70
+ try { res.status(201).json(cron.create(req.body)); }
71
+ catch (e) { res.status(400).json({ error: e.message }); }
72
+ });
73
+ cronRouter.get('/:name', (req, res) => {
74
+ const job = cron.list().find(j => j.name === req.params.name);
75
+ if (!job) return res.status(404).json({ error: 'Job not found' });
76
+ res.json(job);
77
+ });
78
+ cronRouter.patch('/:name', (req, res) => {
79
+ try { res.json(cron.update(req.params.name, req.body)); }
80
+ catch (e) { res.status(400).json({ error: e.message }); }
81
+ });
82
+ cronRouter.post('/:name/run', async (req, res) => {
83
+ try { res.json(await cron.runNow(req.params.name)); }
84
+ catch (e) { res.status(500).json({ error: e.message }); }
85
+ });
86
+ cronRouter.get('/:name/history', (req, res) => {
87
+ res.json({ runs: cron.getRunHistory(req.params.name, req.query.limit) });
88
+ });
89
+ cronRouter.delete('/:name', (req, res) => {
90
+ try { res.json({ success: cron.delete(req.params.name) }); }
91
+ catch (e) { res.status(400).json({ error: e.message }); }
92
+ });
93
+
94
+ module.exports.cronRouter = cronRouter;
95
+
96
+ // ── MESSAGING ─────────────────────────────────────────────────────────────────
97
+ const messagesRouter = express.Router();
98
+ const { MessageBus, PRIORITY } = require('../../messaging/messageBus');
99
+
100
+ messagesRouter.post('/', (req, res) => {
101
+ try { res.status(201).json(MessageBus.send(req.body)); }
102
+ catch (e) { res.status(400).json({ error: e.message }); }
103
+ });
104
+ messagesRouter.post('/broadcast', (req, res) => {
105
+ try { res.json({ messages: MessageBus.broadcast(req.body) }); }
106
+ catch (e) { res.status(400).json({ error: e.message }); }
107
+ });
108
+ messagesRouter.get('/inbox/:agent', (req, res) => {
109
+ res.json({
110
+ messages: MessageBus.inbox(req.params.agent, {
111
+ unreadOnly: req.query.unread === 'true',
112
+ priority: req.query.priority,
113
+ limit: parseInt(req.query.limit) || 50,
114
+ }),
115
+ });
116
+ });
117
+ messagesRouter.get('/sent/:agent', (req, res) => {
118
+ res.json({ messages: MessageBus.sentBy(req.params.agent) });
119
+ });
120
+ messagesRouter.post('/:id/read', (req, res) => {
121
+ try { res.json(MessageBus.markRead(parseInt(req.params.id))); }
122
+ catch (e) { res.status(404).json({ error: e.message }); }
123
+ });
124
+ messagesRouter.post('/inbox/:agent/read-all', (req, res) => {
125
+ res.json({ read: MessageBus.markAllRead(req.params.agent) });
126
+ });
127
+ messagesRouter.post('/:id/reply', (req, res) => {
128
+ try { res.json(MessageBus.reply(parseInt(req.params.id), req.body)); }
129
+ catch (e) { res.status(400).json({ error: e.message }); }
130
+ });
131
+ messagesRouter.delete('/:id', (req, res) => {
132
+ res.json({ success: MessageBus.delete(parseInt(req.params.id)) });
133
+ });
134
+ messagesRouter.get('/stats/overview', (req, res) => {
135
+ res.json({ stats: MessageBus.getStats(), priorities: PRIORITY });
136
+ });
137
+
138
+ module.exports.messagesRouter = messagesRouter;
139
+
140
+ // ── TEAM MEMORY ───────────────────────────────────────────────────────────────
141
+ const teamMemRouter = express.Router();
142
+ const teamMemory = require('../../memory/teamMemory');
143
+
144
+ teamMemRouter.get('/', (req, res) => {
145
+ const entries = teamMemory.get(req.query.team || 'global', {
146
+ type: req.query.type,
147
+ limit: parseInt(req.query.limit) || 50,
148
+ });
149
+ res.json({ entries, stats: teamMemory.getStats() });
150
+ });
151
+ teamMemRouter.post('/', (req, res) => {
152
+ try { res.status(201).json(teamMemory.add(req.body)); }
153
+ catch (e) { res.status(400).json({ error: e.message }); }
154
+ });
155
+ teamMemRouter.get('/search', (req, res) => {
156
+ if (!req.query.q) return res.status(400).json({ error: 'q required' });
157
+ res.json({ results: teamMemory.search(req.query.q, req.query.team) });
158
+ });
159
+ teamMemRouter.get('/teams', (req, res) => {
160
+ res.json({ teams: teamMemory.listTeams() });
161
+ });
162
+ teamMemRouter.delete('/:id', (req, res) => {
163
+ res.json({ success: teamMemory.delete(req.params.id) });
164
+ });
165
+ teamMemRouter.delete('/', (req, res) => {
166
+ if (!req.query.team) return res.status(400).json({ error: 'team query param required' });
167
+ teamMemory.clearTeam(req.query.team);
168
+ res.json({ success: true });
169
+ });
170
+
171
+ module.exports.teamMemRouter = teamMemRouter;
172
+
173
+ // ── CONTEXT VISUALIZER ────────────────────────────────────────────────────────
174
+ const contextVizRouter = express.Router();
175
+ const contextVisualizer = require('../../context/contextVisualizer');
176
+
177
+ contextVizRouter.post('/visualize', (req, res) => {
178
+ const { query, mode, topK, team } = req.body;
179
+ if (!query) return res.status(400).json({ error: 'query required' });
180
+ try {
181
+ const viz = contextVisualizer.visualize(query, { mode, topK, team });
182
+ res.json(viz);
183
+ } catch (e) { res.status(500).json({ error: e.message }); }
184
+ });
185
+
186
+ contextVizRouter.post('/visualize/text', (req, res) => {
187
+ const { query, mode, topK } = req.body;
188
+ if (!query) return res.status(400).json({ error: 'query required' });
189
+ try {
190
+ const viz = contextVisualizer.visualize(query, { mode, topK });
191
+ const text = contextVisualizer.format(viz);
192
+ res.type('text/plain').send(text);
193
+ } catch (e) { res.status(500).json({ error: e.message }); }
194
+ });
195
+
196
+ module.exports.contextVizRouter = contextVizRouter;
package/src/api/server.js CHANGED
@@ -1,29 +1,79 @@
1
- const path = require('path');
2
- require('dotenv').config({ path: path.resolve(process.cwd(), '.env') });
1
+ require('dotenv').config();
3
2
  const express = require('express');
4
3
  const cors = require('cors');
5
4
  const morgan = require('morgan');
6
5
  const logger = require('../utils/logger');
7
- const indexer = require('../core/indexer');
6
+ const dreamer = require('../agents/dreamer');
7
+ const improver = require('../agents/improver');
8
+ const cronScheduler = require('../cron/cronScheduler');
9
+ const pluginManager = require('../plugins/pluginManager');
10
+ const llm = require('../utils/llmClient');
8
11
  const store = require('../storage/store');
9
12
 
13
+ // Routes
10
14
  const ingestRoutes = require('./routes/ingest');
11
15
  const queryRoutes = require('./routes/query');
12
16
  const knowledgeRoutes = require('./routes/knowledge');
17
+ const gitRoutes = require('./routes/git');
18
+ const toolsRoutes = require('./routes/tools');
19
+ const memoryRoutes = require('./routes/memory');
20
+ const tasksRoutes = require('./routes/tasks');
21
+ const sessionsRoutes = require('./routes/sessions');
22
+ const plannerRoutes = require('./routes/planner');
23
+ const agentsRoutes = require('./routes/agents');
24
+ const pipelinesRoutes = require('./routes/pipelines');
25
+ const { skillsRouter, lspRouter, filesRouter, monitorRouter, convRouter, watcherRouter } = require('./routes/newRoutes');
26
+ const { toolsRegistryRouter, promptsRouter, compactorRouter } = require('./routes/extras');
27
+ const { pluginsRouter, worktreesRouter, cronRouter, messagesRouter, teamMemRouter, contextVizRouter } = require('./routes/v5routes');
13
28
 
14
29
  const app = express();
15
30
  const PORT = process.env.PORT || 3000;
16
31
 
32
+ // ── Middleware ────────────────────────────────────────────────
17
33
  app.use(cors());
18
34
  app.use(express.json({ limit: '10mb' }));
19
35
  app.use(morgan('dev', {
20
36
  stream: { write: (msg) => logger.info(msg.trim()) },
21
37
  }));
22
38
 
39
+ // ── Routes ────────────────────────────────────────────────────
23
40
  app.use('/api/ingest', ingestRoutes);
24
41
  app.use('/api/query', queryRoutes);
25
42
  app.use('/api/knowledge', knowledgeRoutes);
43
+ app.use('/api/git', gitRoutes);
44
+ app.use('/api/tools', toolsRoutes);
45
+ app.use('/api/memory', memoryRoutes);
46
+ app.use('/api/tasks', tasksRoutes);
47
+ app.use('/api/sessions', sessionsRoutes);
48
+ app.use('/api', plannerRoutes); // /api/plan, /api/cost
49
+ app.use('/api/agents', agentsRoutes);
50
+ app.use('/api/pipelines', pipelinesRoutes);
51
+ app.use('/api/skills', skillsRouter);
52
+ app.use('/api/lsp', lspRouter);
53
+ app.use('/api/files', filesRouter);
54
+ app.use('/api/monitor', monitorRouter);
55
+ app.use('/api/chat', convRouter);
56
+ app.use('/api/watcher', watcherRouter);
57
+ app.use('/api/registry', toolsRegistryRouter);
58
+ app.use('/api/prompts', promptsRouter);
59
+ app.use('/api/compact', compactorRouter);
60
+ app.use('/api/plugins', pluginsRouter);
61
+ app.use('/api/worktrees', worktreesRouter);
62
+ app.use('/api/cron', cronRouter);
63
+ app.use('/api/messages', messagesRouter);
64
+ app.use('/api/team-memory', teamMemRouter);
65
+ app.use('/api/context', contextVizRouter);
66
+
67
+ // ── Dashboard (single-file HTML UI) ──────────────────────────────────────────
68
+ const path = require('path');
69
+ app.get('/dashboard', (req, res) => {
70
+ res.sendFile(path.join(__dirname, '../dashboard/index.html'));
71
+ });
72
+
73
+ // ── LLM provider info ────────────────────────────────────────────────────────
74
+ app.get('/api/llm/info', (req, res) => res.json(llm.getInfo()));
26
75
 
76
+ // ── Health check ──────────────────────────────────────────────
27
77
  app.get('/health', (req, res) => {
28
78
  const stats = store.getStats();
29
79
  res.json({
@@ -34,11 +84,12 @@ app.get('/health', (req, res) => {
34
84
  });
35
85
  });
36
86
 
87
+ // ── Root info ─────────────────────────────────────────────────
37
88
  app.get('/', (req, res) => {
38
89
  res.json({
39
90
  name: 'Dev MCP Server — Model Context Platform',
40
91
  version: '1.0.0',
41
- description: 'AI that understands YOUR codebase',
92
+ description: '45 tools · 10 agents · 10 teams · Dreamer · Compactor · Prompt Engineering · Plugins · Cron · Worktrees · Messaging',
42
93
  endpoints: {
43
94
  health: 'GET /health',
44
95
  ingest: {
@@ -61,31 +112,108 @@ app.get('/', (req, res) => {
61
112
  files: 'GET /api/knowledge/files',
62
113
  rebuild: 'POST /api/knowledge/rebuild',
63
114
  },
115
+ git: {
116
+ status: 'GET /api/git/status',
117
+ diff: 'GET /api/git/diff',
118
+ commit: 'POST /api/git/commit',
119
+ review: 'POST /api/git/review',
120
+ log: 'GET /api/git/log',
121
+ branches: 'GET /api/git/branches',
122
+ },
123
+ tools: {
124
+ bash: 'POST /api/tools/bash',
125
+ bashPermit: 'POST /api/tools/bash/permit',
126
+ grep: 'GET /api/tools/grep?pattern=<pattern>',
127
+ definitions: 'GET /api/tools/grep/definitions/:symbol',
128
+ imports: 'GET /api/tools/grep/imports/:module',
129
+ todos: 'GET /api/tools/grep/todos',
130
+ },
131
+ memory: {
132
+ list: 'GET /api/memory',
133
+ add: 'POST /api/memory',
134
+ delete: 'DELETE /api/memory/:id',
135
+ clear: 'DELETE /api/memory',
136
+ },
137
+ tasks: {
138
+ list: 'GET /api/tasks',
139
+ create: 'POST /api/tasks',
140
+ get: 'GET /api/tasks/:id',
141
+ update: 'PATCH /api/tasks/:id',
142
+ addNote: 'POST /api/tasks/:id/notes',
143
+ delete: 'DELETE /api/tasks/:id',
144
+ },
145
+ sessions: {
146
+ list: 'GET /api/sessions',
147
+ create: 'POST /api/sessions',
148
+ resume: 'GET /api/sessions/:id',
149
+ addMessage: 'POST /api/sessions/:id/messages',
150
+ export: 'GET /api/sessions/:id/export',
151
+ delete: 'DELETE /api/sessions/:id',
152
+ },
153
+ planner: {
154
+ plan: 'POST /api/plan',
155
+ compact: 'POST /api/plan/compact',
156
+ doctor: 'GET /api/plan/doctor',
157
+ cost: 'GET /api/cost',
158
+ },
64
159
  },
65
160
  });
66
161
  });
67
162
 
163
+ // ── 404 ───────────────────────────────────────────────────────
68
164
  app.use((req, res) => {
69
165
  res.status(404).json({ error: `Route not found: ${req.method} ${req.path}` });
70
166
  });
71
167
 
168
+ // ── Error handler ─────────────────────────────────────────────
72
169
  app.use((err, req, res, next) => {
73
170
  logger.error(`Unhandled error: ${err.message}`);
74
171
  res.status(500).json({ error: 'Internal server error', detail: err.message });
75
172
  });
76
173
 
77
- app.listen(PORT, () => {
174
+ // ── Boot ──────────────────────────────────────────────────────
175
+ app.listen(PORT, async () => {
78
176
  logger.info(`🚀 Dev MCP Server running on http://localhost:${PORT}`);
79
177
  logger.info(`📚 Knowledge base: ${store.getStats().totalDocs} documents`);
80
178
 
179
+ // Auto-build index if data exists
81
180
  const stats = store.getStats();
82
181
  if (stats.totalDocs > 0) {
83
182
  logger.info('🔍 Rebuilding search index...');
183
+ const indexer = require('../core/indexer');
84
184
  const count = indexer.build();
85
185
  logger.info(`✅ Index ready: ${count} documents`);
86
186
  } else {
87
187
  logger.info('📭 Knowledge base is empty — run: node cli.js ingest <path>');
88
188
  }
189
+
190
+ // Start the Dreamer for background cognitive work
191
+ if (process.env.ENABLE_DREAMER !== 'false') {
192
+ const intervalMin = parseInt(process.env.DREAM_INTERVAL_MINUTES) || 30;
193
+ dreamer.start(intervalMin);
194
+ logger.info(`💤 Dreamer started (every ${intervalMin} min)`);
195
+ }
196
+
197
+ // Start Cron Scheduler
198
+ if (process.env.ENABLE_CRON !== 'false') {
199
+ cronScheduler.start();
200
+ logger.info(`⏰ Cron scheduler started`);
201
+ }
202
+
203
+ // Load Plugins
204
+ const toolRegistry = require('../tools/registry');
205
+ await pluginManager.loadAll(app, {
206
+ toolRegistry,
207
+ store,
208
+ indexer: require('../core/indexer'),
209
+ memoryManager: require('../memory/memoryManager').MemoryManager,
210
+ });
211
+ logger.info(`🔌 Plugins: ${pluginManager.getStats().enabled} enabled`);
212
+ if (process.env.ENABLE_MONITOR !== 'false') {
213
+ const { ProactiveMonitor } = require('../monitor/proactiveMonitor');
214
+ ProactiveMonitor.start(process.cwd());
215
+ logger.info(`👁️ Proactive monitor started`);
216
+ }
89
217
  });
90
218
 
91
219
  module.exports = app;