ultra-dex 2.2.1 → 3.2.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 (87) hide show
  1. package/README.md +112 -151
  2. package/assets/agents/00-AGENT_INDEX.md +1 -1
  3. package/assets/code-patterns/clerk-middleware.ts +138 -0
  4. package/assets/code-patterns/prisma-schema.prisma +224 -0
  5. package/assets/code-patterns/rls-policies.sql +246 -0
  6. package/assets/code-patterns/server-actions.ts +191 -0
  7. package/assets/code-patterns/trpc-router.ts +258 -0
  8. package/assets/cursor-rules/13-ai-integration.mdc +155 -0
  9. package/assets/cursor-rules/14-server-components.mdc +81 -0
  10. package/assets/cursor-rules/15-server-actions.mdc +102 -0
  11. package/assets/cursor-rules/16-edge-middleware.mdc +105 -0
  12. package/assets/cursor-rules/17-streaming-ssr.mdc +138 -0
  13. package/assets/docs/LAUNCH-POSTS.md +1 -1
  14. package/assets/docs/QUICK-REFERENCE.md +9 -4
  15. package/assets/docs/VISION-V2.md +1 -1
  16. package/assets/hooks/pre-commit +98 -0
  17. package/assets/saas-plan/04-Imp-Template.md +1 -1
  18. package/bin/ultra-dex.js +132 -4
  19. package/lib/commands/advanced.js +471 -0
  20. package/lib/commands/agent-builder.js +226 -0
  21. package/lib/commands/agents.js +102 -42
  22. package/lib/commands/auto-implement.js +68 -0
  23. package/lib/commands/banner.js +43 -21
  24. package/lib/commands/build.js +78 -183
  25. package/lib/commands/ci-monitor.js +84 -0
  26. package/lib/commands/config.js +207 -0
  27. package/lib/commands/dashboard.js +770 -0
  28. package/lib/commands/diff.js +233 -0
  29. package/lib/commands/doctor.js +416 -0
  30. package/lib/commands/export.js +408 -0
  31. package/lib/commands/fix.js +96 -0
  32. package/lib/commands/generate.js +105 -78
  33. package/lib/commands/hooks.js +251 -76
  34. package/lib/commands/init.js +102 -54
  35. package/lib/commands/memory.js +80 -0
  36. package/lib/commands/plan.js +82 -0
  37. package/lib/commands/review.js +34 -5
  38. package/lib/commands/run.js +233 -0
  39. package/lib/commands/scaffold.js +151 -0
  40. package/lib/commands/serve.js +179 -146
  41. package/lib/commands/state.js +327 -0
  42. package/lib/commands/swarm.js +306 -0
  43. package/lib/commands/sync.js +82 -23
  44. package/lib/commands/team.js +275 -0
  45. package/lib/commands/upgrade.js +190 -0
  46. package/lib/commands/validate.js +34 -0
  47. package/lib/commands/verify.js +81 -0
  48. package/lib/commands/watch.js +79 -0
  49. package/lib/config/theme.js +47 -0
  50. package/lib/mcp/graph.js +92 -0
  51. package/lib/mcp/memory.js +95 -0
  52. package/lib/mcp/resources.js +152 -0
  53. package/lib/mcp/server.js +34 -0
  54. package/lib/mcp/tools.js +481 -0
  55. package/lib/mcp/websocket.js +117 -0
  56. package/lib/providers/index.js +49 -4
  57. package/lib/providers/ollama.js +136 -0
  58. package/lib/providers/router.js +63 -0
  59. package/lib/quality/scanner.js +128 -0
  60. package/lib/swarm/coordinator.js +97 -0
  61. package/lib/swarm/index.js +598 -0
  62. package/lib/swarm/protocol.js +677 -0
  63. package/lib/swarm/tiers.js +485 -0
  64. package/lib/templates/code/clerk-middleware.ts +138 -0
  65. package/lib/templates/code/prisma-schema.prisma +224 -0
  66. package/lib/templates/code/rls-policies.sql +246 -0
  67. package/lib/templates/code/server-actions.ts +191 -0
  68. package/lib/templates/code/trpc-router.ts +258 -0
  69. package/lib/templates/custom-agent.md +10 -0
  70. package/lib/themes/doomsday.js +229 -0
  71. package/lib/ui/index.js +5 -0
  72. package/lib/ui/interface.js +241 -0
  73. package/lib/ui/spinners.js +116 -0
  74. package/lib/ui/theme.js +183 -0
  75. package/lib/utils/agents.js +32 -0
  76. package/lib/utils/files.js +14 -0
  77. package/lib/utils/graph.js +108 -0
  78. package/lib/utils/help.js +64 -0
  79. package/lib/utils/messages.js +35 -0
  80. package/lib/utils/progress.js +24 -0
  81. package/lib/utils/prompts.js +47 -0
  82. package/lib/utils/spinners.js +46 -0
  83. package/lib/utils/status.js +31 -0
  84. package/lib/utils/tables.js +41 -0
  85. package/lib/utils/theme-state.js +9 -0
  86. package/lib/utils/version-display.js +32 -0
  87. package/package.json +31 -13
