ultra-dex 2.2.1 → 3.1.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 (54) hide show
  1. package/README.md +84 -128
  2. package/assets/agents/00-AGENT_INDEX.md +1 -1
  3. package/assets/docs/LAUNCH-POSTS.md +1 -1
  4. package/assets/docs/QUICK-REFERENCE.md +9 -4
  5. package/assets/docs/VISION-V2.md +1 -1
  6. package/assets/hooks/pre-commit +98 -0
  7. package/assets/saas-plan/04-Imp-Template.md +1 -1
  8. package/bin/ultra-dex.js +95 -4
  9. package/lib/commands/advanced.js +471 -0
  10. package/lib/commands/agent-builder.js +226 -0
  11. package/lib/commands/agents.js +99 -42
  12. package/lib/commands/auto-implement.js +68 -0
  13. package/lib/commands/build.js +73 -187
  14. package/lib/commands/ci-monitor.js +84 -0
  15. package/lib/commands/config.js +207 -0
  16. package/lib/commands/dashboard.js +770 -0
  17. package/lib/commands/diff.js +233 -0
  18. package/lib/commands/doctor.js +397 -0
  19. package/lib/commands/export.js +408 -0
  20. package/lib/commands/fix.js +96 -0
  21. package/lib/commands/generate.js +96 -72
  22. package/lib/commands/hooks.js +251 -76
  23. package/lib/commands/init.js +53 -1
  24. package/lib/commands/memory.js +80 -0
  25. package/lib/commands/plan.js +82 -0
  26. package/lib/commands/review.js +34 -5
  27. package/lib/commands/run.js +233 -0
  28. package/lib/commands/serve.js +177 -146
  29. package/lib/commands/state.js +354 -0
  30. package/lib/commands/swarm.js +284 -0
  31. package/lib/commands/sync.js +82 -23
  32. package/lib/commands/team.js +275 -0
  33. package/lib/commands/upgrade.js +190 -0
  34. package/lib/commands/validate.js +34 -0
  35. package/lib/commands/verify.js +81 -0
  36. package/lib/commands/watch.js +79 -0
  37. package/lib/mcp/graph.js +92 -0
  38. package/lib/mcp/memory.js +95 -0
  39. package/lib/mcp/resources.js +152 -0
  40. package/lib/mcp/server.js +34 -0
  41. package/lib/mcp/tools.js +481 -0
  42. package/lib/mcp/websocket.js +117 -0
  43. package/lib/providers/index.js +49 -4
  44. package/lib/providers/ollama.js +136 -0
  45. package/lib/providers/router.js +63 -0
  46. package/lib/quality/scanner.js +128 -0
  47. package/lib/swarm/coordinator.js +97 -0
  48. package/lib/swarm/index.js +598 -0
  49. package/lib/swarm/protocol.js +677 -0
  50. package/lib/swarm/tiers.js +485 -0
  51. package/lib/templates/custom-agent.md +10 -0
  52. package/lib/utils/files.js +14 -0
  53. package/lib/utils/graph.js +108 -0
  54. package/package.json +22 -13
@@ -2,172 +2,203 @@ import chalk from 'chalk';
2
2
  import http from 'http';
3
3
  import fs from 'fs/promises';
4
4
  import path from 'path';
5
- import { readFileSafe } from '../utils/files.js';
5
+ import { loadState, generateMarkdown } from './plan.js';
6
+ import { startMcpServer } from '../mcp/server.js';
7
+ import { projectGraph } from '../mcp/graph.js';
8
+ import { UltraDexSocket } from '../mcp/websocket.js';
9
+ import { swarmCommand } from './swarm.js';
10
+ import { glob } from 'glob';
11
+ import { execSync, spawn } from 'child_process';
6
12
 
