ultra-dex 2.2.0 → 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 (61) hide show
  1. package/README.md +84 -122
  2. package/assets/agents/0-orchestration/orchestrator.md +2 -2
  3. package/assets/agents/00-AGENT_INDEX.md +1 -1
  4. package/assets/docs/LAUNCH-POSTS.md +1 -1
  5. package/assets/docs/QUICK-REFERENCE.md +12 -7
  6. package/assets/docs/ROADMAP.md +5 -5
  7. package/assets/docs/VISION-V2.md +1 -1
  8. package/assets/docs/WORKFLOW-DIAGRAMS.md +1 -1
  9. package/assets/hooks/pre-commit +98 -0
  10. package/assets/saas-plan/04-Imp-Template.md +1 -1
  11. package/assets/templates/README.md +1 -1
  12. package/bin/ultra-dex.js +93 -2096
  13. package/lib/commands/advanced.js +471 -0
  14. package/lib/commands/agent-builder.js +226 -0
  15. package/lib/commands/agents.js +101 -47
  16. package/lib/commands/auto-implement.js +68 -0
  17. package/lib/commands/build.js +73 -187
  18. package/lib/commands/ci-monitor.js +84 -0
  19. package/lib/commands/config.js +207 -0
  20. package/lib/commands/dashboard.js +770 -0
  21. package/lib/commands/diff.js +233 -0
  22. package/lib/commands/doctor.js +397 -0
  23. package/lib/commands/export.js +408 -0
  24. package/lib/commands/fix.js +96 -0
  25. package/lib/commands/generate.js +96 -72
  26. package/lib/commands/hooks.js +251 -76
  27. package/lib/commands/init.js +56 -6
  28. package/lib/commands/memory.js +80 -0
  29. package/lib/commands/plan.js +82 -0
  30. package/lib/commands/review.js +34 -5
  31. package/lib/commands/run.js +233 -0
  32. package/lib/commands/serve.js +188 -40
  33. package/lib/commands/state.js +354 -0
  34. package/lib/commands/swarm.js +284 -0
  35. package/lib/commands/sync.js +94 -0
  36. package/lib/commands/team.js +275 -0
  37. package/lib/commands/upgrade.js +190 -0
  38. package/lib/commands/validate.js +34 -0
  39. package/lib/commands/verify.js +81 -0
  40. package/lib/commands/watch.js +79 -0
  41. package/lib/mcp/graph.js +92 -0
  42. package/lib/mcp/memory.js +95 -0
  43. package/lib/mcp/resources.js +152 -0
  44. package/lib/mcp/server.js +34 -0
  45. package/lib/mcp/tools.js +481 -0
  46. package/lib/mcp/websocket.js +117 -0
  47. package/lib/providers/index.js +49 -4
  48. package/lib/providers/ollama.js +136 -0
  49. package/lib/providers/router.js +63 -0
  50. package/lib/quality/scanner.js +128 -0
  51. package/lib/swarm/coordinator.js +97 -0
  52. package/lib/swarm/index.js +598 -0
  53. package/lib/swarm/protocol.js +677 -0
  54. package/lib/swarm/tiers.js +485 -0
  55. package/lib/templates/context.js +2 -2
  56. package/lib/templates/custom-agent.md +10 -0
  57. package/lib/utils/fallback.js +4 -2
  58. package/lib/utils/files.js +7 -34
  59. package/lib/utils/graph.js +108 -0
  60. package/lib/utils/sync.js +216 -0
  61. package/package.json +22 -13
package/bin/ultra-dex.js CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { Command } from 'commander';
4
3
  import { Command } from 'commander';
5
4
 
6
5
  import { banner } from '../lib/commands/banner.js';
@@ -8,14 +7,38 @@ import { registerInitCommand } from '../lib/commands/init.js';
8
7
  import { registerAuditCommand } from '../lib/commands/audit.js';
9
8
  import { registerExamplesCommand } from '../lib/commands/examples.js';
10
9
  import { registerAgentsCommand, registerPackCommand } from '../lib/commands/agents.js';
11
- import { registerPlaceholderCommands } from '../lib/commands/placeholders.js';
10
+ import { registerAgentBuilderCommand } from '../lib/commands/agent-builder.js';
11
+ import { registerGenerateCommand } from '../lib/commands/generate.js';
12
+ import { registerBuildCommand } from '../lib/commands/build.js';
13
+ import { registerReviewCommand } from '../lib/commands/review.js';
14
+ import { registerRunCommand, registerSwarmCommand } from '../lib/commands/run.js';
15
+ import { registerAutoImplementCommand } from '../lib/commands/auto-implement.js';
16
+ import { registerCiMonitorCommand } from '../lib/commands/ci-monitor.js';
17
+ import { registerAlignCommand, registerStatusCommand, registerPreCommitCommand, registerStateCommand } from '../lib/commands/state.js';
18
+ import { registerDoctorCommand } from '../lib/commands/doctor.js';
19
+ import { registerDashboardCommand } from '../lib/commands/dashboard.js';
20
+ import { registerCheckCommand } from '../lib/commands/advanced.js';
12
21
  import { registerServeCommand } from '../lib/commands/serve.js';
22
+ import { registerVerifyCommand } from '../lib/commands/verify.js';
23
+
24
+ // v3.0 Commands
25
+ import { swarmCommand } from '../lib/commands/swarm.js';
26
+ import { watchCommand } from '../lib/commands/watch.js';
27
+ import { diffCommand } from '../lib/commands/diff.js';
28
+ import { exportCommand } from '../lib/commands/export.js';
29
+ import { upgradeCommand } from '../lib/commands/upgrade.js';
30
+ import { configCommand } from '../lib/commands/config.js';
31
+
13
32
  import { registerWorkflowCommand } from '../lib/commands/workflows.js';
33
+ import { registerPlanCommand } from '../lib/commands/plan.js';
14
34
  import { registerSuggestCommand } from '../lib/commands/suggest.js';
15
35
  import { registerValidateCommand } from '../lib/commands/validate.js';
36
+ import { registerFixCommand } from '../lib/commands/fix.js';
16
37
  import { registerHooksCommand } from '../lib/commands/hooks.js';
17
38
  import { registerFetchCommand } from '../lib/commands/fetch.js';
18
39
  import { registerSyncCommand } from '../lib/commands/sync.js';
40
+ import { registerTeamCommand } from '../lib/commands/team.js';
41
+ import { registerMemoryCommand } from '../lib/commands/memory.js';
19
42
 
20
43
  const program = new Command();
21
44
  program.banner = banner;
@@ -23,2111 +46,85 @@ program.banner = banner;
23
46
  program
24
47
  .name('ultra-dex')
25
48
  .description('CLI for Ultra-Dex SaaS Implementation Framework')
26
- .version('2.0.1');
49
+ .version('3.1.0');
27
50
 
28
51
  registerInitCommand(program);
29
52
  registerAuditCommand(program);
30
53
  registerExamplesCommand(program);
31
54
  registerAgentsCommand(program);
32
- registerPlaceholderCommands(program);
55
+ registerGenerateCommand(program);
56
+ registerBuildCommand(program);
57
+ registerReviewCommand(program);
58
+ registerRunCommand(program);
59
+
60
+ // v3.0 Commands
61
+ program
62
+ .command('swarm <task>')
63
+ .description('Run autonomous agent pipeline')
64
+ .option('--dry-run', 'Show pipeline without executing')
65
+ .option('--parallel', 'Run implementation tier agents in parallel')
66
+ .action(swarmCommand);
67
+
68
+ program
69
+ .command('watch')
70
+ .description('Auto-update state on file changes')
71
+ .option('--interval <ms>', 'Debounce interval in milliseconds', '500')
72
+ .action(watchCommand);
73
+
74
+ program
75
+ .command('diff')
76
+ .description('Compare plan vs implemented code')
77
+ .option('--json', 'Output as JSON')
78
+ .action(diffCommand);
79
+
80
+ program
81
+ .command('export')
82
+ .description('Export project context')
83
+ .option('--format <type>', 'Output format: json, html, markdown, pdf', 'json')
84
+ .option('--output <path>', 'Output file path')
85
+ .option('--include-agents', 'Bundle all agent prompts')
86
+ .action(exportCommand);
87
+
88
+ program
89
+ .command('upgrade')
90
+ .description('Check for CLI updates')
91
+ .option('--check', 'Check only, do not show install instructions')
92
+ .option('--install', 'Automatically install latest version')
93
+ .action(upgradeCommand);
94
+
95
+ program
96
+ .command('config')
97
+ .description('Show or generate configuration')
98
+ .option('--mcp', 'Generate MCP config for Claude Desktop')
99
+ .option('--cursor', 'Generate Cursor IDE rules')
100
+ .option('--vscode', 'Generate VS Code settings.json')
101
+ .option('--show', 'Display current Ultra-Dex config')
102
+ .option('--set <key=value>', 'Set a config value')
103
+ .option('--get <key>', 'Get a specific config value')
104
+ .action(configCommand);
105
+
106
+ registerAutoImplementCommand(program);
107
+ registerCiMonitorCommand(program);
108
+ registerAlignCommand(program);
109
+ registerStatusCommand(program);
110
+ registerPreCommitCommand(program);
111
+ registerStateCommand(program);
112
+ registerDoctorCommand(program);
113
+ registerDashboardCommand(program);
114
+ registerCheckCommand(program);
33
115
  registerServeCommand(program);
116
+ registerVerifyCommand(program);
34
117
  registerPackCommand(program);
35
118
  registerWorkflowCommand(program);
119
+ registerPlanCommand(program);
36
120
  registerSuggestCommand(program);
37
121
  registerValidateCommand(program);
122
+ registerFixCommand(program);
38
123
  registerHooksCommand(program);
39
124
  registerFetchCommand(program);
40
125
  registerSyncCommand(program);
126
+ registerAgentBuilderCommand(program);
127
+ registerTeamCommand(program);
128
+ registerMemoryCommand(program);
41
129
 