@@ -0,0 +1,408 @@
1
+ // cli/lib/commands/export.js
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { readFileSync, writeFileSync, existsSync, readdirSync, statSync } from 'fs';
5
+ import { join, basename, dirname, extname } from 'path';
6
+
7
+ export async function exportCommand(options) {
8
+ const format = options.format || 'json';
9
+ const outputPath = options.output || `ultra-dex-export.${format === 'md' ? 'md' : format}`;
10
+
11
+ console.log(chalk.cyan.bold(`\nšŸ“¦ Ultra-Dex Export\n`));
12
+
13
+ const spinner = ora('Collecting project data...').start();
14
+
15
+ try {
16
+ const context = loadContext(options.includeAgents);
17
+ spinner.succeed(`Collected ${Object.keys(context.files).length} files`);
18
+
19
+ const formatSpinner = ora(`Generating ${format.toUpperCase()} output...`).start();
20
+
21
+ let output;
22
+ switch (format) {
23
+ case 'json':
24
+ output = generateJSON(context);
25
+ break;
26
+ case 'html':
27
+ output = generateHTML(context);
28
+ break;
29
+ case 'markdown':
30
+ case 'md':
31
+ output = generateMarkdown(context);
32
+ break;
33
+ case 'pdf':
34
+ formatSpinner.warn('PDF export requires external tools');
35
+ console.log(chalk.gray(' Generating HTML instead. Convert with: '));
36
+ console.log(chalk.gray(' wkhtmltopdf ultra-dex-export.html ultra-dex-export.pdf'));
37
+ output = generateHTML(context, { forPdf: true });
38
+ break;
39
+ default:
40
+ formatSpinner.fail(`Unknown format: ${format}`);
41
+ console.log(chalk.yellow(' Supported formats: json, html, markdown (md), pdf'));
42
+ return;
43
+ }
44
+
45
+ writeFileSync(outputPath, output);
46
+ formatSpinner.succeed(`Generated ${format.toUpperCase()} output`);
47
+
48
+ console.log(chalk.green(`\nāœ… Exported to ${chalk.bold(outputPath)}`));
49
+ console.log(chalk.gray(` Size: ${(output.length / 1024).toFixed(1)} KB`));
50
+
51
+ if (options.includeAgents && context.agents.length > 0) {
52
+ console.log(chalk.gray(` Agents bundled: ${context.agents.length}`));
53
+ }
54
+ } catch (error) {
55
+ spinner.fail('Export failed');
56
+ console.log(chalk.red(` ${error.message}`));
57
+ }
58
+ }
59
+
60
+ function loadContext(includeAgents = false) {
61
+ const coreFiles = ['CONTEXT.md', 'IMPLEMENTATION-PLAN.md', 'QUICK-START.md', 'CHECKLIST.md'];
62
+ const context = {
63
+ exportedAt: new Date().toISOString(),
64
+ version: '3.0.0',
65
+ project: basename(process.cwd()),
66
+ files: {},
67
+ state: null,
68
+ agents: []
69
+ };
70
+
71
+ // Load core documentation files
72
+ coreFiles.forEach(file => {
73
+ const filePath = join(process.cwd(), file);
74
+ if (existsSync(filePath)) {
75
+ context.files[file] = readFileSync(filePath, 'utf-8');
76
+ }
77
+ });
78
+
79
+ // Load state.json if exists
80
+ const statePath = join(process.cwd(), '.ultra', 'state.json');
81
+ if (existsSync(statePath)) {
82
+ try {
83
+ context.state = JSON.parse(readFileSync(statePath, 'utf-8'));
84
+ } catch { /* invalid state */ }
85
+ }
86
+
87
+ // Load agent prompts if requested
88
+ if (includeAgents) {
89
+ context.agents = loadAgentPrompts();
90
+ }
91
+
92
+ return context;
93
+ }
94
+
95
+ function loadAgentPrompts() {
96
+ const agents = [];
97
+ const agentsDir = join(process.cwd(), 'agents');
98
+
99
+ if (!existsSync(agentsDir)) return agents;
100
+
101
+ const walkDir = (dir, category = '') => {
102
+ try {
103
+ const items = readdirSync(dir);
104
+ for (const item of items) {
105
+ const itemPath = join(dir, item);
106
+ const stat = statSync(itemPath);
107
+
108
+ if (stat.isDirectory()) {
109
+ walkDir(itemPath, item);
110
+ } else if (item.endsWith('.md') && !item.startsWith('README') && !item.startsWith('00-')) {
111
+ try {
112
+ const content = readFileSync(itemPath, 'utf-8');
113
+ agents.push({
114
+ name: basename(item, '.md'),
115
+ category: category || 'root',
116
+ path: itemPath.replace(process.cwd(), '.'),
117
+ content
118
+ });
119
+ } catch { /* skip unreadable */ }
120
+ }
121
+ }
122
+ } catch { /* skip inaccessible dirs */ }
123
+ };
124
+
125
+ walkDir(agentsDir);
126
+ return agents;
127
+ }
128
+
129
+ function generateJSON(context) {
130
+ return JSON.stringify(context, null, 2);
131
+ }
132
+
133
+ function generateHTML(context, options = {}) {
134
+ const { forPdf = false } = options;
135
+
136
+ const styles = `
137
+ :root {
138
+ --bg-primary: #0d1117;
139
+ --bg-secondary: #161b22;
140
+ --bg-tertiary: #21262d;
141
+ --text-primary: #c9d1d9;
142
+ --text-secondary: #8b949e;
143
+ --accent: #58a6ff;
144
+ --accent-green: #3fb950;
145
+ --accent-yellow: #d29922;
146
+ --border: #30363d;
147
+ }
148
+ * { box-sizing: border-box; margin: 0; padding: 0; }
149
+ body {
150
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
151
+ background: var(--bg-primary);
152
+ color: var(--text-primary);
153
+ line-height: 1.6;
154
+ padding: 0;
155
+ }
156
+ .container { max-width: 1000px; margin: 0 auto; padding: 40px 20px; }
157
+ header {
158
+ text-align: center;
159
+ padding: 40px 0;
160
+ border-bottom: 1px solid var(--border);
161
+ margin-bottom: 40px;
162
+ }
163
+ header h1 {
164
+ font-size: 2.5rem;
165
+ color: var(--accent);
166
+ margin-bottom: 10px;
167
+ }
168
+ header .meta { color: var(--text-secondary); font-size: 0.9rem; }
169
+ nav {
170
+ background: var(--bg-secondary);
171
+ border: 1px solid var(--border);
172
+ border-radius: 6px;
173
+ padding: 20px;
174
+ margin-bottom: 30px;
175
+ }
176
+ nav h3 { color: var(--accent); margin-bottom: 15px; }
177
+ nav ul { list-style: none; display: flex; flex-wrap: wrap; gap: 10px; }
178
+ nav a {
179
+ color: var(--text-primary);
180
+ text-decoration: none;
181
+ padding: 6px 12px;
182
+ background: var(--bg-tertiary);
183
+ border-radius: 4px;
184
+ font-size: 0.9rem;
185
+ }
186
+ nav a:hover { background: var(--accent); color: var(--bg-primary); }
187
+ section {
188
+ background: var(--bg-secondary);
189
+ border: 1px solid var(--border);
190
+ border-radius: 6px;
191
+ margin-bottom: 30px;
192
+ overflow: hidden;
193
+ }
194
+ section h2 {
195
+ background: var(--bg-tertiary);
196
+ padding: 15px 20px;
197
+ font-size: 1.2rem;
198
+ border-bottom: 1px solid var(--border);
199
+ color: var(--accent-green);
200
+ }
201
+ section .content {
202
+ padding: 20px;
203
+ white-space: pre-wrap;
204
+ font-family: 'SF Mono', Monaco, 'Courier New', monospace;
205
+ font-size: 0.85rem;
206
+ max-height: ${forPdf ? 'none' : '600px'};
207
+ overflow-y: auto;
208
+ }
209
+ .state-summary {
210
+ display: grid;
211
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
212
+ gap: 15px;
213
+ padding: 20px;
214
+ }
215
+ .state-card {
216
+ background: var(--bg-tertiary);
217
+ padding: 15px;
218
+ border-radius: 6px;
219
+ }
220
+ .state-card label {
221
+ color: var(--text-secondary);
222
+ font-size: 0.8rem;
223
+ text-transform: uppercase;
224
+ }
225
+ .state-card .value {
226
+ font-size: 1.5rem;
227
+ color: var(--accent);
228
+ margin-top: 5px;
229
+ }
230
+ .agents-grid {
231
+ display: grid;
232
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
233
+ gap: 15px;
234
+ padding: 20px;
235
+ }
236
+ .agent-card {
237
+ background: var(--bg-tertiary);
238
+ border-radius: 6px;
239
+ overflow: hidden;
240
+ }
241
+ .agent-card h4 {
242
+ padding: 10px 15px;
243
+ background: var(--bg-primary);
244
+ color: var(--accent-yellow);
245
+ font-size: 0.9rem;
246
+ }
247
+ .agent-card .preview {
248
+ padding: 15px;
249
+ font-family: monospace;
250
+ font-size: 0.75rem;
251
+ color: var(--text-secondary);
252
+ max-height: 150px;
253
+ overflow: hidden;
254
+ }
255
+ footer {
256
+ text-align: center;
257
+ padding: 30px;
258
+ color: var(--text-secondary);
259
+ font-size: 0.85rem;
260
+ border-top: 1px solid var(--border);
261
+ }
262
+ @media print {
263
+ body { background: white; color: black; }
264
+ section .content { max-height: none; }
265
+ }
266
+ `;
267
+
268
+ const escapeHtml = (str) => str
269
+ .replace(/&/g, '&')
270
+ .replace(/</g, '&lt;')
271
+ .replace(/>/g, '&gt;');
272
+
273
+ const fileEntries = Object.entries(context.files);
274
+ const toc = fileEntries.map(([file]) =>
275
+ `<li><a href="#${file.replace(/\./g, '-')}">${file}</a></li>`
276
+ ).join('');
277
+
278
+ const fileSections = fileEntries.map(([file, content]) => `
279
+ <section id="${file.replace(/\./g, '-')}">
280
+ <h2>šŸ“„ ${file}</h2>
281
+ <div class="content">${escapeHtml(content)}</div>
282
+ </section>
283
+ `).join('');
284
+
285
+ const stateSection = context.state ? `
286
+ <section>
287
+ <h2>šŸ“Š Project State</h2>
288
+ <div class="state-summary">
289
+ <div class="state-card">
290
+ <label>Score</label>
291
+ <div class="value">${context.state.score || 'N/A'}/100</div>
292
+ </div>
293
+ <div class="state-card">
294
+ <label>Mode</label>
295
+ <div class="value">${context.state.project?.mode || 'Standard'}</div>
296
+ </div>
297
+ <div class="state-card">
298
+ <label>Updated</label>
299
+ <div class="value" style="font-size: 0.9rem;">${context.state.updatedAt?.split('T')[0] || 'N/A'}</div>
300
+ </div>
301
+ </div>
302
+ </section>
303
+ ` : '';
304
+
305
+ const agentsSection = context.agents.length > 0 ? `
306
+ <section>
307
+ <h2>šŸ¤– Bundled Agents (${context.agents.length})</h2>
308
+ <div class="agents-grid">
309
+ ${context.agents.map(agent => `
310
+ <div class="agent-card">
311
+ <h4>@${agent.name} <span style="color: var(--text-secondary); font-weight: normal;">(${agent.category})</span></h4>
312
+ <div class="preview">${escapeHtml(agent.content.substring(0, 300))}...</div>
313
+ </div>
314
+ `).join('')}
315
+ </div>
316
+ </section>
317
+ ` : '';
318
+
319
+ return `<!DOCTYPE html>
320
+ <html lang="en">
321
+ <head>
322
+ <meta charset="UTF-8">
323
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
324
+ <title>Ultra-Dex Export - ${context.project}</title>
325
+ <style>${styles}</style>
326
+ </head>
327
+ <body>
328
+ <div class="container">
329
+ <header>
330
+ <h1>⚔ Ultra-Dex Export</h1>
331
+ <div class="meta">
332
+ Project: <strong>${context.project}</strong> |
333
+ Exported: ${new Date(context.exportedAt).toLocaleString()} |
334
+ Version: ${context.version}
335
+ </div>
336
+ </header>
337
+
338
+ <nav>
339
+ <h3>šŸ“‘ Contents</h3>
340
+ <ul>${toc}</ul>
341
+ </nav>
342
+
343
+ ${stateSection}
344
+ ${fileSections}
345
+ ${agentsSection}
346
+
347
+ <footer>
348
+ Generated by Ultra-Dex v${context.version} |
349
+ <a href="https://github.com/Srujan0798/Ultra-Dex" style="color: var(--accent);">GitHub</a>
350
+ </footer>
351
+ </div>
352
+ </body>
353
+ </html>`;
354
+ }
355
+
356
+ function generateMarkdown(context) {
357
+ const lines = [
358
+ `# Ultra-Dex Export`,
359
+ ``,
360
+ `> **Project:** ${context.project}`,
361
+ `> **Exported:** ${new Date(context.exportedAt).toLocaleString()}`,
362
+ `> **Version:** ${context.version}`,
363
+ ``,
364
+ `---`,
365
+ ``
366
+ ];
367
+
368
+ // Table of contents
369
+ lines.push(`## Table of Contents`, ``);
370
+ Object.keys(context.files).forEach((file, i) => {
371
+ lines.push(`${i + 1}. [${file}](#${file.toLowerCase().replace(/\./g, '')})`);
372
+ });
373
+ if (context.state) lines.push(`${Object.keys(context.files).length + 1}. [Project State](#project-state)`);
374
+ if (context.agents.length > 0) lines.push(`${Object.keys(context.files).length + 2}. [Agents](#agents)`);
375
+ lines.push(``, `---`, ``);
376
+
377
+ // File contents
378
+ Object.entries(context.files).forEach(([file, content]) => {
379
+ lines.push(`## ${file}`, ``);
380
+ lines.push('```markdown');
381
+ lines.push(content);
382
+ lines.push('```', ``);
383
+ lines.push(`---`, ``);
384
+ });
385
+
386
+ // State
387
+ if (context.state) {
388
+ lines.push(`## Project State`, ``);
389
+ lines.push('```json');
390
+ lines.push(JSON.stringify(context.state, null, 2));
391
+ lines.push('```', ``);
392
+ lines.push(`---`, ``);
393
+ }
394
+
395
+ // Agents
396
+ if (context.agents.length > 0) {
397
+ lines.push(`## Agents`, ``);
398
+ lines.push(`Bundled ${context.agents.length} agent prompts:`, ``);
399
+ context.agents.forEach(agent => {
400
+ lines.push(`### @${agent.name} (${agent.category})`, ``);
401
+ lines.push('```markdown');
402
+ lines.push(agent.content.substring(0, 500) + (agent.content.length > 500 ? '\n...(truncated)' : ''));
403
+ lines.push('```', ``);
404
+ });
405
+ }
406
+
407
+ return lines.join('\n');
408
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * ultra-dex fix command
3
+ * Self-Healing: Scans code and applies AI fixes automatically
4
+ */
5
+
6
+ import chalk from 'chalk';
7
+ import fs from 'fs/promises';
8
+ import path from 'path';
9
+ import { runQualityScan } from '../quality/scanner.js';
10
+ import { createProvider, getDefaultProvider, checkConfiguredProviders } from '../providers/index.js';
11
+
12
+ export function registerFixCommand(program) {
13
+ program
14
+ .command('fix')
15
+ .description('Self-Healing: Scan and fix code quality issues')
16
+ .option('-p, --provider <provider>', 'AI provider')
17
+ .option('-k, --key <apiKey>', 'API key')
18
+ .option('--dry-run', 'Show fixes without applying')
19
+ .action(async (options) => {
20
+ console.log(chalk.cyan('\nšŸš‘ Ultra-Dex Self-Healing\n'));
21
+
22
+ // Check for API key
23
+ const configured = checkConfiguredProviders();
24
+ const hasProvider = configured.some(p => p.configured) || options.key;
25
+
26
+ if (!hasProvider) {
27
+ console.log(chalk.yellow('āš ļø No AI provider configured.'));
28
+ console.log(chalk.white('Self-healing requires an AI provider.'));
29
+ return;
30
+ }
31
+
32
+ console.log(chalk.gray('Scanning project...'));
33
+ const results = await runQualityScan(process.cwd());
34
+
35
+ if (results.failed === 0 && results.warnings === 0) {
36
+ console.log(chalk.green('āœ… No issues found. System healthy.'));
37
+ return;
38
+ }
39
+
40
+ console.log(chalk.yellow(`Found ${results.failed} errors and ${results.warnings} warnings.`));
41
+
42
+ const providerId = options.provider || getDefaultProvider();
43
+ const provider = createProvider(providerId, { apiKey: options.key, maxTokens: 4000 });
44
+
45
+ // Group by file
46
+ const issuesByFile = {};
47
+ results.details.forEach(issue => {
48
+ if (!issuesByFile[issue.file]) issuesByFile[issue.file] = [];
49
+ issuesByFile[issue.file].push(issue);
50
+ });
51
+
52
+ for (const [file, issues] of Object.entries(issuesByFile)) {
53
+ console.log(chalk.bold(`\nFixing ${file}...`));
54
+
55
+ try {
56
+ const filePath = path.resolve(process.cwd(), file);
57
+ const content = await fs.readFile(filePath, 'utf8');
58
+
59
+ const prompt = `You are an expert code fixer. Fix the following issues in the code file.
60
+
61
+ ISSUES TO FIX:
62
+ ${issues.map(i => `- [${i.severity}] ${i.message}`).join('\n')}
63
+
64
+ FILE CONTENT:
65
+ \`\`\`
66
+ ${content}
67
+ \`\`\`
68
+
69
+ Return ONLY the full corrected file content. Do not include markdown code blocks or explanations. Just the code.`;
70
+
71
+ if (options.dryRun) {
72
+ console.log(chalk.gray('Dry run: Skipping AI generation.'));
73
+ continue;
74
+ }
75
+
76
+ const result = await provider.generate('You are a code fixing bot. Output only code.', prompt);
77
+ let fixedCode = result.content.trim();
78
+
79
+ // clean up markdown code blocks if AI added them
80
+ if (fixedCode.startsWith('```')) {
81
+ fixedCode = fixedCode.replace(/^```[a-z]*\n/, '').replace(/\n```$/, '');
82
+ }
83
+
84
+ await fs.writeFile(filePath, fixedCode);
85
+ console.log(chalk.green(`āœ“ Fixed ${issues.length} issues in ${file}`));
86
+
87
+ } catch (err) {
88
+ console.log(chalk.red(`āœ— Failed to fix ${file}: ${err.message}`));
89
+ }
90
+ }
91
+
92
+ console.log(chalk.green('\n✨ Self-healing complete.'));
93
+ });
94
+ }
95
+
96
+ export default { registerFixCommand };