ultra-dex 3.1.0 → 3.3.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 (52) hide show
  1. package/README.md +79 -74
  2. package/assets/code-patterns/clerk-middleware.ts +138 -0
  3. package/assets/code-patterns/prisma-schema.prisma +224 -0
  4. package/assets/code-patterns/rls-policies.sql +246 -0
  5. package/assets/code-patterns/server-actions.ts +191 -0
  6. package/assets/code-patterns/trpc-router.ts +258 -0
  7. package/assets/cursor-rules/13-ai-integration.mdc +155 -0
  8. package/assets/cursor-rules/14-server-components.mdc +81 -0
  9. package/assets/cursor-rules/15-server-actions.mdc +102 -0
  10. package/assets/cursor-rules/16-edge-middleware.mdc +105 -0
  11. package/assets/cursor-rules/17-streaming-ssr.mdc +138 -0
  12. package/bin/ultra-dex.js +50 -1
  13. package/lib/commands/agents.js +16 -13
  14. package/lib/commands/banner.js +43 -21
  15. package/lib/commands/build.js +26 -17
  16. package/lib/commands/cloud.js +780 -0
  17. package/lib/commands/doctor.js +98 -79
  18. package/lib/commands/exec.js +434 -0
  19. package/lib/commands/generate.js +19 -16
  20. package/lib/commands/github.js +475 -0
  21. package/lib/commands/init.js +52 -56
  22. package/lib/commands/scaffold.js +151 -0
  23. package/lib/commands/search.js +477 -0
  24. package/lib/commands/serve.js +15 -13
  25. package/lib/commands/state.js +43 -70
  26. package/lib/commands/swarm.js +31 -9
  27. package/lib/config/theme.js +47 -0
  28. package/lib/mcp/client.js +502 -0
  29. package/lib/providers/agent-sdk.js +630 -0
  30. package/lib/providers/anthropic-agents.js +580 -0
  31. package/lib/templates/code/clerk-middleware.ts +138 -0
  32. package/lib/templates/code/prisma-schema.prisma +224 -0
  33. package/lib/templates/code/rls-policies.sql +246 -0
  34. package/lib/templates/code/server-actions.ts +191 -0
  35. package/lib/templates/code/trpc-router.ts +258 -0
  36. package/lib/themes/doomsday.js +229 -0
  37. package/lib/ui/index.js +5 -0
  38. package/lib/ui/interface.js +241 -0
  39. package/lib/ui/spinners.js +116 -0
  40. package/lib/ui/theme.js +183 -0
  41. package/lib/utils/agents.js +32 -0
  42. package/lib/utils/browser.js +373 -0
  43. package/lib/utils/help.js +64 -0
  44. package/lib/utils/messages.js +35 -0
  45. package/lib/utils/progress.js +24 -0
  46. package/lib/utils/prompts.js +47 -0
  47. package/lib/utils/spinners.js +46 -0
  48. package/lib/utils/status.js +31 -0
  49. package/lib/utils/tables.js +41 -0
  50. package/lib/utils/theme-state.js +9 -0
  51. package/lib/utils/version-display.js +32 -0
  52. package/package.json +19 -4
@@ -4,12 +4,13 @@
4
4
  */
5
5
 
6
6
  import chalk from 'chalk';
7
- import ora from 'ora';
8
7
  import inquirer from 'inquirer';
9
8
  import fs from 'fs/promises';
10
9
  import path from 'path';
11
10
  import { execSync } from 'child_process';
12
11
  import { checkConfiguredProviders } from '../providers/index.js';
12
+ import { icons, header, statusLine } from '../utils/status.js';
13
+ import { createSpinner } from '../utils/spinners.js';
13
14
 
14
15
  // Default configuration