42
- program
43
- .command('audit')
44
- .description('Audit your Ultra-Dex project for completeness')
45
- .option('-d, --dir <directory>', 'Project directory to audit', '.')
46
- .action(async (options) => {
47
- console.log(chalk.cyan('\nšŸ” Ultra-Dex Project Audit\n'));
48
-
49
- const projectDir = path.resolve(options.dir);
50
- let score = 0;
51
- let maxScore = 0;
52
- const results = [];
53
-
54
- // Helper function to check file exists and has content
55
- async function checkFile(filePath, description, points) {
56
- maxScore += points;
57
- try {
58
- const content = await fs.readFile(path.join(projectDir, filePath), 'utf-8');
59
- if (content.length > 50) {
60
- score += points;
61
- results.push({ status: 'āœ…', item: description, points: `+${points}` });
62
- return content;
63
- } else {
64
- results.push({ status: 'āš ļø', item: `${description} (empty/too short)`, points: '0' });
65
- return null;
66
- }
67
- } catch {
68
- results.push({ status: 'āŒ', item: `${description} (missing)`, points: '0' });
69
- return null;
70
- }
71
- }
72
-
73
- // Helper to check content has section
74
- function hasSection(content, sectionName, points) {
75
- maxScore += points;
76
- if (content && content.toLowerCase().includes(sectionName.toLowerCase())) {
77
- score += points;
78
- results.push({ status: 'āœ…', item: `Has ${sectionName}`, points: `+${points}` });
79
- return true;
80
- } else {
81
- results.push({ status: 'āŒ', item: `Missing ${sectionName}`, points: '0' });
82
- return false;
83
- }
84
- }
85
-
86
- // Check core files
87
- console.log(chalk.bold('Checking project files...\n'));
88
-
89
- const quickStart = await checkFile('QUICK-START.md', 'QUICK-START.md', 10);
90
- const context = await checkFile('CONTEXT.md', 'CONTEXT.md', 5);
91
- const implPlan = await checkFile('IMPLEMENTATION-PLAN.md', 'IMPLEMENTATION-PLAN.md', 5);
92
- const fullTemplate = await checkFile('04-Imp-Template.md', '04-Imp-Template.md', 10);
93
-
94
- // Check for alternative file names
95
- const readme = await checkFile('README.md', 'README.md', 5);
96
-
97
- // Check content quality if QUICK-START exists
98
- if (quickStart) {
99
- hasSection(quickStart, 'idea', 5);
100
- hasSection(quickStart, 'problem', 5);
101
- hasSection(quickStart, 'mvp', 5);
102
- hasSection(quickStart, 'tech stack', 10);
103
- hasSection(quickStart, 'feature', 5);
104
- }
105
-
106
- // Check for implementation details
107
- if (implPlan) {
108
- hasSection(implPlan, 'database', 5);
109
- hasSection(implPlan, 'api', 5);
110
- hasSection(implPlan, 'auth', 5);
111
- }
112
-
113
- // Check for docs folder
114
- try {
115
- await fs.access(path.join(projectDir, 'docs'));
116
- score += 5;
117
- maxScore += 5;
118
- results.push({ status: 'āœ…', item: 'docs/ folder exists', points: '+5' });
119
- } catch {
120
- maxScore += 5;
121
- results.push({ status: 'āš ļø', item: 'docs/ folder (optional)', points: '0' });
122
- }
123
-
124
- // Print results
125
- console.log(chalk.bold('Audit Results:\n'));
126
- results.forEach(r => {
127
- const statusColor = r.status === 'āœ…' ? chalk.green : r.status === 'āŒ' ? chalk.red : chalk.yellow;
128
- console.log(` ${statusColor(r.status)} ${r.item} ${chalk.gray(r.points)}`);
129
- });
130
-
131
- // Calculate percentage
132
- const percentage = Math.round((score / maxScore) * 100);
133
-
134
- console.log('\n' + chalk.bold('─'.repeat(50)));
135
- console.log(chalk.bold(`\nScore: ${score}/${maxScore} (${percentage}%)\n`));
136
-
137
- // Grade
138
- let grade, gradeColor, message;
139
- if (percentage >= 90) {
140
- grade = 'A';
141
- gradeColor = chalk.green;
142
- message = 'Excellent! Your project is well-documented.';
143
- } else if (percentage >= 75) {
144
- grade = 'B';
145
- gradeColor = chalk.green;
146
- message = 'Good! A few more sections would help.';
147
- } else if (percentage >= 60) {
148
- grade = 'C';
149
- gradeColor = chalk.yellow;
150
- message = 'Fair. Consider filling more sections before coding.';
151
- } else if (percentage >= 40) {
152
- grade = 'D';
153
- gradeColor = chalk.yellow;
154
- message = 'Needs work. Use QUICK-START.md to define your project.';
155
- } else {
156
- grade = 'F';
157
- gradeColor = chalk.red;
158
- message = 'Run "npx ultra-dex init" to get started properly.';
159
- }
160
-
161
- console.log(gradeColor(`Grade: ${grade}`));
162
- console.log(chalk.gray(message));
163
-
164
- // Suggestions
165
- const missing = results.filter(r => r.status === 'āŒ');
166
- if (missing.length > 0) {
167
- console.log(chalk.bold('\nšŸ“‹ To improve your score:\n'));
168
- missing.slice(0, 5).forEach(m => {
169
- console.log(chalk.cyan(` → Add ${m.item.replace(' (missing)', '')}`));
170
- });
171
- }
172
-
173
- console.log('\n' + chalk.gray('Learn more: https://github.com/Srujan0798/Ultra-Dex\n'));
174
- });
175
-
176
- program
177
- .command('examples')
178
- .description('List available examples')
179
- .action(() => {
180
- console.log(chalk.bold('\nAvailable Ultra-Dex Examples:\n'));
181
-
182
- const examples = [
183
- {
184
- name: 'TaskFlow',
185
- type: 'Task Management',
186
- url: 'https://github.com/Srujan0798/Ultra-Dex/blob/main/@%20Ultra%20DeX/Saas%20plan/Examples/TaskFlow-Complete.md',
187
- },
188
- {
189
- name: 'InvoiceFlow',
190
- type: 'Invoicing',
191
- url: 'https://github.com/Srujan0798/Ultra-Dex/blob/main/@%20Ultra%20DeX/Saas%20plan/Examples/InvoiceFlow-Complete.md',
192
- },
193
- {
194
- name: 'HabitStack',
195
- type: 'Habit Tracking',
196
- url: 'https://github.com/Srujan0798/Ultra-Dex/blob/main/@%20Ultra%20DeX/Saas%20plan/Examples/HabitStack-Complete.md',
197
- },
198
- ];
199
-
200
- examples.forEach((ex, i) => {
201
- console.log(chalk.cyan(`${i + 1}. ${ex.name}`) + chalk.gray(` (${ex.type})`));
202
- console.log(chalk.gray(` ${ex.url}\n`));
203
- });
204
- });
205
-
206
- // Agent definitions (organized by tier)
207
- const AGENTS = [
208
- // Leadership Tier
209
- { name: 'cto', description: 'Architecture & tech decisions', file: '1-leadership/cto.md', tier: 'Leadership' },
210
- { name: 'planner', description: 'Task breakdown & planning', file: '1-leadership/planner.md', tier: 'Leadership' },
211
- { name: 'research', description: 'Technology evaluation & comparison', file: '1-leadership/research.md', tier: 'Leadership' },
212
- // Development Tier
213
- { name: 'backend', description: 'API & server logic', file: '2-development/backend.md', tier: 'Development' },
214
- { name: 'database', description: 'Schema design & queries', file: '2-development/database.md', tier: 'Development' },
215
- { name: 'frontend', description: 'UI & components', file: '2-development/frontend.md', tier: 'Development' },
216
- // Security Tier
217
- { name: 'auth', description: 'Authentication & authorization', file: '3-security/auth.md', tier: 'Security' },
218
- { name: 'security', description: 'Security audits & vulnerability fixes', file: '3-security/security.md', tier: 'Security' },
219
- // DevOps Tier
220
- { name: 'devops', description: 'Deployment & infrastructure', file: '4-devops/devops.md', tier: 'DevOps' },
221
- // Quality Tier
222
- { name: 'debugger', description: 'Bug fixing & troubleshooting', file: '5-quality/debugger.md', tier: 'Quality' },
223
- { name: 'documentation', description: 'Technical writing & docs maintenance', file: '5-quality/documentation.md', tier: 'Quality' },
224
- { name: 'reviewer', description: 'Code review & quality check', file: '5-quality/reviewer.md', tier: 'Quality' },
225
- { name: 'testing', description: 'QA & test automation', file: '5-quality/testing.md', tier: 'Quality' },
226
- // Specialist Tier
227
- { name: 'performance', description: 'Performance optimization', file: '6-specialist/performance.md', tier: 'Specialist' },
228
- { name: 'refactoring', description: 'Code quality & design patterns', file: '6-specialist/refactoring.md', tier: 'Specialist' },
229
- ];
230
-
231
- program
232
- .command('agents')
233
- .description('List available AI agent prompts')
234
- .action(() => {
235
- console.log(chalk.bold('\nšŸ¤– Ultra-Dex AI Agents (15 Total)\n'));
236
- console.log(chalk.gray('Organized by tier for production pipeline\n'));
237
-
238
- let currentTier = '';
239
- AGENTS.forEach((agent) => {
240
- if (agent.tier !== currentTier) {
241
- currentTier = agent.tier;
242
- console.log(chalk.bold(`\n ${currentTier} Tier:`));
243
- }
244
- console.log(chalk.cyan(` ${agent.name}`) + chalk.gray(` - ${agent.description}`));
245
- });
246
-
247
- console.log('\n' + chalk.bold('Usage:'));
248
- console.log(chalk.gray(' ultra-dex agent <name> Show agent prompt'));
249
- console.log(chalk.gray(' ultra-dex agent backend Example: show backend agent'));
250
-
251
- console.log('\n' + chalk.gray('Agent Index: https://github.com/Srujan0798/Ultra-Dex/blob/main/agents/00-AGENT_INDEX.md\n'));
252
- });
253
-
254
- // ========================================
255
- // GENERATE COMMAND - AI-Powered Plan Generation (v2.0)
256
- // ========================================
257
- const GENERATE_PROVIDERS = {
258
- claude: {
259
- name: 'Claude (Anthropic)',
260
- envKey: 'ANTHROPIC_API_KEY',
261
- model: 'claude-sonnet-4-20250514',
262
- endpoint: 'https://api.anthropic.com/v1/messages'
263
- },
264
- openai: {
265
- name: 'GPT-4 (OpenAI)',
266
- envKey: 'OPENAI_API_KEY',
267
- model: 'gpt-4o',
268
- endpoint: 'https://api.openai.com/v1/chat/completions'
269
- },
270
- gemini: {
271
- name: 'Gemini (Google)',
272
- envKey: 'GOOGLE_AI_KEY',
273
- model: 'gemini-2.0-flash',
274
- endpoint: 'https://generativelanguage.googleapis.com/v1beta/models'
275
- }
276
- };
277
-
278
- const GENERATE_SECTIONS = [
279
- '1. Project Identity', '2. Vision & Problem', '3. Target Users', '4. Core Value Proposition',
280
- '5. Feature Set (MVP)', '6. Feature Set (Future)', '7. User Journeys', '8. Tech Stack',
281
- '9. System Architecture', '10. Database Schema', '11. API Design', '12. Authentication',
282
- '13. Security Requirements', '14. Performance Requirements', '15. UI/UX Guidelines',
283
- '16. Component Library', '17. State Management', '18. Error Handling', '19. Testing Strategy',
284
- '20. CI/CD Pipeline', '21. Deployment Strategy', '22. Monitoring & Logging', '23. Cost Estimation',
285
- '24. Timeline & Milestones', '25. Team Structure', '26. Risk Assessment', '27. Compliance',
286
- '28. Documentation Plan', '29. Launch Checklist', '30. Success Metrics', '31. Scaling Plan',
287
- '32. Support Strategy', '33. Iteration Roadmap', '34. Project Metadata'
288
- ];
289
-
290
- const GENERATE_SYSTEM_PROMPT = `You are an expert SaaS architect. Generate a comprehensive implementation plan.
291
-
292
- For the given idea, create detailed content for ALL 34 sections:
293
- ${GENERATE_SECTIONS.map(s => `- ${s}`).join('\n')}
294
-
295
- Output format - use EXACTLY this markdown structure:
296
- ## 1. Project Identity
297
- [content]
298
-
299
- ## 2. Vision & Problem
300
- [content]
301
-
302
- ... continue for all 34 sections ...
303
-
304
- Be specific, actionable, and production-ready. Include real code examples, database schemas, API endpoints.`;
305
-
306
- async function generateWithClaude(idea, apiKey, model) {
307
- const response = await fetch('https://api.anthropic.com/v1/messages', {
308
- method: 'POST',
309
- headers: {
310
- 'Content-Type': 'application/json',
311
- 'x-api-key': apiKey,
312
- 'anthropic-version': '2023-06-01'
313
- },
314
- body: JSON.stringify({
315
- model: model,
316
- max_tokens: 8192,
317
- messages: [{ role: 'user', content: `${GENERATE_SYSTEM_PROMPT}\n\nIdea: ${idea}` }]
318
- })
319
- });
320
- if (!response.ok) throw new Error(`Claude API error: ${response.status}`);
321
- const data = await response.json();
322
- return data.content[0].text;
323
- }
324
-
325
- async function generateWithOpenAI(idea, apiKey, model) {
326
- const response = await fetch('https://api.openai.com/v1/chat/completions', {
327
- method: 'POST',
328
- headers: {
329
- 'Content-Type': 'application/json',
330
- 'Authorization': `Bearer ${apiKey}`
331
- },
332
- body: JSON.stringify({
333
- model: model,
334
- messages: [
335
- { role: 'system', content: GENERATE_SYSTEM_PROMPT },
336
- { role: 'user', content: `Idea: ${idea}` }
337
- ],
338
- max_tokens: 8192
339
- })
340
- });
341
- if (!response.ok) throw new Error(`OpenAI API error: ${response.status}`);
342
- const data = await response.json();
343
- return data.choices[0].message.content;
344
- }
345
-
346
- async function generateWithGemini(idea, apiKey, model) {
347
- const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`;
348
- const response = await fetch(url, {
349
- method: 'POST',
350
- headers: { 'Content-Type': 'application/json' },
351
- body: JSON.stringify({
352
- contents: [{ parts: [{ text: `${GENERATE_SYSTEM_PROMPT}\n\nIdea: ${idea}` }] }],
353
- generationConfig: { maxOutputTokens: 8192 }
354
- })
355
- });
356
- if (!response.ok) throw new Error(`Gemini API error: ${response.status}`);
357
- const data = await response.json();
358
- return data.candidates[0].content.parts[0].text;
359
- }
360
-
361
- program
362
- .command('generate')
363
- .description('Generate a full implementation plan from an idea using AI')
364
- .argument('[idea]', 'Your SaaS idea in one sentence')
365
- .option('-p, --provider <provider>', 'AI provider: claude, openai, gemini', 'claude')
366
- .option('-m, --model <model>', 'Specific model to use')
367
- .option('-o, --output <dir>', 'Output directory', '.')
368
- .option('-k, --key <key>', 'API key (or use environment variable)')
369
- .option('--dry-run', 'Show what would be generated without calling AI')
370
- .action(async (idea, options) => {
371
- console.log(chalk.cyan('\n' + banner));
372
- console.log(chalk.bold.green('✨ Ultra-Dex Generate - AI-Powered Plan Creation\n'));
373
-
374
- // Get idea if not provided
375
- if (!idea) {
376
- const response = await inquirer.prompt([{
377
- type: 'input',
378
- name: 'idea',
379
- message: 'Describe your SaaS idea in one sentence:',
380
- validate: (input) => input.length > 10 || 'Please provide more detail'
381
- }]);
382
- idea = response.idea;
383
- }
384
-
385
- console.log(chalk.gray(`\nIdea: "${idea}"\n`));
386
-
387
- // Validate provider
388
- const provider = options.provider.toLowerCase();
389
- if (!GENERATE_PROVIDERS[provider]) {
390
- console.log(chalk.red(`Unknown provider: ${provider}`));
391
- console.log(chalk.gray(`Available: ${Object.keys(GENERATE_PROVIDERS).join(', ')}`));
392
- return;
393
- }
394
-
395
- const providerConfig = GENERATE_PROVIDERS[provider];
396
- const apiKey = options.key || process.env[providerConfig.envKey];
397
- const model = options.model || providerConfig.model;
398
-
399
- if (!apiKey && !options.dryRun) {
400
- console.log(chalk.red(`\nāŒ No API key found for ${providerConfig.name}`));
401
- console.log(chalk.gray(`Set ${providerConfig.envKey} environment variable or use --key flag`));
402
- return;
403
- }
404
-
405
- console.log(chalk.cyan(`Provider: ${providerConfig.name}`));
406
- console.log(chalk.cyan(`Model: ${model}`));
407
- console.log(chalk.cyan(`Output: ${options.output}\n`));
408
-
409
- if (options.dryRun) {
410
- console.log(chalk.yellow('šŸ” Dry run mode - showing plan structure:\n'));
411
- GENERATE_SECTIONS.forEach((section, i) => {
412
- console.log(chalk.gray(` ${section}`));
413
- });
414
- console.log(chalk.green('\nāœ“ Would generate IMPLEMENTATION-PLAN.md with all 34 sections'));
415
- return;
416
- }
417
-
418
- const spinner = ora('Generating implementation plan...').start();
419
-
420
- try {
421
- let result;
422
- spinner.text = `Calling ${providerConfig.name} API...`;
423
-
424
- if (provider === 'claude') {
425
- result = await generateWithClaude(idea, apiKey, model);
426
- } else if (provider === 'openai') {
427
- result = await generateWithOpenAI(idea, apiKey, model);
428
- } else if (provider === 'gemini') {
429
- result = await generateWithGemini(idea, apiKey, model);
430
- }
431
-
432
- spinner.succeed('AI generation complete!');
433
-
434
- // Create output files
435
- const outputDir = path.resolve(options.output);
436
- await fs.mkdir(outputDir, { recursive: true });
437
-
438
- // Write IMPLEMENTATION-PLAN.md
439
- const planPath = path.join(outputDir, 'IMPLEMENTATION-PLAN.md');
440
- const planContent = `# Implementation Plan
441
-
442
- > Generated by Ultra-Dex AI • ${new Date().toISOString().split('T')[0]}
443
- > Idea: "${idea}"
444
-
445
- ---
446
-
447
- ${result}
448
- `;
449
- await fs.writeFile(planPath, planContent);
450
- console.log(chalk.green(`\nāœ“ Created: ${planPath}`));
451
-
452
- // Write QUICK-START.md
453
- const quickStartPath = path.join(outputDir, 'QUICK-START.md');
454
- const quickStartContent = `# Quick Start Guide
455
-
456
- > Generated from: ${idea}
457
-
458
- ## Getting Started
459
-
460
- 1. Review \`IMPLEMENTATION-PLAN.md\` for full architecture
461
- 2. Run \`ultra-dex build\` to start development with AI assistance
462
- 3. Use \`ultra-dex review\` to check implementation against plan
463
-
464
- ## Next Steps
465
-
466
- \`\`\`bash
467
- # Start building with AI assistance
468
- ultra-dex build --agent planner
469
-
470
- # Review your progress
471
- ultra-dex review
472
- \`\`\`
473
-
474
- ---
475
- *Generated by Ultra-Dex v2.1.0*
476
- `;
477
- await fs.writeFile(quickStartPath, quickStartContent);
478
- console.log(chalk.green(`āœ“ Created: ${quickStartPath}`));
479
-
480
- console.log(chalk.bold.green('\nšŸŽ‰ Plan generation complete!'));
481
- console.log(chalk.gray('Next: Review the plan and run `ultra-dex build` to start development\n'));
482
-
483
- } catch (error) {
484
- spinner.fail('Generation failed');
485
- console.log(chalk.red(`\nError: ${error.message}`));
486
- if (error.message.includes('401')) {
487
- console.log(chalk.yellow('Check your API key is valid'));
488
- }
489
- }
490
- });
491
-
492
- // ========================================
493
- // BUILD COMMAND - AI-Assisted Development (v2.1)
494
- // ========================================
495
- const BUILD_AGENTS = {
496
- planner: { name: '@Planner', tier: 'Leadership', task: 'Break down features into atomic tasks' },
497
- cto: { name: '@CTO', tier: 'Leadership', task: 'Architecture decisions' },
498
- backend: { name: '@Backend', tier: 'Development', task: 'API endpoints and business logic' },
499
- frontend: { name: '@Frontend', tier: 'Development', task: 'UI components and pages' },
500
- database: { name: '@Database', tier: 'Development', task: 'Schema design and migrations' },
501
- auth: { name: '@Auth', tier: 'Security', task: 'Authentication and authorization' },
502
- security: { name: '@Security', tier: 'Security', task: 'Security audit' },
503
- testing: { name: '@Testing', tier: 'Quality', task: 'Write and run tests' },
504
- reviewer: { name: '@Reviewer', tier: 'Quality', task: 'Code review' },
505
- devops: { name: '@DevOps', tier: 'DevOps', task: 'Deployment and CI/CD' },
506
- };
507
-
508
- program
509
- .command('build')
510
- .description('Start AI-assisted development with auto-loaded context')
511
- .option('-a, --agent <agent>', 'Agent to use (planner, backend, frontend, etc.)')
512
- .option('-t, --task <task>', 'Specific task to work on')
513
- .option('--copy', 'Copy prompt to clipboard instead of displaying')
514
- .action(async (options) => {
515
- console.log(chalk.cyan('\nšŸ”§ Ultra-Dex Build Mode\n'));
516
-
517
- async function fileExists(fp) {
518
- try { await fs.access(fp); return true; } catch { return false; }
519
- }
520
- async function readFileSafe(fp) {
521
- try { return await fs.readFile(fp, 'utf-8'); } catch { return null; }
522
- }
523
-
524
- const hasContext = await fileExists('CONTEXT.md');
525
- const hasPlan = await fileExists('IMPLEMENTATION-PLAN.md');
526
-
527
- if (!hasContext && !hasPlan) {
528
- console.log(chalk.yellow('āš ļø No Ultra-Dex project found in current directory.\n'));
529
- console.log(chalk.white('Run one of these first:'));
530
- console.log(chalk.gray(' npx ultra-dex init # Create from template'));
531
- console.log(chalk.gray(' npx ultra-dex generate # Generate from idea\n'));
532
- return;
533
- }
534
-
535
- const context = await readFileSafe('CONTEXT.md');
536
- const plan = await readFileSafe('IMPLEMENTATION-PLAN.md');
537
-
538
- console.log(chalk.green('āœ“ Context loaded'));
539
-
540
- let agent = options.agent;
541
- if (!agent) {
542
- const { selectedAgent } = await inquirer.prompt([{
543
- type: 'list',
544
- name: 'selectedAgent',
545
- message: 'Select an agent:',
546
- choices: [
547
- new inquirer.Separator('── Leadership ──'),
548
- { name: 'šŸ“‹ @Planner - Break down tasks', value: 'planner' },
549
- { name: 'šŸ—ļø @CTO - Architecture decisions', value: 'cto' },
550
- new inquirer.Separator('── Development ──'),
551
- { name: 'āš™ļø @Backend - API endpoints', value: 'backend' },
552
- { name: 'šŸŽØ @Frontend - UI components', value: 'frontend' },
553
- { name: 'šŸ—„ļø @Database - Schema design', value: 'database' },
554
- new inquirer.Separator('── Security ──'),
555
- { name: 'šŸ” @Auth - Authentication', value: 'auth' },
556
- { name: 'šŸ›”ļø @Security - Security audit', value: 'security' },
557
- new inquirer.Separator('── Quality ──'),
558
- { name: '🧪 @Testing - Write tests', value: 'testing' },
559
- { name: 'šŸ‘ļø @Reviewer - Code review', value: 'reviewer' },
560
- new inquirer.Separator('── DevOps ──'),
561
- { name: 'šŸš€ @DevOps - Deployment', value: 'devops' },
562
- ],
563
- }]);
564
- agent = selectedAgent;
565
- }
566
-
567
- const agentConfig = BUILD_AGENTS[agent];
568
- if (!agentConfig) {
569
- console.log(chalk.red(`Unknown agent: ${agent}`));
570
- console.log(chalk.gray(`Available: ${Object.keys(BUILD_AGENTS).join(', ')}`));
571
- return;
572
- }
573
-
574
- let task = options.task;
575
- if (!task) {
576
- const { taskInput } = await inquirer.prompt([{
577
- type: 'input',
578
- name: 'taskInput',
579
- message: `What should ${agentConfig.name} do?`,
580
- default: agentConfig.task,
581
- }]);
582
- task = taskInput;
583
- }
584
-
585
- const contextSection = context ? `## Project Context\n${context}\n` : '';
586
- const planSection = plan ? `## Implementation Plan (Summary)\n${plan.slice(0, 8000)}...\n[Full plan in IMPLEMENTATION-PLAN.md]\n` : '';
587
-
588
- const prompt = `# ${agentConfig.name} Agent Session
589
-
590
- You are acting as ${agentConfig.name} for this project.
591
-
592
- ${contextSection}
593
- ${planSection}
594
-
595
- ## Your Task
596
- ${task}
597
-
598
- ## Instructions
599
- 1. Read the context and plan carefully
600
- 2. Focus ONLY on your assigned task
601
- 3. Follow Ultra-Dex 21-step verification for any code changes
602
- 4. Document your work in a way the next agent can continue
603
-
604
- ## Output Format
605
- - For code: Include full file paths and production-ready code
606
- - For plans: Use atomic tasks (4-9 hours each)
607
- - For reviews: Use severity levels (critical, warning, info)
608
-
609
- Begin working on: ${task}
610
- `;
611
-
612
- console.log(chalk.green(`\nāœ… ${agentConfig.name} prompt ready\n`));
613
-
614
- if (options.copy) {
615
- try {
616
- const { exec } = await import('child_process');
617
- const { promisify } = await import('util');
618
- const execAsync = promisify(exec);
619
- const platform = process.platform;
620
- if (platform === 'darwin') {
621
- await execAsync(`echo ${JSON.stringify(prompt)} | pbcopy`);
622
- console.log(chalk.cyan('šŸ“‹ Prompt copied to clipboard!'));
623
- } else {
624
- console.log(chalk.yellow('Clipboard not supported. Displaying instead:'));
625
- console.log(chalk.gray('─'.repeat(60)));
626
- console.log(prompt);
627
- console.log(chalk.gray('─'.repeat(60)));
628
- }
629
- } catch {
630
- console.log(chalk.gray('─'.repeat(60)));
631
- console.log(prompt);
632
- console.log(chalk.gray('─'.repeat(60)));
633
- }
634
- } else {
635
- console.log(chalk.gray('─'.repeat(60)));
636
- console.log(prompt);
637
- console.log(chalk.gray('─'.repeat(60)));
638
- console.log(chalk.cyan('\nšŸ“‹ Copy this prompt into your AI tool'));
639
- console.log(chalk.gray('Or use --copy to copy to clipboard\n'));
640
- }
641
- });
642
-
643
- // ========================================
644
- // REVIEW COMMAND - Code vs Plan Alignment (v2.2)
645
- // ========================================
646
- program
647
- .command('review')
648
- .description('Review code against the implementation plan')
649
- .option('-d, --dir <directory>', 'Directory to review', '.')
650
- .option('--quick', 'Quick review without AI (checks file structure only)')
651
- .action(async (options) => {
652
- console.log(chalk.cyan('\nšŸ” Ultra-Dex Code Review\n'));
653
-
654
- const reviewDir = path.resolve(options.dir);
655
-
656
- async function readFileSafe(fp) {
657
- try { return await fs.readFile(fp, 'utf-8'); } catch { return null; }
658
- }
659
- async function fileExists(fp) {
660
- try { await fs.access(fp); return true; } catch { return false; }
661
- }
662
-
663
- const planPath = path.join(reviewDir, 'IMPLEMENTATION-PLAN.md');
664
- const plan = await readFileSafe(planPath);
665
-
666
- if (!plan) {
667
- console.log(chalk.yellow('āš ļø No IMPLEMENTATION-PLAN.md found.\n'));
668
- console.log(chalk.white('Run one of these first:'));
669
- console.log(chalk.gray(' npx ultra-dex init'));
670
- console.log(chalk.gray(' npx ultra-dex generate\n'));
671
- return;
672
- }
673
-
674
- async function getDirectoryStructure(dir, depth = 3, prefix = '') {
675
- let structure = '';
676
- try {
677
- const entries = await fs.readdir(dir, { withFileTypes: true });
678
- for (const entry of entries) {
679
- if (['node_modules', '.git', '.next', 'dist', 'build'].includes(entry.name)) continue;
680
- const entryPath = path.join(dir, entry.name);
681
- if (entry.isDirectory()) {
682
- structure += `${prefix}šŸ“ ${entry.name}/\n`;
683
- if (depth > 1) structure += await getDirectoryStructure(entryPath, depth - 1, prefix + ' ');
684
- } else {
685
- structure += `${prefix}šŸ“„ ${entry.name}\n`;
686
- }
687
- }
688
- } catch { /* ignore errors */ }
689
- return structure;
690
- }
691
-
692
- const spinner = ora('Scanning codebase...').start();
693
- const structure = await getDirectoryStructure(reviewDir);
694
- spinner.succeed('Codebase scanned');
695
-
696
- console.log(chalk.white('\nšŸ“ Project Structure:\n'));
697
- console.log(chalk.gray(structure));
698
-
699
- const checks = [
700
- { name: 'IMPLEMENTATION-PLAN.md', path: 'IMPLEMENTATION-PLAN.md' },
701
- { name: 'CONTEXT.md', path: 'CONTEXT.md' },
702
- { name: 'package.json', path: 'package.json' },
703
- { name: 'Database schema', path: 'prisma/schema.prisma' },
704
- { name: 'Tests', path: 'tests' },
705
- ];
706
-
707
- console.log(chalk.white('šŸ“‹ Structure Checks:\n'));
708
- for (const check of checks) {
709
- const exists = await fileExists(path.join(reviewDir, check.path));
710
- const icon = exists ? chalk.green('āœ…') : chalk.red('āŒ');
711
- console.log(` ${icon} ${check.name}`);
712
- }
713
-
714
- // Check for key sections in plan
715
- console.log(chalk.white('\nšŸ“‹ Plan Completeness:\n'));
716
- const planChecks = [
717
- { name: 'Database schema (Section 10)', pattern: /section 10|data model/i },
718
- { name: 'API endpoints (Section 11)', pattern: /section 11|api blueprint/i },
719
- { name: 'Tech stack (Section 15)', pattern: /section 15|tech stack/i },
720
- { name: 'Implementation tasks (Section 16)', pattern: /section 16|implementation plan/i },
721
- ];
722
- for (const check of planChecks) {
723
- const found = check.pattern.test(plan);
724
- const icon = found ? chalk.green('āœ…') : chalk.yellow('āš ļø');
725
- console.log(` ${icon} ${check.name}`);
726
- }
727
-
728
- console.log(chalk.cyan('\nšŸ’” Tips:'));
729
- console.log(chalk.gray(' • Use "npx ultra-dex audit" for a detailed score'));
730
- console.log(chalk.gray(' • Use "npx ultra-dex build" to start AI-assisted development\n'));
731
- });
732
-
733
- // ========================================
734
- // MCP SERVER (Enhanced Context over HTTP)
735
- // ========================================
736
- program
737
- .command('serve')
738
- .description('Serve Ultra-Dex context over HTTP (MCP-compatible)')
739
- .option('-p, --port <port>', 'Port to listen on', '3001')
740
- .option('-w, --watch', 'Watch for file changes and notify clients')
741
- .action(async (options) => {
742
- const port = Number.parseInt(options.port, 10);
743
- if (Number.isNaN(port)) {
744
- console.log(chalk.red('Invalid port. Use a numeric value.'));
745
- process.exit(1);
746
- }
747
-
748
- async function readFileSafe(filePath, label) {
749
- try {
750
- const content = await fs.readFile(filePath, 'utf-8');
751
- return { label, content, exists: true };
752
- } catch {
753
- return { label, content: '', exists: false };
754
- }
755
- }
756
-
757
- async function getProjectState() {
758
- const [context, plan, quickStart] = await Promise.all([
759
- readFileSafe('CONTEXT.md', 'CONTEXT.md'),
760
- readFileSafe('IMPLEMENTATION-PLAN.md', 'IMPLEMENTATION-PLAN.md'),
761
- readFileSafe('QUICK-START.md', 'QUICK-START.md'),
762
- ]);
763
-
764
- // Calculate quick stats
765
- let planSections = 0;
766
- if (plan.content) {
767
- const matches = plan.content.match(/## (SECTION \d+|Section \d+)/gi);
768
- planSections = matches ? matches.length : 0;
769
- }
770
-
771
- return {
772
- meta: {
773
- protocol: 'ultra-dex-mcp',
774
- version: '2.1.0',
775
- timestamp: new Date().toISOString(),
776
- },
777
- stats: {
778
- hasContext: context.exists,
779
- hasPlan: plan.exists,
780
- hasQuickStart: quickStart.exists,
781
- planSections,
782
- },
783
- files: [context, plan, quickStart].filter(f => f.exists),
784
- };
785
- }
786
-
787
- // Available agents for quick reference
788
- const agentsList = Object.entries(BUILD_AGENTS).map(([id, cfg]) => ({
789
- id,
790
- name: cfg.name,
791
- tier: cfg.tier,
792
- task: cfg.task,
793
- }));
794
-
795
- const server = http.createServer(async (req, res) => {
796
- // CORS headers for browser access
797
- res.setHeader('Access-Control-Allow-Origin', '*');
798
- res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
799
- res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
800
-
801
- if (req.method === 'OPTIONS') {
802
- res.writeHead(204);
803
- res.end();
804
- return;
805
- }
806
-
807
- const url = new URL(req.url, `http://localhost:${port}`);
808
-
809
- // Health check
810
- if (url.pathname === '/' || url.pathname === '/health') {
811
- res.writeHead(200, { 'Content-Type': 'application/json' });
812
- res.end(JSON.stringify({
813
- status: 'ok',
814
- service: 'ultra-dex-mcp',
815
- version: '2.1.0',
816
- endpoints: ['/context', '/agents', '/plan', '/state'],
817
- }));
818
- return;
819
- }
820
-
821
- // Full context (all files)
822
- if (url.pathname === '/context') {
823
- const state = await getProjectState();
824
- res.writeHead(200, { 'Content-Type': 'application/json' });
825
- res.end(JSON.stringify(state));
826
- return;
827
- }
828
-
829
- // Just the plan
830
- if (url.pathname === '/plan') {
831
- const plan = await readFileSafe('IMPLEMENTATION-PLAN.md', 'IMPLEMENTATION-PLAN.md');
832
- res.writeHead(200, { 'Content-Type': 'application/json' });
833
- res.end(JSON.stringify({ plan: plan.content, exists: plan.exists }));
834
- return;
835
- }
836
-
837
- // Project state (quick check)
838
- if (url.pathname === '/state') {
839
- const state = await getProjectState();
840
- res.writeHead(200, { 'Content-Type': 'application/json' });
841
- res.end(JSON.stringify({ meta: state.meta, stats: state.stats }));
842
- return;
843
- }
844
-
845
- // List agents
846
- if (url.pathname === '/agents') {
847
- res.writeHead(200, { 'Content-Type': 'application/json' });
848
- res.end(JSON.stringify({ agents: agentsList }));
849
- return;
850
- }
851
-
852
- // Get specific agent prompt
853
- if (url.pathname.startsWith('/agents/')) {
854
- const agentId = url.pathname.split('/')[2];
855
- const agentConfig = BUILD_AGENTS[agentId];
856
- if (!agentConfig) {
857
- res.writeHead(404, { 'Content-Type': 'application/json' });
858
- res.end(JSON.stringify({ error: 'Agent not found', available: Object.keys(BUILD_AGENTS) }));
859
- return;
860
- }
861
-
862
- // Build prompt with context
863
- const context = await readFileSafe('CONTEXT.md', 'CONTEXT.md');
864
- const plan = await readFileSafe('IMPLEMENTATION-PLAN.md', 'IMPLEMENTATION-PLAN.md');
865
-
866
- const prompt = `# ${agentConfig.name} Agent Session
867
-
868
- You are acting as ${agentConfig.name} for this project.
869
-
870
- ${context.content ? `## Project Context\n${context.content}\n` : ''}
871
- ${plan.content ? `## Implementation Plan\n${plan.content.slice(0, 10000)}\n` : ''}
872
-
873
- ## Default Task
874
- ${agentConfig.task}
875
-
876
- ## Instructions
877
- 1. Read the context and plan carefully
878
- 2. Focus ONLY on your assigned task
879
- 3. Follow Ultra-Dex 21-step verification for code changes
880
- `;
881
-
882
- res.writeHead(200, { 'Content-Type': 'application/json' });
883
- res.end(JSON.stringify({
884
- agent: agentConfig,
885
- prompt,
886
- contextLength: context.content.length,
887
- planLength: plan.content.length,
888
- }));
889
- return;
890
- }
891
-
892
- res.writeHead(404, { 'Content-Type': 'application/json' });
893
- res.end(JSON.stringify({ error: 'Not found' }));
894
- });
895
-
896
- server.listen(port, () => {
897
- console.log(chalk.green(`\nāœ… Ultra-Dex MCP Server v2.1.0`));
898
- console.log(chalk.cyan(` Running on http://localhost:${port}\n`));
899
- console.log(chalk.white(' Endpoints:'));
900
- console.log(chalk.gray(' GET / - Health check + endpoint list'));
901
- console.log(chalk.gray(' GET /context - Full context (all files)'));
902
- console.log(chalk.gray(' GET /plan - Just IMPLEMENTATION-PLAN.md'));
903
- console.log(chalk.gray(' GET /state - Quick project state'));
904
- console.log(chalk.gray(' GET /agents - List all agents'));
905
- console.log(chalk.gray(' GET /agents/:id - Get agent prompt with context\n'));
906
- console.log(chalk.yellow(' Example: curl http://localhost:' + port + '/agents/backend\n'));
907
- });
908
- });
909
-
910
- program
911
- .command('agent <name>')
912
- .description('Show a specific agent prompt')
913
- .action(async (name) => {
914
- const agent = AGENTS.find(a => a.name.toLowerCase() === name.toLowerCase());
915
-
916
- if (!agent) {
917
- console.log(chalk.red(`\nāŒ Agent "${name}" not found.\n`));
918
- console.log(chalk.gray('Available agents:'));
919
- AGENTS.forEach(a => console.log(chalk.cyan(` - ${a.name}`)));
920
- console.log('\n' + chalk.gray('Run "ultra-dex agents" to see all agents.\n'));
921
- process.exit(1);
922
- }
923
-
924
- // Try to read agent file
925
- const agentPath = path.join(ASSETS_ROOT, 'agents', agent.file);
926
- try {
927
- const content = await fs.readFile(agentPath, 'utf-8');
928
- console.log(chalk.bold(`\nšŸ¤– ${agent.name.toUpperCase()} Agent\n`));
929
- console.log(chalk.gray('─'.repeat(60)));
930
- console.log(content);
931
- console.log(chalk.gray('─'.repeat(60)));
932
- console.log(chalk.bold('\nšŸ“‹ Copy the above prompt and paste into your AI tool.\n'));
933
- } catch (err) {
934
- const fallbackPath = path.join(ROOT_FALLBACK, 'agents', agent.file);
935
- try {
936
- const content = await fs.readFile(fallbackPath, 'utf-8');
937
- console.log(chalk.bold(`\nšŸ¤– ${agent.name.toUpperCase()} Agent\n`));
938
- console.log(chalk.gray('─'.repeat(60)));
939
- console.log(content);
940
- console.log(chalk.gray('─'.repeat(60)));
941
- console.log(chalk.bold('\nšŸ“‹ Copy the above prompt and paste into your AI tool.\n'));
942
- } catch (fallbackErr) {
943
- console.log(chalk.bold(`\nšŸ¤– ${agent.name.toUpperCase()} Agent\n`));
944
- console.log(chalk.gray('View full prompt on GitHub:'));
945
- console.log(chalk.blue(` https://github.com/Srujan0798/Ultra-Dex/blob/main/agents/${agent.file}\n`));
946
- }
947
- }
948
- });
949
-
950
- // Pack command - assemble context for any AI tool
951
- program
952
- .command('pack <agent>')
953
- .description('Package project context + agent prompt for any AI tool')
954
- .option('-c, --clipboard', 'Copy to clipboard (requires pbcopy/xclip)')
955
- .action(async (agentName, options) => {
956
- // Find agent
957
- const agent = AGENTS.find(a => a.name.toLowerCase() === agentName.toLowerCase());
958
- if (!agent) {
959
- console.log(chalk.red(`\nāŒ Agent "${agentName}" not found.\n`));
960
- console.log(chalk.gray('Available agents:'));
961
- AGENTS.forEach(a => console.log(chalk.cyan(` - ${a.name}`)));
962
- process.exit(1);
963
- }
964
-
965
- let output = '';
966
-
967
- // 1. Read Agent Prompt
968
- const agentPath = path.join(ASSETS_ROOT, 'agents', agent.file);
969
- try {
970
- const agentPrompt = await fs.readFile(agentPath, 'utf-8');
971
- output += agentPrompt + '\n\n';
972
- } catch (err) {
973
- const fallbackPath = path.join(ROOT_FALLBACK, 'agents', agent.file);
974
- try {
975
- const agentPrompt = await fs.readFile(fallbackPath, 'utf-8');
976
- output += agentPrompt + '\n\n';
977
- } catch (fallbackErr) {
978
- output += `# ${agent.name.toUpperCase()} Agent\n\nSee: https://github.com/Srujan0798/Ultra-Dex/blob/main/agents/${agent.file}\n\n`;
979
- }
980
- }
981
-
982
- output += '---\n\n';
983
-
984
- // 2. Read CONTEXT.md
985
- try {
986
- const context = await fs.readFile('CONTEXT.md', 'utf-8');
987
- output += '# PROJECT CONTEXT\n\n' + context + '\n\n';
988
- } catch (err) {
989
- output += '# PROJECT CONTEXT\n\n*No CONTEXT.md found. Run `ultra-dex init` first.*\n\n';
990
- }
991
-
992
- output += '---\n\n';
993
-
994
- // 3. Read IMPLEMENTATION-PLAN.md
995
- try {
996
- const plan = await fs.readFile('IMPLEMENTATION-PLAN.md', 'utf-8');
997
- output += '# IMPLEMENTATION PLAN\n\n' + plan + '\n';
998
- } catch (err) {
999
- output += '# IMPLEMENTATION PLAN\n\n*No IMPLEMENTATION-PLAN.md found. Run `ultra-dex init` first.*\n';
1000
- }
1001
-
1002
- // Output
1003
- console.log(chalk.bold(`\nšŸ“¦ Packed context for @${agent.name}\n`));
1004
- console.log(chalk.gray('─'.repeat(60)));
1005
- console.log(output);
1006
- console.log(chalk.gray('─'.repeat(60)));
1007
-
1008
- // Try to copy to clipboard if requested
1009
- if (options.clipboard) {
1010
- try {
1011
- const { execSync } = require('child_process');
1012
- const platform = process.platform;
1013
- if (platform === 'darwin') {
1014
- execSync('pbcopy', { input: output });
1015
- console.log(chalk.green('\nāœ… Copied to clipboard!\n'));
1016
- } else if (platform === 'linux') {
1017
- execSync('xclip -selection clipboard', { input: output });
1018
- console.log(chalk.green('\nāœ… Copied to clipboard!\n'));
1019
- } else {
1020
- console.log(chalk.yellow('\nāš ļø Clipboard not supported on this platform. Copy manually.\n'));
1021
- }
1022
- } catch (err) {
1023
- console.log(chalk.yellow('\nāš ļø Could not copy to clipboard. Copy manually.\n'));
1024
- }
1025
- } else {
1026
- console.log(chalk.cyan('\nšŸ’” Tip: Use --clipboard flag to copy directly\n'));
1027
- }
1028
- });
1029
-
1030
- // Workflow examples map
1031
- const WORKFLOWS = {
1032
- auth: {
1033
- name: 'Authentication',
1034
- agents: ['@Planner', '@Research', '@CTO', '@Database', '@Backend', '@Frontend', '@Security', '@DevOps'],
1035
- description: 'Complete authentication with email/password and OAuth',
1036
- example: 'supabase',
1037
- },
1038
- supabase: {
1039
- name: 'Supabase Authentication Setup',
1040
- agents: ['@Planner', '@Research', '@CTO', '@Database', '@Backend', '@Frontend', '@Security', '@DevOps'],
1041
- description: 'Set up Supabase auth with RLS policies',
1042
- steps: [
1043
- '1. Create Supabase project and get API keys',
1044
- '2. Set up database schema with RLS policies',
1045
- '3. Configure authentication providers (email + Google OAuth)',
1046
- '4. Implement backend auth middleware',
1047
- '5. Build frontend auth UI components',
1048
- '6. Test authentication flow',
1049
- ],
1050
- },
1051
- payments: {
1052
- name: 'Payment Integration (Stripe)',
1053
- agents: ['@Planner', '@Research', '@CTO', '@Database', '@Backend', '@Frontend', '@Testing', '@Security', '@DevOps'],
1054
- description: 'Integrate Stripe for subscriptions and one-time payments',
1055
- steps: [
1056
- '1. Create Stripe account and get API keys',
1057
- '2. Design subscription/payment schema',
1058
- '3. Implement Stripe Checkout API',
1059
- '4. Handle webhooks for payment events',
1060
- '5. Build payment UI with checkout flow',
1061
- '6. Test with Stripe test cards',
1062
- ],
1063
- },
1064
- deployment: {
1065
- name: 'Deployment Pipeline',
1066
- agents: ['@Planner', '@CTO', '@Frontend', '@DevOps'],
1067
- description: 'Deploy to Vercel with staging and production environments',
1068
- example: 'vercel',
1069
- },
1070
- vercel: {
1071
- name: 'Vercel Deployment Pipeline',
1072
- agents: ['@Planner', '@CTO', '@Frontend', '@DevOps'],
1073
- description: 'Deploy Next.js app to Vercel',
1074
- steps: [
1075
- '1. Set up Vercel project and link Git repository',
1076
- '2. Configure environment variables for staging/production',
1077
- '3. Set up custom domain',
1078
- '4. Configure preview deployments for PRs',
1079
- '5. Set up deployment protection rules',
1080
- '6. Test deployment pipeline',
1081
- ],
1082
- },
1083
- cicd: {
1084
- name: 'GitHub Actions CI/CD',
1085
- agents: ['@Planner', '@CTO', '@Testing', '@DevOps'],
1086
- description: 'Automated testing and deployment with GitHub Actions',
1087
- steps: [
1088
- '1. Create workflow file for CI (tests + lint)',
1089
- '2. Add build verification job',
1090
- '3. Add deployment job for production',
1091
- '4. Configure secrets for deployment',
1092
- '5. Add status badges to README',
1093
- '6. Test workflow on PR',
1094
- ],
1095
- },
1096
- database: {
1097
- name: 'Database Migration',
1098
- agents: ['@Planner', '@CTO', '@Database', '@Backend', '@Testing'],
1099
- description: 'Database schema migration and data sync',
1100
- steps: [
1101
- '1. Design new schema changes',
1102
- '2. Write migration scripts',
1103
- '3. Test migrations in staging',
1104
- '4. Back up production database',
1105
- '5. Run migrations in production',
1106
- '6. Verify data integrity',
1107
- ],
1108
- },
1109
- email: {
1110
- name: 'Email Notification System',
1111
- agents: ['@Planner', '@Research', '@CTO', '@Backend', '@Frontend', '@Testing'],
1112
- description: 'Transactional emails with templates',
1113
- steps: [
1114
- '1. Choose email service (Resend, SendGrid)',
1115
- '2. Set up email templates',
1116
- '3. Implement email API endpoints',
1117
- '4. Add email queue for async sending',
1118
- '5. Test email delivery',
1119
- '6. Monitor deliverability',
1120
- ],
1121
- },
1122
- realtime: {
1123
- name: 'Real-Time Features',
1124
- agents: ['@Planner', '@CTO', '@Backend', '@Frontend', '@Testing'],
1125
- description: 'Live notifications with WebSockets',
1126
- steps: [
1127
- '1. Choose WebSocket library (Socket.io, Pusher)',
1128
- '2. Set up WebSocket server',
1129
- '3. Implement event broadcasting',
1130
- '4. Build frontend listeners',
1131
- '5. Test real-time updates',
1132
- '6. Handle reconnection logic',
1133
- ],
1134
- },
1135
- sentry: {
1136
- name: 'Sentry Error Tracking',
1137
- agents: ['@Planner', '@Research', '@CTO', '@Backend', '@Frontend', '@DevOps'],
1138
- description: 'Error monitoring with Sentry',
1139
- steps: [
1140
- '1. Create Sentry account and project',
1141
- '2. Install Sentry SDKs for frontend and backend',
1142
- '3. Configure error boundaries for React',
1143
- '4. Set up source maps for debugging',
1144
- '5. Configure alerts and notifications',
1145
- '6. Test error capture in development',
1146
- ],
1147
- },
1148
- shopify: {
1149
- name: 'Shopify Product Integration',
1150
- agents: ['@Planner', '@Research', '@CTO', '@Database', '@Backend', '@DevOps'],
1151
- description: 'Sync products from Shopify store',
1152
- steps: [
1153
- '1. Create Shopify Partner account and development store',
1154
- '2. Set up Shopify app with Admin API access',
1155
- '3. Design database schema for products',
1156
- '4. Build product sync endpoint',
1157
- '5. Implement webhook handlers for product updates',
1158
- '6. Schedule full product sync (cron job)',
1159
- ],
1160
- },
1161
- analytics: {
1162
- name: 'PostHog Analytics Integration',
1163
- agents: ['@Planner', '@Research', '@CTO', '@Backend', '@Frontend', '@DevOps'],
1164
- description: 'Track user behavior with PostHog',
1165
- steps: [
1166
- '1. Create PostHog account and project',
1167
- '2. Install PostHog SDKs for frontend and backend',
1168
- '3. Set up core event tracking (signup, login, feature usage)',
1169
- '4. Create conversion funnel dashboard',
1170
- '5. Set up feature flags (optional)',
1171
- '6. Configure user identification',
1172
- ],
1173
- },
1174
- };
1175
-
1176
- program
1177
- .command('workflow <feature>')
1178
- .description('Show workflow for common features (auth, payments, deployment, etc.)')
1179
- .action((feature) => {
1180
- const workflow = WORKFLOWS[feature.toLowerCase()];
1181
-
1182
- if (!workflow) {
1183
- console.log(chalk.red(`\nāŒ Workflow "${feature}" not found.\n`));
1184
- console.log(chalk.gray('Available workflows:'));
1185
- Object.keys(WORKFLOWS).forEach(key => {
1186
- console.log(chalk.cyan(` - ${key}`) + chalk.gray(` (${WORKFLOWS[key].name})`));
1187
- });
1188
- console.log('\n' + chalk.gray('Usage: ultra-dex workflow <feature>\n'));
1189
- process.exit(1);
1190
- }
1191
-
1192
- console.log(chalk.bold(`\nšŸ“‹ ${workflow.name} Workflow\n`));
1193
- console.log(chalk.gray(workflow.description));
1194
-
1195
- console.log(chalk.bold('\nšŸ¤– Agents Involved:\n'));
1196
- workflow.agents.forEach((agent, i) => {
1197
- console.log(chalk.cyan(` ${i + 1}. ${agent}`));
1198
- });
1199
-
1200
- if (workflow.steps) {
1201
- console.log(chalk.bold('\nšŸ“ Implementation Steps:\n'));
1202
- workflow.steps.forEach(step => {
1203
- console.log(chalk.gray(` ${step}`));
1204
- });
1205
- }
1206
-
1207
- console.log(chalk.bold('\nšŸ“š Full Example:\n'));
1208
- console.log(chalk.blue(' https://github.com/Srujan0798/Ultra-Dex/blob/main/guides/ADVANCED-WORKFLOWS.md'));
1209
- console.log(chalk.gray(` (Search for "Example: ${workflow.name}")\n`));
1210
- });
1211
-
1212
- program
1213
- .command('suggest')
1214
- .description('Get AI agent suggestions for your task')
1215
- .action(async () => {
1216
- console.log(chalk.cyan('\nšŸ¤– Ultra-Dex Agent Suggester\n'));
1217
-
1218
- const answers = await inquirer.prompt([
1219
- {
1220
- type: 'list',
1221
- name: 'taskType',
1222
- message: 'What are you trying to build?',
1223
- choices: [
1224
- 'New feature from scratch',
1225
- 'Authentication system',
1226
- 'Payment integration',
1227
- 'Database changes',
1228
- 'Bug fix',
1229
- 'Performance optimization',
1230
- 'Deployment/DevOps',
1231
- 'API endpoint',
1232
- 'UI component',
1233
- 'Testing',
1234
- ],
1235
- },
1236
- {
1237
- type: 'input',
1238
- name: 'description',
1239
- message: 'Briefly describe your task:',
1240
- default: '',
1241
- },
1242
- ]);
1243
-
1244
- console.log(chalk.bold('\nšŸ’” Suggested Agent Workflow:\n'));
1245
-
1246
- // Agent suggestions based on task type
1247
- let suggestedAgents = [];
1248
- let reasoning = '';
1249
-
1250
- switch (answers.taskType) {
1251
- case 'New feature from scratch':
1252
- suggestedAgents = ['@Planner', '@CTO', '@Database', '@Backend', '@Frontend', '@Testing', '@Reviewer', '@DevOps'];
1253
- reasoning = 'Complete feature requires planning, architecture, implementation, testing, and deployment';
1254
- break;
1255
-
1256
- case 'Authentication system':
1257
- suggestedAgents = ['@Planner', '@Research', '@CTO', '@Database', '@Backend', '@Frontend', '@Security', '@DevOps'];
1258
- reasoning = 'Auth requires research (providers), security review, and full-stack implementation';
1259
- break;
1260
-
1261
- case 'Payment integration':
1262
- suggestedAgents = ['@Planner', '@Research', '@CTO', '@Database', '@Backend', '@Frontend', '@Testing', '@Security', '@DevOps'];
1263
- reasoning = 'Payments need provider research, webhook handling, testing, and security audit';
1264
- break;
1265
-
1266
- case 'Database changes':
1267
- suggestedAgents = ['@Planner', '@CTO', '@Database', '@Backend', '@Testing'];
1268
- reasoning = 'Schema changes need planning, architecture review, migration, and testing';
1269
- break;
1270
-
1271
- case 'Bug fix':
1272
- suggestedAgents = ['@Debugger', '@Testing', '@Reviewer'];
1273
- reasoning = 'Debug issue, add test to prevent regression, review fix';
1274
- break;
1275
-
1276
- case 'Performance optimization':
1277
- suggestedAgents = ['@Performance', '@Backend', '@Frontend', '@Database', '@Testing'];
1278
- reasoning = 'Identify bottlenecks, optimize code/queries, verify improvements';
1279
- break;
1280
-
1281
- case 'Deployment/DevOps':
1282
- suggestedAgents = ['@DevOps', '@CTO', '@Security'];
1283
- reasoning = 'Infrastructure setup with security review';
1284
- break;
1285
-
1286
- case 'API endpoint':
1287
- suggestedAgents = ['@Backend', '@Database', '@Testing', '@Reviewer'];
1288
- reasoning = 'Implement endpoint, add tests, review code quality';
1289
- break;
1290
-
1291
- case 'UI component':
1292
- suggestedAgents = ['@Frontend', '@Reviewer'];
1293
- reasoning = 'Build component, review for quality and accessibility';
1294
- break;
1295
-
1296
- case 'Testing':
1297
- suggestedAgents = ['@Testing', '@Reviewer'];
1298
- reasoning = 'Write tests, review coverage';
1299
- break;
1300
-
1301
- default:
1302
- suggestedAgents = ['@Planner', '@CTO'];
1303
- reasoning = 'Start with planning and architecture review';
1304
- }
1305
-
1306
- console.log(chalk.gray(reasoning + '\n'));
1307
-
1308
- suggestedAgents.forEach((agent, i) => {
1309
- const agentName = agent.replace('@', '').toLowerCase();
1310
- const agentInfo = AGENTS.find(a => a.name === agentName);
1311
- const arrow = i < suggestedAgents.length - 1 ? ' →' : '';
1312
- console.log(chalk.cyan(` ${i + 1}. ${agent}`) + chalk.gray(` - ${agentInfo?.description || ''}`) + arrow);
1313
- });
1314
-
1315
- console.log(chalk.bold('\nšŸ“š Next Steps:\n'));
1316
- console.log(chalk.gray(` 1. Start with ${suggestedAgents[0]} to plan the task`));
1317
- console.log(chalk.gray(` 2. Hand off to each agent in sequence`));
1318
- console.log(chalk.gray(' 3. Use "ultra-dex agent <name>" to see full prompts\n'));
1319
-
1320
- console.log(chalk.bold('šŸ”— Related Workflows:\n'));
1321
- if (answers.taskType === 'Authentication system') {
1322
- console.log(chalk.blue(' ultra-dex workflow auth'));
1323
- console.log(chalk.blue(' ultra-dex workflow supabase\n'));
1324
- } else if (answers.taskType === 'Payment integration') {
1325
- console.log(chalk.blue(' ultra-dex workflow payments\n'));
1326
- } else if (answers.taskType === 'Deployment/DevOps') {
1327
- console.log(chalk.blue(' ultra-dex workflow vercel'));
1328
- console.log(chalk.blue(' ultra-dex workflow cicd\n'));
1329
- } else {
1330
- console.log(chalk.gray(' Use "ultra-dex workflow <feature>" to see examples\n'));
1331
- }
1332
- });
1333
-
1334
- program
1335
- .command('validate')
1336
- .description('Validate project structure against Ultra-Dex standards')
1337
- .option('-d, --dir <directory>', 'Project directory to validate', '.')
1338
- .action(async (options) => {
1339
- console.log(chalk.cyan('\nāœ… Ultra-Dex Structure Validator\n'));
1340
-
1341
- const projectDir = path.resolve(options.dir);
1342
- let passed = 0;
1343
- let failed = 0;
1344
- const warnings = [];
1345
-
1346
- // Helper to check file/directory exists
1347
- async function checkExists(itemPath, type = 'file') {
1348
- try {
1349
- const stats = await fs.stat(path.join(projectDir, itemPath));
1350
- if (type === 'file' && stats.isFile()) return true;
1351
- if (type === 'dir' && stats.isDirectory()) return true;
1352
- return false;
1353
- } catch {
1354
- return false;
1355
- }
1356
- }
1357
-
1358
- console.log(chalk.bold('Checking required files...\n'));
1359
-
1360
- // Check core planning files
1361
- const coreFiles = [
1362
- { path: 'QUICK-START.md', required: true },
1363
- { path: 'IMPLEMENTATION-PLAN.md', required: true },
1364
- { path: 'CONTEXT.md', required: false },
1365
- { path: 'README.md', required: false },
1366
- ];
1367
-
1368
- for (const file of coreFiles) {
1369
- const exists = await checkExists(file.path);
1370
- if (exists) {
1371
- passed++;
1372
- console.log(chalk.green(` āœ… ${file.path}`));
1373
- } else if (file.required) {
1374
- failed++;
1375
- console.log(chalk.red(` āŒ ${file.path} (required)`));
1376
- } else {
1377
- warnings.push(file.path);
1378
- console.log(chalk.yellow(` āš ļø ${file.path} (recommended)`));
1379
- }
1380
- }
1381
-
1382
- console.log(chalk.bold('\nChecking directory structure...\n'));
1383
-
1384
- const directories = [
1385
- { path: 'docs', required: false },
1386
- { path: '.agents', required: false },
1387
- { path: '.cursor/rules', required: false },
1388
- ];
1389
-
1390
- for (const dir of directories) {
1391
- const exists = await checkExists(dir.path, 'dir');
1392
- if (exists) {
1393
- passed++;
1394
- console.log(chalk.green(` āœ… ${dir.path}/`));
1395
- } else {
1396
- warnings.push(dir.path);
1397
- console.log(chalk.yellow(` āš ļø ${dir.path}/ (optional)`));
1398
- }
1399
- }
1400
-
1401
- console.log(chalk.bold('\nValidating content quality...\n'));
1402
-
1403
- // Check if QUICK-START has key sections
1404
- try {
1405
- const quickStart = await fs.readFile(path.join(projectDir, 'QUICK-START.md'), 'utf-8');
1406
-
1407
- const sections = ['idea', 'problem', 'feature', 'tech stack', 'tasks'];
1408
- let sectionsFound = 0;
1409
-
1410
- sections.forEach(section => {
1411
- if (quickStart.toLowerCase().includes(section)) {
1412
- sectionsFound++;
1413
- }
1414
- });
1415
-
1416
- if (sectionsFound >= 4) {
1417
- passed++;
1418
- console.log(chalk.green(` āœ… QUICK-START.md has ${sectionsFound}/${sections.length} key sections`));
1419
- } else {
1420
- failed++;
1421
- console.log(chalk.red(` āŒ QUICK-START.md missing key sections (${sectionsFound}/${sections.length})`));
1422
- }
1423
- } catch {
1424
- console.log(chalk.gray(' ⊘ Could not validate QUICK-START.md content'));
1425
- }
1426
-
1427
- // Check if implementation plan has content
1428
- try {
1429
- const implPlan = await fs.readFile(path.join(projectDir, 'IMPLEMENTATION-PLAN.md'), 'utf-8');
1430
-
1431
- if (implPlan.length > 500) {
1432
- passed++;
1433
- console.log(chalk.green(` āœ… IMPLEMENTATION-PLAN.md has substantial content`));
1434
- } else {
1435
- warnings.push('IMPLEMENTATION-PLAN.md needs more detail');
1436
- console.log(chalk.yellow(` āš ļø IMPLEMENTATION-PLAN.md is sparse (${implPlan.length} chars)`));
1437
- }
1438
- } catch {
1439
- console.log(chalk.gray(' ⊘ Could not validate IMPLEMENTATION-PLAN.md content'));
1440
- }
1441
-
1442
- // Summary
1443
- console.log('\n' + chalk.bold('─'.repeat(50)));
1444
- console.log(chalk.bold('\nValidation Summary:\n'));
1445
- console.log(chalk.green(` āœ… Passed: ${passed}`));
1446
- console.log(chalk.red(` āŒ Failed: ${failed}`));
1447
- console.log(chalk.yellow(` āš ļø Warnings: ${warnings.length}`));
1448
-
1449
- // Overall status
1450
- if (failed === 0) {
1451
- console.log(chalk.bold.green('\nāœ… VALIDATION PASSED\n'));
1452
- console.log(chalk.gray('Your project structure follows Ultra-Dex standards.'));
1453
- } else {
1454
- console.log(chalk.bold.yellow('\nāš ļø VALIDATION INCOMPLETE\n'));
1455
- console.log(chalk.gray('Fix required files to meet Ultra-Dex standards.'));
1456
- }
1457
-
1458
- // Recommendations
1459
- if (warnings.length > 0) {
1460
- console.log(chalk.bold('\nšŸ’” Recommendations:\n'));
1461
- warnings.slice(0, 3).forEach(w => {
1462
- console.log(chalk.cyan(` → Consider adding ${w}`));
1463
- });
1464
- }
1465
-
1466
- console.log('\n' + chalk.gray('Run "ultra-dex init" to set up a proper Ultra-Dex project.\n'));
1467
- });
1468
-
1469
- // ========================================
1470
- // HOOKS COMMAND - Automated Verification
1471
- // ========================================
1472
- program
1473
- .command('hooks')
1474
- .description('Set up git hooks for automated verification')
1475
- .option('--remove', 'Remove Ultra-Dex git hooks')
1476
- .action(async (options) => {
1477
- console.log(chalk.cyan('\nšŸŖ Ultra-Dex Git Hooks Setup\n'));
1478
-
1479
- const gitDir = path.join(process.cwd(), '.git');
1480
- const hooksDir = path.join(gitDir, 'hooks');
1481
-
1482
- // Check if git repo exists
1483
- try {
1484
- await fs.access(gitDir);
1485
- } catch {
1486
- console.log(chalk.red('āŒ Not a git repository. Run "git init" first.\n'));
1487
- process.exit(1);
1488
- }
1489
-
1490
- // Create hooks directory if it doesn't exist
1491
- await fs.mkdir(hooksDir, { recursive: true });
1492
-
1493
- const preCommitPath = path.join(hooksDir, 'pre-commit');
1494
-
1495
- if (options.remove) {
1496
- // Remove hooks
1497
- try {
1498
- const content = await fs.readFile(preCommitPath, 'utf-8');
1499
- if (content.includes('ultra-dex')) {
1500
- await fs.unlink(preCommitPath);
1501
- console.log(chalk.green('āœ… Ultra-Dex pre-commit hook removed.\n'));
1502
- } else {
1503
- console.log(chalk.yellow('āš ļø Pre-commit hook exists but is not from Ultra-Dex.\n'));
1504
- }
1505
- } catch {
1506
- console.log(chalk.gray('No Ultra-Dex hooks found.\n'));
1507
- }
1508
- return;
1509
- }
1510
-
1511
- // Generate pre-commit hook
1512
- const preCommitScript = `#!/bin/sh
1513
- # Ultra-Dex Pre-Commit Hook
1514
- # Validates project structure before allowing commits
1515
- # Remove with: npx ultra-dex hooks --remove
1516
-
1517
- echo "šŸ” Ultra-Dex: Validating project structure..."
1518
-
1519
- # Run validation
1520
- npx ultra-dex validate --dir . > /tmp/ultra-dex-validate.log 2>&1
1521
- RESULT=$?
1522
-
1523
- if [ $RESULT -ne 0 ]; then
1524
- echo ""
1525
- echo "āŒ Ultra-Dex validation failed. Commit blocked."
1526
- echo ""
1527
- echo "Run 'npx ultra-dex validate' to see details."
1528
- echo "Fix issues or bypass with: git commit --no-verify"
1529
- echo ""
1530
- exit 1
1531
- fi
1532
-
1533
- # Check for required files
1534
- if [ ! -f "QUICK-START.md" ]; then
1535
- echo "āš ļø Warning: QUICK-START.md not found"
1536
- fi
1537
-
1538
- if [ ! -f "IMPLEMENTATION-PLAN.md" ]; then
1539
- echo "āš ļø Warning: IMPLEMENTATION-PLAN.md not found"
1540
- fi
1541
-
1542
- echo "āœ… Ultra-Dex validation passed."
1543
- exit 0
1544
- `;
1545
-
1546
- // Check if pre-commit already exists
1547
- try {
1548
- const existing = await fs.readFile(preCommitPath, 'utf-8');
1549
- if (existing.includes('ultra-dex')) {
1550
- console.log(chalk.yellow('āš ļø Ultra-Dex pre-commit hook already exists.\n'));
1551
- console.log(chalk.gray(' Use --remove to remove it first.\n'));
1552
- return;
1553
- } else {
1554
- // Append to existing hook
1555
- const combined = existing + '\n\n' + preCommitScript;
1556
- await fs.writeFile(preCommitPath, combined);
1557
- await fs.chmod(preCommitPath, '755');
1558
- console.log(chalk.green('āœ… Ultra-Dex hook appended to existing pre-commit.\n'));
1559
- }
1560
- } catch {
1561
- // No existing hook, create new
1562
- await fs.writeFile(preCommitPath, preCommitScript);
1563
- await fs.chmod(preCommitPath, '755');
1564
- console.log(chalk.green('āœ… Pre-commit hook installed.\n'));
1565
- }
1566
-
1567
- console.log(chalk.bold('What this does:\n'));
1568
- console.log(chalk.gray(' • Runs "ultra-dex validate" before each commit'));
1569
- console.log(chalk.gray(' • Blocks commits if required files are missing'));
1570
- console.log(chalk.gray(' • Warns about incomplete sections\n'));
1571
-
1572
- console.log(chalk.bold('To bypass (not recommended):\n'));
1573
- console.log(chalk.cyan(' git commit --no-verify\n'));
1574
-
1575
- console.log(chalk.bold('To remove:\n'));
1576
- console.log(chalk.cyan(' npx ultra-dex hooks --remove\n'));
1577
- });
1578
-
1579
- // ========================================
1580
- // FETCH COMMAND - Offline Mode Support
1581
- // ========================================
1582
- program
1583
- .command('fetch')
1584
- .description('Download all Ultra-Dex assets for offline use')
1585
- .option('-d, --dir <directory>', 'Target directory', '.ultra-dex')
1586
- .option('--agents', 'Fetch only agent prompts')
1587
- .option('--rules', 'Fetch only cursor rules')
1588
- .option('--docs', 'Fetch only documentation')
1589
- .action(async (options) => {
1590
- console.log(chalk.cyan('\nšŸ“¦ Ultra-Dex Asset Fetcher\n'));
1591
-
1592
- const targetDir = path.resolve(options.dir);
1593
- const fetchAll = !options.agents && !options.rules && !options.docs;
1594
-
1595
- // GitHub raw URLs
1596
- const GITHUB_RAW = 'https://raw.githubusercontent.com/Srujan0798/Ultra-Dex/main';
1597
-
1598
- // Helper to download a file
1599
- async function downloadFile(url, destPath) {
1600
- try {
1601
- const response = await fetch(url);
1602
- if (!response.ok) throw new Error(`HTTP ${response.status}`);
1603
- const content = await response.text();
1604
- await fs.mkdir(path.dirname(destPath), { recursive: true });
1605
- await fs.writeFile(destPath, content);
1606
- return true;
1607
- } catch (err) {
1608
- return false;
1609
- }
1610
- }
1611
-
1612
- const spinner = ora('Preparing to fetch assets...').start();
1613
-
1614
- // Create target directory
1615
- await fs.mkdir(targetDir, { recursive: true });
1616
-
1617
- let downloaded = 0;
1618
- let failed = 0;
1619
-
1620
- // Fetch cursor rules
1621
- if (fetchAll || options.rules) {
1622
- spinner.text = 'Fetching cursor rules...';
1623
- const rulesDir = path.join(targetDir, 'cursor-rules');
1624
- await fs.mkdir(rulesDir, { recursive: true });
1625
-
1626
- const ruleFiles = [
1627
- '00-ultra-dex-core.mdc',
1628
- '01-database.mdc',
1629
- '02-api.mdc',
1630
- '03-auth.mdc',
1631
- '04-frontend.mdc',
1632
- '05-payments.mdc',
1633
- '06-testing.mdc',
1634
- '07-security.mdc',
1635
- '08-deployment.mdc',
1636
- '09-error-handling.mdc',
1637
- '10-performance.mdc',
1638
- '11-nextjs-v15.mdc',
1639
- '12-multi-tenancy.mdc',
1640
- ];
1641
-
1642
- for (const file of ruleFiles) {
1643
- const url = `${GITHUB_RAW}/cursor-rules/${file}`;
1644
- const dest = path.join(rulesDir, file);
1645
- if (await downloadFile(url, dest)) {
1646
- downloaded++;
1647
- } else {
1648
- failed++;
1649
- }
1650
- }
1651
-
1652
- // Also fetch load.sh
1653
- await downloadFile(`${GITHUB_RAW}/cursor-rules/load.sh`, path.join(rulesDir, 'load.sh'));
1654
- try {
1655
- await fs.chmod(path.join(rulesDir, 'load.sh'), '755');
1656
- } catch {}
1657
- }
1658
-
1659
- // Fetch agent prompts
1660
- if (fetchAll || options.agents) {
1661
- spinner.text = 'Fetching agent prompts...';
1662
- const agentsDir = path.join(targetDir, 'agents');
1663
-
1664
- const agentPaths = [
1665
- '00-AGENT_INDEX.md',
1666
- 'README.md',
1667
- 'AGENT-INSTRUCTIONS.md',
1668
- '1-leadership/cto.md',
1669
- '1-leadership/planner.md',
1670
- '1-leadership/research.md',
1671
- '2-development/backend.md',
1672
- '2-development/frontend.md',
1673
- '2-development/database.md',
1674
- '3-security/security.md',
1675
- '4-devops/devops.md',
1676
- '5-quality/reviewer.md',
1677
- '5-quality/testing.md',
1678
- '5-quality/debugger.md',
1679
- '6-specialist/performance.md',
1680
- '6-specialist/refactoring.md',
1681
- '6-specialist/documentation.md',
1682
- ];
1683
-
1684
- for (const agentPath of agentPaths) {
1685
- const url = `${GITHUB_RAW}/agents/${agentPath}`;
1686
- const dest = path.join(agentsDir, agentPath);
1687
- if (await downloadFile(url, dest)) {
1688
- downloaded++;
1689
- } else {
1690
- failed++;
1691
- }
1692
- }
1693
- }
1694
-
1695
- // Fetch documentation
1696
- if (fetchAll || options.docs) {
1697
- spinner.text = 'Fetching documentation...';
1698
- const docsDir = path.join(targetDir, 'docs');
1699
-
1700
- const docFiles = [
1701
- 'VERIFICATION.md',
1702
- 'BUILD-AUTH-30M.md',
1703
- 'QUICK-REFERENCE.md',
1704
- 'TROUBLESHOOTING.md',
1705
- ];
1706
-
1707
- for (const file of docFiles) {
1708
- const url = `${GITHUB_RAW}/docs/${file}`;
1709
- const dest = path.join(docsDir, file);
1710
- if (await downloadFile(url, dest)) {
1711
- downloaded++;
1712
- } else {
1713
- failed++;
1714
- }
1715
- }
1716
-
1717
- // Fetch guides
1718
- const guidesDir = path.join(targetDir, 'guides');
1719
- const guideFiles = [
1720
- 'PROJECT-ORCHESTRATION.md',
1721
- 'ADVANCED-WORKFLOWS.md',
1722
- 'DATABASE-DECISION-FRAMEWORK.md',
1723
- 'ARCHITECTURE-PATTERNS.md',
1724
- ];
1725
-
1726
- for (const file of guideFiles) {
1727
- const url = `${GITHUB_RAW}/guides/${file}`;
1728
- const dest = path.join(guidesDir, file);
1729
- if (await downloadFile(url, dest)) {
1730
- downloaded++;
1731
- } else {
1732
- failed++;
1733
- }
1734
- }
1735
- }
1736
-
1737
- if (failed === 0) {
1738
- spinner.succeed(chalk.green(`Downloaded ${downloaded} files to ${targetDir}`));
1739
- } else {
1740
- spinner.warn(chalk.yellow(`Downloaded ${downloaded} files, ${failed} failed`));
1741
- }
1742
-
1743
- console.log(chalk.bold('\nšŸ“ Assets downloaded to:\n'));
1744
- if (fetchAll || options.rules) {
1745
- console.log(chalk.gray(` ${targetDir}/cursor-rules/ (12 .mdc files)`));
1746
- }
1747
- if (fetchAll || options.agents) {
1748
- console.log(chalk.gray(` ${targetDir}/agents/ (16 agent prompts)`));
1749
- }
1750
- if (fetchAll || options.docs) {
1751
- console.log(chalk.gray(` ${targetDir}/docs/ (documentation)`));
1752
- console.log(chalk.gray(` ${targetDir}/guides/ (guides)`));
1753
- }
1754
-
1755
- console.log(chalk.bold('\nšŸ’” Usage:\n'));
1756
- console.log(chalk.cyan(' # Copy cursor rules to project'));
1757
- console.log(chalk.gray(` cp -r ${targetDir}/cursor-rules .cursor/rules`));
1758
- console.log(chalk.cyan('\n # Copy agents to project'));
1759
- console.log(chalk.gray(` cp -r ${targetDir}/agents .agents`));
1760
- console.log(chalk.cyan('\n # Works offline now!'));
1761
- console.log(chalk.gray(' No GitHub access needed after fetch.\n'));
1762
- });
1763
-
1764
- // ========================================
1765
- // ALIGN COMMAND - Quick Alignment Score (v2.2)
1766
- // ========================================
1767
- program
1768
- .command('align')
1769
- .description('Quick alignment score - check how well code matches plan')
1770
- .option('-d, --dir <directory>', 'Directory to check', '.')
1771
- .option('--json', 'Output as JSON')
1772
- .action(async (options) => {
1773
- const checkDir = path.resolve(options.dir);
1774
-
1775
- async function readFileSafe(fp) {
1776
- try { return await fs.readFile(fp, 'utf-8'); } catch { return null; }
1777
- }
1778
- async function fileExists(fp) {
1779
- try { await fs.access(fp); return true; } catch { return false; }
1780
- }
1781
- async function countFiles(dir, ext) {
1782
- try {
1783
- const entries = await fs.readdir(dir, { withFileTypes: true, recursive: true });
1784
- return entries.filter(e => e.isFile() && e.name.endsWith(ext)).length;
1785
- } catch { return 0; }
1786
- }
1787
-
1788
- const plan = await readFileSafe(path.join(checkDir, 'IMPLEMENTATION-PLAN.md'));
1789
- if (!plan) {
1790
- if (options.json) {
1791
- console.log(JSON.stringify({ error: 'No IMPLEMENTATION-PLAN.md found', score: 0 }));
1792
- } else {
1793
- console.log(chalk.red('\nāŒ No IMPLEMENTATION-PLAN.md found'));
1794
- console.log(chalk.gray('Run `ultra-dex generate` or `ultra-dex init` first\n'));
1795
- }
1796
- return;
1797
- }
1798
-
1799
- const spinner = ora('Calculating alignment...').start();
1800
-
1801
- // Score components
1802
- let score = 0;
1803
- const checks = [];
1804
-
1805
- // 1. Core files exist (30 points)
1806
- const coreFiles = [
1807
- { file: 'IMPLEMENTATION-PLAN.md', points: 10, name: 'Implementation Plan' },
1808
- { file: 'CONTEXT.md', points: 5, name: 'Context File' },
1809
- { file: 'package.json', points: 5, name: 'Package Config' },
1810
- { file: 'README.md', points: 5, name: 'Documentation' },
1811
- { file: '.gitignore', points: 5, name: 'Git Config' },
1812
- ];
1813
- for (const cf of coreFiles) {
1814
- const exists = await fileExists(path.join(checkDir, cf.file));
1815
- if (exists) score += cf.points;
1816
- checks.push({ name: cf.name, status: exists ? 'pass' : 'fail', points: exists ? cf.points : 0 });
1817
- }
1818
-
1819
- // 2. Plan completeness - check for key sections (30 points)
1820
- const sections = [
1821
- { pattern: /## 1\.|project identity/i, name: 'Project Identity', points: 3 },
1822
- { pattern: /## 5\.|feature set|mvp/i, name: 'Feature Set', points: 5 },
1823
- { pattern: /## 8\.|tech stack/i, name: 'Tech Stack', points: 3 },
1824
- { pattern: /## 10\.|database schema/i, name: 'Database Schema', points: 5 },
1825
- { pattern: /## 11\.|api design/i, name: 'API Design', points: 5 },
1826
- { pattern: /## 12\.|authentication/i, name: 'Authentication', points: 4 },
1827
- { pattern: /## 19\.|testing/i, name: 'Testing Strategy', points: 5 },
1828
- ];
1829
- for (const sec of sections) {
1830
- const found = sec.pattern.test(plan);
1831
- if (found) score += sec.points;
1832
- checks.push({ name: sec.name, status: found ? 'pass' : 'missing', points: found ? sec.points : 0 });
1833
- }
1834
-
1835
- // 3. Code structure (20 points)
1836
- const codeStructure = [
1837
- { path: 'src', points: 5, name: 'Source Directory' },
1838
- { path: 'tests', points: 5, name: 'Tests Directory' },
1839
- { path: 'prisma/schema.prisma', points: 5, name: 'Database Schema' },
1840
- { path: '.env.example', points: 5, name: 'Environment Template' },
1841
- ];
1842
- for (const cs of codeStructure) {
1843
- const exists = await fileExists(path.join(checkDir, cs.path));
1844
- if (exists) score += cs.points;
1845
- checks.push({ name: cs.name, status: exists ? 'pass' : 'missing', points: exists ? cs.points : 0 });
1846
- }
1847
-
1848
- // 4. Code presence (20 points)
1849
- const jsFiles = await countFiles(checkDir, '.js') + await countFiles(checkDir, '.ts');
1850
- const testFiles = await countFiles(path.join(checkDir, 'tests'), '.js') +
1851
- await countFiles(path.join(checkDir, 'tests'), '.ts') +
1852
- await countFiles(path.join(checkDir, '__tests__'), '.js');
1853
-
1854
- if (jsFiles > 0) { score += 10; checks.push({ name: 'Source Code', status: 'pass', points: 10 }); }
1855
- else { checks.push({ name: 'Source Code', status: 'missing', points: 0 }); }
1856
-
1857
- if (testFiles > 0) { score += 10; checks.push({ name: 'Test Files', status: 'pass', points: 10 }); }
1858
- else { checks.push({ name: 'Test Files', status: 'missing', points: 0 }); }
1859
-
1860
- spinner.succeed('Alignment calculated');
1861
-
1862
- // Determine grade
1863
- let grade, color;
1864
- if (score >= 90) { grade = 'A'; color = chalk.green; }
1865
- else if (score >= 80) { grade = 'B'; color = chalk.green; }
1866
- else if (score >= 70) { grade = 'C'; color = chalk.yellow; }
1867
- else if (score >= 60) { grade = 'D'; color = chalk.yellow; }
1868
- else { grade = 'F'; color = chalk.red; }
1869
-
1870
- if (options.json) {
1871
- console.log(JSON.stringify({ score, grade, checks }, null, 2));
1872
- return;
1873
- }
1874
-
1875
- console.log(chalk.cyan('\n╔═════════════════════════════════════╗'));
1876
- console.log(chalk.cyan('ā•‘') + chalk.bold(' Ultra-Dex Alignment Score ') + chalk.cyan('ā•‘'));
1877
- console.log(chalk.cyan('ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•\n'));
1878
-
1879
- console.log(color.bold(` Score: ${score}/100 (${grade})\n`));
1880
-
1881
- // Group by status
1882
- const passed = checks.filter(c => c.status === 'pass');
1883
- const failed = checks.filter(c => c.status !== 'pass');
1884
-
1885
- if (passed.length > 0) {
1886
- console.log(chalk.green(' āœ… Implemented:'));
1887
- passed.forEach(c => console.log(chalk.gray(` • ${c.name} (+${c.points})`)));
1888
- }
1889
-
1890
- if (failed.length > 0) {
1891
- console.log(chalk.yellow('\n āš ļø Missing:'));
1892
- failed.forEach(c => console.log(chalk.gray(` • ${c.name}`)));
1893
- }
1894
-
1895
- console.log(chalk.gray('\n ─────────────────────────────────'));
1896
- console.log(chalk.cyan(' šŸ’” Run `ultra-dex review` for detailed analysis'));
1897
- console.log(chalk.cyan(' šŸ’” Run `ultra-dex build` to continue development\n'));
1898
- });
1899
-
1900
- // ========================================
1901
- // WATCH COMMAND - Live Context Sync
1902
- // ========================================
1903
- program
1904
- .command('watch')
1905
- .description('Watch for file changes and keep context up to date')
1906
- .option('-d, --dir <directory>', 'Directory to watch', '.')
1907
- .option('--serve', 'Also start the MCP server')
1908
- .option('-p, --port <port>', 'Port for MCP server', '3001')
1909
- .action(async (options) => {
1910
- console.log(chalk.cyan('\nšŸ‘ļø Ultra-Dex Watch Mode\n'));
1911
-
1912
- const watchDir = path.resolve(options.dir);
1913
-
1914
- async function readFileSafe(fp) {
1915
- try { return await fs.readFile(fp, 'utf-8'); } catch { return null; }
1916
- }
1917
-
1918
- async function getStats() {
1919
- const plan = await readFileSafe(path.join(watchDir, 'IMPLEMENTATION-PLAN.md'));
1920
- const context = await readFileSafe(path.join(watchDir, 'CONTEXT.md'));
1921
-
1922
- let stats = {
1923
- hasPlan: !!plan,
1924
- hasContext: !!context,
1925
- planSections: 0,
1926
- lastUpdate: new Date().toISOString(),
1927
- };
1928
-
1929
- if (plan) {
1930
- const matches = plan.match(/## (SECTION|Section) \d+/gi);
1931
- stats.planSections = matches ? matches.length : 0;
1932
- }
1933
-
1934
- return stats;
1935
- }
1936
-
1937
- // Initial state
1938
- let lastStats = await getStats();
1939
- console.log(chalk.green('āœ“ Watching for changes...'));
1940
- console.log(chalk.gray(` Directory: ${watchDir}`));
1941
- console.log(chalk.gray(` Plan sections: ${lastStats.planSections}`));
1942
- console.log(chalk.gray(` Press Ctrl+C to stop\n`));
1943
-
1944
- // Track changes
1945
- let debounceTimer = null;
1946
-
1947
- fsWatch(watchDir, { recursive: true }, async (eventType, filename) => {
1948
- // Ignore certain files
1949
- if (!filename ||
1950
- filename.includes('node_modules') ||
1951
- filename.includes('.git') ||
1952
- filename.startsWith('.')) {
1953
- return;
1954
- }
1955
-
1956
- // Debounce
1957
- if (debounceTimer) clearTimeout(debounceTimer);
1958
- debounceTimer = setTimeout(async () => {
1959
- const newStats = await getStats();
1960
-
1961
- // Check what changed
1962
- const changes = [];
1963
- if (newStats.hasPlan !== lastStats.hasPlan) {
1964
- changes.push(newStats.hasPlan ? 'šŸ“„ Plan created' : 'āŒ Plan removed');
1965
- }
1966
- if (newStats.planSections !== lastStats.planSections) {
1967
- const diff = newStats.planSections - lastStats.planSections;
1968
- changes.push(`šŸ“Š Sections: ${lastStats.planSections} → ${newStats.planSections} (${diff > 0 ? '+' : ''}${diff})`);
1969
- }
1970
-
1971
- if (changes.length > 0 || filename.endsWith('.md')) {
1972
- const time = new Date().toLocaleTimeString();
1973
- console.log(chalk.cyan(`[${time}]`) + chalk.gray(` ${filename}`));
1974
- changes.forEach(c => console.log(chalk.yellow(` ${c}`)));
1975
- }
1976
-
1977
- lastStats = newStats;
1978
- }, 500);
1979
- });
1980
-
1981
- // Keep process alive
1982
- process.on('SIGINT', () => {
1983
- console.log(chalk.yellow('\n\nšŸ‘‹ Watch mode stopped.\n'));
1984
- process.exit(0);
1985
- });
1986
-
1987
- // If --serve flag, also start MCP server
1988
- if (options.serve) {
1989
- const port = Number.parseInt(options.port, 10);
1990
- console.log(chalk.green(`\n🌐 Also starting MCP server on port ${port}...`));
1991
- console.log(chalk.gray(` Access context at: http://localhost:${port}/context\n`));
1992
-
1993
- const server = http.createServer(async (req, res) => {
1994
- res.setHeader('Access-Control-Allow-Origin', '*');
1995
-
1996
- if (req.url === '/') {
1997
- res.writeHead(200, { 'Content-Type': 'application/json' });
1998
- res.end(JSON.stringify({ status: 'ok', mode: 'watch', stats: await getStats() }));
1999
- return;
2000
- }
2001
-
2002
- if (req.url === '/context') {
2003
- const [context, plan, quickStart] = await Promise.all([
2004
- readFileSafe(path.join(watchDir, 'CONTEXT.md')),
2005
- readFileSafe(path.join(watchDir, 'IMPLEMENTATION-PLAN.md')),
2006
- readFileSafe(path.join(watchDir, 'QUICK-START.md')),
2007
- ]);
2008
- res.writeHead(200, { 'Content-Type': 'application/json' });
2009
- res.end(JSON.stringify({
2010
- meta: { timestamp: new Date().toISOString(), mode: 'watch' },
2011
- files: [
2012
- { label: 'CONTEXT.md', content: context || '' },
2013
- { label: 'IMPLEMENTATION-PLAN.md', content: plan || '' },
2014
- { label: 'QUICK-START.md', content: quickStart || '' },
2015
- ],
2016
- }));
2017
- return;
2018
- }
2019
-
2020
- res.writeHead(404);
2021
- res.end(JSON.stringify({ error: 'Not found' }));
2022
- });
2023
-
2024
- server.listen(port);
2025
- }
2026
-
2027
- // Keep process running
2028
- await new Promise(() => {});
2029
- });
2030
-
2031
- // ========================================
2032
- // STATE COMMAND - Machine-Readable State
2033
- // ========================================
2034
- program
2035
- .command('state')
2036
- .description('Output machine-readable project state (.ultra/state.json)')
2037
- .option('-d, --dir <directory>', 'Project directory', '.')
2038
- .option('--update', 'Update .ultra/state.json')
2039
- .option('--json', 'Output state to stdout')
2040
- .action(async (options) => {
2041
- const projectDir = path.resolve(options.dir);
2042
- const ultraDir = path.join(projectDir, '.ultra');
2043
- const statePath = path.join(ultraDir, 'state.json');
2044
-
2045
- async function readFileSafe(fp) {
2046
- try { return await fs.readFile(fp, 'utf-8'); } catch { return null; }
2047
- }
2048
- async function fileExists(fp) {
2049
- try { await fs.access(fp); return true; } catch { return false; }
2050
- }
2051
-
2052
- // Gather state
2053
- const plan = await readFileSafe(path.join(projectDir, 'IMPLEMENTATION-PLAN.md'));
2054
- const context = await readFileSafe(path.join(projectDir, 'CONTEXT.md'));
2055
- const pkg = await readFileSafe(path.join(projectDir, 'package.json'));
2056
-
2057
- // Parse plan sections
2058
- let sections = [];
2059
- if (plan) {
2060
- const sectionMatches = plan.matchAll(/## (SECTION \d+|Section \d+)[:\s]*([^\n]*)/gi);
2061
- for (const match of sectionMatches) {
2062
- sections.push({ number: match[1], title: match[2].trim() });
2063
- }
2064
- }
2065
-
2066
- // Parse package.json
2067
- let projectInfo = { name: 'unknown', version: '0.0.0' };
2068
- if (pkg) {
2069
- try {
2070
- const parsed = JSON.parse(pkg);
2071
- projectInfo = { name: parsed.name, version: parsed.version };
2072
- } catch {}
2073
- }
2074
-
2075
- const state = {
2076
- version: '2.1.0',
2077
- timestamp: new Date().toISOString(),
2078
- project: projectInfo,
2079
- files: {
2080
- plan: { exists: !!plan, sections: sections.length },
2081
- context: { exists: !!context },
2082
- package: { exists: !!pkg },
2083
- tests: { exists: await fileExists(path.join(projectDir, 'tests')) },
2084
- prisma: { exists: await fileExists(path.join(projectDir, 'prisma/schema.prisma')) },
2085
- },
2086
- sections,
2087
- score: {
2088
- total: sections.length,
2089
- target: 34,
2090
- percentage: Math.round((sections.length / 34) * 100),
2091
- },
2092
- };
2093
-
2094
- if (options.json) {
2095
- console.log(JSON.stringify(state, null, 2));
2096
- return;
2097
- }
2098
-
2099
- if (options.update) {
2100
- await fs.mkdir(ultraDir, { recursive: true });
2101
- await fs.writeFile(statePath, JSON.stringify(state, null, 2));
2102
- console.log(chalk.green(`\nāœ… Updated ${statePath}`));
2103
- console.log(chalk.gray(` Sections: ${state.sections.length}/34`));
2104
- console.log(chalk.gray(` Score: ${state.score.percentage}%\n`));
2105
- return;
2106
- }
2107
-
2108
- // Display state
2109
- console.log(chalk.cyan('\nšŸ“Š Ultra-Dex Project State\n'));
2110
- console.log(chalk.white(` Project: ${state.project.name} v${state.project.version}`));
2111
- console.log(chalk.white(` Sections: ${state.sections.length}/34 (${state.score.percentage}%)`));
2112
-
2113
- console.log(chalk.white('\n Files:'));
2114
- for (const [name, info] of Object.entries(state.files)) {
2115
- const icon = info.exists ? chalk.green('āœ…') : chalk.red('āŒ');
2116
- console.log(` ${icon} ${name}`);
2117
- }
2118
-
2119
- if (state.sections.length > 0) {
2120
- console.log(chalk.white('\n Completed Sections:'));
2121
- state.sections.slice(0, 5).forEach(s => {
2122
- console.log(chalk.gray(` • ${s.number}: ${s.title}`));
2123
- });
2124
- if (state.sections.length > 5) {
2125
- console.log(chalk.gray(` ... and ${state.sections.length - 5} more`));
2126
- }
2127
- }
2128
-
2129
- console.log(chalk.cyan('\n šŸ’” Run with --update to save to .ultra/state.json'));
2130
- console.log(chalk.cyan(' šŸ’” Run with --json for machine output\n'));
2131
- });
2132
-
2133
- program.parse();
130
+ program.parse();