ultra-dex 3.1.0 → 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 +79 -74
- 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/bin/ultra-dex.js +38 -1
- package/lib/commands/agents.js +16 -13
- package/lib/commands/banner.js +43 -21
- package/lib/commands/build.js +26 -17
- package/lib/commands/doctor.js +98 -79
- package/lib/commands/generate.js +19 -16
- package/lib/commands/init.js +52 -56
- package/lib/commands/scaffold.js +151 -0
- package/lib/commands/serve.js +15 -13
- package/lib/commands/state.js +43 -70
- package/lib/commands/swarm.js +31 -9
- package/lib/config/theme.js +47 -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/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/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 +10 -1
package/lib/commands/state.js
CHANGED
|
@@ -4,9 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import chalk from 'chalk';
|
|
7
|
-
import ora from 'ora';
|
|
8
7
|
import fs from 'fs/promises';
|
|
9
|
-
import { watch as fsWatch } from 'fs';
|
|
10
8
|
import path from 'path';
|
|
11
9
|
import { validateSafePath } from '../utils/validation.js';
|
|
12
10
|
import { buildGraph } from '../utils/graph.js';
|
|
@@ -34,19 +32,16 @@ export async function saveState(state) {
|
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
export async function computeState() {
|
|
37
|
-
// Try to load existing state first to check schema
|
|
38
35
|
const existing = await loadState();
|
|
39
|
-
if (existing && existing.project?.mode === '
|
|
40
|
-
// In God Mode, we update the timestamp
|
|
36
|
+
if (existing && existing.project?.mode === 'ULTRA_MODE') {
|
|
41
37
|
existing.updatedAt = new Date().toISOString();
|
|
42
38
|
return existing;
|
|
43
39
|
}
|
|
44
40
|
|
|
45
|
-
// Legacy computation logic
|
|
46
41
|
const state = {
|
|
47
|
-
version: '2.
|
|
42
|
+
version: '3.2.0',
|
|
48
43
|
updatedAt: new Date().toISOString(),
|
|
49
|
-
project: { name: path.basename(process.cwd()) },
|
|
44
|
+
project: { name: path.basename(process.cwd()), mode: 'ULTRA_MODE' },
|
|
50
45
|
files: {},
|
|
51
46
|
sections: { total: 34, completed: 0, list: [] },
|
|
52
47
|
score: 0
|
|
@@ -73,7 +68,7 @@ export async function computeState() {
|
|
|
73
68
|
} catch { /* no plan */ }
|
|
74
69
|
|
|
75
70
|
const fileScore = Object.values(state.files).filter(f => f.exists).length / coreFiles.length * 40;
|
|
76
|
-
const sectionScore = state.sections.completed / state.sections.total * 60;
|
|
71
|
+
const sectionScore = Math.min(state.sections.completed / state.sections.total * 60, 60);
|
|
77
72
|
state.score = Math.round(fileScore + sectionScore);
|
|
78
73
|
|
|
79
74
|
return state;
|
|
@@ -92,10 +87,8 @@ export function registerAlignCommand(program) {
|
|
|
92
87
|
.option('--strict', 'Exit with error if score < 70')
|
|
93
88
|
.option('--json', 'Output as JSON')
|
|
94
89
|
.action(async (options) => {
|
|
95
|
-
// 1. Compute Base State
|
|
96
90
|
const state = await computeState();
|
|
97
91
|
|
|
98
|
-
// 2. Compute Graph Score (God Mode)
|
|
99
92
|
let graphScore = 0;
|
|
100
93
|
let graphStats = { nodes: 0, edges: 0 };
|
|
101
94
|
|
|
@@ -103,9 +96,6 @@ export function registerAlignCommand(program) {
|
|
|
103
96
|
const graph = await buildGraph();
|
|
104
97
|
graphStats = { nodes: graph.nodes.length, edges: graph.edges.length };
|
|
105
98
|
|
|
106
|
-
// Simple heuristic: A healthy project has nodes and edges
|
|
107
|
-
// 10+ nodes = 20 points
|
|
108
|
-
// 10+ edges = 20 points
|
|
109
99
|
const nodesPoints = Math.min(graph.nodes.length * 2, 20);
|
|
110
100
|
const edgesPoints = Math.min(graph.edges.length * 2, 20);
|
|
111
101
|
graphScore = nodesPoints + edgesPoints;
|
|
@@ -113,14 +103,12 @@ export function registerAlignCommand(program) {
|
|
|
113
103
|
// Graph failed
|
|
114
104
|
}
|
|
115
105
|
|
|
116
|
-
// 3. Combine Scores
|
|
117
|
-
// Legacy score (files/plan) is 60% weight, Graph is 40%
|
|
118
106
|
const totalScore = Math.min(Math.round((state.score * 0.6) + graphScore), 100);
|
|
119
107
|
|
|
120
108
|
if (options.json) {
|
|
121
|
-
console.log(JSON.stringify({
|
|
109
|
+
console.log(JSON.stringify({
|
|
122
110
|
score: totalScore,
|
|
123
|
-
|
|
111
|
+
documentationScore: state.score,
|
|
124
112
|
graphScore,
|
|
125
113
|
graphStats,
|
|
126
114
|
files: Object.values(state.files).filter(f => f.exists).length,
|
|
@@ -129,7 +117,7 @@ export function registerAlignCommand(program) {
|
|
|
129
117
|
} else {
|
|
130
118
|
const icon = totalScore >= 80 ? '✅' : totalScore >= 50 ? '⚠️' : '❌';
|
|
131
119
|
console.log(`${icon} Alignment: ${totalScore}/100`);
|
|
132
|
-
console.log(chalk.gray(` •
|
|
120
|
+
console.log(chalk.gray(` • Documentation: ${state.score}/100`));
|
|
133
121
|
console.log(chalk.gray(` • Code Graph: ${graphScore}/40 (Nodes: ${graphStats.nodes}, Edges: ${graphStats.edges})`));
|
|
134
122
|
}
|
|
135
123
|
|
|
@@ -153,7 +141,7 @@ export function registerStatusCommand(program) {
|
|
|
153
141
|
|
|
154
142
|
let state = await loadState();
|
|
155
143
|
if (!state) {
|
|
156
|
-
console.log(chalk.yellow('\n
|
|
144
|
+
console.log(chalk.yellow('\nℹ️ Initializing project state...\n'));
|
|
157
145
|
state = await computeState();
|
|
158
146
|
await saveState(state);
|
|
159
147
|
}
|
|
@@ -166,13 +154,12 @@ export function registerStatusCommand(program) {
|
|
|
166
154
|
console.log(chalk.bold('\n📊 Ultra-Dex Status\n'));
|
|
167
155
|
console.log(chalk.gray('─'.repeat(50)));
|
|
168
156
|
|
|
169
|
-
if (state.
|
|
170
|
-
|
|
171
|
-
console.log(chalk.
|
|
172
|
-
console.log(chalk.gray(` Version: ${state.project.version}`));
|
|
157
|
+
if (state.phases) {
|
|
158
|
+
console.log(chalk.cyan(` MODE: ${state.project?.mode || 'ULTRA_MODE'}`));
|
|
159
|
+
console.log(chalk.gray(` Version: ${state.project?.version || state.version}`));
|
|
173
160
|
console.log(chalk.gray('─'.repeat(50)));
|
|
174
161
|
|
|
175
|
-
console.log(chalk.bold('\n🚀 Phases:'));
|
|
162
|
+
console.log(chalk.bold('\n🚀 Implementation Phases:'));
|
|
176
163
|
state.phases.forEach(phase => {
|
|
177
164
|
const icon = phase.status === 'completed' ? '✅' : phase.status === 'in_progress' ? '🔄' : '⏳';
|
|
178
165
|
console.log(` ${icon} ${chalk.bold(phase.name)}`);
|
|
@@ -183,31 +170,32 @@ export function registerStatusCommand(program) {
|
|
|
183
170
|
console.log('');
|
|
184
171
|
});
|
|
185
172
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
173
|
+
if (state.agents) {
|
|
174
|
+
console.log(chalk.bold('🤖 Orchestration Agents:'));
|
|
175
|
+
state.agents.registry?.forEach(agent => {
|
|
176
|
+
const active = state.agents.active?.includes(agent) ? chalk.green('(Active)') : '';
|
|
177
|
+
console.log(` • @${agent} ${active}`);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
191
180
|
|
|
192
181
|
} else {
|
|
193
|
-
// Render Legacy Status
|
|
194
182
|
const scoreColor = state.score >= 80 ? 'green' : state.score >= 50 ? 'yellow' : 'red';
|
|
195
183
|
console.log(chalk[scoreColor](` Score: ${state.score}/100`));
|
|
196
184
|
console.log(chalk.gray(` Updated: ${state.updatedAt}`));
|
|
197
185
|
console.log(chalk.gray('─'.repeat(50)));
|
|
198
186
|
|
|
199
|
-
console.log(chalk.bold('\n📁 Files:'));
|
|
187
|
+
console.log(chalk.bold('\n📁 Documentation Files:'));
|
|
200
188
|
if (state.files) {
|
|
201
189
|
Object.entries(state.files).forEach(([name, info]) => {
|
|
202
|
-
const icon = info.exists ? chalk.green('✓') : chalk.red('
|
|
190
|
+
const icon = info.exists ? chalk.green('✓') : chalk.red('✕');
|
|
203
191
|
const size = info.exists ? chalk.gray(` (${info.size} bytes)`) : '';
|
|
204
192
|
console.log(` ${icon} ${name}${size}`);
|
|
205
193
|
});
|
|
206
194
|
}
|
|
207
195
|
|
|
208
|
-
console.log(chalk.bold('\n📝 Sections:'));
|
|
209
|
-
console.log(` ${state.sections.completed}/${state.sections.total}
|
|
210
|
-
if (state.sections.list
|
|
196
|
+
console.log(chalk.bold('\n📝 Implementation Sections:'));
|
|
197
|
+
console.log(` ${state.sections.completed}/${state.sections.total} completed`);
|
|
198
|
+
if (state.sections.list?.length > 0) {
|
|
211
199
|
const recent = state.sections.list.slice(-3);
|
|
212
200
|
recent.forEach(s => console.log(chalk.gray(` ${s.number}. ${s.title}`)));
|
|
213
201
|
if (state.sections.list.length > 3) {
|
|
@@ -220,19 +208,15 @@ export function registerStatusCommand(program) {
|
|
|
220
208
|
}
|
|
221
209
|
|
|
222
210
|
export function registerWatchCommand(program) {
|
|
223
|
-
// This is now handled by watch.js, but keeping here for legacy imports if any.
|
|
224
|
-
// In God Mode, watch.js replaces this.
|
|
225
|
-
// The bin/ultra-dex.js uses watch.js, so this might be dead code or overwritten.
|
|
226
|
-
// I will leave it as is or update it to be safe.
|
|
227
211
|
program
|
|
228
|
-
.command('watch-legacy')
|
|
212
|
+
.command('watch-legacy')
|
|
229
213
|
.action(() => console.log("Use 'ultra-dex watch' instead."));
|
|
230
214
|
}
|
|
231
215
|
|
|
232
216
|
export function registerPreCommitCommand(program) {
|
|
233
217
|
program
|
|
234
218
|
.command('pre-commit')
|
|
235
|
-
.description('Pre-commit hook - verify before commit')
|
|
219
|
+
.description('Pre-commit hook - verify standards before commit')
|
|
236
220
|
.option('--install', 'Install git pre-commit hook')
|
|
237
221
|
.option('--scan', 'Include deep code quality scan in hook')
|
|
238
222
|
.option('--ai', 'Run AI-powered quality review on staged changes')
|
|
@@ -254,7 +238,7 @@ export function registerPreCommitCommand(program) {
|
|
|
254
238
|
# Ultra-Dex pre-commit hook
|
|
255
239
|
npx ultra-dex align --strict${scanCmd}${aiCmd}
|
|
256
240
|
if [ $? -ne 0 ]; then
|
|
257
|
-
echo "
|
|
241
|
+
echo "✕ Ultra-Dex quality gate failed."
|
|
258
242
|
echo " Run 'ultra-dex review' or 'ultra-dex validate --scan' for details."
|
|
259
243
|
exit 1
|
|
260
244
|
fi
|
|
@@ -262,22 +246,20 @@ fi
|
|
|
262
246
|
try {
|
|
263
247
|
await fs.mkdir(path.dirname(hookPath), { recursive: true });
|
|
264
248
|
await fs.writeFile(hookPath, hookScript, { mode: 0o755 });
|
|
265
|
-
console.log(chalk.green('
|
|
249
|
+
console.log(chalk.green('✓ Pre-commit hook installed!'));
|
|
266
250
|
console.log(chalk.gray(' Commits will be blocked if alignment score < 70 or AI review fails.'));
|
|
267
251
|
} catch (e) {
|
|
268
|
-
console.log(chalk.red('
|
|
252
|
+
console.log(chalk.red('✕ Failed to install hook: ' + e.message));
|
|
269
253
|
}
|
|
270
254
|
return;
|
|
271
255
|
}
|
|
272
256
|
|
|
273
257
|
const state = await loadState();
|
|
274
258
|
|
|
275
|
-
// AI Quality Gate (God Mode)
|
|
276
259
|
if (options.ai) {
|
|
277
|
-
const spinner = (await import('ora')).default('🤖 AI Quality
|
|
260
|
+
const spinner = (await import('ora')).default('🤖 AI Quality Review: Analyzing staged changes...').start();
|
|
278
261
|
try {
|
|
279
262
|
const { execSync } = await import('child_process');
|
|
280
|
-
// Get staged changes
|
|
281
263
|
const staged = execSync('git diff --cached --name-only', { encoding: 'utf8' }).split('\n').filter(Boolean);
|
|
282
264
|
if (staged.length === 0) {
|
|
283
265
|
spinner.succeed('No staged changes to review.');
|
|
@@ -291,28 +273,23 @@ fi
|
|
|
291
273
|
const reviewResult = await runAgentLoop('reviewer', `Review these staged files for architectural violations (e.g. missing validation, security risks):\n${staged.join('\n')}`, provider, { state });
|
|
292
274
|
|
|
293
275
|
if (reviewResult.toLowerCase().includes('reject') || reviewResult.toLowerCase().includes('blocking violation')) {
|
|
294
|
-
spinner.fail('
|
|
295
|
-
console.log(chalk.red('\
|
|
276
|
+
spinner.fail('Quality Gate: REJECTED');
|
|
277
|
+
console.log(chalk.red('\nViolations found:'));
|
|
296
278
|
console.log(reviewResult);
|
|
297
279
|
process.exit(1);
|
|
298
280
|
}
|
|
299
|
-
spinner.succeed('
|
|
281
|
+
spinner.succeed('Quality Gate: PASSED');
|
|
300
282
|
} catch (e) {
|
|
301
|
-
spinner.warn('
|
|
283
|
+
spinner.warn('Quality Gate skipped: ' + e.message);
|
|
302
284
|
}
|
|
303
285
|
}
|
|
304
286
|
|
|
305
|
-
if (state && state.project?.mode === 'GOD_MODE') {
|
|
306
|
-
console.log(chalk.green(`✅ Alignment OK: GOD MODE ACTIVE`));
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
287
|
if (state && state.score < 70) {
|
|
311
|
-
console.log(chalk.red(
|
|
288
|
+
console.log(chalk.red(`✕ BLOCKED: Alignment score ${state.score}/100 (required: 70)`));
|
|
312
289
|
console.log(chalk.yellow(' Run `ultra-dex review` for detailed analysis.'));
|
|
313
290
|
process.exit(1);
|
|
314
291
|
} else {
|
|
315
|
-
console.log(chalk.green(
|
|
292
|
+
console.log(chalk.green(`✓ Alignment verified: ${state ? state.score : 'N/A'}/100`));
|
|
316
293
|
}
|
|
317
294
|
});
|
|
318
295
|
}
|
|
@@ -320,25 +297,21 @@ fi
|
|
|
320
297
|
export function registerStateCommand(program) {
|
|
321
298
|
program
|
|
322
299
|
.command('state')
|
|
323
|
-
.description('Manage
|
|
324
|
-
.option('--init', 'Initialize
|
|
325
|
-
.option('--refresh', 'Refresh state from
|
|
300
|
+
.description('Manage project state')
|
|
301
|
+
.option('--init', 'Initialize state directory')
|
|
302
|
+
.option('--refresh', 'Refresh state from documentation')
|
|
326
303
|
.action(async (options) => {
|
|
327
304
|
if (options.init || options.refresh) {
|
|
328
305
|
const state = await computeState();
|
|
329
306
|
await saveState(state);
|
|
330
|
-
console.log(chalk.green('
|
|
331
|
-
|
|
332
|
-
console.log(chalk.gray(` Mode: GOD_MODE`));
|
|
333
|
-
} else {
|
|
334
|
-
console.log(chalk.gray(` Score: ${state.score}/100`));
|
|
335
|
-
}
|
|
307
|
+
console.log(chalk.green('✓ Project state updated'));
|
|
308
|
+
console.log(chalk.gray(` Score: ${state.score}/100`));
|
|
336
309
|
return;
|
|
337
310
|
}
|
|
338
311
|
|
|
339
312
|
const state = await loadState();
|
|
340
313
|
if (!state) {
|
|
341
|
-
console.log(chalk.yellow('No
|
|
314
|
+
console.log(chalk.yellow('No state file found. Run `ultra-dex state --init`'));
|
|
342
315
|
return;
|
|
343
316
|
}
|
|
344
317
|
console.log(JSON.stringify(state, null, 2));
|
|
@@ -351,4 +324,4 @@ export default {
|
|
|
351
324
|
registerWatchCommand,
|
|
352
325
|
registerPreCommitCommand,
|
|
353
326
|
registerStateCommand,
|
|
354
|
-
};
|
|
327
|
+
};
|
package/lib/commands/swarm.js
CHANGED
|
@@ -8,6 +8,9 @@ import { join } from 'path';
|
|
|
8
8
|
import { glob } from 'glob';
|
|
9
9
|
import { projectGraph } from '../mcp/graph.js';
|
|
10
10
|
import { updateState, loadState, saveState } from './state.js';
|
|
11
|
+
import { agents } from '../utils/agents.js';
|
|
12
|
+
import { isDoomsdayMode } from '../utils/theme-state.js';
|
|
13
|
+
import { showSwarmAssemble as showDoomsdaySwarm } from '../themes/doomsday.js';
|
|
11
14
|
|
|
12
15
|
const AGENT_PIPELINE = [
|
|
13
16
|
{ name: 'planner', description: 'Break down task into steps', tier: '1-planning' },
|
|
@@ -20,6 +23,25 @@ const AGENT_PIPELINE = [
|
|
|
20
23
|
{ name: 'reviewer', description: 'Code review', tier: '4-quality' }
|
|
21
24
|
];
|
|
22
25
|
|
|
26
|
+
export function showSwarmAssemble(activeAgents) {
|
|
27
|
+
if (isDoomsdayMode()) {
|
|
28
|
+
return showDoomsdaySwarm(activeAgents);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
console.log('');
|
|
32
|
+
console.log(chalk.hex('#8b5cf6').bold(' ⚡ AGENT PIPELINE INITIALIZED'));
|
|
33
|
+
console.log('');
|
|
34
|
+
|
|
35
|
+
activeAgents.forEach((agentInfo) => {
|
|
36
|
+
const agent = agents[agentInfo.name];
|
|
37
|
+
if (agent) {
|
|
38
|
+
console.log(` ${agent.emoji} ${chalk.hex('#6366f1').bold(agent.name)}`);
|
|
39
|
+
console.log(` ${chalk.dim('"' + agent.tagline + '"')}`);
|
|
40
|
+
console.log('');
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
23
45
|
async function runAgent(agent, task, context, previousOutput, provider) {
|
|
24
46
|
const agentPrompt = await loadAgentPrompt(agent.name);
|
|
25
47
|
const prompt = `
|
|
@@ -67,7 +89,7 @@ async function writeSwarmLog(logDir, task, results, stats) {
|
|
|
67
89
|
}
|
|
68
90
|
|
|
69
91
|
export async function swarmCommand(task, options) {
|
|
70
|
-
console.log(chalk.cyan.bold('\n🐝 Ultra-Dex Swarm Mode
|
|
92
|
+
console.log(chalk.cyan.bold('\n🐝 Ultra-Dex Swarm Mode\n'));
|
|
71
93
|
console.log(chalk.white(`Task: "${task}"\n`));
|
|
72
94
|
|
|
73
95
|
const startTime = Date.now();
|
|
@@ -78,12 +100,12 @@ export async function swarmCommand(task, options) {
|
|
|
78
100
|
console.log(` ${i + 1}. @${agent.name} - ${agent.description} [${agent.tier}]`);
|
|
79
101
|
});
|
|
80
102
|
if (options.parallel) {
|
|
81
|
-
console.log(chalk.blue('\nℹ️ Parallel execution enabled for
|
|
103
|
+
console.log(chalk.blue('\nℹ️ Parallel execution enabled for implementation tier'));
|
|
82
104
|
}
|
|
83
105
|
return;
|
|
84
106
|
}
|
|
85
107
|
|
|
86
|
-
// Load context & Graph
|
|
108
|
+
// Load context & Graph
|
|
87
109
|
const contextPath = join(process.cwd(), 'CONTEXT.md');
|
|
88
110
|
const planPath = join(process.cwd(), 'IMPLEMENTATION-PLAN.md');
|
|
89
111
|
|
|
@@ -108,7 +130,7 @@ export async function swarmCommand(task, options) {
|
|
|
108
130
|
// Get AI provider
|
|
109
131
|
const provider = getProvider();
|
|
110
132
|
if (!provider) {
|
|
111
|
-
console.log(chalk.red('No AI provider configured. Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or
|
|
133
|
+
console.log(chalk.red('No AI provider configured. Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY'));
|
|
112
134
|
return;
|
|
113
135
|
}
|
|
114
136
|
|
|
@@ -116,7 +138,7 @@ export async function swarmCommand(task, options) {
|
|
|
116
138
|
const logDir = await ensureLogDirectory();
|
|
117
139
|
|
|
118
140
|
// Update State to indicate Swarm is running
|
|
119
|
-
const state = await loadState() || { project: { mode: '
|
|
141
|
+
const state = await loadState() || { project: { mode: 'ULTRA_MODE' }, agents: { active: [] } };
|
|
120
142
|
state.agents = state.agents || { active: [] };
|
|
121
143
|
state.updatedAt = new Date().toISOString();
|
|
122
144
|
await saveState(state);
|
|
@@ -126,7 +148,7 @@ export async function swarmCommand(task, options) {
|
|
|
126
148
|
const agentResults = [];
|
|
127
149
|
const agentTimings = {};
|
|
128
150
|
|
|
129
|
-
// Define execution tiers
|
|
151
|
+
// Define execution tiers
|
|
130
152
|
const executionTiers = options.parallel
|
|
131
153
|
? [
|
|
132
154
|
{ name: '1-Planning', agents: AGENT_PIPELINE.filter(a => a.tier === '1-planning'), parallel: false },
|
|
@@ -144,7 +166,7 @@ export async function swarmCommand(task, options) {
|
|
|
144
166
|
}
|
|
145
167
|
|
|
146
168
|
if (tier.parallel) {
|
|
147
|
-
// Parallel Execution
|
|
169
|
+
// Parallel Execution
|
|
148
170
|
const tierStart = Date.now();
|
|
149
171
|
const promises = tier.agents.map(async (agent) => {
|
|
150
172
|
const agentStart = Date.now();
|
|
@@ -263,7 +285,7 @@ export async function swarmCommand(task, options) {
|
|
|
263
285
|
});
|
|
264
286
|
console.log(chalk.gray(`\n Log saved: ${logPath}`));
|
|
265
287
|
|
|
266
|
-
console.log(chalk.green.bold('\n✅ Swarm complete!\n'));
|
|
288
|
+
console.log(chalk.green.bold('\n✅ Swarm execution complete!\n'));
|
|
267
289
|
}
|
|
268
290
|
|
|
269
291
|
async function loadAgentPrompt(name) {
|
|
@@ -281,4 +303,4 @@ async function loadAgentPrompt(name) {
|
|
|
281
303
|
}
|
|
282
304
|
|
|
283
305
|
return `You are the @${name} agent.`;
|
|
284
|
-
}
|
|
306
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
|
|
3
|
+
export const themes = {
|
|
4
|
+
default: {
|
|
5
|
+
primary: '#6366f1',
|
|
6
|
+
secondary: '#8b5cf6',
|
|
7
|
+
accent: '#d946ef',
|
|
8
|
+
success: '#22c55e',
|
|
9
|
+
warning: '#eab308',
|
|
10
|
+
error: '#ef4444',
|
|
11
|
+
dim: '#6b7280'
|
|
12
|
+
},
|
|
13
|
+
ocean: {
|
|
14
|
+
primary: '#0ea5e9',
|
|
15
|
+
secondary: '#06b6d4',
|
|
16
|
+
accent: '#14b8a6',
|
|
17
|
+
success: '#22c55e',
|
|
18
|
+
warning: '#f59e0b',
|
|
19
|
+
error: '#f43f5e',
|
|
20
|
+
dim: '#64748b'
|
|
21
|
+
},
|
|
22
|
+
forest: {
|
|
23
|
+
primary: '#22c55e',
|
|
24
|
+
secondary: '#10b981',
|
|
25
|
+
accent: '#14b8a6',
|
|
26
|
+
success: '#22c55e',
|
|
27
|
+
warning: '#eab308',
|
|
28
|
+
error: '#ef4444',
|
|
29
|
+
dim: '#6b7280'
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
let currentTheme = themes.default;
|
|
34
|
+
|
|
35
|
+
export function getTheme() {
|
|
36
|
+
return currentTheme;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function setTheme(name) {
|
|
40
|
+
if (themes[name]) {
|
|
41
|
+
currentTheme = themes[name];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function styled(type, text) {
|
|
46
|
+
return chalk.hex(currentTheme[type])(text);
|
|
47
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// Ultra-Dex Production Pattern: Clerk Middleware
|
|
2
|
+
// Copy to middleware.ts in your Next.js root
|
|
3
|
+
|
|
4
|
+
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
|
|
5
|
+
import { NextResponse } from 'next/server';
|
|
6
|
+
|
|
7
|
+
// =============================================================================
|
|
8
|
+
// ROUTE MATCHERS
|
|
9
|
+
// =============================================================================
|
|
10
|
+
|
|
11
|
+
// Public routes - accessible without authentication
|
|
12
|
+
const isPublicRoute = createRouteMatcher([
|
|
13
|
+
'/',
|
|
14
|
+
'/sign-in(.*)',
|
|
15
|
+
'/sign-up(.*)',
|
|
16
|
+
'/api/webhooks(.*)',
|
|
17
|
+
'/pricing',
|
|
18
|
+
'/about',
|
|
19
|
+
'/blog(.*)',
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
// Admin routes - require admin role
|
|
23
|
+
const isAdminRoute = createRouteMatcher([
|
|
24
|
+
'/admin(.*)',
|
|
25
|
+
'/api/admin(.*)',
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
// API routes that need special handling
|
|
29
|
+
const isApiRoute = createRouteMatcher(['/api(.*)']);
|
|
30
|
+
|
|
31
|
+
// =============================================================================
|
|
32
|
+
// MIDDLEWARE
|
|
33
|
+
// =============================================================================
|
|
34
|
+
|
|
35
|
+
export default clerkMiddleware(async (auth, req) => {
|
|
36
|
+
const { userId, sessionClaims } = await auth();
|
|
37
|
+
|
|
38
|
+
// Allow public routes
|
|
39
|
+
if (isPublicRoute(req)) {
|
|
40
|
+
return NextResponse.next();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Protect all non-public routes
|
|
44
|
+
if (!userId) {
|
|
45
|
+
const signInUrl = new URL('/sign-in', req.url);
|
|
46
|
+
signInUrl.searchParams.set('redirect_url', req.url);
|
|
47
|
+
return NextResponse.redirect(signInUrl);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Check admin routes
|
|
51
|
+
if (isAdminRoute(req)) {
|
|
52
|
+
const role = sessionClaims?.metadata?.role as string | undefined;
|
|
53
|
+
|
|
54
|
+
if (role !== 'admin' && role !== 'super_admin') {
|
|
55
|
+
return NextResponse.redirect(new URL('/unauthorized', req.url));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Add user info to headers for API routes
|
|
60
|
+
if (isApiRoute(req)) {
|
|
61
|
+
const requestHeaders = new Headers(req.headers);
|
|
62
|
+
requestHeaders.set('x-user-id', userId);
|
|
63
|
+
|
|
64
|
+
return NextResponse.next({
|
|
65
|
+
request: {
|
|
66
|
+
headers: requestHeaders,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return NextResponse.next();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
export const config = {
|
|
75
|
+
matcher: [
|
|
76
|
+
// Skip Next.js internals and static files
|
|
77
|
+
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
|
|
78
|
+
// Always run for API routes
|
|
79
|
+
'/(api|trpc)(.*)',
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// =============================================================================
|
|
84
|
+
// USAGE EXAMPLES
|
|
85
|
+
// =============================================================================
|
|
86
|
+
|
|
87
|
+
/*
|
|
88
|
+
// In a Server Component - get current user:
|
|
89
|
+
|
|
90
|
+
import { auth, currentUser } from '@clerk/nextjs/server';
|
|
91
|
+
|
|
92
|
+
export default async function DashboardPage() {
|
|
93
|
+
const { userId } = await auth();
|
|
94
|
+
const user = await currentUser();
|
|
95
|
+
|
|
96
|
+
if (!userId) {
|
|
97
|
+
redirect('/sign-in');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return <div>Welcome, {user?.firstName}!</div>;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// In a Client Component - use hooks:
|
|
104
|
+
|
|
105
|
+
'use client';
|
|
106
|
+
|
|
107
|
+
import { useUser, useAuth } from '@clerk/nextjs';
|
|
108
|
+
|
|
109
|
+
export function UserProfile() {
|
|
110
|
+
const { user, isLoaded } = useUser();
|
|
111
|
+
const { signOut } = useAuth();
|
|
112
|
+
|
|
113
|
+
if (!isLoaded) return <div>Loading...</div>;
|
|
114
|
+
|
|
115
|
+
return (
|
|
116
|
+
<div>
|
|
117
|
+
<p>Hello, {user?.firstName}</p>
|
|
118
|
+
<button onClick={() => signOut()}>Sign Out</button>
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// In an API Route:
|
|
124
|
+
|
|
125
|
+
import { auth } from '@clerk/nextjs/server';
|
|
126
|
+
import { NextResponse } from 'next/server';
|
|
127
|
+
|
|
128
|
+
export async function GET() {
|
|
129
|
+
const { userId } = await auth();
|
|
130
|
+
|
|
131
|
+
if (!userId) {
|
|
132
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Your logic here
|
|
136
|
+
return NextResponse.json({ userId });
|
|
137
|
+
}
|
|
138
|
+
*/
|