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
@@ -7,29 +7,40 @@ import path from 'path';
7
7
  import { QUICK_START_TEMPLATE } from '../templates/quick-start.js';
8
8
  import { CONTEXT_TEMPLATE } from '../templates/context.js';
9
9
  import { validateProjectName, validateSafePath } from '../utils/validation.js';
10
- import { ASSETS_ROOT, ROOT_FALLBACK } from '../config/paths.js';
11
- import { githubBlobUrl, githubWebUrl } from '../config/urls.js';
10
+ import { ASSETS_ROOT, ROOT_FALLBACK, LIVE_TEMPLATES_ROOT } from '../config/paths.js';
11
+ import { githubBlobUrl } from '../config/urls.js';
12
12
  import { copyWithFallback, listWithFallback, readWithFallback } from '../utils/fallback.js';
13
+ import { copyDirectory, pathExists } from '../utils/files.js';
14
+ import { getRandomMessage } from '../utils/messages.js';
15
+
16
+ const LIVE_STACKS = {
17
+ 'next15-prisma-clerk': 'Next.js 15 + Prisma + Clerk',
18
+ 'remix-supabase': 'Remix + Supabase',
19
+ 'sveltekit-drizzle': 'SvelteKit + Drizzle',
20
+ };
13
21
 
14
22
  export function registerInitCommand(program) {
15
23
  program
16
24
  .command('init')
17
- .description('Initialize a new Ultra-Dex project')
25
+ .description('Initialize a new Ultra-Dex Project')
18
26
  .option('-n, --name <name>', 'Project name')
19
27
  .option('-d, --dir <directory>', 'Output directory', '.')
20
28
  .option('--preview', 'Preview files without creating them')
29
+ .option('--live', 'Generate a runnable scaffold')
30
+ .option('--stack <preset>', 'Preset: next15-prisma-clerk, remix-supabase, sveltekit-drizzle')
21
31
  .action(async (options) => {
22
32
  console.log(chalk.cyan(program.banner));
23
- console.log(chalk.bold('\nWelcome to Ultra-Dex! Let\'s plan your SaaS.\n'));
33
+ console.log(chalk.hex('#8b5cf6').bold('\n⚔ INITIALIZING PROJECT PROTOCOL...\n'));
34
+ console.log(chalk.italic(chalk.gray(`"${getRandomMessage('start')}"`)));
35
+ console.log('');
24
36
 
25
37
  if (options.preview) {
26
- console.log('\nšŸ“‹ Files that would be created:\n');
38
+ console.log('\nšŸ“‹ Project Preview (Files that would be created):\n');
27
39
  console.log(' QUICK-START.md');
28
40
  console.log(' CONTEXT.md');
29
41
  console.log(' IMPLEMENTATION-PLAN.md');
30
42
  console.log(' docs/CHECKLIST.md');
31
43
  console.log(' docs/AI-PROMPTS.md');
32
- console.log('\nRun without --preview to create files.');
33
44
  return;
34
45
  }
35
46
 
@@ -39,107 +50,150 @@ export function registerInitCommand(program) {
39
50
  process.exit(1);
40
51
  }
41
52
 
53
+ if (options.live) {
54
+ const preset = options.stack || 'next15-prisma-clerk';
55
+ if (!LIVE_STACKS[preset]) {
56
+ console.log(chalk.red(`Unknown preset: ${preset}`));
57
+ console.log(chalk.gray(`Available presets: ${Object.keys(LIVE_STACKS).join(', ')}`));
58
+ process.exit(1);
59
+ }
60
+
61
+ const outputDir = path.resolve(options.dir);
62
+ if (await pathExists(outputDir, 'dir')) {
63
+ const existing = await fs.readdir(outputDir);
64
+ if (existing.length > 0) {
65
+ console.log(chalk.red('Target directory is not empty. Execution halted to prevent data loss.'));
66
+ process.exit(1);
67
+ }
68
+ }
69
+
70
+ const liveSourcePath = path.join(LIVE_TEMPLATES_ROOT, preset);
71
+ const fallbackLivePath = path.join(ROOT_FALLBACK, 'cli', 'assets', 'live-templates', preset);
72
+ let sourcePath = liveSourcePath;
73
+ try {
74
+ await fs.access(liveSourcePath);
75
+ } catch {
76
+ sourcePath = fallbackLivePath;
77
+ }
78
+
79
+ const spinner = ora(`Generating ${LIVE_STACKS[preset]} scaffold...`).start();
80
+ try {
81
+ await copyDirectory(sourcePath, outputDir);
82
+ spinner.succeed(chalk.green('Project scaffold generated successfully!'));
83
+ console.log(chalk.gray(`\nPreset: ${preset}`));
84
+ console.log(chalk.gray(`Next steps:`));
85
+ console.log(chalk.cyan(` 1. cd ${outputDir}`));
86
+ console.log(chalk.cyan(' 2. npm install'));
87
+ console.log(chalk.cyan(' 3. npm run dev\n'));
88
+ } catch (error) {
89
+ spinner.fail(chalk.red('Failed to generate project scaffold'));
90
+ console.error(`[init] ${error?.message ?? error}`);
91
+ process.exit(1);
92
+ }
93
+ return;
94
+ }
95
+
42
96
  const answers = await inquirer.prompt([
43
97
  {
44
98
  type: 'input',
45
99
  name: 'projectName',
46
- message: 'What\'s your project name?',
100
+ message: 'What is the name of this project?',
47
101
  default: options.name || 'my-saas',
48
102
  validate: validateProjectName,
49
103
  },
50
104
  {
51
105
  type: 'input',
52
106
  name: 'ideaWhat',
53
- message: 'What are you building? (1 sentence)',
54
- validate: (input) => input.length > 0 || 'Please describe your idea',
107
+ message: 'Define the core purpose (What are you building?):',
108
+ validate: (input) => input.length > 0 || 'Please describe your project',
55
109
  },
56
110
  {
57
111
  type: 'input',
58
112
  name: 'ideaFor',
59
- message: 'Who is it for?',
60
- validate: (input) => input.length > 0 || 'Please specify your target users',
113
+ message: 'Target audience (Who are the users)?',
114
+ validate: (input) => input.length > 0 || 'Please specify your target audience',
61
115
  },
62
116
  {
63
117
  type: 'input',
64
118
  name: 'problem1',
65
- message: 'Problem #1 you\'re solving:',
119
+ message: 'Primary problem to solve:',
66
120
  default: '',
67
121
  },
68
122
  {
69
123
  type: 'input',
70
124
  name: 'problem2',
71
- message: 'Problem #2 you\'re solving:',
125
+ message: 'Secondary problem to solve:',
72
126
  default: '',
73
127
  },
74
128
  {
75
129
  type: 'input',
76
130
  name: 'problem3',
77
- message: 'Problem #3 you\'re solving:',
131
+ message: 'Tertiary problem to solve:',
78
132
  default: '',
79
133
  },
80
134
  {
81
135
  type: 'input',
82
136
  name: 'feature1',
83
- message: 'Critical production feature:',
137
+ message: 'Core feature:',
84
138
  default: '',
85
139
  },
86
140
  {
87
141
  type: 'list',
88
142
  name: 'frontend',
89
- message: 'Frontend framework:',
143
+ message: 'Frontend Technology Stack:',
90
144
  choices: ['Next.js', 'Remix', 'SvelteKit', 'Nuxt', 'Other'],
91
145
  },
92
146
  {
93
147
  type: 'list',
94
148
  name: 'database',
95
- message: 'Database:',
149
+ message: 'Database Infrastructure:',
96
150
  choices: ['PostgreSQL', 'Supabase', 'MongoDB', 'PlanetScale', 'Other'],
97
151
  },
98
152
  {
99
153
  type: 'list',
100
154
  name: 'auth',
101
- message: 'Authentication:',
155
+ message: 'Authentication Provider:',
102
156
  choices: ['NextAuth', 'Clerk', 'Auth0', 'Supabase Auth', 'Other'],
103
157
  },
104
158
  {
105
159
  type: 'list',
106
160
  name: 'payments',
107
- message: 'Payments:',
161
+ message: 'Payment Processor:',
108
162
  choices: ['Stripe', 'Lemonsqueezy', 'Paddle', 'None (free)', 'Other'],
109
163
  },
110
164
  {
111
165
  type: 'list',
112
166
  name: 'hosting',
113
- message: 'Hosting:',
167
+ message: 'Deployment Platform:',
114
168
  choices: ['Vercel', 'Railway', 'Fly.io', 'AWS', 'Other'],
115
169
  },
116
170
  {
117
171
  type: 'confirm',
118
172
  name: 'includeCursorRules',
119
- message: 'Include cursor-rules for AI assistants? (Cursor, Copilot)',
173
+ message: 'Install IDE intelligence protocols? (Cursor/Copilot Rules)',
120
174
  default: true,
121
175
  },
122
176
  {
123
177
  type: 'confirm',
124
178
  name: 'includeFullTemplate',
125
- message: 'Copy full 34-section template locally?',
179
+ message: 'Include full 34-section project template?',
126
180
  default: false,
127
181
  },
128
182
  {
129
183
  type: 'confirm',
130
184
  name: 'includeDocs',
131
- message: 'Copy VERIFICATION.md & AGENT-INSTRUCTIONS.md to docs/?',
185
+ message: 'Include project documentation standards?',
132
186
  default: true,
133
187
  },
134
188
  {
135
189
  type: 'confirm',
136
190
  name: 'includeAgents',
137
- message: 'Include AI agent prompts? (.agents/ folder)',
191
+ message: 'Configure AI agent orchestration?',
138
192
  default: true,
139
193
  },
140
194
  ]);
141
195
 
142
- const spinner = ora('Creating project files...').start();
196
+ const spinner = ora(getRandomMessage('loading')).start();
143
197
 
144
198
  try {
145
199
  const outputDir = path.resolve(options.dir, answers.projectName);
@@ -187,15 +241,8 @@ ${answers.ideaWhat} for ${answers.ideaFor}.
187
241
  ## Next Steps
188
242
 
189
243
  1. Open QUICK-START.md and complete the remaining sections
190
- 2. Copy sections from the full Ultra-Dex template as needed
191
- 3. Use the TaskFlow example as reference
192
- 4. Start building!
193
-
194
- ## Resources
195
-
196
- - [Full Template](${githubBlobUrl('@%20Ultra%20DeX/Saas%20plan/04-Imp-Template.md')})
197
- - [TaskFlow Example](${githubBlobUrl('@%20Ultra%20DeX/Saas%20plan/Examples/TaskFlow-Complete.md')})
198
- - [Methodology](${githubBlobUrl('@%20Ultra%20DeX/Saas%20plan/03-METHODOLOGY.md')})
244
+ 2. Customize the implementation plan based on your requirements
245
+ 3. Start the agent orchestration to begin development
199
246
  `;
200
247
 
201
248
  await fs.writeFile(path.join(outputDir, 'IMPLEMENTATION-PLAN.md'), planContent);
@@ -222,11 +269,11 @@ ${answers.ideaWhat} for ${answers.ideaFor}.
222
269
  await fs.mkdir(dotGithub, { recursive: true });
223
270
  await fs.writeFile(path.join(dotGithub, 'copilot-instructions.md'), coreContent);
224
271
  } catch {
225
- // Core rule not available - skip Copilot setup
272
+ // Core rule not available
226
273
  }
227
274
  } catch {
228
- console.log(chalk.red('\n āŒ Cursor rules not found in assets or repo.'));
229
- console.log(chalk.cyan(' Fetch: npx ultra-dex fetch --rules'));
275
+ console.log(chalk.red('\n āœ• IDE intelligence protocols not found.'));
276
+ console.log(chalk.cyan(' Run: ultra-dex fetch --rules'));
230
277
  }
231
278
  }
232
279
 
@@ -236,8 +283,8 @@ ${answers.ideaWhat} for ${answers.ideaFor}.
236
283
  try {
237
284
  await copyWithFallback(templatePath, fallbackTemplatePath, path.join(outputDir, 'docs', 'MASTER-PLAN.md'));
238
285
  } catch {
239
- console.log(chalk.red('\n āŒ Full template not found in assets or repo.'));
240
- console.log(chalk.cyan(' Fetch: npx ultra-dex fetch --docs'));
286
+ console.log(chalk.red('\n āœ• Project template not found.'));
287
+ console.log(chalk.cyan(' Run: ultra-dex fetch --docs'));
241
288
  }
242
289
  }
243
290
 
@@ -250,8 +297,8 @@ ${answers.ideaWhat} for ${answers.ideaFor}.
250
297
  await copyWithFallback(verificationPath, fallbackVerificationPath, path.join(outputDir, 'docs', 'CHECKLIST.md'));
251
298
  await copyWithFallback(agentPath, fallbackAgentPath, path.join(outputDir, 'docs', 'AI-PROMPTS.md'));
252
299
  } catch {
253
- console.log(chalk.red('\n āŒ Docs not found in assets or repo.'));
254
- console.log(chalk.cyan(' Fetch: npx ultra-dex fetch --docs'));
300
+ console.log(chalk.red('\n āœ• Documentation standards not found.'));
301
+ console.log(chalk.cyan(' Run: ultra-dex fetch --docs'));
255
302
  }
256
303
  }
257
304
 
@@ -293,43 +340,44 @@ ${answers.ideaWhat} for ${answers.ideaFor}.
293
340
  path.join(agentsDir, 'README.md')
294
341
  );
295
342
  } catch {
296
- console.log(chalk.red('\n āŒ Agent prompts not found in assets or repo.'));
297
- console.log(chalk.cyan(' Fetch: npx ultra-dex fetch --agents'));
343
+ console.log(chalk.red('\n āœ• Agent orchestration assets not found.'));
344
+ console.log(chalk.cyan(' Run: ultra-dex fetch --agents'));
298
345
  }
299
346
  }
300
347
 
301
- spinner.succeed(chalk.green('Project created successfully!'));
348
+ spinner.succeed(chalk.green('Project initialized successfully!'));
302
349
 
303
- console.log('\n' + chalk.bold('Files created:'));
350
+ console.log('\n' + chalk.bold('Artifacts created:'));
304
351
  console.log(chalk.gray(` ${outputDir}/`));
305
352
  console.log(chalk.gray(' ā”œā”€ā”€ QUICK-START.md'));
306
353
  console.log(chalk.gray(' ā”œā”€ā”€ CONTEXT.md'));
307
354
  console.log(chalk.gray(' ā”œā”€ā”€ IMPLEMENTATION-PLAN.md'));
308
355
  if (answers.includeFullTemplate) {
309
- console.log(chalk.gray(' ā”œā”€ā”€ docs/MASTER-PLAN.md (34 sections)'));
356
+ console.log(chalk.gray(' ā”œā”€ā”€ docs/MASTER-PLAN.md'));
310
357
  }
311
358
  if (answers.includeDocs) {
312
359
  console.log(chalk.gray(' ā”œā”€ā”€ docs/CHECKLIST.md'));
313
360
  console.log(chalk.gray(' ā”œā”€ā”€ docs/AI-PROMPTS.md'));
314
361
  }
315
362
  if (answers.includeCursorRules) {
316
- console.log(chalk.gray(' ā”œā”€ā”€ .cursor/rules/ (11 AI rule files)'));
363
+ console.log(chalk.gray(' ā”œā”€ā”€ .cursor/rules/'));
317
364
  }
318
365
  if (answers.includeAgents) {
319
- console.log(chalk.gray(' └── .agents/ (15 AI agent prompts in 6 tiers)'));
366
+ console.log(chalk.gray(' └── .agents/'));
320
367
  }
321
368
 
322
369
  console.log('\n' + chalk.bold('Next steps:'));
323
370
  console.log(chalk.cyan(` 1. cd ${answers.projectName}`));
324
- console.log(chalk.cyan(' 2. Open QUICK-START.md and complete it'));
325
- console.log(chalk.cyan(' 3. Start building! šŸš€'));
371
+ console.log(chalk.cyan(' 2. Open QUICK-START.md'));
372
+ console.log(chalk.cyan(' 3. ultra-dex swarm "Analyze requirements"'));
326
373
 
327
- console.log('\n' + chalk.gray('Full Ultra-Dex repo:'));
328
- console.log(chalk.blue(` ${githubWebUrl()}`));
374
+ console.log('\n' + chalk.hex('#8b5cf6').bold(' āœ“ SYSTEM READY.'));
375
+ console.log('');
376
+
329
377
  } catch (error) {
330
- spinner.fail(chalk.red('Failed to create project'));
378
+ spinner.fail(chalk.red('Failed to initialize project'));
331
379
  console.error(`[init] ${error?.message ?? error}`);
332
380
  process.exit(1);
333
381
  }
334
382
  });
335
- }
383
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * ultra-dex memory command
3
+ * Manage persistent memory for AI agents
4
+ */
5
+
6
+ import chalk from 'chalk';
7
+ import { ultraMemory } from '../mcp/memory.js';
8
+
9
+ export function registerMemoryCommand(program) {
10
+ const memory = program
11
+ .command('memory')
12
+ .description('Manage persistent agent memory');
13
+
14
+ memory
15
+ .command('list')
16
+ .description('List all remembered facts')
17
+ .option('--json', 'Output as JSON')
18
+ .action(async (options) => {
19
+ const items = await ultraMemory.getAll();
20
+
21
+ if (options.json) {
22
+ console.log(JSON.stringify(items, null, 2));
23
+ return;
24
+ }
25
+
26
+ console.log(chalk.cyan.bold('\n🧠 Ultra-Dex Persistent Memory\n'));
27
+
28
+ if (items.length === 0) {
29
+ console.log(chalk.gray(' Memory is empty.'));
30
+ return;
31
+ }
32
+
33
+ items.forEach((item, i) => {
34
+ console.log(chalk.white(`${i + 1}. [${new Date(item.timestamp).toLocaleDateString()}] (${item.source})`));
35
+ console.log(chalk.gray(` ${item.text}`));
36
+ if (item.tags && item.tags.length > 0) {
37
+ console.log(chalk.blue(` Tags: ${item.tags.join(', ')}`));
38
+ }
39
+ console.log();
40
+ });
41
+ });
42
+
43
+ memory
44
+ .command('add <text>')
45
+ .description('Add a fact to memory')
46
+ .option('-t, --tags <tags>', 'Comma-separated tags')
47
+ .action(async (text, options) => {
48
+ const tags = options.tags ? options.tags.split(',').map(t => t.trim()) : [];
49
+ await ultraMemory.remember(text, tags, 'manual');
50
+ console.log(chalk.green('āœ… Fact remembered.'));
51
+ });
52
+
53
+ memory
54
+ .command('search <query>')
55
+ .description('Search memory')
56
+ .action(async (query) => {
57
+ const results = await ultraMemory.search(query);
58
+ console.log(chalk.cyan.bold(`\nšŸ” Search Results for "${query}":\n`));
59
+
60
+ if (results.length === 0) {
61
+ console.log(chalk.gray(' No matches found.'));
62
+ return;
63
+ }
64
+
65
+ results.forEach((item, i) => {
66
+ console.log(chalk.white(`${i + 1}. [${new Date(item.timestamp).toLocaleDateString()}]`));
67
+ console.log(chalk.gray(` ${item.text}`));
68
+ console.log();
69
+ });
70
+ });
71
+
72
+ memory
73
+ .command('clear')
74
+ .description('Clear all memory')
75
+ .option('--before <date>', 'Clear before date (ISO)')
76
+ .action(async (options) => {
77
+ await ultraMemory.clear(options.before);
78
+ console.log(chalk.green('āœ… Memory cleared.'));
79
+ });
80
+ }
@@ -0,0 +1,82 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+
5
+ export async function loadState() {
6
+ try {
7
+ const content = await fs.readFile(path.resolve(process.cwd(), '.ultra/state.json'), 'utf8');
8
+ return JSON.parse(content);
9
+ } catch (error) {
10
+ console.error(chalk.red('Failed to load .ultra/state.json. Is the project initialized?'));
11
+ return null;
12
+ }
13
+ }
14
+
15
+ export async function saveState(state) {
16
+ try {
17
+ await fs.mkdir(path.resolve(process.cwd(), '.ultra'), { recursive: true });
18
+ await fs.writeFile(
19
+ path.resolve(process.cwd(), '.ultra/state.json'),
20
+ JSON.stringify(state, null, 2)
21
+ );
22
+ return true;
23
+ } catch (error) {
24
+ console.error(chalk.red('Failed to save state:'), error);
25
+ return false;
26
+ }
27
+ }
28
+
29
+ export function generateMarkdown(state) {
30
+ const { project, phases } = state;
31
+ let md = `# ${project.name} - Implementation Plan\n\n`;
32
+ md += `> **Generated by Ultra-Dex Core**\n`;
33
+ md += `> Version: ${project.version}\n`;
34
+ md += `> Mode: ${project.mode}\n\n`;
35
+
36
+ md += `## šŸš€ Execution Phases\n\n`;
37
+
38
+ phases.forEach(phase => {
39
+ const statusIcon = phase.status === 'completed' ? 'āœ…' : phase.status === 'in_progress' ? 'šŸ”„' : 'ā³';
40
+ md += `### ${statusIcon} ${phase.name}\n\n`;
41
+
42
+ if (phase.steps && phase.steps.length > 0) {
43
+ phase.steps.forEach(step => {
44
+ const stepIcon = step.status === 'completed' ? '- [x]' : '- [ ]';
45
+ md += `${stepIcon} **${step.id}**: ${step.task}\n`;
46
+ });
47
+ } else {
48
+ md += `_No steps defined for this phase._\n`;
49
+ }
50
+ md += `\n`;
51
+ });
52
+
53
+ md += `## šŸ¤– Agent Registry\n\n`;
54
+ if (state.agents && state.agents.registry) {
55
+ state.agents.registry.forEach(agent => {
56
+ const active = state.agents.active.includes(agent) ? '(Active)' : '';
57
+ md += `- ${agent} ${active}\n`;
58
+ });
59
+ }
60
+
61
+ md += `\n---\n`;
62
+ md += `*This file is strictly read-only. Edit .ultra/state.json to update.*`;
63
+
64
+ return md;
65
+ }
66
+
67
+ export function registerPlanCommand(program) {
68
+ program
69
+ .command('plan')
70
+ .description('Generate IMPLEMENTATION-PLAN.md from state.json')
71
+ .action(async () => {
72
+ const state = await loadState();
73
+ if (!state) return;
74
+
75
+ console.log(chalk.blue(`Generating plan for ${state.project.name}...`));
76
+
77
+ const markdown = generateMarkdown(state);
78
+ await fs.writeFile(path.resolve(process.cwd(), 'IMPLEMENTATION-PLAN.md'), markdown);
79
+
80
+ console.log(chalk.green(`āœ… IMPLEMENTATION-PLAN.md generated successfully.`));
81
+ });
82
+ }
@@ -10,6 +10,8 @@ import fs from 'fs/promises';
10
10
  import path from 'path';
11
11
  import { createProvider, getDefaultProvider, checkConfiguredProviders } from '../providers/index.js';
12
12
  import { SYSTEM_PROMPT, generateReviewPrompt } from '../templates/prompts/review-code.js';
13
+ import { validateSafePath } from '../utils/validation.js';
14
+ import { buildGraph, queryGraph, getImpactAnalysis } from '../utils/graph.js'; // Import CPG utils
13
15
 
14
16
  // File patterns to scan
15
17
  const CODE_PATTERNS = {
@@ -106,6 +108,12 @@ export function registerReviewCommand(program) {
106
108
  .action(async (options) => {
107
109
  console.log(chalk.cyan('\nšŸ” Ultra-Dex Code Review\n'));
108
110
 
111
+ const dirValidation = validateSafePath(options.dir, 'Review directory');
112
+ if (dirValidation !== true) {
113
+ console.log(chalk.red(dirValidation));
114
+ process.exit(1);
115
+ }
116
+
109
117
  const reviewDir = path.resolve(options.dir);
110
118
 
111
119
  // Check for plan
@@ -120,11 +128,29 @@ export function registerReviewCommand(program) {
120
128
  return;
121
129
  }
122
130
 
123
- // Get directory structure
124
- const spinner = ora('Scanning codebase...').start();
131
+ // Get directory structure & Build Graph
132
+ const spinner = ora('Scanning codebase & Building Graph...').start();
125
133
  const structure = await getDirectoryStructure(reviewDir);
126
134
  const keyFiles = await findKeyFiles(reviewDir);
127
- spinner.succeed('Codebase scanned');
135
+
136
+ // GOD MODE: Build CPG
137
+ let graphSummary = "Graph Not Available";
138
+ try {
139
+ const graph = await buildGraph();
140
+ graphSummary = `
141
+ Code Property Graph Stats:
142
+ - Files: ${graph.nodes.filter(n => n.type === 'file').length}
143
+ - Functions: ${graph.nodes.filter(n => n.type === 'function').length}
144
+ - Dependencies (Edges): ${graph.edges.length}
145
+
146
+ Top Dependencies:
147
+ ${graph.edges.slice(0, 10).map(e => `- ${e.source} -> ${e.target}`).join('\n')}
148
+ `;
149
+ } catch (e) {
150
+ // Fallback if graph fails
151
+ }
152
+
153
+ spinner.succeed('Codebase scanned & Graph built');
128
154
 
129
155
  if (options.quick) {
130
156
  // Quick review - just check structure
@@ -181,13 +207,16 @@ export function registerReviewCommand(program) {
181
207
 
182
208
  // Build file summary
183
209
  const filesSummary = keyFiles.map(f => `### ${f.path}\n\`\`\`\n${f.content}\n\`\`\``).join('\n\n');
210
+
211
+ // Inject Graph Summary into context
212
+ const contextWithGraph = `${structure}\n\n## ARCHITECTURAL GRAPH (TRUTH)\n${graphSummary}`;
184
213
 
185
- spinner.start('Analyzing code against plan...');
214
+ spinner.start('Analyzing code & graph against plan...');
186
215
 
187
216
  try {
188
217
  const result = await provider.generate(
189
218
  SYSTEM_PROMPT,
190
- generateReviewPrompt(plan.slice(0, 15000), structure, filesSummary)
219
+ generateReviewPrompt(plan.slice(0, 15000), contextWithGraph, filesSummary)
191
220
  );
192
221
 
193
222
  spinner.succeed('Analysis complete');