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
@@ -0,0 +1,598 @@
1
+ /**
2
+ * Ultra-Dex Swarm Coordination System v3.0
3
+ * Main entry point for agent orchestration.
4
+ */
5
+
6
+ import chalk from 'chalk';
7
+ import ora from 'ora';
8
+ import fs from 'fs/promises';
9
+ import {
10
+ AgentMessage,
11
+ HandoffPayload,
12
+ ExecutionTrace,
13
+ AgentSchemas,
14
+ createMessage,
15
+ createHandover
16
+ } from './protocol.js';
17
+ import {
18
+ TIERS,
19
+ AGENTS,
20
+ TIER_FLOW,
21
+ getAgent,
22
+ getAgentsByTier,
23
+ getTier,
24
+ getExecutionOrder,
25
+ findParallelGroups,
26
+ validatePipeline,
27
+ getAgentDependencies
28
+ } from './tiers.js';
29
+
30
+ // Re-export from protocol for convenience
31
+ export { AgentMessage, HandoffPayload, ExecutionTrace, AgentSchemas };
32
+ export { createMessage, createHandover };
33
+
34
+ // Re-export from tiers
35
+ export { TIERS, AGENTS, TIER_FLOW, getAgent, getAgentsByTier, getTier };
36
+
37
+ // ============================================================================
38
+ // SWARM COORDINATOR CLASS
39
+ // ============================================================================
40
+
41
+ /**
42
+ * Main coordinator class for managing agent swarms.
43
+ */
44
+ export class SwarmCoordinator {
45
+ constructor(provider, options = {}) {
46
+ this.provider = provider;
47
+ this.agents = new Map();
48
+ this.history = [];
49
+ this.traces = new Map();
50
+ this.currentTrace = null;
51
+ this.options = {
52
+ verbose: options.verbose || false,
53
+ saveArtifacts: options.saveArtifacts !== false,
54
+ artifactDir: options.artifactDir || '.ultra-dex/swarm',
55
+ maxRetries: options.maxRetries || 3,
56
+ enableRollback: options.enableRollback !== false
57
+ };
58
+
59
+ // Register default agents from tiers
60
+ this._registerDefaultAgents();
61
+ }
62
+
63
+ /**
64
+ * Register default agents from the tier system.
65
+ */
66
+ _registerDefaultAgents() {
67
+ for (const [name, config] of Object.entries(AGENTS)) {
68
+ this.agents.set(name, {
69
+ ...config,
70
+ handler: null // Will be set when agent is loaded
71
+ });
72
+ }
73
+ }
74
+
75
+ // ==========================================================================
76
+ // AGENT MANAGEMENT
77
+ // ==========================================================================
78
+
79
+ /**
80
+ * Add or update an agent in the swarm.
81
+ */
82
+ addAgent(name, config) {
83
+ const normalized = name.toLowerCase().replace('@', '');
84
+ const existing = this.agents.get(normalized) || {};
85
+
86
+ this.agents.set(normalized, {
87
+ ...existing,
88
+ ...config,
89
+ name: config.name || existing.name || normalized
90
+ });
91
+
92
+ if (this.options.verbose) {
93
+ console.log(chalk.gray(`[Swarm] Registered agent: ${normalized}`));
94
+ }
95
+
96
+ return this;
97
+ }
98
+
99
+ /**
100
+ * Get an agent by name.
101
+ */
102
+ getAgent(name) {
103
+ const normalized = name.toLowerCase().replace('@', '');
104
+ return this.agents.get(normalized) || null;
105
+ }
106
+
107
+ /**
108
+ * List all registered agents.
109
+ */
110
+ listAgents() {
111
+ return Array.from(this.agents.entries()).map(([name, config]) => ({
112
+ name,
113
+ ...config
114
+ }));
115
+ }
116
+
117
+ /**
118
+ * Check if an agent is registered.
119
+ */
120
+ hasAgent(name) {
121
+ const normalized = name.toLowerCase().replace('@', '');
122
+ return this.agents.has(normalized);
123
+ }
124
+
125
+ // ==========================================================================
126
+ // PIPELINE EXECUTION
127
+ // ==========================================================================
128
+
129
+ /**
130
+ * Run a pipeline of agent tasks.
131
+ * @param {Object} options - Pipeline configuration
132
+ * @param {string} options.goal - The goal of the pipeline
133
+ * @param {Array} options.steps - Array of step objects { agent, task, context? }
134
+ * @param {boolean} options.parallel - Enable parallel execution where possible
135
+ */
136
+ async runPipeline(options) {
137
+ const { goal, steps, parallel = false } = options;
138
+
139
+ // Create execution trace
140
+ const trace = new ExecutionTrace(null, goal);
141
+ this.currentTrace = trace;
142
+ this.traces.set(trace.taskId, trace);
143
+
144
+ // Add steps to trace
145
+ steps.forEach((step, index) => {
146
+ trace.addStep(index + 1, step.agent, step.task, step.dependencies || []);
147
+ });
148
+
149
+ // Validate pipeline
150
+ const validation = validatePipeline(steps);
151
+ if (!validation.valid) {
152
+ console.log(chalk.red('\n❌ Pipeline validation failed:'));
153
+ validation.errors.forEach(err => {
154
+ console.log(chalk.red(` Step ${err.step} (${err.agent}): ${err.error}`));
155
+ });
156
+ trace.status = 'failed';
157
+ return trace;
158
+ }
159
+
160
+ // Start execution
161
+ trace.start();
162
+ const spinner = ora(`🐝 Swarm: Executing pipeline for "${goal}"`).start();
163
+
164
+ try {
165
+ if (parallel) {
166
+ await this._executeParallel(steps, trace, spinner);
167
+ } else {
168
+ await this._executeSequential(steps, trace, spinner);
169
+ }
170
+
171
+ trace.complete(true);
172
+ spinner.succeed(chalk.green(`Pipeline completed: ${goal}`));
173
+ } catch (error) {
174
+ trace.complete(false);
175
+ spinner.fail(chalk.red(`Pipeline failed: ${error.message}`));
176
+
177
+ if (this.options.enableRollback) {
178
+ await this._attemptRollback(trace);
179
+ }
180
+ }
181
+
182
+ // Save trace
183
+ await this._saveTrace(trace);
184
+ this.history.push(trace);
185
+
186
+ return trace;
187
+ }
188
+
189
+ /**
190
+ * Execute steps sequentially.
191
+ */
192
+ async _executeSequential(steps, trace, spinner) {
193
+ let previousResult = null;
194
+
195
+ for (const step of steps) {
196
+ const stepNum = steps.indexOf(step) + 1;
197
+ spinner.text = `Step ${stepNum}/${steps.length}: [${step.agent}] ${step.task}`;
198
+ trace.startStep(stepNum);
199
+
200
+ try {
201
+ // Create checkpoint before execution
202
+ if (this.options.enableRollback) {
203
+ trace.createCheckpoint(`before-step-${stepNum}`, { previousResult });
204
+ }
205
+
206
+ // Execute step
207
+ const result = await this._executeStep(step, previousResult, trace);
208
+ trace.recordResult(step.agent, result, true);
209
+ previousResult = result;
210
+
211
+ // Create handoff for next step
212
+ if (stepNum < steps.length) {
213
+ const nextStep = steps[stepNum];
214
+ const handoff = new HandoffPayload(step.agent, nextStep.agent, {
215
+ summary: `Completed: ${step.task}`,
216
+ artifacts: result.artifacts || [],
217
+ nextTask: nextStep.task
218
+ });
219
+ this.history.push(handoff.toMessage());
220
+ }
221
+
222
+ } catch (error) {
223
+ trace.recordResult(step.agent, error.message, false);
224
+ throw error;
225
+ }
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Execute steps in parallel where possible.
231
+ */
232
+ async _executeParallel(steps, trace, spinner) {
233
+ const agents = steps.map(s => s.agent);
234
+ const groups = findParallelGroups(agents);
235
+
236
+ let groupNum = 0;
237
+ let previousResults = {};
238
+
239
+ for (const group of groups) {
240
+ groupNum++;
241
+ spinner.text = `Group ${groupNum}/${groups.length}: Running ${group.join(', ')} in parallel`;
242
+
243
+ // Create checkpoint before group
244
+ if (this.options.enableRollback) {
245
+ trace.createCheckpoint(`before-group-${groupNum}`, { previousResults });
246
+ }
247
+
248
+ // Find steps for this group
249
+ const groupSteps = steps.filter(s =>
250
+ group.includes(s.agent.toLowerCase().replace('@', ''))
251
+ );
252
+
253
+ // Execute in parallel
254
+ const promises = groupSteps.map(async (step) => {
255
+ const stepNum = steps.indexOf(step) + 1;
256
+ trace.startStep(stepNum);
257
+
258
+ try {
259
+ const result = await this._executeStep(step, previousResults, trace);
260
+ trace.recordResult(step.agent, result, true);
261
+ return { agent: step.agent, result, success: true };
262
+ } catch (error) {
263
+ trace.recordResult(step.agent, error.message, false);
264
+ return { agent: step.agent, error, success: false };
265
+ }
266
+ });
267
+
268
+ const results = await Promise.all(promises);
269
+
270
+ // Check for failures
271
+ const failures = results.filter(r => !r.success);
272
+ if (failures.length > 0) {
273
+ const failedAgents = failures.map(f => f.agent).join(', ');
274
+ throw new Error(`Parallel execution failed for: ${failedAgents}`);
275
+ }
276
+
277
+ // Update previous results
278
+ for (const { agent, result } of results) {
279
+ previousResults[agent] = result;
280
+ }
281
+
282
+ // Track parallel execution count
283
+ if (group.length > 1) {
284
+ trace.metadata.parallelExecutions++;
285
+ }
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Execute a single step.
291
+ */
292
+ async _executeStep(step, context, trace) {
293
+ const agent = this.getAgent(step.agent);
294
+ if (!agent) {
295
+ throw new Error(`Unknown agent: ${step.agent}`);
296
+ }
297
+
298
+ // If agent has a handler, use it
299
+ if (agent.handler) {
300
+ return await agent.handler(step.task, context, trace);
301
+ }
302
+
303
+ // Otherwise, use provider to generate response
304
+ const systemPrompt = this._buildSystemPrompt(agent);
305
+ const userPrompt = this._buildUserPrompt(step, context);
306
+
307
+ const result = await this.provider.generate(systemPrompt, userPrompt);
308
+
309
+ // Parse result
310
+ return {
311
+ output: result.content,
312
+ artifacts: [],
313
+ timestamp: new Date().toISOString()
314
+ };
315
+ }
316
+
317
+ /**
318
+ * Build system prompt for an agent.
319
+ */
320
+ _buildSystemPrompt(agent) {
321
+ return `You are the ${agent.name} agent in the Ultra-Dex swarm.
322
+ Role: ${agent.role}
323
+ Capabilities: ${agent.capabilities?.join(', ') || 'General'}
324
+
325
+ Respond with actionable output. Be concise and specific.
326
+ If creating files, list them clearly.
327
+ If making decisions, explain the reasoning briefly.`;
328
+ }
329
+
330
+ /**
331
+ * Build user prompt for a step.
332
+ */
333
+ _buildUserPrompt(step, context) {
334
+ let prompt = `Task: ${step.task}`;
335
+
336
+ if (context && typeof context === 'object') {
337
+ const contextStr = Object.entries(context)
338
+ .map(([k, v]) => `${k}: ${typeof v === 'object' ? JSON.stringify(v) : v}`)
339
+ .join('\n');
340
+ prompt += `\n\nContext from previous steps:\n${contextStr}`;
341
+ }
342
+
343
+ return prompt;
344
+ }
345
+
346
+ // ==========================================================================
347
+ // ROLLBACK SUPPORT
348
+ // ==========================================================================
349
+
350
+ /**
351
+ * Attempt rollback on failure.
352
+ */
353
+ async _attemptRollback(trace) {
354
+ const checkpoint = trace.getLastCheckpoint();
355
+ if (!checkpoint) {
356
+ console.log(chalk.yellow(' No checkpoint available for rollback'));
357
+ return;
358
+ }
359
+
360
+ console.log(chalk.yellow(` Rolling back to checkpoint: ${checkpoint.name}`));
361
+
362
+ try {
363
+ const state = trace.rollbackTo(checkpoint.id);
364
+ console.log(chalk.green(` Rollback successful`));
365
+ return state;
366
+ } catch (error) {
367
+ console.log(chalk.red(` Rollback failed: ${error.message}`));
368
+ }
369
+ }
370
+
371
+ /**
372
+ * Manual rollback to a specific checkpoint.
373
+ */
374
+ rollback(taskId, checkpointId) {
375
+ const trace = this.traces.get(taskId);
376
+ if (!trace) {
377
+ throw new Error(`No trace found for task: ${taskId}`);
378
+ }
379
+
380
+ return trace.rollbackTo(checkpointId);
381
+ }
382
+
383
+ // ==========================================================================
384
+ // HISTORY & PERSISTENCE
385
+ // ==========================================================================
386
+
387
+ /**
388
+ * Get execution history.
389
+ */
390
+ getHistory() {
391
+ return this.history;
392
+ }
393
+
394
+ /**
395
+ * Get a specific trace by task ID.
396
+ */
397
+ getTrace(taskId) {
398
+ return this.traces.get(taskId) || null;
399
+ }
400
+
401
+ /**
402
+ * Get all traces.
403
+ */
404
+ getAllTraces() {
405
+ return Array.from(this.traces.values());
406
+ }
407
+
408
+ /**
409
+ * Save trace to disk.
410
+ */
411
+ async _saveTrace(trace) {
412
+ if (!this.options.saveArtifacts) return;
413
+
414
+ try {
415
+ await fs.mkdir(this.options.artifactDir, { recursive: true });
416
+ const filename = `${this.options.artifactDir}/trace-${trace.taskId}.json`;
417
+ await fs.writeFile(filename, JSON.stringify(trace.toJSON(), null, 2));
418
+
419
+ if (this.options.verbose) {
420
+ console.log(chalk.gray(` Trace saved to ${filename}`));
421
+ }
422
+ } catch (error) {
423
+ if (this.options.verbose) {
424
+ console.log(chalk.yellow(` Failed to save trace: ${error.message}`));
425
+ }
426
+ }
427
+ }
428
+
429
+ /**
430
+ * Load trace from disk.
431
+ */
432
+ async loadTrace(taskId) {
433
+ const filename = `${this.options.artifactDir}/trace-${taskId}.json`;
434
+
435
+ try {
436
+ const content = await fs.readFile(filename, 'utf-8');
437
+ const data = JSON.parse(content);
438
+ const trace = ExecutionTrace.fromJSON(data);
439
+ this.traces.set(taskId, trace);
440
+ return trace;
441
+ } catch (error) {
442
+ throw new Error(`Failed to load trace: ${error.message}`);
443
+ }
444
+ }
445
+
446
+ /**
447
+ * Clear history.
448
+ */
449
+ clearHistory() {
450
+ this.history = [];
451
+ this.traces.clear();
452
+ this.currentTrace = null;
453
+ }
454
+
455
+ // ==========================================================================
456
+ // CONVENIENCE METHODS
457
+ // ==========================================================================
458
+
459
+ /**
460
+ * Plan a feature using the planner agent.
461
+ */
462
+ async plan(feature) {
463
+ const spinner = ora('🧠 Planning feature implementation...').start();
464
+
465
+ const plannerPrompt = `
466
+ You are the Hive Mind Planner.
467
+ Break down the feature "${feature}" into sequential atomic tasks for other agents.
468
+
469
+ Available Agents:
470
+ ${Object.entries(AGENTS)
471
+ .filter(([_, a]) => a.tier > 0)
472
+ .map(([name, a]) => `- @${name} (${a.role})`)
473
+ .join('\n')}
474
+
475
+ Output STRICT JSON format only:
476
+ {
477
+ "tasks": [
478
+ {
479
+ "id": 1,
480
+ "agent": "agentname",
481
+ "task": "Description of the task",
482
+ "context": "Additional context",
483
+ "dependencies": []
484
+ }
485
+ ]
486
+ }`;
487
+
488
+ try {
489
+ const result = await this.provider.generate(plannerPrompt, `Feature: ${feature}`);
490
+
491
+ let jsonStr = result.content.trim();
492
+ if (jsonStr.startsWith('```json')) {
493
+ jsonStr = jsonStr.replace(/^```json\n?/, '').replace(/\n?```$/, '');
494
+ } else if (jsonStr.startsWith('```')) {
495
+ jsonStr = jsonStr.replace(/^```\n?/, '').replace(/\n?```$/, '');
496
+ }
497
+
498
+ const plan = JSON.parse(jsonStr);
499
+ spinner.succeed(`Plan generated: ${plan.tasks.length} tasks identified.`);
500
+ return plan.tasks;
501
+ } catch (error) {
502
+ spinner.fail('Planning failed.');
503
+ console.error(chalk.red(error.message));
504
+ return null;
505
+ }
506
+ }
507
+
508
+ /**
509
+ * Execute a pre-planned set of tasks.
510
+ */
511
+ async execute(tasks) {
512
+ return this.runPipeline({
513
+ goal: 'Execute planned tasks',
514
+ steps: tasks.map(t => ({
515
+ agent: t.agent,
516
+ task: t.task,
517
+ context: t.context,
518
+ dependencies: t.dependencies
519
+ })),
520
+ parallel: false
521
+ });
522
+ }
523
+
524
+ /**
525
+ * Run a single agent task.
526
+ */
527
+ async runAgent(agent, task, context = {}) {
528
+ return this.runPipeline({
529
+ goal: task,
530
+ steps: [{ agent, task, context }],
531
+ parallel: false
532
+ });
533
+ }
534
+
535
+ /**
536
+ * Get suggested agents for a task description.
537
+ */
538
+ suggestAgents(taskDescription) {
539
+ const keywords = {
540
+ backend: ['api', 'endpoint', 'server', 'route', 'controller', 'service'],
541
+ frontend: ['ui', 'component', 'page', 'button', 'form', 'css', 'react', 'vue'],
542
+ database: ['schema', 'table', 'migration', 'query', 'sql', 'model'],
543
+ auth: ['login', 'authentication', 'authorization', 'password', 'session', 'jwt'],
544
+ security: ['vulnerability', 'audit', 'secure', 'encryption', 'xss', 'csrf'],
545
+ testing: ['test', 'spec', 'coverage', 'jest', 'mocha', 'e2e'],
546
+ devops: ['deploy', 'ci', 'cd', 'docker', 'kubernetes', 'aws', 'pipeline'],
547
+ performance: ['slow', 'optimize', 'cache', 'speed', 'latency', 'memory'],
548
+ debugger: ['bug', 'fix', 'error', 'crash', 'issue', 'debug'],
549
+ documentation: ['docs', 'readme', 'guide', 'api docs', 'comment'],
550
+ refactoring: ['refactor', 'clean', 'reorganize', 'pattern', 'simplify'],
551
+ planner: ['plan', 'break down', 'tasks', 'sprint', 'estimate'],
552
+ cto: ['architecture', 'tech stack', 'design', 'decision'],
553
+ research: ['compare', 'evaluate', 'research', 'options', 'alternatives'],
554
+ reviewer: ['review', 'approve', 'check', 'quality']
555
+ };
556
+
557
+ const lower = taskDescription.toLowerCase();
558
+ const matches = [];
559
+
560
+ for (const [agent, words] of Object.entries(keywords)) {
561
+ const matchCount = words.filter(w => lower.includes(w)).length;
562
+ if (matchCount > 0) {
563
+ matches.push({ agent, score: matchCount });
564
+ }
565
+ }
566
+
567
+ return matches
568
+ .sort((a, b) => b.score - a.score)
569
+ .map(m => m.agent);
570
+ }
571
+ }
572
+
573
+ // ============================================================================
574
+ // FACTORY FUNCTIONS
575
+ // ============================================================================
576
+
577
+ /**
578
+ * Create a new SwarmCoordinator instance.
579
+ */
580
+ export function createSwarm(provider, options = {}) {
581
+ return new SwarmCoordinator(provider, options);
582
+ }
583
+
584
+ // ============================================================================
585
+ // DEFAULT EXPORT
586
+ // ============================================================================
587
+
588
+ export default {
589
+ SwarmCoordinator,
590
+ createSwarm,
591
+ AgentMessage,
592
+ HandoffPayload,
593
+ ExecutionTrace,
594
+ AgentSchemas,
595
+ TIERS,
596
+ AGENTS,
597
+ TIER_FLOW
598
+ };