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
@@ -10,6 +10,9 @@ 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, generateUserPrompt } from '../templates/prompts/generate-plan.js';
13
+ import { validateSafePath } from '../utils/validation.js';
14
+ import { githubTreeUrl, githubWebUrl } from '../config/urls.js';
15
+ import { saveState } from './plan.js';
13
16
 
14
17
  export function registerGenerateCommand(program) {
15
18
  program
@@ -24,6 +27,12 @@ export function registerGenerateCommand(program) {
24
27
  .action(async (idea, options) => {
25
28
  console.log(chalk.cyan('\nšŸš€ Ultra-Dex Plan Generator\n'));
26
29
 
30
+ const dirValidation = validateSafePath(options.output, 'Output directory');
31
+ if (dirValidation !== true) {
32
+ console.log(chalk.red(dirValidation));
33
+ process.exit(1);
34
+ }
35
+
27
36
  // Check configured providers
28
37
  const configured = checkConfiguredProviders();
29
38
  const hasProvider = configured.some(p => p.configured) || options.key;
@@ -119,99 +128,114 @@ export function registerGenerateCommand(program) {
119
128
  // Add header to plan
120
129
  const header = `# Implementation Plan
121
130
 
122
- > Generated by Ultra-Dex on ${new Date().toISOString().split('T')[0]}
123
- > Idea: "${idea}"
124
-
125
- ---
131
+ > Generated by Ultra-Dex AI Plan Generator
126
132
 
127
133
  `;
128
- await fs.writeFile(planPath, header + planContent);
134
+ if (!planContent.startsWith('#')) {
135
+ planContent = header + planContent;
136
+ }
137
+
138
+ await fs.writeFile(planPath, planContent);
139
+
140
+ // --- NEW: Generate state.json (ACTIVE SCALFOLDING) ---
141
+ const projectName = idea.split(' ').slice(0, 3).join('-').toLowerCase().replace(/[^a-z0-9-]/g, '');
142
+
143
+ const state = {
144
+ project: {
145
+ name: projectName,
146
+ version: '0.1.0',
147
+ mode: 'AI-First',
148
+ idea: idea
149
+ },
150
+ phases: [
151
+ {
152
+ id: '1',
153
+ name: 'Phase 1: Foundation',
154
+ status: 'in_progress',
155
+ steps: [
156
+ { id: '1.1', task: 'Setup project boilerplate', status: 'pending' },
157
+ { id: '1.2', task: 'Database schema design', status: 'pending' },
158
+ { id: '1.3', task: 'Authentication implementation', status: 'pending' }
159
+ ]
160
+ },
161
+ {
162
+ id: '2',
163
+ name: 'Phase 2: Core Features',
164
+ status: 'pending',
165
+ steps: [
166
+ { id: '2.1', task: 'Implement primary feature loop', status: 'pending' },
167
+ { id: '2.2', task: 'API endpoint development', status: 'pending' }
168
+ ]
169
+ }
170
+ ],
171
+ agents: {
172
+ active: ['planner', 'cto'],
173
+ registry: ['planner', 'cto', 'backend', 'frontend', 'database', 'testing', 'reviewer']
174
+ }
175
+ };
176
+
177
+ await saveState(state);
129
178
 
130
179
  // Generate CONTEXT.md
131
180
  const contextContent = `# Project Context
132
181
 
133
- ## Overview
182
+ ## Project Info
183
+ **Created:** ${new Date().toLocaleDateString()}
184
+ **Idea:** ${idea}
185
+ **Status:** Planning
186
+
187
+ ## Summary
134
188
  ${idea}
135
189
 
136
- ## Generated
137
- - Date: ${new Date().toISOString().split('T')[0]}
138
- - Provider: ${provider.getName()}
139
- - Model: ${provider.model}
140
-
141
- ## Files
142
- - IMPLEMENTATION-PLAN.md - Full 34-section plan
143
- - QUICK-START.md - Quick reference
144
- - CONTEXT.md - This file
145
-
146
- ## Usage
147
- Provide this context to any AI agent:
148
- \`\`\`
149
- Act as @Backend. Read CONTEXT.md and IMPLEMENTATION-PLAN.md first.
150
- Task: [your task]
151
- \`\`\`
190
+ ## Current Focus
191
+ Review implementation plan and begin development.
192
+
193
+ ## Ultra-Dex Resources
194
+ - Official Template: ${githubWebUrl()}
195
+ - Documentation: ${githubTreeUrl('docs')}
152
196
  `;
197
+
153
198
  await fs.writeFile(contextPath, contextContent);
154
199
 
155
200
  // Generate QUICK-START.md
156
201
  const quickStartContent = `# Quick Start
157
202
 
158
- ## Your Idea
203
+ ## Project Idea
159
204
  ${idea}
160
205
 
161
206
  ## Next Steps
162
-
163
- 1. **Review the plan**: Open IMPLEMENTATION-PLAN.md
164
- 2. **Load into AI**: Copy CONTEXT.md to your AI tool
165
- 3. **Start building**: Use \`npx ultra-dex build\` or paste prompts
166
-
167
- ## Useful Commands
168
-
169
- \`\`\`bash
170
- npx ultra-dex build # Start AI-assisted build
171
- npx ultra-dex review # Check code against plan
172
- npx ultra-dex serve # Serve context via HTTP
173
- npx ultra-dex agents # List available agents
174
- \`\`\`
175
-
176
- ## Agent Quick Start
177
-
178
- \`\`\`
179
- @Planner - Break down tasks
180
- @Backend - API endpoints
181
- @Frontend - UI components
182
- @Database - Schema design
183
- @Auth - Authentication
184
- @Testing - Write tests
185
- \`\`\`
207
+ 1. Review IMPLEMENTATION-PLAN.md
208
+ 2. Start with the first feature
209
+ 3. Use Ultra-Dex agents for guidance
210
+
211
+ ## AI Agents
212
+ - @Planner: Break down tasks
213
+ - @CTO: Architecture decisions
214
+ - @Backend: API logic
215
+ - @Frontend: UI components
216
+ - @Testing: QA and tests
186
217
  `;
187
- await fs.writeFile(quickStartPath, quickStartContent);
188
-
189
- // Print summary
190
- console.log(chalk.green('\nāœ… Plan generated successfully!\n'));
191
- console.log(chalk.white('Files created:'));
192
- console.log(chalk.gray(` šŸ“„ ${planPath}`));
193
- console.log(chalk.gray(` šŸ“„ ${contextPath}`));
194
- console.log(chalk.gray(` šŸ“„ ${quickStartPath}`));
195
-
196
- console.log(chalk.white('\nStats:'));
197
- console.log(chalk.gray(` ā±ļø Time: ${elapsed}s`));
198
- console.log(chalk.gray(` šŸ“Š Tokens: ${result.usage.inputTokens} in / ${result.usage.outputTokens} out`));
199
- console.log(chalk.gray(` šŸ’° Cost: ~$${cost.total.toFixed(4)}`));
200
218
 
201
- console.log(chalk.cyan('\nšŸ“‹ Next steps:'));
202
- console.log(chalk.white(' 1. Review IMPLEMENTATION-PLAN.md'));
203
- console.log(chalk.white(' 2. Run: npx ultra-dex build'));
204
- console.log(chalk.white(' 3. Start coding with AI agents\n'));
219
+ await fs.writeFile(quickStartPath, quickStartContent);
205
220
 
221
+ spinner.succeed('Plan generated successfully!');
222
+
223
+ console.log(chalk.green('\nāœ… Files created:'));
224
+ console.log(chalk.gray(` ${planPath}`));
225
+ console.log(chalk.gray(` ${contextPath}`));
226
+ console.log(chalk.gray(` ${quickStartPath}`));
227
+ console.log(chalk.gray(` .ultra/state.json (GOD MODE ACTIVE)`));
228
+ console.log(chalk.gray(`\nā±ļø Time: ${elapsed}s`));
229
+ console.log(chalk.gray(`šŸ’° Est. cost: ${cost}`));
230
+
231
+ console.log(chalk.bold('\nNext steps:'));
232
+ console.log(chalk.cyan(' 1. Review IMPLEMENTATION-PLAN.md'));
233
+ console.log(chalk.cyan(' 2. Run `ultra-dex dashboard` to visualize your progress'));
234
+ console.log(chalk.cyan(' 3. Run `ultra-dex build` to let Auto-Pilot take the first task'));
235
+ console.log(chalk.cyan(' 4. Use AI agents for specialized guidance\n'));
206
236
  } catch (err) {
207
- spinner.fail('Generation failed');
208
- console.log(chalk.red(`\nError: ${err.message}`));
209
-
210
- if (err.message.includes('API')) {
211
- console.log(chalk.yellow('\nTip: Check your API key and try again.'));
212
- }
237
+ spinner.fail('Failed to generate plan');
238
+ console.error(chalk.red('Error:'), err.message);
213
239
  }
214
240
  });
215
241
  }
216
-
217
- export default { registerGenerateCommand };
@@ -1,105 +1,280 @@
1
1
  import chalk from 'chalk';
2
2
  import fs from 'fs/promises';
3
3
  import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
4
8
 
5
9
  export function registerHooksCommand(program) {
6
- program
10
+ const hooks = program
7
11
  .command('hooks')
8
- .description('Set up git hooks for automated verification')
9
- .option('--remove', 'Remove Ultra-Dex git hooks')
12
+ .description('Manage Ultra-Dex git hooks for automated verification');
13
+
14
+ // Install subcommand
15
+ hooks
16
+ .command('install')
17
+ .description('Install Ultra-Dex pre-commit hook to .git/hooks/')
18
+ .option('--force', 'Overwrite existing hooks')
19
+ .option('--min-score <score>', 'Minimum alignment score (default: 70)', '70')
10
20
  .action(async (options) => {
11
- console.log(chalk.cyan('\nšŸŖ Ultra-Dex Git Hooks Setup\n'));
21
+ console.log(chalk.cyan('\nšŸŖ Ultra-Dex Git Hooks Installation\n'));
22
+ await installHook(options);
23
+ });
12
24
 
13
- const gitDir = path.join(process.cwd(), '.git');
14
- const hooksDir = path.join(gitDir, 'hooks');
25
+ // Remove subcommand
26
+ hooks
27
+ .command('remove')
28
+ .alias('uninstall')
29
+ .description('Remove Ultra-Dex git hooks')
30
+ .action(async () => {
31
+ console.log(chalk.cyan('\nšŸŖ Ultra-Dex Git Hooks Removal\n'));
32
+ await removeHook();
33
+ });
15
34
 
16
- try {
17
- await fs.access(gitDir);
18
- } catch {
19
- console.log(chalk.red('āŒ Not a git repository. Run "git init" first.\n'));
20
- process.exit(1);
35
+ // Status subcommand
36
+ hooks
37
+ .command('status')
38
+ .description('Check if Ultra-Dex hooks are installed')
39
+ .action(async () => {
40
+ console.log(chalk.cyan('\nšŸŖ Ultra-Dex Git Hooks Status\n'));
41
+ await checkHookStatus();
42
+ });
43
+
44
+ // Default action (legacy support)
45
+ hooks
46
+ .option('--remove', 'Remove Ultra-Dex git hooks (deprecated: use "hooks remove")')
47
+ .action(async (options) => {
48
+ if (options.remove) {
49
+ console.log(chalk.cyan('\nšŸŖ Ultra-Dex Git Hooks Removal\n'));
50
+ await removeHook();
51
+ } else {
52
+ // Show help if no subcommand
53
+ hooks.outputHelp();
21
54
  }
55
+ });
56
+ }
22
57
 
23
- await fs.mkdir(hooksDir, { recursive: true });
58
+ async function getGitHooksDir() {
59
+ const gitDir = path.join(process.cwd(), '.git');
60
+ const hooksDir = path.join(gitDir, 'hooks');
24
61
 
25
- const preCommitPath = path.join(hooksDir, 'pre-commit');
62
+ try {
63
+ await fs.access(gitDir);
64
+ } catch {
65
+ console.log(chalk.red('āŒ Not a git repository. Run "git init" first.\n'));
66
+ process.exit(1);
67
+ }
26
68
 
27
- if (options.remove) {
28
- try {
29
- const content = await fs.readFile(preCommitPath, 'utf-8');
30
- if (content.includes('ultra-dex')) {
31
- await fs.unlink(preCommitPath);
32
- console.log(chalk.green('āœ… Ultra-Dex pre-commit hook removed.\n'));
33
- } else {
34
- console.log(chalk.yellow('āš ļø Pre-commit hook exists but is not from Ultra-Dex.\n'));
35
- }
36
- } catch {
37
- console.log(chalk.gray('No Ultra-Dex hooks found.\n'));
38
- }
69
+ await fs.mkdir(hooksDir, { recursive: true });
70
+ return hooksDir;
71
+ }
72
+
73
+ async function getPreCommitHookPath() {
74
+ // Try to find the bundled hook first
75
+ const possiblePaths = [
76
+ path.join(__dirname, '..', '..', 'assets', 'hooks', 'pre-commit'),
77
+ path.join(__dirname, '..', '..', '..', 'assets', 'hooks', 'pre-commit'),
78
+ ];
79
+
80
+ for (const hookPath of possiblePaths) {
81
+ try {
82
+ await fs.access(hookPath);
83
+ return hookPath;
84
+ } catch {
85
+ // Continue to next path
86
+ }
87
+ }
88
+
89
+ return null;
90
+ }
91
+
92
+ async function installHook(options) {
93
+ const hooksDir = await getGitHooksDir();
94
+ const preCommitPath = path.join(hooksDir, 'pre-commit');
95
+ const minScore = parseInt(options.minScore, 10) || 70;
96
+
97
+ // Try to use bundled hook
98
+ const bundledHookPath = await getPreCommitHookPath();
99
+ let hookScript;
100
+
101
+ if (bundledHookPath) {
102
+ hookScript = await fs.readFile(bundledHookPath, 'utf-8');
103
+ // Update minimum score if specified
104
+ hookScript = hookScript.replace(/MIN_ALIGNMENT_SCORE=\d+/, `MIN_ALIGNMENT_SCORE=${minScore}`);
105
+ console.log(chalk.gray(` Using bundled hook from: ${bundledHookPath}`));
106
+ } else {
107
+ // Fallback to embedded script
108
+ hookScript = generatePreCommitScript(minScore);
109
+ console.log(chalk.gray(' Using embedded hook script'));
110
+ }
111
+
112
+ try {
113
+ const existing = await fs.readFile(preCommitPath, 'utf-8');
114
+ if (existing.includes('ultra-dex') || existing.includes('Ultra-Dex')) {
115
+ if (options.force) {
116
+ await fs.writeFile(preCommitPath, hookScript);
117
+ await fs.chmod(preCommitPath, '755');
118
+ console.log(chalk.green('āœ… Ultra-Dex pre-commit hook updated (--force).\n'));
119
+ } else {
120
+ console.log(chalk.yellow('āš ļø Ultra-Dex pre-commit hook already exists.\n'));
121
+ console.log(chalk.gray(' Use --force to overwrite, or "hooks remove" first.\n'));
39
122
  return;
40
123
  }
124
+ } else {
125
+ // Append to existing hook
126
+ const combined = existing + '\n\n' + hookScript;
127
+ await fs.writeFile(preCommitPath, combined);
128
+ await fs.chmod(preCommitPath, '755');
129
+ console.log(chalk.green('āœ… Ultra-Dex hook appended to existing pre-commit.\n'));
130
+ }
131
+ } catch {
132
+ // No existing hook, create new one
133
+ await fs.writeFile(preCommitPath, hookScript);
134
+ await fs.chmod(preCommitPath, '755');
135
+ console.log(chalk.green('āœ… Pre-commit hook installed.\n'));
136
+ }
137
+
138
+ printHookInfo(minScore);
139
+ }
41
140
 
42
- const preCommitScript = `#!/bin/sh
43
- # Ultra-Dex Pre-Commit Hook
44
- # Validates project structure before allowing commits
45
- # Remove with: npx ultra-dex hooks --remove
141
+ async function removeHook() {
142
+ const hooksDir = await getGitHooksDir();
143
+ const preCommitPath = path.join(hooksDir, 'pre-commit');
46
144
 
47
- echo "šŸ” Ultra-Dex: Validating project structure..."
145
+ try {
146
+ const content = await fs.readFile(preCommitPath, 'utf-8');
147
+ if (content.includes('ultra-dex') || content.includes('Ultra-Dex')) {
148
+ await fs.unlink(preCommitPath);
149
+ console.log(chalk.green('āœ… Ultra-Dex pre-commit hook removed.\n'));
150
+ } else {
151
+ console.log(chalk.yellow('āš ļø Pre-commit hook exists but is not from Ultra-Dex.\n'));
152
+ }
153
+ } catch {
154
+ console.log(chalk.gray('No Ultra-Dex hooks found.\n'));
155
+ }
156
+ }
48
157
 
49
- # Run validation
50
- npx ultra-dex validate --dir . > /tmp/ultra-dex-validate.log 2>&1
51
- RESULT=$?
52
-
53
- if [ $RESULT -ne 0 ]; then
54
- echo ""
55
- echo "āŒ Ultra-Dex validation failed. Commit blocked."
56
- echo ""
57
- echo "Run 'npx ultra-dex validate' to see details."
58
- echo "Fix issues or bypass with: git commit --no-verify"
59
- echo ""
60
- exit 1
158
+ async function checkHookStatus() {
159
+ const hooksDir = await getGitHooksDir();
160
+ const preCommitPath = path.join(hooksDir, 'pre-commit');
161
+
162
+ try {
163
+ const content = await fs.readFile(preCommitPath, 'utf-8');
164
+ if (content.includes('ultra-dex') || content.includes('Ultra-Dex')) {
165
+ console.log(chalk.green('āœ… Ultra-Dex pre-commit hook is installed.\n'));
166
+
167
+ // Extract min score if present
168
+ const scoreMatch = content.match(/MIN_ALIGNMENT_SCORE=(\d+)/);
169
+ if (scoreMatch) {
170
+ console.log(chalk.gray(` Minimum alignment score: ${scoreMatch[1]}%\n`));
171
+ }
172
+ } else {
173
+ console.log(chalk.yellow('āš ļø Pre-commit hook exists but is not from Ultra-Dex.\n'));
174
+ }
175
+ } catch {
176
+ console.log(chalk.gray('āŒ No pre-commit hook installed.\n'));
177
+ console.log(chalk.cyan(' Install with: npx ultra-dex hooks install\n'));
178
+ }
179
+ }
180
+
181
+ function printHookInfo(minScore) {
182
+ console.log(chalk.bold('What this does:\n'));
183
+ console.log(chalk.gray(` • Checks alignment score (minimum: ${minScore}%)`));
184
+ console.log(chalk.gray(' • Runs "ultra-dex validate" before each commit'));
185
+ console.log(chalk.gray(' • Blocks commits if validation fails'));
186
+ console.log(chalk.gray(' • Warns about missing documentation\n'));
187
+
188
+ console.log(chalk.bold('To bypass (not recommended):\n'));
189
+ console.log(chalk.cyan(' git commit --no-verify\n'));
190
+
191
+ console.log(chalk.bold('To check status:\n'));
192
+ console.log(chalk.cyan(' npx ultra-dex hooks status\n'));
193
+
194
+ console.log(chalk.bold('To remove:\n'));
195
+ console.log(chalk.cyan(' npx ultra-dex hooks remove\n'));
196
+ }
197
+
198
+ function generatePreCommitScript(minScore = 70) {
199
+ return `#!/bin/sh
200
+ # Ultra-Dex Pre-Commit Hook v3.0
201
+ # Validates project alignment and structure before allowing commits
202
+ # Install with: npx ultra-dex hooks install
203
+ # Remove with: npx ultra-dex hooks remove
204
+
205
+ set -e
206
+
207
+ echo ""
208
+ echo "šŸŽÆ Ultra-Dex: Running pre-commit validation..."
209
+ echo ""
210
+
211
+ # Configuration
212
+ MIN_ALIGNMENT_SCORE=${minScore}
213
+ VALIDATION_LOG="/tmp/ultra-dex-validate.log"
214
+ ALIGN_LOG="/tmp/ultra-dex-align.log"
215
+
216
+ # Check if ultra-dex is available
217
+ if ! command -v ultra-dex &> /dev/null && ! npx ultra-dex --version &> /dev/null 2>&1; then
218
+ echo "āš ļø Ultra-Dex not found. Skipping validation."
219
+ echo " Install with: npm install -g ultra-dex"
220
+ exit 0
61
221
  fi
62
222
 
63
- # Check for required files
64
- if [ ! -f "QUICK-START.md" ]; then
65
- echo "āš ļø Warning: QUICK-START.md not found"
223
+ # Run alignment check and capture score
224
+ echo "šŸ“Š Checking alignment score..."
225
+ npx ultra-dex align --dir . > "$ALIGN_LOG" 2>&1 || true
226
+
227
+ # Extract score from output
228
+ SCORE=$(grep -oE '[0-9]+%' "$ALIGN_LOG" | head -1 | tr -d '%' || echo "0")
229
+
230
+ if [ -z "$SCORE" ] || [ "$SCORE" = "0" ]; then
231
+ SCORE=$(grep -oE 'Score: [0-9]+' "$ALIGN_LOG" | grep -oE '[0-9]+' | head -1 || echo "85")
66
232
  fi
67
233
 
68
- if [ ! -f "IMPLEMENTATION-PLAN.md" ]; then
69
- echo "āš ļø Warning: IMPLEMENTATION-PLAN.md not found"
234
+ echo " Current alignment score: \${SCORE}%"
235
+
236
+ # Check minimum score threshold
237
+ if [ "$SCORE" -lt "$MIN_ALIGNMENT_SCORE" ]; then
238
+ echo ""
239
+ echo "āŒ COMMIT BLOCKED: Alignment score (\$SCORE%) is below minimum ($MIN_ALIGNMENT_SCORE%)"
240
+ echo ""
241
+ echo "šŸ“‹ To fix this:"
242
+ echo " 1. Run: npx ultra-dex validate"
243
+ echo " 2. Run: npx ultra-dex fix (to auto-fix issues)"
244
+ echo " 3. Review and commit again"
245
+ echo ""
246
+ echo "šŸ”“ To bypass (not recommended):"
247
+ echo " git commit --no-verify"
248
+ echo ""
249
+ exit 1
70
250
  fi
71
251
 
72
- echo "āœ… Ultra-Dex validation passed."
73
- exit 0
74
- `;
252
+ # Run validation
253
+ echo "šŸ” Running validation checks..."
254
+ npx ultra-dex validate --dir . --scan > "$VALIDATION_LOG" 2>&1
255
+ VALIDATE_RESULT=$?
75
256
 
76
- try {
77
- const existing = await fs.readFile(preCommitPath, 'utf-8');
78
- if (existing.includes('ultra-dex')) {
79
- console.log(chalk.yellow('āš ļø Ultra-Dex pre-commit hook already exists.\n'));
80
- console.log(chalk.gray(' Use --remove to remove it first.\n'));
81
- return;
82
- } else {
83
- const combined = existing + '\n\n' + preCommitScript;
84
- await fs.writeFile(preCommitPath, combined);
85
- await fs.chmod(preCommitPath, '755');
86
- console.log(chalk.green('āœ… Ultra-Dex hook appended to existing pre-commit.\n'));
87
- }
88
- } catch {
89
- await fs.writeFile(preCommitPath, preCommitScript);
90
- await fs.chmod(preCommitPath, '755');
91
- console.log(chalk.green('āœ… Pre-commit hook installed.\n'));
92
- }
257
+ if [ $VALIDATE_RESULT -ne 0 ]; then
258
+ echo ""
259
+ echo "āŒ COMMIT BLOCKED: Validation failed"
260
+ echo ""
261
+ cat "$VALIDATION_LOG"
262
+ echo ""
263
+ echo "šŸ“‹ Run 'npx ultra-dex validate' for details"
264
+ echo "šŸ”“ To bypass: git commit --no-verify"
265
+ echo ""
266
+ exit 1
267
+ fi
93
268
 
94
- console.log(chalk.bold('What this does:\n'));
95
- console.log(chalk.gray(' • Runs "ultra-dex validate" before each commit'));
96
- console.log(chalk.gray(' • Blocks commits if required files are missing'));
97
- console.log(chalk.gray(' • Warns about incomplete sections\n'));
269
+ # Success
270
+ echo ""
271
+ echo "āœ… Ultra-Dex validation passed!"
272
+ echo " Score: \${SCORE}% (minimum: $MIN_ALIGNMENT_SCORE%)"
273
+ echo ""
98
274
 
99
- console.log(chalk.bold('To bypass (not recommended):\n'));
100
- console.log(chalk.cyan(' git commit --no-verify\n'));
275
+ # Cleanup
276
+ rm -f "$VALIDATION_LOG" "$ALIGN_LOG" 2>/dev/null || true
101
277
 
102
- console.log(chalk.bold('To remove:\n'));
103
- console.log(chalk.cyan(' npx ultra-dex hooks --remove\n'));
104
- });
278
+ exit 0
279
+ `;
105
280
  }
@@ -7,9 +7,16 @@ 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';
10
+ import { ASSETS_ROOT, ROOT_FALLBACK, LIVE_TEMPLATES_ROOT } from '../config/paths.js';
11
11
  import { githubBlobUrl, githubWebUrl } from '../config/urls.js';
12
12
  import { copyWithFallback, listWithFallback, readWithFallback } from '../utils/fallback.js';
13
+ import { copyDirectory, pathExists } from '../utils/files.js';
14
+
15
+ const LIVE_STACKS = {
16
+ 'next15-prisma-clerk': 'Next.js 15 + Prisma + Clerk',
17
+ 'remix-supabase': 'Remix + Supabase',
18
+ 'sveltekit-drizzle': 'SvelteKit + Drizzle',
19
+ };
13
20
 
14
21
  export function registerInitCommand(program) {
15
22
  program
@@ -18,6 +25,8 @@ export function registerInitCommand(program) {
18
25
  .option('-n, --name <name>', 'Project name')
19
26
  .option('-d, --dir <directory>', 'Output directory', '.')
20
27
  .option('--preview', 'Preview files without creating them')
28
+ .option('--live', 'Generate a runnable scaffold')
29
+ .option('--stack <preset>', 'Preset: next15-prisma-clerk, remix-supabase, sveltekit-drizzle')
21
30
  .action(async (options) => {
22
31
  console.log(chalk.cyan(program.banner));
23
32
  console.log(chalk.bold('\nWelcome to Ultra-Dex! Let\'s plan your SaaS.\n'));
@@ -39,6 +48,49 @@ export function registerInitCommand(program) {
39
48
  process.exit(1);
40
49
  }
41
50
 
51
+ if (options.live) {
52
+ const preset = options.stack || 'next15-prisma-clerk';
53
+ if (!LIVE_STACKS[preset]) {
54
+ console.log(chalk.red(`Unknown preset: ${preset}`));
55
+ console.log(chalk.gray(`Available presets: ${Object.keys(LIVE_STACKS).join(', ')}`));
56
+ process.exit(1);
57
+ }
58
+
59
+ const outputDir = path.resolve(options.dir);
60
+ if (await pathExists(outputDir, 'dir')) {
61
+ const existing = await fs.readdir(outputDir);
62
+ if (existing.length > 0) {
63
+ console.log(chalk.red('Target directory is not empty.'));
64
+ process.exit(1);
65
+ }
66
+ }
67
+
68
+ const liveSourcePath = path.join(LIVE_TEMPLATES_ROOT, preset);
69
+ const fallbackLivePath = path.join(ROOT_FALLBACK, 'cli', 'assets', 'live-templates', preset);
70
+ let sourcePath = liveSourcePath;
71
+ try {
72
+ await fs.access(liveSourcePath);
73
+ } catch {
74
+ sourcePath = fallbackLivePath;
75
+ }
76
+
77
+ const spinner = ora(`Generating ${LIVE_STACKS[preset]} scaffold...`).start();
78
+ try {
79
+ await copyDirectory(sourcePath, outputDir);
80
+ spinner.succeed(chalk.green('Live scaffold created successfully!'));
81
+ console.log(chalk.gray(`\nPreset: ${preset}`));
82
+ console.log(chalk.gray(`Next steps:`));
83
+ console.log(chalk.cyan(` 1. cd ${outputDir}`));
84
+ console.log(chalk.cyan(' 2. npm install'));
85
+ console.log(chalk.cyan(' 3. npm run dev\n'));
86
+ } catch (error) {
87
+ spinner.fail(chalk.red('Failed to create live scaffold'));
88
+ console.error(`[init] ${error?.message ?? error}`);
89
+ process.exit(1);
90
+ }
91
+ return;
92
+ }
93
+
42
94
  const answers = await inquirer.prompt([
43
95
  {
44
96
  type: 'input',
@@ -207,12 +259,10 @@ ${answers.ideaWhat} for ${answers.ideaFor}.
207
259
  const cursorRulesPath = path.join(ASSETS_ROOT, 'cursor-rules');
208
260
  const fallbackRulesPath = path.join(ROOT_FALLBACK, 'cursor-rules');
209
261
  try {
210
- const ruleFiles = await listWithFallback(cursorRulesPath, fallbackRulesPath);
211
- const sourcePath = ruleFiles ? cursorRulesPath : fallbackRulesPath;
262
+ const { files: ruleFiles, sourcePath } = await listWithFallback(cursorRulesPath, fallbackRulesPath);
212
263
  for (const file of ruleFiles.filter(f => f.endsWith('.mdc'))) {
213
- await copyWithFallback(
264
+ await fs.copyFile(
214
265
  path.join(sourcePath, file),
215
- null,
216
266
  path.join(rulesDir, file)
217
267
  );
218
268
  }
@@ -330,7 +380,7 @@ ${answers.ideaWhat} for ${answers.ideaFor}.
330
380
  console.log(chalk.blue(` ${githubWebUrl()}`));
331
381
  } catch (error) {
332
382
  spinner.fail(chalk.red('Failed to create project'));
333
- console.error(error);
383
+ console.error(`[init] ${error?.message ?? error}`);
334
384
  process.exit(1);
335
385
  }
336
386
  });