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
@@ -0,0 +1,434 @@
1
+ /**
2
+ * ultra-dex exec command
3
+ * Docker-based code execution sandbox for running generated code safely
4
+ * This is what makes Ultra-Dex truly autonomous - it can VERIFY code works
5
+ */
6
+
7
+ import chalk from 'chalk';
8
+ import ora from 'ora';
9
+ import fs from 'fs/promises';
10
+ import path from 'path';
11
+ import { spawn, exec as execCallback } from 'child_process';
12
+ import { promisify } from 'util';
13
+
14
+ const execAsync = promisify(execCallback);
15
+
16
+ // ============================================================================
17
+ // SANDBOX CONFIGURATION
18
+ // ============================================================================
19
+
20
+ const SANDBOX_CONFIG = {
21
+ // Docker image for sandboxed execution
22
+ defaultImage: 'node:20-alpine',
23
+
24
+ // Language-specific images
25
+ images: {
26
+ javascript: 'node:20-alpine',
27
+ typescript: 'node:20-alpine',
28
+ python: 'python:3.12-alpine',
29
+ rust: 'rust:1.75-alpine',
30
+ go: 'golang:1.22-alpine',
31
+ ruby: 'ruby:3.3-alpine',
32
+ },
33
+
34
+ // Resource limits
35
+ limits: {
36
+ memory: '512m',
37
+ cpus: '1.0',
38
+ timeout: 60000, // 60 seconds
39
+ networkDisabled: true,
40
+ },
41
+
42
+ // Workspace settings
43
+ workspace: {
44
+ containerPath: '/workspace',
45
+ tempDir: '.ultra-dex/sandbox',
46
+ }
47
+ };
48
+
49
+ // ============================================================================
50
+ // DOCKER UTILITIES
51
+ // ============================================================================
52
+
53
+ /**
54
+ * Check if Docker is available
55
+ */
56
+ async function checkDocker() {
57
+ try {
58
+ await execAsync('docker --version');
59
+ return true;
60
+ } catch {
61
+ return false;
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Pull Docker image if not available
67
+ */
68
+ async function ensureImage(image, spinner) {
69
+ try {
70
+ await execAsync(`docker image inspect ${image} > /dev/null 2>&1`);
71
+ return true;
72
+ } catch {
73
+ spinner.text = `Pulling Docker image: ${image}...`;
74
+ try {
75
+ await execAsync(`docker pull ${image}`);
76
+ return true;
77
+ } catch (err) {
78
+ return false;
79
+ }
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Detect language from file extension
85
+ */
86
+ function detectLanguage(filepath) {
87
+ const ext = path.extname(filepath).toLowerCase();
88
+ const langMap = {
89
+ '.js': 'javascript',
90
+ '.mjs': 'javascript',
91
+ '.ts': 'typescript',
92
+ '.tsx': 'typescript',
93
+ '.py': 'python',
94
+ '.rs': 'rust',
95
+ '.go': 'go',
96
+ '.rb': 'ruby',
97
+ };
98
+ return langMap[ext] || 'javascript';
99
+ }
100
+
101
+ /**
102
+ * Get execution command for language
103
+ */
104
+ function getExecCommand(language, filename) {
105
+ const commands = {
106
+ javascript: `node ${filename}`,
107
+ typescript: `npx tsx ${filename}`,
108
+ python: `python ${filename}`,
109
+ rust: `rustc ${filename} -o /tmp/out && /tmp/out`,
110
+ go: `go run ${filename}`,
111
+ ruby: `ruby ${filename}`,
112
+ };
113
+ return commands[language] || `node ${filename}`;
114
+ }
115
+
116
+ // ============================================================================
117
+ // SANDBOX EXECUTOR
118
+ // ============================================================================
119
+
120
+ /**
121
+ * Execute code in Docker sandbox
122
+ */
123
+ export async function executeInSandbox(code, options = {}) {
124
+ const {
125
+ language = 'javascript',
126
+ filename = 'main.js',
127
+ timeout = SANDBOX_CONFIG.limits.timeout,
128
+ allowNetwork = false,
129
+ env = {},
130
+ workdir = process.cwd(),
131
+ } = options;
132
+
133
+ const image = SANDBOX_CONFIG.images[language] || SANDBOX_CONFIG.defaultImage;
134
+ const tempDir = path.join(workdir, SANDBOX_CONFIG.workspace.tempDir);
135
+ const tempFile = path.join(tempDir, filename);
136
+
137
+ // Ensure temp directory exists
138
+ await fs.mkdir(tempDir, { recursive: true });
139
+
140
+ // Write code to temp file
141
+ await fs.writeFile(tempFile, code, 'utf8');
142
+
143
+ // Build Docker command
144
+ const dockerArgs = [
145
+ 'run',
146
+ '--rm',
147
+ '-i',
148
+ `--memory=${SANDBOX_CONFIG.limits.memory}`,
149
+ `--cpus=${SANDBOX_CONFIG.limits.cpus}`,
150
+ allowNetwork ? '' : '--network=none',
151
+ `-v`, `${tempDir}:${SANDBOX_CONFIG.workspace.containerPath}:ro`,
152
+ `-w`, SANDBOX_CONFIG.workspace.containerPath,
153
+ ];
154
+
155
+ // Add environment variables
156
+ for (const [key, value] of Object.entries(env)) {
157
+ dockerArgs.push('-e', `${key}=${value}`);
158
+ }
159
+
160
+ dockerArgs.push(image);
161
+
162
+ // Add execution command
163
+ const execCmd = getExecCommand(language, filename);
164
+ dockerArgs.push('sh', '-c', execCmd);
165
+
166
+ // Filter empty strings
167
+ const filteredArgs = dockerArgs.filter(Boolean);
168
+
169
+ return new Promise((resolve, reject) => {
170
+ const result = {
171
+ stdout: '',
172
+ stderr: '',
173
+ exitCode: null,
174
+ timedOut: false,
175
+ duration: 0,
176
+ };
177
+
178
+ const startTime = Date.now();
179
+ const proc = spawn('docker', filteredArgs);
180
+
181
+ const timeoutId = setTimeout(() => {
182
+ result.timedOut = true;
183
+ proc.kill('SIGKILL');
184
+ }, timeout);
185
+
186
+ proc.stdout.on('data', (data) => {
187
+ result.stdout += data.toString();
188
+ });
189
+
190
+ proc.stderr.on('data', (data) => {
191
+ result.stderr += data.toString();
192
+ });
193
+
194
+ proc.on('close', (code) => {
195
+ clearTimeout(timeoutId);
196
+ result.exitCode = code;
197
+ result.duration = Date.now() - startTime;
198
+ resolve(result);
199
+ });
200
+
201
+ proc.on('error', (err) => {
202
+ clearTimeout(timeoutId);
203
+ reject(err);
204
+ });
205
+ });
206
+ }
207
+
208
+ /**
209
+ * Execute a file in sandbox
210
+ */
211
+ export async function executeFile(filepath, options = {}) {
212
+ const code = await fs.readFile(filepath, 'utf8');
213
+ const language = detectLanguage(filepath);
214
+ const filename = path.basename(filepath);
215
+
216
+ return executeInSandbox(code, {
217
+ ...options,
218
+ language,
219
+ filename,
220
+ });
221
+ }
222
+
223
+ /**
224
+ * Execute npm/shell command in sandbox
225
+ */
226
+ export async function executeCommand(command, options = {}) {
227
+ const {
228
+ timeout = SANDBOX_CONFIG.limits.timeout,
229
+ workdir = process.cwd(),
230
+ allowNetwork = true, // Commands often need network
231
+ } = options;
232
+
233
+ const tempDir = path.join(workdir, SANDBOX_CONFIG.workspace.tempDir);
234
+ await fs.mkdir(tempDir, { recursive: true });
235
+
236
+ const dockerArgs = [
237
+ 'run',
238
+ '--rm',
239
+ '-i',
240
+ `--memory=${SANDBOX_CONFIG.limits.memory}`,
241
+ `--cpus=${SANDBOX_CONFIG.limits.cpus}`,
242
+ allowNetwork ? '' : '--network=none',
243
+ `-v`, `${workdir}:${SANDBOX_CONFIG.workspace.containerPath}`,
244
+ `-w`, SANDBOX_CONFIG.workspace.containerPath,
245
+ SANDBOX_CONFIG.defaultImage,
246
+ 'sh', '-c', command,
247
+ ].filter(Boolean);
248
+
249
+ return new Promise((resolve, reject) => {
250
+ const result = {
251
+ stdout: '',
252
+ stderr: '',
253
+ exitCode: null,
254
+ timedOut: false,
255
+ duration: 0,
256
+ };
257
+
258
+ const startTime = Date.now();
259
+ const proc = spawn('docker', dockerArgs);
260
+
261
+ const timeoutId = setTimeout(() => {
262
+ result.timedOut = true;
263
+ proc.kill('SIGKILL');
264
+ }, timeout);
265
+
266
+ proc.stdout.on('data', (data) => {
267
+ result.stdout += data.toString();
268
+ });
269
+
270
+ proc.stderr.on('data', (data) => {
271
+ result.stderr += data.toString();
272
+ });
273
+
274
+ proc.on('close', (code) => {
275
+ clearTimeout(timeoutId);
276
+ result.exitCode = code;
277
+ result.duration = Date.now() - startTime;
278
+ resolve(result);
279
+ });
280
+
281
+ proc.on('error', (err) => {
282
+ clearTimeout(timeoutId);
283
+ reject(err);
284
+ });
285
+ });
286
+ }
287
+
288
+ // ============================================================================
289
+ // TEST RUNNER
290
+ // ============================================================================
291
+
292
+ /**
293
+ * Run tests in sandbox
294
+ */
295
+ export async function runTests(testCommand = 'npm test', options = {}) {
296
+ const spinner = ora('Running tests in sandbox...').start();
297
+
298
+ try {
299
+ const result = await executeCommand(testCommand, {
300
+ ...options,
301
+ allowNetwork: true, // Tests may need to install deps
302
+ });
303
+
304
+ if (result.exitCode === 0) {
305
+ spinner.succeed(chalk.green('Tests passed!'));
306
+ } else {
307
+ spinner.fail(chalk.red('Tests failed'));
308
+ }
309
+
310
+ return result;
311
+ } catch (err) {
312
+ spinner.fail(chalk.red(`Test execution failed: ${err.message}`));
313
+ throw err;
314
+ }
315
+ }
316
+
317
+ // ============================================================================
318
+ // CLI COMMAND
319
+ // ============================================================================
320
+
321
+ export function registerExecCommand(program) {
322
+ program
323
+ .command('exec [file]')
324
+ .description('Execute code in isolated Docker sandbox')
325
+ .option('-c, --code <code>', 'Execute inline code')
326
+ .option('-l, --language <lang>', 'Language (js, ts, py, go, rs, rb)')
327
+ .option('-t, --timeout <ms>', 'Timeout in milliseconds', '60000')
328
+ .option('--allow-network', 'Allow network access in sandbox')
329
+ .option('--command <cmd>', 'Run shell command instead of file')
330
+ .option('--test', 'Run npm test in sandbox')
331
+ .action(async (file, options) => {
332
+ console.log(chalk.cyan('\n🐳 Ultra-Dex Code Sandbox\n'));
333
+
334
+ // Check Docker availability
335
+ const spinner = ora('Checking Docker...').start();
336
+ const hasDocker = await checkDocker();
337
+
338
+ if (!hasDocker) {
339
+ spinner.fail(chalk.red('Docker not found. Please install Docker to use the sandbox.'));
340
+ console.log(chalk.yellow('\nInstall Docker: https://docs.docker.com/get-docker/'));
341
+ return;
342
+ }
343
+ spinner.succeed('Docker available');
344
+
345
+ const timeout = parseInt(options.timeout, 10);
346
+
347
+ try {
348
+ let result;
349
+
350
+ if (options.test) {
351
+ // Run tests
352
+ result = await runTests('npm test', { timeout, allowNetwork: true });
353
+ } else if (options.command) {
354
+ // Run shell command
355
+ spinner.start(`Executing: ${options.command}`);
356
+ result = await executeCommand(options.command, {
357
+ timeout,
358
+ allowNetwork: options.allowNetwork,
359
+ });
360
+ } else if (options.code) {
361
+ // Execute inline code
362
+ const language = options.language || 'javascript';
363
+ const image = SANDBOX_CONFIG.images[language];
364
+
365
+ spinner.start('Preparing sandbox...');
366
+ await ensureImage(image, spinner);
367
+
368
+ spinner.text = 'Executing code...';
369
+ result = await executeInSandbox(options.code, {
370
+ language,
371
+ timeout,
372
+ allowNetwork: options.allowNetwork,
373
+ });
374
+ } else if (file) {
375
+ // Execute file
376
+ const language = options.language || detectLanguage(file);
377
+ const image = SANDBOX_CONFIG.images[language];
378
+
379
+ spinner.start('Preparing sandbox...');
380
+ await ensureImage(image, spinner);
381
+
382
+ spinner.text = `Executing ${file}...`;
383
+ result = await executeFile(file, {
384
+ timeout,
385
+ allowNetwork: options.allowNetwork,
386
+ });
387
+ } else {
388
+ spinner.fail('No code, file, or command specified');
389
+ console.log(chalk.yellow('\nUsage:'));
390
+ console.log(' ultra-dex exec script.js');
391
+ console.log(' ultra-dex exec -c "console.log(1+1)"');
392
+ console.log(' ultra-dex exec --command "npm test"');
393
+ console.log(' ultra-dex exec --test');
394
+ return;
395
+ }
396
+
397
+ // Show results
398
+ if (result.timedOut) {
399
+ spinner.fail(chalk.red(`Execution timed out after ${timeout}ms`));
400
+ } else if (result.exitCode === 0) {
401
+ spinner.succeed(chalk.green(`Completed in ${result.duration}ms`));
402
+ } else {
403
+ spinner.warn(chalk.yellow(`Exited with code ${result.exitCode}`));
404
+ }
405
+
406
+ // Print output
407
+ if (result.stdout) {
408
+ console.log(chalk.bold('\nšŸ“¤ Output:'));
409
+ console.log(result.stdout);
410
+ }
411
+
412
+ if (result.stderr) {
413
+ console.log(chalk.bold('\nāš ļø Stderr:'));
414
+ console.log(chalk.red(result.stderr));
415
+ }
416
+
417
+ // Summary
418
+ console.log(chalk.gray(`\nā±ļø Duration: ${result.duration}ms`));
419
+ console.log(chalk.gray(`šŸ”’ Network: ${options.allowNetwork ? 'Enabled' : 'Disabled'}`));
420
+
421
+ } catch (err) {
422
+ spinner.fail(chalk.red(`Execution failed: ${err.message}`));
423
+ }
424
+ });
425
+ }
426
+
427
+ export default {
428
+ registerExecCommand,
429
+ executeInSandbox,
430
+ executeFile,
431
+ executeCommand,
432
+ runTests,
433
+ checkDocker,
434
+ };
@@ -13,11 +13,12 @@ import { SYSTEM_PROMPT, generateUserPrompt } from '../templates/prompts/generate
13
13
  import { validateSafePath } from '../utils/validation.js';
14
14
  import { githubTreeUrl, githubWebUrl } from '../config/urls.js';
15
15
  import { saveState } from './plan.js';
16
+ import { getRandomMessage } from '../utils/messages.js';
16
17
 
17
18
  export function registerGenerateCommand(program) {
18
19
  program
19
20
  .command('generate [idea]')
20
- .description('Generate a full implementation plan from an idea using AI')
21
+ .description('Create the plan (Thanos style) - AI Generates Full Plan')
21
22
  .option('-p, --provider <provider>', 'AI provider (claude, openai, gemini)')
22
23
  .option('-m, --model <model>', 'Specific model to use')
23
24
  .option('-o, --output <directory>', 'Output directory', '.')
@@ -25,7 +26,9 @@ export function registerGenerateCommand(program) {
25
26
  .option('--stream', 'Stream output in real-time', true)
26
27
  .option('--no-stream', 'Disable streaming')
27
28
  .action(async (idea, options) => {
28
- console.log(chalk.cyan('\nšŸš€ Ultra-Dex Plan Generator\n'));
29
+ console.log(chalk.cyan('\nšŸš€ Ultra-Dex Plan Generator (Reality Stone Mode)\n'));
30
+ console.log(chalk.hex('#7c3aed').italic(`"${getRandomMessage('start')}"`));
31
+ console.log('');
29
32
 
30
33
  const dirValidation = validateSafePath(options.output, 'Output directory');
31
34
  if (dirValidation !== true) {
@@ -38,7 +41,7 @@ export function registerGenerateCommand(program) {
38
41
  const hasProvider = configured.some(p => p.configured) || options.key;
39
42
 
40
43
  if (!hasProvider) {
41
- console.log(chalk.yellow('āš ļø No AI provider configured.\n'));
44
+ console.log(chalk.yellow('āš ļø No Infinity Stones (AI Keys) configured.\n'));
42
45
  console.log(chalk.white('Set one of these environment variables:'));
43
46
  configured.forEach(p => {
44
47
  console.log(chalk.gray(` export ${p.envKey}=your-key-here`));
@@ -54,7 +57,7 @@ export function registerGenerateCommand(program) {
54
57
  {
55
58
  type: 'input',
56
59
  name: 'idea',
57
- message: 'Describe your SaaS idea:',
60
+ message: 'Describe the reality you wish to create:',
58
61
  validate: input => input.trim().length > 10 || 'Please provide a more detailed description',
59
62
  },
60
63
  ]);
@@ -85,7 +88,7 @@ export function registerGenerateCommand(program) {
85
88
  }
86
89
 
87
90
  // Generate the plan
88
- const spinner = ora('Generating your implementation plan...').start();
91
+ const spinner = ora('Reshaping reality (Generating Plan)...').start();
89
92
  const startTime = Date.now();
90
93
 
91
94
  try {
@@ -94,7 +97,7 @@ export function registerGenerateCommand(program) {
94
97
 
95
98
  if (options.stream) {
96
99
  spinner.stop();
97
- console.log(chalk.cyan('šŸ“ Generating plan:\n'));
100
+ console.log(chalk.cyan('šŸ“ Manifesting Reality:\n'));
98
101
  console.log(chalk.gray('─'.repeat(60)));
99
102
 
100
103
  result = await provider.generateStream(
@@ -128,7 +131,7 @@ export function registerGenerateCommand(program) {
128
131
  // Add header to plan
129
132
  const header = `# Implementation Plan
130
133
 
131
- > Generated by Ultra-Dex AI Plan Generator
134
+ > Generated by Ultra-Dex AI Plan Generator (Doomsday Edition)
132
135
 
133
136
  `;
134
137
  if (!planContent.startsWith('#')) {
@@ -208,17 +211,17 @@ ${idea}
208
211
  2. Start with the first feature
209
212
  3. Use Ultra-Dex agents for guidance
210
213
 
211
- ## AI Agents
212
- - @Planner: Break down tasks
213
- - @CTO: Architecture decisions
214
- - @Backend: API logic
215
- - @Frontend: UI components
216
- - @Testing: QA and tests
214
+ ## AI Agents (The Avengers)
215
+ - @Planner (Nick Fury): Break down tasks
216
+ - @CTO (Iron Man): Architecture decisions
217
+ - @Backend (Thor): API logic
218
+ - @Frontend (Spider-Man): UI components
219
+ - @Testing (Ant-Man): QA and tests
217
220
  `;
218
221
 
219
222
  await fs.writeFile(quickStartPath, quickStartContent);
220
223
 
221
- spinner.succeed('Plan generated successfully!');
224
+ spinner.succeed(chalk.green('Reality successfully rewritten!'));
222
225
 
223
226
  console.log(chalk.green('\nāœ… Files created:'));
224
227
  console.log(chalk.gray(` ${planPath}`));
@@ -232,9 +235,9 @@ ${idea}
232
235
  console.log(chalk.cyan(' 1. Review IMPLEMENTATION-PLAN.md'));
233
236
  console.log(chalk.cyan(' 2. Run `ultra-dex dashboard` to visualize your progress'));
234
237
  console.log(chalk.cyan(' 3. Run `ultra-dex build` to let Auto-Pilot take the first task'));
235
- console.log(chalk.cyan(' 4. Use AI agents for specialized guidance\n'));
238
+ console.log(chalk.cyan(' 4. Summon Avengers (AI agents) for guidance\n'));
236
239
  } catch (err) {
237
- spinner.fail('Failed to generate plan');
240
+ spinner.fail(chalk.red('Failed to manifest reality'));
238
241
  console.error(chalk.red('Error:'), err.message);
239
242
  }
240
243
  });