7
- // State management helpers
8
- async function loadState() {
13
+ export function registerServeCommand(program) {
14
+ program
15
+ .command('serve')
16
+ .description('Start the Ultra-Dex Active Kernel (MCP + Dashboard + API)')
17
+ .option('-p, --port <port>', 'Port to listen on', '3001')
18
+ .option('--stdio', 'Run in Stdio mode (MCP Standard Only)', false)
19
+ .action(async (options) => {
20
+ if (options.stdio) {
21
+ // Run only MCP Stdio server
22
+ try {
23
+ await startMcpServer();
24
+ } catch (error) {
25
+ console.error("Failed to start MCP Server:", error);
26
+ process.exit(1);
27
+ }
28
+ } else {
29
+ // Run full Unified Kernel (HTTP + WebSocket + Dashboard + MCP over HTTP)
30
+ await startUnifiedKernel(options.port);
31
+ }
32
+ });
33
+ }
34
+
35
+ async function getGitInfo() {
9
36
  try {
10
- const content = await fs.readFile(path.resolve(process.cwd(), '.ultra/state.json'), 'utf8');
11
- return JSON.parse(content);
37
+ const branch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();
38
+ const lastCommit = execSync('git log -1 --format="%h %s" 2>/dev/null', { encoding: 'utf8' }).trim();
39
+ const status = execSync('git status --porcelain 2>/dev/null', { encoding: 'utf8' });
40
+ const changedFiles = status.split('\n').filter(l => l.trim()).length;
41
+ return { branch, lastCommit, changedFiles };
12
42
  } catch {
13
- return null;
43
+ return { branch: 'unknown', lastCommit: 'N/A', changedFiles: 0 };
14
44
  }
15
45
  }
16
46
 
17
- async function computeState() {
18
- const state = {
19
- version: '2.1.0',
20
- updatedAt: new Date().toISOString(),
21
- project: { name: path.basename(process.cwd()) },
22
- files: {},
23
- sections: { total: 34, completed: 0, list: [] },
24
- score: 0
25
- };
26
-
27
- const coreFiles = ['CONTEXT.md', 'IMPLEMENTATION-PLAN.md', 'CHECKLIST.md', 'QUICK-START.md'];
28
- for (const file of coreFiles) {
29
- try {
30
- const stat = await fs.stat(path.resolve(process.cwd(), file));
31
- state.files[file] = { exists: true, size: stat.size };
32
- } catch {
33
- state.files[file] = { exists: false };
34
- }
35
- }
47
+ // Re-using dashboard HTML generation logic (modularized)
48
+ async function getDashboardHTML() {
49
+ const { generateDashboardHTML } = await import('./dashboard.js');
50
+ const state = await loadState();
51
+ const gitInfo = await getGitInfo();
52
+ await projectGraph.scan();
53
+ const summary = projectGraph.getSummary();
54
+ return generateDashboardHTML(state, gitInfo, { nodes: summary.nodeCount, edges: summary.edgeCount });
55
+ }
56
+
57
+ async function startUnifiedKernel(portStr) {
58
+ const port = Number.parseInt(portStr, 10);
59
+
60
+ console.log(chalk.bold.cyan('\nšŸš€ Ultra-Dex Active Kernel Starting (GOD MODE)...\n'));
36
61
 
62
+ // Initialize Graph
63
+ console.log(chalk.gray('🧠 Initializing Neural Link (Code Graph)...'));
37
64
  try {
38
- const plan = await fs.readFile(path.resolve(process.cwd(), 'IMPLEMENTATION-PLAN.md'), 'utf8');
39
- const sectionRegex = /^##\s+(\d+)\.\s+(.+)$/gm;
40
- let match;
41
- while ((match = sectionRegex.exec(plan)) !== null) {
42
- state.sections.list.push({ number: parseInt(match[1]), title: match[2].trim() });
43
- }
44
- state.sections.completed = state.sections.list.length;
45
- } catch { /* no plan */ }
65
+ await projectGraph.scan();
66
+ console.log(chalk.green(`āœ… Graph loaded: ${projectGraph.nodes.size} nodes`));
67
+ } catch (e) {
68
+ console.log(chalk.yellow(`āš ļø Graph init failed: ${e.message}`));
69
+ }
46
70
 
47
- const fileScore = Object.values(state.files).filter(f => f.exists).length / coreFiles.length * 40;
48
- const sectionScore = state.sections.completed / state.sections.total * 60;
49
- state.score = Math.round(fileScore + sectionScore);
71
+ const server = http.createServer(async (req, res) => {
72
+ // CORS headers for local tools
73
+ res.setHeader('Access-Control-Allow-Origin', '*');
74
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
75
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
50
76
 
51
- return state;
52
- }
77
+ if (req.method === 'OPTIONS') {
78
+ res.writeHead(204);
79
+ res.end();
80
+ return;
81
+ }
53
82
 
54
- const BUILD_AGENTS = [
55
- { name: 'planner', tier: 'architect', task: 'Break down requirements into tasks' },
56
- { name: 'cto', tier: 'architect', task: 'Technical decisions & architecture' },
57
- { name: 'backend', tier: 'core', task: 'API, business logic, services' },
58
- { name: 'frontend', tier: 'core', task: 'UI components, pages, styling' },
59
- { name: 'database', tier: 'core', task: 'Schema design, migrations, queries' },
60
- { name: 'auth', tier: 'specialist', task: 'Authentication & authorization' },
61
- { name: 'security', tier: 'specialist', task: 'Security audit & hardening' },
62
- { name: 'testing', tier: 'specialist', task: 'Test strategy & implementation' },
63
- { name: 'reviewer', tier: 'quality', task: 'Code review & best practices' },
64
- { name: 'devops', tier: 'quality', task: 'CI/CD, deployment, infrastructure' }
65
- ];
83
+ const url = new URL(req.url, `http://${req.headers.host}`);
84
+ const pathname = url.pathname;
66
85
 
67
- export function registerServeCommand(program) {
68
- program
69
- .command('serve')
70
- .description('Serve Ultra-Dex context over HTTP (MCP-compatible)')
71
- .option('-p, --port <port>', 'Port to listen on', '3001')
72
- .action(async (options) => {
73
- const port = Number.parseInt(options.port, 10);
74
- if (Number.isNaN(port)) {
75
- console.log(chalk.red('Invalid port. Use a numeric value.'));
76
- process.exit(1);
86
+ try {
87
+ // Dashboard UI
88
+ if (pathname === '/' || pathname === '/dashboard') {
89
+ const html = await getDashboardHTML();
90
+ res.writeHead(200, { 'Content-Type': 'text/html' });
91
+ res.end(html);
92
+ return;
77
93
  }
78
94
 
79
- const server = http.createServer(async (req, res) => {
80
- res.setHeader('Access-Control-Allow-Origin', '*');
81
-
82
- if (!req.url || req.url === '/') {
83
- res.writeHead(200, { 'Content-Type': 'application/json' });
84
- res.end(JSON.stringify({
85
- name: 'Ultra-Dex MCP Server',
86
- version: '2.1.0',
87
- endpoints: ['/context', '/state', '/score', '/agents', '/agent/:name', '/refresh']
88
- }));
89
- return;
90
- }
95
+ // Endpoint: /api/info
96
+ if (pathname === '/api/info') {
97
+ res.writeHead(200, { 'Content-Type': 'application/json' });
98
+ res.end(JSON.stringify({
99
+ name: 'Ultra-Dex Active Kernel',
100
+ version: '2.4.1',
101
+ status: 'online',
102
+ endpoints: ['/api/state', '/api/plan', '/api/context', '/api/graph', '/api/swarm']
103
+ }, null, 2));
104
+ return;
105
+ }
91
106
 
92
- if (req.url === '/context') {
93
- const meta = {
94
- protocol: 'mcp-lite',
95
- version: '0.1',
96
- generatedAt: new Date().toISOString(),
97
- };
98
- const [context, plan, quickStart] = await Promise.all([
99
- readFileSafe('CONTEXT.md', 'CONTEXT.md'),
100
- readFileSafe('IMPLEMENTATION-PLAN.md', 'IMPLEMENTATION-PLAN.md'),
101
- readFileSafe('QUICK-START.md', 'QUICK-START.md'),
102
- ]);
103
-
104
- res.writeHead(200, { 'Content-Type': 'application/json' });
105
- res.end(JSON.stringify({ meta, files: [context, plan, quickStart] }));
106
- return;
107
- }
107
+ // Endpoint: /api/graph
108
+ if (pathname === '/api/graph' || pathname === '/graph') {
109
+ const summary = projectGraph.getSummary();
110
+ res.writeHead(200, { 'Content-Type': 'application/json' });
111
+ res.end(JSON.stringify(summary, null, 2));
112
+ return;
113
+ }
108
114
 
109
- // /state - returns .ultra/state.json
110
- if (req.url === '/state') {
111
- let state = await loadState();
112
- if (!state) state = await computeState();
113
- res.writeHead(200, { 'Content-Type': 'application/json' });
114
- res.end(JSON.stringify(state));
115
- return;
116
- }
115
+ // Endpoint: /api/state
116
+ if (pathname === '/api/state' || pathname === '/state') {
117
+ const state = await loadState();
118
+ res.writeHead(200, { 'Content-Type': 'application/json' });
119
+ res.end(JSON.stringify(state, null, 2));
120
+ return;
121
+ }
117
122
 
118
- // /score - quick alignment score
119
- if (req.url === '/score') {
120
- const state = await computeState();
121
- res.writeHead(200, { 'Content-Type': 'application/json' });
122
- res.end(JSON.stringify({ score: state.score, sections: state.sections.completed, total: 34 }));
123
- return;
124
- }
123
+ // Endpoint: /api/swarm (Execute Swarm)
124
+ if ((pathname === '/api/swarm' || pathname === '/swarm') && req.method === 'POST') {
125
+ let body = '';
126
+ req.on('data', chunk => body += chunk);
127
+ req.on('end', async () => {
128
+ try {
129
+ const { task, feature, parallel } = JSON.parse(body);
130
+ const objective = task || feature;
131
+ if (!objective) throw new Error('Task/Feature objective is required');
132
+
133
+ // Run swarm
134
+ swarmCommand(objective, { parallel, dryRun: false }).catch(err => console.error(err));
135
+
136
+ res.writeHead(202, { 'Content-Type': 'application/json' });
137
+ res.end(JSON.stringify({ status: 'accepted', message: 'Swarm started' }));
138
+ } catch (e) {
139
+ res.writeHead(400, { 'Content-Type': 'application/json' });
140
+ res.end(JSON.stringify({ error: e.message }));
141
+ }
142
+ });
143
+ return;
144
+ }
125
145
 
126
- // /agents - list available agents
127
- if (req.url === '/agents') {
128
- res.writeHead(200, { 'Content-Type': 'application/json' });
129
- res.end(JSON.stringify({ agents: BUILD_AGENTS }));
130
- return;
131
- }
146
+ // Endpoint: /api/plan
147
+ if (pathname === '/api/plan' || pathname === '/plan') {
148
+ const state = await loadState();
149
+ const markdown = generateMarkdown(state);
150
+ res.writeHead(200, { 'Content-Type': 'text/markdown' });
151
+ res.end(markdown);
152
+ return;
153
+ }
132
154
 
133
- // /agent/:name - get specific agent prompt
134
- if (req.url.startsWith('/agent/')) {
135
- const agentName = req.url.replace('/agent/', '');
136
- try {
137
- const agentPath = path.resolve(process.cwd(), `agents/${agentName}.md`);
138
- const content = await fs.readFile(agentPath, 'utf8');
139
- res.writeHead(200, { 'Content-Type': 'application/json' });
140
- res.end(JSON.stringify({ agent: agentName, prompt: content }));
141
- } catch {
142
- res.writeHead(404, { 'Content-Type': 'application/json' });
143
- res.end(JSON.stringify({ error: `Agent ${agentName} not found` }));
144
- }
155
+ // SSE Events for Dashboard
156
+ if (pathname === '/events') {
157
+ res.writeHead(200, {
158
+ 'Content-Type': 'text/event-stream',
159
+ 'Cache-Control': 'no-cache',
160
+ 'Connection': 'keep-alive'
161
+ });
162
+ res.write(`data: ${JSON.stringify({ type: 'log', message: 'Connected to Active Kernel' })}\n\n`);
163
+ // We'd need to manage clients here if we wanted to push updates
145
164
  return;
146
- }
165
+ }
147
166
 
148
- // /refresh - force state refresh
149
- if (req.url === '/refresh') {
150
- const state = await computeState();
151
- res.writeHead(200, { 'Content-Type': 'application/json' });
152
- res.end(JSON.stringify({ refreshed: true, score: state.score }));
153
- return;
154
- }
167
+ res.writeHead(404, { 'Content-Type': 'application/json' });
168
+ res.end(JSON.stringify({ error: 'Not found' }));
155
169
 
156
- res.writeHead(404, { 'Content-Type': 'application/json' });
157
- res.end(JSON.stringify({ error: 'Not found' }));
158
- });
159
-
160
- server.listen(port, () => {
161
- console.log(chalk.green(`\nāœ… Ultra-Dex MCP server running on http://localhost:${port}`));
162
- console.log(chalk.bold('\nšŸ“” Endpoints:'));
163
- console.log(chalk.gray(' GET / → Server info & endpoint list'));
164
- console.log(chalk.gray(' GET /context → All context files'));
165
- console.log(chalk.gray(' GET /state → Full project state'));
166
- console.log(chalk.gray(' GET /score → Quick alignment score'));
167
- console.log(chalk.gray(' GET /agents → List available agents'));
168
- console.log(chalk.gray(' GET /agent/:n → Get specific agent prompt'));
169
- console.log(chalk.gray(' GET /refresh → Force state refresh'));
170
- console.log(chalk.cyan('\nšŸ’” Connect your AI tool to this server for live context.\n'));
171
- });
170
+ } catch (error) {
171
+ res.writeHead(500, { 'Content-Type': 'application/json' });
172
+ res.end(JSON.stringify({ error: error.message }));
173
+ }
174
+ });
175
+
176
+ const wss = new UltraDexSocket(server);
177
+
178
+ server.listen(port, () => {
179
+ console.log(chalk.green(`āœ… Unified Kernel active at http://localhost:${port}`));
180
+ console.log(chalk.gray(` • Dashboard: http://localhost:${port}/`));
181
+ console.log(chalk.gray(` • MCP API: http://localhost:${port}/api/info`));
182
+
183
+ console.log(chalk.bold.magenta('\nšŸ”Œ AI Tool Integration:'));
184
+ console.log(chalk.white(' Cursor IDE: '));
185
+ console.log(chalk.cyan(` URL: http://localhost:${port}/api/info`));
186
+ console.log(chalk.white(' Claude Desktop:'));
187
+ console.log(chalk.cyan(` Run "ultra-dex config --mcp" to register.`));
188
+
189
+ // Auto-Pilot
190
+ fs.watch(process.cwd(), { recursive: true }, async (eventType, filename) => {
191
+ if (!filename || filename.includes('node_modules') || filename.includes('.git') || filename.includes('IMPLEMENTATION-PLAN.md')) return;
192
+
193
+ console.log(chalk.gray(`\nšŸ”„ Change in ${filename}. Synchronizing...`));
194
+ try {
195
+ const state = await loadState();
196
+ if (state) {
197
+ const markdown = generateMarkdown(state);
198
+ await fs.writeFile(path.resolve(process.cwd(), 'IMPLEMENTATION-PLAN.md'), markdown);
199
+ wss.sendStateUpdate(state);
200
+ }
201
+ } catch (e) {}
172
202
  });
173
- }
203
+ });
204
+ }