15
16
  const DEFAULT_CONFIG = {
@@ -55,17 +56,18 @@ async function saveConfig(config, global = false) {
55
56
  export function registerDoctorCommand(program) {
56
57
  program
57
58
  .command('doctor')
58
- .description('Diagnose Ultra-Dex setup and configuration')
59
+ .description('System Diagnostics - Check System Health')
59
60
  .option('--fix', 'Attempt to fix issues automatically')
60
61
  .action(async (options) => {
61
- console.log(chalk.cyan('\n🩺 Ultra-Dex Doctor\n'));
62
- console.log(chalk.gray('Checking your setup...\n'));
62
+ header('System Health Diagnostics');
63
+ console.log(chalk.gray(' Analyzing system components...\n'));
63
64
 
64
65
  const checks = [];
65
66
  let hasErrors = false;
66
67
 
67
68
  // Check 1: Node.js version
68
- const nodeSpinner = ora('Checking Node.js version...').start();
69
+ const nodeSpinner = createSpinner('Scanning Node.js environment...');
70
+ nodeSpinner.start();
69
71
  try {
70
72
  const nodeVersion = process.version;
71
73
  const major = parseInt(nodeVersion.slice(1).split('.')[0]);
@@ -83,7 +85,8 @@ export function registerDoctorCommand(program) {
83
85
  }
84
86
 
85
87
  // Check 2: Git
86
- const gitSpinner = ora('Checking Git...').start();
88
+ const gitSpinner = createSpinner('Checking Git repository...');
89
+ gitSpinner.start();
87
90
  try {
88
91
  const gitVersion = execSync('git --version', { encoding: 'utf8' }).trim();
89
92
  gitSpinner.succeed(`${gitVersion} āœ“`);
@@ -95,20 +98,22 @@ export function registerDoctorCommand(program) {
95
98
  }
96
99
 
97
100
  // Check 3: AI Providers
98
- const providerSpinner = ora('Checking AI providers...').start();
101
+ const providerSpinner = createSpinner('Locating AI Providers...');
102
+ providerSpinner.start();
99
103
  const providers = checkConfiguredProviders();
100
104
  const configuredProviders = providers.filter(p => p.configured);
101
105
 
102
106
  if (configuredProviders.length > 0) {
103
- providerSpinner.succeed(`AI providers: ${configuredProviders.map(p => p.name).join(', ')} āœ“`);
107
+ providerSpinner.succeed(`Providers found: ${configuredProviders.map(p => p.name).join(', ')} āœ“`);
104
108
  checks.push({ name: 'AI Providers', status: 'ok', detail: configuredProviders.map(p => p.name).join(', ') });
105
109
  } else {
106
- providerSpinner.warn('No AI providers configured');
110
+ providerSpinner.warn('No AI Providers found');
107
111
  checks.push({ name: 'AI Providers', status: 'warn', detail: 'Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY' });
108
112
  }
109
113
 
110
114
  // Check 4: Project structure
111
- const structureSpinner = ora('Checking project structure...').start();
115
+ const structureSpinner = createSpinner('Verifying Project Structure...');
116
+ structureSpinner.start();
112
117
  const requiredFiles = ['CONTEXT.md', 'IMPLEMENTATION-PLAN.md'];
113
118
  const optionalFiles = ['CHECKLIST.md', 'QUICK-START.md', '.ultra/state.json'];
114
119
  const foundRequired = [];
@@ -129,26 +134,27 @@ export function registerDoctorCommand(program) {
129
134
  }
130
135
 
131
136
  if (foundRequired.length === requiredFiles.length) {
132
- structureSpinner.succeed(`Project structure: ${foundRequired.length}/${requiredFiles.length} required files āœ“`);
137
+ structureSpinner.succeed(`Structure valid: ${foundRequired.length}/${requiredFiles.length} required artifacts āœ“`);
133
138
  checks.push({ name: 'Project Structure', status: 'ok', detail: `${foundRequired.join(', ')}` });
134
139
  } else if (foundRequired.length > 0) {
135
- structureSpinner.warn(`Project structure: ${foundRequired.length}/${requiredFiles.length} required files`);
140
+ structureSpinner.warn(`Structure incomplete: ${foundRequired.length}/${requiredFiles.length} required artifacts`);
136
141
  checks.push({ name: 'Project Structure', status: 'warn', detail: `Missing: ${requiredFiles.filter(f => !foundRequired.includes(f)).join(', ')}` });
137
142
  } else {
138
143
  structureSpinner.info('No Ultra-Dex project found');
139
- checks.push({ name: 'Project Structure', status: 'info', detail: 'Run `ultra-dex init` to create a project' });
144
+ checks.push({ name: 'Project Structure', status: 'info', detail: 'Run `ultra-dex init` to create a new project' });
140
145
  }
141
146
 
142
147
  // Check 5: Git hooks
143
- const hooksSpinner = ora('Checking git hooks...').start();
148
+ const hooksSpinner = createSpinner('Checking Git hooks...');
149
+ hooksSpinner.start();
144
150
  try {
145
151
  const hookPath = path.resolve(process.cwd(), '.git/hooks/pre-commit');
146
152
  const hookContent = await fs.readFile(hookPath, 'utf8');
147
153
  if (hookContent.includes('ultra-dex')) {
148
- hooksSpinner.succeed('Pre-commit hook installed āœ“');
154
+ hooksSpinner.succeed('Pre-commit active āœ“');
149
155
  checks.push({ name: 'Git Hooks', status: 'ok', detail: 'Pre-commit active' });
150
156
  } else {
151
- hooksSpinner.info('Pre-commit hook exists but not Ultra-Dex');
157
+ hooksSpinner.info('Pre-commit active but not Ultra-Dex');
152
158
  checks.push({ name: 'Git Hooks', status: 'info', detail: 'Custom hook present' });
153
159
  }
154
160
  } catch {
@@ -157,13 +163,15 @@ export function registerDoctorCommand(program) {
157
163
  }
158
164
 
159
165
  // Check 6: Configuration
160
- const configSpinner = ora('Checking configuration...').start();
166
+ const configSpinner = createSpinner('Reading Configuration...');
167
+ configSpinner.start();
161
168
  const config = await loadConfig();
162
- configSpinner.succeed(`Config loaded from: ${config.source}`);
169
+ configSpinner.succeed(`Configuration loaded from: ${config.source}`);
163
170
  checks.push({ name: 'Configuration', status: 'ok', detail: `Source: ${config.source}` });
164
171
 
165
172
  // Check 7: MCP Server port
166
- const portSpinner = ora('Checking MCP server port...').start();
173
+ const portSpinner = createSpinner('Checking MCP Port...');
174
+ portSpinner.start();
167
175
  try {
168
176
  const net = await import('net');
169
177
  const server = net.createServer();
@@ -175,51 +183,52 @@ export function registerDoctorCommand(program) {
175
183
  });
176
184
  server.listen(config.mcpPort);
177
185
  });
178
- portSpinner.succeed(`Port ${config.mcpPort} available āœ“`);
186
+ portSpinner.succeed(`Port ${config.mcpPort} open āœ“`);
179
187
  checks.push({ name: 'MCP Port', status: 'ok', detail: `Port ${config.mcpPort} free` });
180
188
  } catch {
181
- portSpinner.warn(`Port ${config.mcpPort} in use`);
189
+ portSpinner.warn(`Portal ${config.mcpPort} blocked`);
182
190
  checks.push({ name: 'MCP Port', status: 'warn', detail: `Port ${config.mcpPort} busy - change with config` });
183
191
  }
184
192
 
185
193
  // Summary
186
- console.log(chalk.bold('\nšŸ“‹ Summary\n'));
187
- console.log(chalk.gray('─'.repeat(50)));
194
+ header('Diagnostics Report');
188
195
 
189
196
  const okCount = checks.filter(c => c.status === 'ok').length;
190
197
  const warnCount = checks.filter(c => c.status === 'warn').length;
191
198
  const errorCount = checks.filter(c => c.status === 'error').length;
192
199
 
193
200
  checks.forEach(check => {
194
- const icon = check.status === 'ok' ? chalk.green('āœ“') :
195
- check.status === 'warn' ? chalk.yellow('⚠') :
196
- check.status === 'error' ? chalk.red('āœ—') :
197
- chalk.blue('ℹ');
198
- console.log(` ${icon} ${check.name.padEnd(18)} ${chalk.gray(check.detail)}`);
201
+ let icon;
202
+ if (check.status === 'ok') icon = icons.success;
203
+ else if (check.status === 'warn') icon = icons.warning;
204
+ else if (check.status === 'error') icon = icons.error;
205
+ else icon = icons.info;
206
+
207
+ statusLine(icon, `${check.name.padEnd(18)} ${chalk.gray(check.detail)}`);
199
208
  });
200
209
 
201
- console.log(chalk.gray('─'.repeat(50)));
210
+ console.log(chalk.gray(' ' + '─'.repeat(50)));
202
211
  console.log(` ${chalk.green(okCount + ' passed')} ${chalk.yellow(warnCount + ' warnings')} ${chalk.red(errorCount + ' errors')}`);
203
212
 
204
213
  if (hasErrors) {
205
- console.log(chalk.red('\nāŒ Some checks failed. Fix issues above.\n'));
214
+ console.log(chalk.red('\nāŒ System check failed. Fix issues above.\n'));
206
215
  process.exit(1);
207
216
  } else if (warnCount > 0) {
208
- console.log(chalk.yellow('\nāš ļø Some warnings. Setup works but could be improved.\n'));
217
+ console.log(chalk.yellow('\nāš ļø System operational but has warnings.\n'));
209
218
  } else {
210
- console.log(chalk.green('\nāœ… All checks passed! Ultra-Dex is ready.\n'));
219
+ console.log(chalk.green('\nāœ… All systems operational.\n'));
211
220
  }
212
221
 
213
222
  // Suggestions
214
223
  if (configuredProviders.length === 0) {
215
- console.log(chalk.cyan('šŸ’” To enable AI features, set an API key:'));
224
+ console.log(chalk.cyan('šŸ’” To configure AI providers, set an API key:'));
216
225
  console.log(chalk.gray(' export ANTHROPIC_API_KEY=sk-ant-...'));
217
226
  console.log(chalk.gray(' export OPENAI_API_KEY=sk-...'));
218
227
  console.log(chalk.gray(' export GEMINI_API_KEY=...\n'));
219
228
  }
220
229
 
221
230
  if (foundRequired.length === 0) {
222
- console.log(chalk.cyan('šŸ’” To start a new project:'));
231
+ console.log(chalk.cyan('šŸ’” To initialize a new project:'));
223
232
  console.log(chalk.gray(' ultra-dex init\n'));
224
233
  }
225
234
  });
@@ -257,7 +266,7 @@ export function registerConfigCommand(program) {
257
266
 
258
267
  console.log(chalk.cyan('\nšŸ“ Config file locations:'));
259
268
  console.log(chalk.gray(' macOS: ~/Library/Application Support/Claude/claude_desktop_config.json'));
260
- console.log(chalk.gray(' Windows: %APPDATA%\\Claude\\claude_desktop_config.json'));
269
+ console.log(chalk.gray(' Windows: %APPDATA%\Claude\claude_desktop_config.json'));
261
270
  console.log(chalk.gray(' Linux: ~/.config/Claude/claude_desktop_config.json\n'));
262
271
  return;
263
272
  }
@@ -313,19 +322,21 @@ export function registerConfigCommand(program) {
313
322
  // Interactive mode
314
323
  console.log(chalk.cyan('\nāš™ļø Ultra-Dex Configuration\n'));
315
324
 
316
- const { action } = await inquirer.prompt([{
317
- type: 'list',
318
- name: 'action',
319
- message: 'What would you like to do?',
320
- choices: [
321
- { name: 'View current config', value: 'view' },
322
- { name: 'Set default AI provider', value: 'provider' },
323
- { name: 'Set minimum alignment score', value: 'minScore' },
324
- { name: 'Set MCP server port', value: 'mcpPort' },
325
- { name: 'Generate MCP config for Claude', value: 'mcp' },
326
- { name: 'Create new config file', value: 'init' },
327
- ]
328
- }]);
325
+ const { action } = await inquirer.prompt([
326
+ {
327
+ type: 'list',
328
+ name: 'action',
329
+ message: 'What would you like to do?',
330
+ choices: [
331
+ { name: 'View current config', value: 'view' },
332
+ { name: 'Set default AI provider', value: 'provider' },
333
+ { name: 'Set minimum alignment score', value: 'minScore' },
334
+ { name: 'Set MCP server port', value: 'mcpPort' },
335
+ { name: 'Generate MCP config for Claude', value: 'mcp' },
336
+ { name: 'Create new config file', value: 'init' },
337
+ ]
338
+ }
339
+ ]);
329
340
 
330
341
  switch (action) {
331
342
  case 'view':
@@ -333,39 +344,45 @@ export function registerConfigCommand(program) {
333
344
  break;
334
345
 
335
346
  case 'provider':
336
- const { provider } = await inquirer.prompt([{
337
- type: 'list',
338
- name: 'provider',
339
- message: 'Select default AI provider:',
340
- choices: ['claude', 'openai', 'gemini'],
341
- default: config.provider
342
- }]);
347
+ const { provider } = await inquirer.prompt([
348
+ {
349
+ type: 'list',
350
+ name: 'provider',
351
+ message: 'Select default AI provider:',
352
+ choices: ['claude', 'openai', 'gemini'],
353
+ default: config.provider
354
+ }
355
+ ]);
343
356
  config.provider = provider;
344
357
  await saveConfig(config, options.global);
345
358
  console.log(chalk.green(`\nāœ… Default provider set to: ${provider}\n`));
346
359
  break;
347
360
 
348
361
  case 'minScore':
349
- const { minScore } = await inquirer.prompt([{
350
- type: 'number',
351
- name: 'minScore',
352
- message: 'Minimum alignment score (0-100):',
353
- default: config.minScore,
354
- validate: n => n >= 0 && n <= 100 || 'Must be 0-100'
355
- }]);
362
+ const { minScore } = await inquirer.prompt([
363
+ {
364
+ type: 'number',
365
+ name: 'minScore',
366
+ message: 'Minimum alignment score (0-100):',
367
+ default: config.minScore,
368
+ validate: n => n >= 0 && n <= 100 || 'Must be 0-100'
369
+ }
370
+ ]);
356
371
  config.minScore = minScore;
357
372
  await saveConfig(config, options.global);
358
373
  console.log(chalk.green(`\nāœ… Minimum score set to: ${minScore}\n`));
359
374
  break;
360
375
 
361
376
  case 'mcpPort':
362
- const { mcpPort } = await inquirer.prompt([{
363
- type: 'number',
364
- name: 'mcpPort',
365
- message: 'MCP server port:',
366
- default: config.mcpPort,
367
- validate: n => n > 0 && n < 65536 || 'Invalid port'
368
- }]);
377
+ const { mcpPort } = await inquirer.prompt([
378
+ {
379
+ type: 'number',
380
+ name: 'mcpPort',
381
+ message: 'MCP server port:',
382
+ default: config.mcpPort,
383
+ validate: n => n > 0 && n < 65536 || 'Invalid port'
384
+ }
385
+ ]);
369
386
  config.mcpPort = mcpPort;
370
387
  await saveConfig(config, options.global);
371
388
  console.log(chalk.green(`\nāœ… MCP port set to: ${mcpPort}\n`));
@@ -378,15 +395,17 @@ export function registerConfigCommand(program) {
378
395
  break;
379
396
 
380
397
  case 'init':
381
- const { scope } = await inquirer.prompt([{
382
- type: 'list',
383
- name: 'scope',
384
- message: 'Create config in:',
385
- choices: [
386
- { name: 'This project (.ultra-dex.json)', value: 'project' },
387
- { name: 'Global (~/.ultra-dex.json)', value: 'global' },
388
- ]
389
- }]);
398
+ const { scope } = await inquirer.prompt([
399
+ {
400
+ type: 'list',
401
+ name: 'scope',
402
+ message: 'Create config in:',
403
+ choices: [
404
+ { name: 'This project (.ultra-dex.json)', value: 'project' },
405
+ { name: 'Global (~/.ultra-dex.json)', value: 'global' },
406
+ ]
407
+ }
408
+ ]);
390
409
  const configPath = await saveConfig(DEFAULT_CONFIG, scope === 'global');
391
410
  console.log(chalk.green(`\nāœ… Config created: ${configPath}\n`));
392
411
  break;
@@ -394,4 +413,4 @@ export function registerConfigCommand(program) {
394
413
  });
395
414
  }
396
415
 
397
- export default { registerDoctorCommand, registerConfigCommand };
416
+ export default { registerDoctorCommand, registerConfigCommand };