ultra-dex 2.2.1 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +112 -151
- package/assets/agents/00-AGENT_INDEX.md +1 -1
- package/assets/code-patterns/clerk-middleware.ts +138 -0
- package/assets/code-patterns/prisma-schema.prisma +224 -0
- package/assets/code-patterns/rls-policies.sql +246 -0
- package/assets/code-patterns/server-actions.ts +191 -0
- package/assets/code-patterns/trpc-router.ts +258 -0
- package/assets/cursor-rules/13-ai-integration.mdc +155 -0
- package/assets/cursor-rules/14-server-components.mdc +81 -0
- package/assets/cursor-rules/15-server-actions.mdc +102 -0
- package/assets/cursor-rules/16-edge-middleware.mdc +105 -0
- package/assets/cursor-rules/17-streaming-ssr.mdc +138 -0
- package/assets/docs/LAUNCH-POSTS.md +1 -1
- package/assets/docs/QUICK-REFERENCE.md +9 -4
- package/assets/docs/VISION-V2.md +1 -1
- package/assets/hooks/pre-commit +98 -0
- package/assets/saas-plan/04-Imp-Template.md +1 -1
- package/bin/ultra-dex.js +132 -4
- package/lib/commands/advanced.js +471 -0
- package/lib/commands/agent-builder.js +226 -0
- package/lib/commands/agents.js +102 -42
- package/lib/commands/auto-implement.js +68 -0
- package/lib/commands/banner.js +43 -21
- package/lib/commands/build.js +78 -183
- package/lib/commands/ci-monitor.js +84 -0
- package/lib/commands/config.js +207 -0
- package/lib/commands/dashboard.js +770 -0
- package/lib/commands/diff.js +233 -0
- package/lib/commands/doctor.js +416 -0
- package/lib/commands/export.js +408 -0
- package/lib/commands/fix.js +96 -0
- package/lib/commands/generate.js +105 -78
- package/lib/commands/hooks.js +251 -76
- package/lib/commands/init.js +102 -54
- package/lib/commands/memory.js +80 -0
- package/lib/commands/plan.js +82 -0
- package/lib/commands/review.js +34 -5
- package/lib/commands/run.js +233 -0
- package/lib/commands/scaffold.js +151 -0
- package/lib/commands/serve.js +179 -146
- package/lib/commands/state.js +327 -0
- package/lib/commands/swarm.js +306 -0
- package/lib/commands/sync.js +82 -23
- package/lib/commands/team.js +275 -0
- package/lib/commands/upgrade.js +190 -0
- package/lib/commands/validate.js +34 -0
- package/lib/commands/verify.js +81 -0
- package/lib/commands/watch.js +79 -0
- package/lib/config/theme.js +47 -0
- package/lib/mcp/graph.js +92 -0
- package/lib/mcp/memory.js +95 -0
- package/lib/mcp/resources.js +152 -0
- package/lib/mcp/server.js +34 -0
- package/lib/mcp/tools.js +481 -0
- package/lib/mcp/websocket.js +117 -0
- package/lib/providers/index.js +49 -4
- package/lib/providers/ollama.js +136 -0
- package/lib/providers/router.js +63 -0
- package/lib/quality/scanner.js +128 -0
- package/lib/swarm/coordinator.js +97 -0
- package/lib/swarm/index.js +598 -0
- package/lib/swarm/protocol.js +677 -0
- package/lib/swarm/tiers.js +485 -0
- package/lib/templates/code/clerk-middleware.ts +138 -0
- package/lib/templates/code/prisma-schema.prisma +224 -0
- package/lib/templates/code/rls-policies.sql +246 -0
- package/lib/templates/code/server-actions.ts +191 -0
- package/lib/templates/code/trpc-router.ts +258 -0
- package/lib/templates/custom-agent.md +10 -0
- package/lib/themes/doomsday.js +229 -0
- package/lib/ui/index.js +5 -0
- package/lib/ui/interface.js +241 -0
- package/lib/ui/spinners.js +116 -0
- package/lib/ui/theme.js +183 -0
- package/lib/utils/agents.js +32 -0
- package/lib/utils/files.js +14 -0
- package/lib/utils/graph.js +108 -0
- package/lib/utils/help.js +64 -0
- package/lib/utils/messages.js +35 -0
- package/lib/utils/progress.js +24 -0
- package/lib/utils/prompts.js +47 -0
- package/lib/utils/spinners.js +46 -0
- package/lib/utils/status.js +31 -0
- package/lib/utils/tables.js +41 -0
- package/lib/utils/theme-state.js +9 -0
- package/lib/utils/version-display.js +32 -0
- package/package.json +31 -13
package/lib/commands/generate.js
CHANGED
|
@@ -10,11 +10,15 @@ 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';
|
|
16
|
+
import { getRandomMessage } from '../utils/messages.js';
|
|
13
17
|
|
|
14
18
|
export function registerGenerateCommand(program) {
|
|
15
19
|
program
|
|
16
20
|
.command('generate [idea]')
|
|
17
|
-
.description('
|
|
21
|
+
.description('Create the plan (Thanos style) - AI Generates Full Plan')
|
|
18
22
|
.option('-p, --provider <provider>', 'AI provider (claude, openai, gemini)')
|
|
19
23
|
.option('-m, --model <model>', 'Specific model to use')
|
|
20
24
|
.option('-o, --output <directory>', 'Output directory', '.')
|
|
@@ -22,14 +26,22 @@ export function registerGenerateCommand(program) {
|
|
|
22
26
|
.option('--stream', 'Stream output in real-time', true)
|
|
23
27
|
.option('--no-stream', 'Disable streaming')
|
|
24
28
|
.action(async (idea, options) => {
|
|
25
|
-
console.log(chalk.cyan('\n🚀 Ultra-Dex Plan Generator\n'));
|
|
29
|
+
console.log(chalk.cyan('\n🚀 Ultra-Dex Plan Generator (Reality Stone Mode)\n'));
|
|
30
|
+
console.log(chalk.hex('#7c3aed').italic(`"${getRandomMessage('start')}"`));
|
|
31
|
+
console.log('');
|
|
32
|
+
|
|
33
|
+
const dirValidation = validateSafePath(options.output, 'Output directory');
|
|
34
|
+
if (dirValidation !== true) {
|
|
35
|
+
console.log(chalk.red(dirValidation));
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
26
38
|
|
|
27
39
|
// Check configured providers
|
|
28
40
|
const configured = checkConfiguredProviders();
|
|
29
41
|
const hasProvider = configured.some(p => p.configured) || options.key;
|
|
30
42
|
|
|
31
43
|
if (!hasProvider) {
|
|
32
|
-
console.log(chalk.yellow('⚠️ No AI
|
|
44
|
+
console.log(chalk.yellow('⚠️ No Infinity Stones (AI Keys) configured.\n'));
|
|
33
45
|
console.log(chalk.white('Set one of these environment variables:'));
|
|
34
46
|
configured.forEach(p => {
|
|
35
47
|
console.log(chalk.gray(` export ${p.envKey}=your-key-here`));
|
|
@@ -45,7 +57,7 @@ export function registerGenerateCommand(program) {
|
|
|
45
57
|
{
|
|
46
58
|
type: 'input',
|
|
47
59
|
name: 'idea',
|
|
48
|
-
message: 'Describe
|
|
60
|
+
message: 'Describe the reality you wish to create:',
|
|
49
61
|
validate: input => input.trim().length > 10 || 'Please provide a more detailed description',
|
|
50
62
|
},
|
|
51
63
|
]);
|
|
@@ -76,7 +88,7 @@ export function registerGenerateCommand(program) {
|
|
|
76
88
|
}
|
|
77
89
|
|
|
78
90
|
// Generate the plan
|
|
79
|
-
const spinner = ora('
|
|
91
|
+
const spinner = ora('Reshaping reality (Generating Plan)...').start();
|
|
80
92
|
const startTime = Date.now();
|
|
81
93
|
|
|
82
94
|
try {
|
|
@@ -85,7 +97,7 @@ export function registerGenerateCommand(program) {
|
|
|
85
97
|
|
|
86
98
|
if (options.stream) {
|
|
87
99
|
spinner.stop();
|
|
88
|
-
console.log(chalk.cyan('📝
|
|
100
|
+
console.log(chalk.cyan('📝 Manifesting Reality:\n'));
|
|
89
101
|
console.log(chalk.gray('─'.repeat(60)));
|
|
90
102
|
|
|
91
103
|
result = await provider.generateStream(
|
|
@@ -119,99 +131,114 @@ export function registerGenerateCommand(program) {
|
|
|
119
131
|
// Add header to plan
|
|
120
132
|
const header = `# Implementation Plan
|
|
121
133
|
|
|
122
|
-
> Generated by Ultra-Dex
|
|
123
|
-
> Idea: "${idea}"
|
|
124
|
-
|
|
125
|
-
---
|
|
134
|
+
> Generated by Ultra-Dex AI Plan Generator (Doomsday Edition)
|
|
126
135
|
|
|
127
136
|
`;
|
|
128
|
-
|
|
137
|
+
if (!planContent.startsWith('#')) {
|
|
138
|
+
planContent = header + planContent;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
await fs.writeFile(planPath, planContent);
|
|
142
|
+
|
|
143
|
+
// --- NEW: Generate state.json (ACTIVE SCALFOLDING) ---
|
|
144
|
+
const projectName = idea.split(' ').slice(0, 3).join('-').toLowerCase().replace(/[^a-z0-9-]/g, '');
|
|
145
|
+
|
|
146
|
+
const state = {
|
|
147
|
+
project: {
|
|
148
|
+
name: projectName,
|
|
149
|
+
version: '0.1.0',
|
|
150
|
+
mode: 'AI-First',
|
|
151
|
+
idea: idea
|
|
152
|
+
},
|
|
153
|
+
phases: [
|
|
154
|
+
{
|
|
155
|
+
id: '1',
|
|
156
|
+
name: 'Phase 1: Foundation',
|
|
157
|
+
status: 'in_progress',
|
|
158
|
+
steps: [
|
|
159
|
+
{ id: '1.1', task: 'Setup project boilerplate', status: 'pending' },
|
|
160
|
+
{ id: '1.2', task: 'Database schema design', status: 'pending' },
|
|
161
|
+
{ id: '1.3', task: 'Authentication implementation', status: 'pending' }
|
|
162
|
+
]
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
id: '2',
|
|
166
|
+
name: 'Phase 2: Core Features',
|
|
167
|
+
status: 'pending',
|
|
168
|
+
steps: [
|
|
169
|
+
{ id: '2.1', task: 'Implement primary feature loop', status: 'pending' },
|
|
170
|
+
{ id: '2.2', task: 'API endpoint development', status: 'pending' }
|
|
171
|
+
]
|
|
172
|
+
}
|
|
173
|
+
],
|
|
174
|
+
agents: {
|
|
175
|
+
active: ['planner', 'cto'],
|
|
176
|
+
registry: ['planner', 'cto', 'backend', 'frontend', 'database', 'testing', 'reviewer']
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
await saveState(state);
|
|
129
181
|
|
|
130
182
|
// Generate CONTEXT.md
|
|
131
183
|
const contextContent = `# Project Context
|
|
132
184
|
|
|
133
|
-
##
|
|
185
|
+
## Project Info
|
|
186
|
+
**Created:** ${new Date().toLocaleDateString()}
|
|
187
|
+
**Idea:** ${idea}
|
|
188
|
+
**Status:** Planning
|
|
189
|
+
|
|
190
|
+
## Summary
|
|
134
191
|
${idea}
|
|
135
192
|
|
|
136
|
-
##
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
\`\`\`
|
|
193
|
+
## Current Focus
|
|
194
|
+
Review implementation plan and begin development.
|
|
195
|
+
|
|
196
|
+
## Ultra-Dex Resources
|
|
197
|
+
- Official Template: ${githubWebUrl()}
|
|
198
|
+
- Documentation: ${githubTreeUrl('docs')}
|
|
152
199
|
`;
|
|
200
|
+
|
|
153
201
|
await fs.writeFile(contextPath, contextContent);
|
|
154
202
|
|
|
155
203
|
// Generate QUICK-START.md
|
|
156
204
|
const quickStartContent = `# Quick Start
|
|
157
205
|
|
|
158
|
-
##
|
|
206
|
+
## Project Idea
|
|
159
207
|
${idea}
|
|
160
208
|
|
|
161
209
|
## Next Steps
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
\`\`\`
|
|
210
|
+
1. Review IMPLEMENTATION-PLAN.md
|
|
211
|
+
2. Start with the first feature
|
|
212
|
+
3. Use Ultra-Dex agents for guidance
|
|
213
|
+
|
|
214
|
+
## AI Agents (The Avengers)
|
|
215
|
+
- @Planner (Nick Fury): Break down tasks
|
|
216
|
+
- @CTO (Iron Man): Architecture decisions
|
|
217
|
+
- @Backend (Thor): API logic
|
|
218
|
+
- @Frontend (Spider-Man): UI components
|
|
219
|
+
- @Testing (Ant-Man): QA and tests
|
|
186
220
|
`;
|
|
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
221
|
|
|
201
|
-
|
|
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'));
|
|
222
|
+
await fs.writeFile(quickStartPath, quickStartContent);
|
|
205
223
|
|
|
224
|
+
spinner.succeed(chalk.green('Reality successfully rewritten!'));
|
|
225
|
+
|
|
226
|
+
console.log(chalk.green('\n✅ Files created:'));
|
|
227
|
+
console.log(chalk.gray(` ${planPath}`));
|
|
228
|
+
console.log(chalk.gray(` ${contextPath}`));
|
|
229
|
+
console.log(chalk.gray(` ${quickStartPath}`));
|
|
230
|
+
console.log(chalk.gray(` .ultra/state.json (GOD MODE ACTIVE)`));
|
|
231
|
+
console.log(chalk.gray(`\n⏱️ Time: ${elapsed}s`));
|
|
232
|
+
console.log(chalk.gray(`💰 Est. cost: ${cost}`));
|
|
233
|
+
|
|
234
|
+
console.log(chalk.bold('\nNext steps:'));
|
|
235
|
+
console.log(chalk.cyan(' 1. Review IMPLEMENTATION-PLAN.md'));
|
|
236
|
+
console.log(chalk.cyan(' 2. Run `ultra-dex dashboard` to visualize your progress'));
|
|
237
|
+
console.log(chalk.cyan(' 3. Run `ultra-dex build` to let Auto-Pilot take the first task'));
|
|
238
|
+
console.log(chalk.cyan(' 4. Summon Avengers (AI agents) for guidance\n'));
|
|
206
239
|
} catch (err) {
|
|
207
|
-
spinner.fail('
|
|
208
|
-
console.
|
|
209
|
-
|
|
210
|
-
if (err.message.includes('API')) {
|
|
211
|
-
console.log(chalk.yellow('\nTip: Check your API key and try again.'));
|
|
212
|
-
}
|
|
240
|
+
spinner.fail(chalk.red('Failed to manifest reality'));
|
|
241
|
+
console.error(chalk.red('Error:'), err.message);
|
|
213
242
|
}
|
|
214
243
|
});
|
|
215
244
|
}
|
|
216
|
-
|
|
217
|
-
export default { registerGenerateCommand };
|
package/lib/commands/hooks.js
CHANGED
|
@@ -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('
|
|
9
|
-
|
|
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
|
|
21
|
+
console.log(chalk.cyan('\n🪝 Ultra-Dex Git Hooks Installation\n'));
|
|
22
|
+
await installHook(options);
|
|
23
|
+
});
|
|
12
24
|
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
58
|
+
async function getGitHooksDir() {
|
|
59
|
+
const gitDir = path.join(process.cwd(), '.git');
|
|
60
|
+
const hooksDir = path.join(gitDir, 'hooks');
|
|
24
61
|
|
|
25
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
-
#
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
69
|
-
|
|
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
|
-
|
|
73
|
-
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
269
|
+
# Success
|
|
270
|
+
echo ""
|
|
271
|
+
echo "✅ Ultra-Dex validation passed!"
|
|
272
|
+
echo " Score: \${SCORE}% (minimum: $MIN_ALIGNMENT_SCORE%)"
|
|
273
|
+
echo ""
|
|
98
274
|
|
|
99
|
-
|
|
100
|
-
|
|
275
|
+
# Cleanup
|
|
276
|
+
rm -f "$VALIDATION_LOG" "$ALIGN_LOG" 2>/dev/null || true
|
|
101
277
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
});
|
|
278
|
+
exit 0
|
|
279
|
+
`;
|
|
105
280
|
}
|