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
@@ -3,8 +3,11 @@ import fs from 'fs/promises';
3
3
  import path from 'path';
4
4
  import { ASSETS_ROOT, ROOT_FALLBACK } from '../config/paths.js';
5
5
  import { githubBlobUrl } from '../config/urls.js';
6
+ import { readWithFallback } from '../utils/fallback.js';
7
+ import { pathExists } from '../utils/files.js';
6
8
 
7
9
  export const AGENTS = [
10
+ { name: 'orchestrator', description: 'Multi-agent coordination', file: '0-orchestration/orchestrator.md', tier: 'Orchestration' },
8
11
  { name: 'cto', description: 'Architecture & tech decisions', file: '1-leadership/cto.md', tier: 'Leadership' },
9
12
  { name: 'planner', description: 'Task breakdown & planning', file: '1-leadership/planner.md', tier: 'Leadership' },
10
13
  { name: 'research', description: 'Technology evaluation & comparison', file: '1-leadership/research.md', tier: 'Leadership' },
@@ -22,67 +25,118 @@ export const AGENTS = [
22
25
  { name: 'refactoring', description: 'Code quality & design patterns', file: '6-specialist/refactoring.md', tier: 'Specialist' },
23
26
  ];
24
27
 
25
- async function readAgentPrompt(agent) {
26
- const agentPath = path.join(ASSETS_ROOT, 'agents', agent.file);
28
+ const CUSTOM_AGENTS_DIR = path.join(process.cwd(), '.ultra-dex', 'custom-agents');
29
+
30
+ export function findBuiltInAgent(name) {
31
+ return AGENTS.find(a => a.name.toLowerCase() === name.toLowerCase());
32
+ }
33
+
34
+ export async function listCustomAgents() {
27
35
  try {
28
- return await fs.readFile(agentPath, 'utf-8');
29
- } catch (err) {
30
- const fallbackPath = path.join(ROOT_FALLBACK, 'agents', agent.file);
31
- return await fs.readFile(fallbackPath, 'utf-8');
36
+ const entries = await fs.readdir(CUSTOM_AGENTS_DIR, { withFileTypes: true });
37
+ return entries
38
+ .filter(entry => entry.isFile() && entry.name.endsWith('.md'))
39
+ .map(entry => entry.name.replace(/\.md$/, ''));
40
+ } catch {
41
+ return [];
42
+ }
43
+ }
44
+
45
+ export async function getCustomAgentPath(name) {
46
+ const filePath = path.join(CUSTOM_AGENTS_DIR, `${name}.md`);
47
+ if (await pathExists(filePath)) {
48
+ return filePath;
49
+ }
50
+ return null;
51
+ }
52
+
53
+ export async function readCustomAgent(name) {
54
+ const filePath = await getCustomAgentPath(name);
55
+ if (!filePath) {
56
+ throw new Error(`Custom agent "${name}" not found.`);
32
57
  }
58
+ return fs.readFile(filePath, 'utf-8');
59
+ }
60
+
61
+ export async function readAgentPrompt(agent) {
62
+ const agentPath = path.join(ASSETS_ROOT, 'agents', agent.file);
63
+ const fallbackPath = path.join(ROOT_FALLBACK, 'agents', agent.file);
64
+ return readWithFallback(agentPath, fallbackPath, 'utf-8');
33
65
  }
34
66
 
35
67
  export function registerAgentsCommand(program) {
36
- program
68
+ const agents = program
37
69
  .command('agents')
38
70
  .description('List available AI agent prompts')
39
- .action(() => {
40
- console.log(chalk.bold('\n🤖 Ultra-Dex AI Agents (15 Total)\n'));
41
- console.log(chalk.gray('Organized by tier for production pipeline\n'));
42
-
43
- let currentTier = '';
44
- AGENTS.forEach((agent) => {
45
- if (agent.tier !== currentTier) {
46
- currentTier = agent.tier;
47
- console.log(chalk.bold(`\n ${currentTier} Tier:`));
48
- }
49
- console.log(chalk.cyan(` ${agent.name}`) + chalk.gray(` - ${agent.description}`));
50
- });
51
-
52
- console.log('\n' + chalk.bold('Usage:'));
53
- console.log(chalk.gray(' ultra-dex agent <name> Show agent prompt'));
54
- console.log(chalk.gray(' ultra-dex agent backend Example: show backend agent'));
55
-
56
- console.log(`\n${chalk.gray(`Agent Index: ${githubBlobUrl('agents/00-AGENT_INDEX.md')}\n`)}`);
71
+ .action(async () => {
72
+ await listAgents();
57
73
  });
58
74
 
59
75
  program
60
- .command('agent <name>')
61
- .description('Show a specific agent prompt')
76
+ .command('agent [name]')
77
+ .description('Show a specific agent prompt or list all agents')
62
78
  .action(async (name) => {
63
- const agent = AGENTS.find(a => a.name.toLowerCase() === name.toLowerCase());
64
-
65
- if (!agent) {
66
- console.log(chalk.red(`\n❌ Agent "${name}" not found.\n`));
67
- console.log(chalk.gray('Available agents:'));
68
- AGENTS.forEach(a => console.log(chalk.cyan(` - ${a.name}`)));
69
- console.log('\n' + chalk.gray('Run "ultra-dex agents" to see all agents.\n'));
70
- process.exit(1);
79
+ if (!name) {
80
+ await listAgents();
81
+ } else {
82
+ await showAgent(name);
71
83
  }
84
+ });
85
+ }
72
86
 
73
- try {
74
- const content = await readAgentPrompt(agent);
75
- console.log(chalk.bold(`\n🤖 ${agent.name.toUpperCase()} Agent\n`));
76
- console.log(chalk.gray('─'.repeat(60)));
77
- console.log(content);
78
- console.log(chalk.gray('─'.repeat(60)));
79
- console.log(chalk.bold('\n📋 Copy the above prompt and paste into your AI tool.\n'));
80
- } catch (err) {
81
- console.log(chalk.bold(`\n🤖 ${agent.name.toUpperCase()} Agent\n`));
82
- console.log(chalk.gray('View full prompt on GitHub:'));
83
- console.log(chalk.blue(` ${githubBlobUrl(`agents/${agent.file}`)}\n`));
84
- }
87
+ async function listAgents() {
88
+ const customAgents = await listCustomAgents();
89
+ const totalAgents = AGENTS.length + customAgents.length;
90
+ console.log(chalk.bold(`\n🤖 Ultra-Dex AI Agents (${totalAgents} Total)\n`));
91
+ console.log(chalk.gray('Organized by tier for production pipeline\n'));
92
+
93
+ let currentTier = '';
94
+ AGENTS.forEach((agent) => {
95
+ if (agent.tier !== currentTier) {
96
+ currentTier = agent.tier;
97
+ console.log(chalk.bold(`\n ${currentTier} Tier:`));
98
+ }
99
+ console.log(chalk.cyan(` ${agent.name}`) + chalk.gray(` - ${agent.description}`));
100
+ });
101
+
102
+ if (customAgents.length > 0) {
103
+ console.log(chalk.bold('\n Custom Agents:'));
104
+ customAgents.forEach((name) => {
105
+ console.log(chalk.cyan(` ${name}`));
85
106
  });
107
+ }
108
+
109
+ console.log('\n' + chalk.bold('Usage:'));
110
+ console.log(chalk.gray(' ultra-dex agent show <name> Show agent prompt'));
111
+ console.log(chalk.gray(' ultra-dex pack <name> Package agent + context'));
112
+
113
+ console.log(`\n${chalk.gray(`Agent Index: ${githubBlobUrl('agents/00-AGENT_INDEX.md')}\n`)}`);
114
+ }
115
+
116
+ async function showAgent(name) {
117
+ const agent = AGENTS.find(a => a.name.toLowerCase() === name.toLowerCase());
118
+ if (!agent) {
119
+ const custom = await getCustomAgentPath(name);
120
+ if (custom) {
121
+ const content = await fs.readFile(custom, 'utf-8');
122
+ console.log(chalk.bold(`\n🤖 Custom Agent: ${name}\n`));
123
+ console.log(content);
124
+ return;
125
+ }
126
+ console.log(chalk.red(`\n❌ Agent "${name}" not found.`));
127
+ return;
128
+ }
129
+
130
+ try {
131
+ const prompt = await readAgentPrompt(agent);
132
+ console.log(chalk.bold(`\n🤖 Agent: ${agent.name} (${agent.tier})\n`));
133
+ console.log(chalk.gray(agent.description) + '\n');
134
+ console.log(chalk.gray('─'.repeat(60)));
135
+ console.log(prompt);
136
+ console.log(chalk.gray('─'.repeat(60)));
137
+ } catch (err) {
138
+ console.log(chalk.red(`\n❌ Could not read prompt for ${agent.name}`));
139
+ }
86
140
  }
87
141
 
88
142
  export function registerPackCommand(program) {
@@ -0,0 +1,68 @@
1
+ /**
2
+ * ultra-dex auto-implement command
3
+ * Fully autonomous feature implementation (GOD MODE)
4
+ */
5
+
6
+ import chalk from 'chalk';
7
+ import ora from 'ora';
8
+ import { updateState } from './state.js';
9
+ import { buildGraph } from '../utils/graph.js';
10
+ import { createProvider, getDefaultProvider } from '../providers/index.js';
11
+ import { runAgentLoop } from './run.js';
12
+
13
+ export function registerAutoImplementCommand(program) {
14
+ program
15
+ .command('auto-implement <feature>')
16
+ .description('Autonomous implementation: Plan -> Code -> Verify (God Mode)')
17
+ .option('-p, --provider <provider>', 'AI provider (defaults to router if configured)')
18
+ .option('--dry-run', 'Show plan without making changes')
19
+ .action(async (feature, options) => {
20
+ console.log(chalk.cyan('\n🚀 Ultra-Dex Autonomous Implementation Engine\n'));
21
+ console.log(chalk.bold(`Target Feature: ${feature}\n`));
22
+
23
+ const providerId = options.provider || getDefaultProvider() || 'router';
24
+ const provider = createProvider(providerId);
25
+
26
+ const spinner = ora('Initializing God Mode Swarm...').start();
27
+
28
+ try {
29
+ // 1. Structural Awareness (CPG)
30
+ const graph = await buildGraph();
31
+ spinner.text = 'Analyzing architectural impact...';
32
+
33
+ // 2. Planning Phase (@Planner)
34
+ spinner.text = '@Planner is breaking down the feature...';
35
+ const projectContext = {
36
+ context: `Feature Request: ${feature}\nCodebase Nodes: ${graph.nodes.length}\nEdges: ${graph.edges.length}`,
37
+ graph
38
+ };
39
+
40
+ const plan = await runAgentLoop('planner', `Break down this feature: ${feature}`, provider, projectContext);
41
+
42
+ if (options.dryRun) {
43
+ spinner.succeed('Planning complete (Dry Run)');
44
+ console.log(chalk.white('\nProposed Plan:'));
45
+ console.log(chalk.gray(plan));
46
+ return;
47
+ }
48
+
49
+ // 3. Execution Phase (@Backend/@Frontend)
50
+ spinner.text = 'Agents are implementing code...';
51
+ await runAgentLoop('orchestrator', `Coordinate the implementation of this plan:\n${plan}`, provider, projectContext);
52
+
53
+ // 4. Verification Phase (@Testing)
54
+ spinner.text = '@Testing is verifying changes...';
55
+ const verification = await runAgentLoop('testing', `Verify the implementation of: ${feature}`, provider, projectContext);
56
+
57
+ // 5. Finalize
58
+ await updateState();
59
+ spinner.succeed(chalk.green('Feature implemented autonomously!'));
60
+
61
+ console.log(chalk.bold('\nFinal Report:'));
62
+ console.log(chalk.gray(verification));
63
+
64
+ } catch (e) {
65
+ spinner.fail(chalk.red(`Auto-Implementation failed: ${e.message}`));
66
+ }
67
+ });
68
+ }
@@ -1,214 +1,100 @@
1
1
  /**
2
- * ultra-dex build command
3
- * Auto-loads context and starts AI-assisted development
2
+ * ultra-dex build command (GOD MODE)
3
+ * Auto-Pilot: Finds the next pending task and executes it using Agents.
4
4
  */
5
5
 
6
6
  import chalk from 'chalk';
7
7
  import ora from 'ora';
8
- import inquirer from 'inquirer';
9
8
  import fs from 'fs/promises';
10
9
  import path from 'path';
11
- import { exec } from 'child_process';
12
- import { promisify } from 'util';
13
-
14
- const execAsync = promisify(exec);
15
-
16
- // Agent configurations
17
- const AGENTS = {
18
- planner: { name: '@Planner', tier: 'Leadership', task: 'Break down features into atomic tasks' },
19
- cto: { name: '@CTO', tier: 'Leadership', task: 'Architecture decisions' },
20
- backend: { name: '@Backend', tier: 'Development', task: 'API endpoints and business logic' },
21
- frontend: { name: '@Frontend', tier: 'Development', task: 'UI components and pages' },
22
- database: { name: '@Database', tier: 'Development', task: 'Schema design and migrations' },
23
- auth: { name: '@Auth', tier: 'Security', task: 'Authentication and authorization' },
24
- security: { name: '@Security', tier: 'Security', task: 'Security audit' },
25
- testing: { name: '@Testing', tier: 'Quality', task: 'Write and run tests' },
26
- reviewer: { name: '@Reviewer', tier: 'Quality', task: 'Code review' },
27
- devops: { name: '@DevOps', tier: 'DevOps', task: 'Deployment and CI/CD' },
28
- };
29
-
30
- async function readFileSafe(filePath) {
31
- try {
32
- return await fs.readFile(filePath, 'utf-8');
33
- } catch {
34
- return null;
35
- }
36
- }
37
-
38
- async function fileExists(filePath) {
39
- try {
40
- await fs.access(filePath);
41
- return true;
42
- } catch {
43
- return false;
44
- }
10
+ import { loadState } from './plan.js';
11
+ import { runAgentLoop } from './run.js';
12
+ import { createProvider, getDefaultProvider, checkConfiguredProviders } from '../providers/index.js';
13
+
14
+ async function readProjectContext() {
15
+ const context = {};
16
+ try { context.plan = await fs.readFile('IMPLEMENTATION-PLAN.md', 'utf8'); } catch { context.plan = null; }
17
+ try { context.context = await fs.readFile('CONTEXT.md', 'utf8'); } catch { context.context = null; }
18
+ context.state = await loadState();
19
+ return context;
45
20
  }
46
21
 
47
22
  export function registerBuildCommand(program) {
48
23
  program
49
24
  .command('build')
50
- .description('Start AI-assisted development with auto-loaded context')
51
- .option('-a, --agent <agent>', 'Agent to use (planner, backend, frontend, etc.)')
52
- .option('-t, --task <task>', 'Specific task to work on')
53
- .option('--copy', 'Copy prompt to clipboard instead of displaying')
54
- .option('--cursor', 'Open in Cursor IDE')
25
+ .description('Auto-Pilot: Execute the next pending task from the plan')
26
+ .option('-p, --provider <provider>', 'AI provider')
27
+ .option('-k, --key <apiKey>', 'API key')
28
+ .option('--dry-run', 'Preview the task without executing')
55
29
  .action(async (options) => {
56
- console.log(chalk.cyan('\n🔧 Ultra-Dex Build Mode\n'));
57
-
58
- // Check for required files
59
- const hasContext = await fileExists('CONTEXT.md');
60
- const hasPlan = await fileExists('IMPLEMENTATION-PLAN.md');
61
- const hasQuickStart = await fileExists('QUICK-START.md');
62
-
63
- if (!hasContext && !hasPlan) {
64
- console.log(chalk.yellow('⚠️ No Ultra-Dex project found in current directory.\n'));
65
- console.log(chalk.white('Run one of these first:'));
66
- console.log(chalk.gray(' npx ultra-dex init # Create from template'));
67
- console.log(chalk.gray(' npx ultra-dex generate # Generate from idea\n'));
30
+ console.log(chalk.cyan('\n\u{1F30B} Ultra-Dex Auto-Pilot (Build Mode)\n'));
31
+
32
+ // Check for API key
33
+ const configured = checkConfiguredProviders();
34
+ const hasProvider = configured.some(p => p.configured) || options.key;
35
+
36
+ if (!hasProvider && !options.dryRun) {
37
+ console.log(chalk.yellow('⚠️ No AI provider configured.'));
38
+ console.log(chalk.white('Set an API key to enable Auto-Pilot.'));
68
39
  return;
69
40
  }
70
41
 
71
- // Load context files
72
- const spinner = ora('Loading project context...').start();
73
-
74
- const context = await readFileSafe('CONTEXT.md');
75
- const plan = await readFileSafe('IMPLEMENTATION-PLAN.md');
76
- const quickStart = await readFileSafe('QUICK-START.md');
77
-
78
- spinner.succeed('Context loaded');
79
-
80
- // Select agent if not provided
81
- let agent = options.agent;
82
- if (!agent) {
83
- const { selectedAgent } = await inquirer.prompt([
84
- {
85
- type: 'list',
86
- name: 'selectedAgent',
87
- message: 'Select an agent:',
88
- choices: [
89
- new inquirer.Separator('── Leadership ──'),
90
- { name: '📋 @Planner - Break down tasks', value: 'planner' },
91
- { name: '🏗️ @CTO - Architecture decisions', value: 'cto' },
92
- new inquirer.Separator('── Development ──'),
93
- { name: '⚙️ @Backend - API endpoints', value: 'backend' },
94
- { name: '🎨 @Frontend - UI components', value: 'frontend' },
95
- { name: '🗄️ @Database - Schema design', value: 'database' },
96
- new inquirer.Separator('── Security ──'),
97
- { name: '🔐 @Auth - Authentication', value: 'auth' },
98
- { name: '🛡️ @Security - Security audit', value: 'security' },
99
- new inquirer.Separator('── Quality ──'),
100
- { name: '🧪 @Testing - Write tests', value: 'testing' },
101
- { name: '👁️ @Reviewer - Code review', value: 'reviewer' },
102
- new inquirer.Separator('── DevOps ──'),
103
- { name: '🚀 @DevOps - Deployment', value: 'devops' },
104
- ],
105
- },
106
- ]);
107
- agent = selectedAgent;
42
+ const state = await loadState();
43
+ if (!state) {
44
+ console.log(chalk.red('❌ No state found. Run "ultra-dex init" first.'));
45
+ return;
108
46
  }
109
47
 
110
- const agentConfig = AGENTS[agent];
111
- if (!agentConfig) {
112
- console.log(chalk.red(`Unknown agent: ${agent}`));
113
- console.log(chalk.gray(`Available: ${Object.keys(AGENTS).join(', ')}`));
114
- return;
48
+ // Find next pending task
49
+ let nextTask = null;
50
+ let currentPhase = null;
51
+
52
+ for (const phase of state.phases) {
53
+ const pending = phase.steps.find(s => s.status !== 'completed');
54
+ if (pending) {
55
+ nextTask = pending;
56
+ currentPhase = phase;
57
+ break;
58
+ }
115
59
  }
116
60
 
117
- // Get task if not provided
118
- let task = options.task;
119
- if (!task) {
120
- const { taskInput } = await inquirer.prompt([
121
- {
122
- type: 'input',
123
- name: 'taskInput',
124
- message: `What should ${agentConfig.name} do?`,
125
- default: agentConfig.task,
126
- },
127
- ]);
128
- task = taskInput;
61
+ if (!nextTask) {
62
+ console.log(chalk.green('✅ All phases completed! You are ready to launch.'));
63
+ return;
129
64
  }
130
65
 
131
- // Build the prompt
132
- const contextSection = context ? `## Project Context\n${context}\n` : '';
133
- const planSection = plan ? `## Implementation Plan (Summary)\n${plan.slice(0, 8000)}...\n[Full plan in IMPLEMENTATION-PLAN.md]\n` : '';
134
-
135
- const prompt = `# ${agentConfig.name} Agent Session
136
-
137
- You are acting as ${agentConfig.name} for this project.
138
-
139
- ${contextSection}
140
- ${planSection}
141
-
142
- ## Your Task
143
- ${task}
144
-
145
- ## Instructions
146
- 1. Read the context and plan carefully
147
- 2. Focus ONLY on your assigned task
148
- 3. Follow Ultra-Dex 21-step verification for any code changes
149
- 4. Document your work in a way the next agent can continue
150
-
151
- ## Output Format
152
- - For code: Include full file paths and production-ready code
153
- - For plans: Use atomic tasks (4-9 hours each)
154
- - For reviews: Use severity levels (critical, warning, info)
155
-
156
- Begin working on: ${task}
157
- `;
158
-
159
- // Output the prompt
160
- console.log(chalk.green(`\n✅ ${agentConfig.name} prompt ready\n`));
161
-
162
- if (options.copy) {
163
- // Copy to clipboard
164
- try {
165
- const platform = process.platform;
166
- if (platform === 'darwin') {
167
- await execAsync(`echo ${JSON.stringify(prompt)} | pbcopy`);
168
- } else if (platform === 'linux') {
169
- await execAsync(`echo ${JSON.stringify(prompt)} | xclip -selection clipboard`);
170
- } else if (platform === 'win32') {
171
- await execAsync(`echo ${JSON.stringify(prompt)} | clip`);
172
- }
173
- console.log(chalk.cyan('📋 Prompt copied to clipboard!'));
174
- console.log(chalk.gray('Paste into your AI tool (Cursor, Claude, ChatGPT)\n'));
175
- } catch {
176
- console.log(chalk.yellow('Could not copy to clipboard. Displaying prompt instead:\n'));
177
- console.log(chalk.gray('─'.repeat(60)));
178
- console.log(prompt);
179
- console.log(chalk.gray('─'.repeat(60)));
180
- }
181
- } else if (options.cursor) {
182
- // Save prompt and open Cursor
183
- const promptPath = path.join('.ultra-dex', 'current-prompt.md');
184
- await fs.mkdir('.ultra-dex', { recursive: true });
185
- await fs.writeFile(promptPath, prompt);
186
-
187
- console.log(chalk.gray(`Prompt saved to: ${promptPath}`));
188
- console.log(chalk.cyan('Opening Cursor...\n'));
189
-
190
- try {
191
- await execAsync('cursor .');
192
- } catch {
193
- console.log(chalk.yellow('Could not open Cursor. Is it installed?'));
194
- console.log(chalk.gray('Install: https://cursor.sh'));
195
- }
196
- } else {
197
- // Display the prompt
198
- console.log(chalk.gray('─'.repeat(60)));
199
- console.log(prompt);
200
- console.log(chalk.gray('─'.repeat(60)));
201
-
202
- console.log(chalk.cyan('\n📋 Copy this prompt into your AI tool'));
203
- console.log(chalk.gray('Or use --copy to copy to clipboard\n'));
66
+ console.log(chalk.bold(`Phase: ${currentPhase.name}`));
67
+ console.log(chalk.bold(`Task: ${nextTask.task}`));
68
+
69
+ // Heuristic to pick agent (naive)
70
+ let agentName = 'backend'; // default
71
+ const taskLower = nextTask.task.toLowerCase();
72
+ if (taskLower.includes('ui') || taskLower.includes('component') || taskLower.includes('page')) agentName = 'frontend';
73
+ if (taskLower.includes('db') || taskLower.includes('schema') || taskLower.includes('database')) agentName = 'database';
74
+ if (taskLower.includes('plan') || taskLower.includes('break down')) agentName = 'planner';
75
+ if (taskLower.includes('test')) agentName = 'testing';
76
+
77
+ console.log(chalk.gray(`Selected Agent: @${agentName}`));
78
+
79
+ if (options.dryRun) {
80
+ console.log(chalk.yellow('\nDry run mode. Exiting.'));
81
+ return;
204
82
  }
205
83
 
206
- // Show next steps
207
- console.log(chalk.white('Tips:'));
208
- console.log(chalk.gray(' • Paste the prompt into Cursor, Claude, or ChatGPT'));
209
- console.log(chalk.gray(' • Use "npx ultra-dex serve" for MCP-compatible context'));
210
- console.log(chalk.gray(' • Run "npx ultra-dex review" after making changes\n'));
84
+ const providerId = options.provider || getDefaultProvider();
85
+ const provider = createProvider(providerId, { apiKey: options.key, maxTokens: 8000 });
86
+ const context = await readProjectContext();
87
+
88
+ console.log(chalk.gray(''.repeat(50)));
89
+
90
+ const result = await runAgentLoop(agentName, nextTask.task, provider, context);
91
+
92
+ // Save output
93
+ const filename = `task-${nextTask.id}-${agentName}.md`;
94
+ await fs.writeFile(filename, result);
95
+ console.log(chalk.green(`\n✅ Task output saved to ${filename}`));
96
+ console.log(chalk.gray('Review the code and mark the task as completed in .ultra/state.json'));
211
97
  });
212
98
  }
213
99
 
214
- export default { registerBuildCommand };
100
+ export default { registerBuildCommand };
@@ -0,0 +1,84 @@
1
+ /**
2
+ * ultra-dex ci-monitor command
3
+ * Self-healing CI/CD pipeline monitor (The Autonomic Nervous System)
4
+ */
5
+
6
+ import chalk from 'chalk';
7
+ import http from 'http';
8
+ import { createProvider, getDefaultProvider } from '../providers/index.js';
9
+ import { runAgentLoop } from './run.js';
10
+ import { buildGraph } from '../utils/graph.js';
11
+
12
+ export function registerCiMonitorCommand(program) {
13
+ program
14
+ .command('ci-monitor')
15
+ .description('Start the Self-Healing CI/CD Webhook Listener')
16
+ .option('-p, --port <port>', 'Webhook port', '3003')
17
+ .option('--provider <provider>', 'AI provider for fixes')
18
+ .action(async (options) => {
19
+ const port = parseInt(options.port);
20
+ console.log(chalk.cyan('\n🛡️ Ultra-Dex Self-Healing CI Monitor\n'));
21
+ console.log(chalk.gray(`Listening for GitHub Webhooks on port ${port}...`));
22
+
23
+ const server = http.createServer(async (req, res) => {
24
+ if (req.method === 'POST') {
25
+ let body = '';
26
+ req.on('data', chunk => { body += chunk.toString(); });
27
+ req.on('end', async () => {
28
+ try {
29
+ const payload = JSON.parse(body);
30
+
31
+ // Filter for Workflow Failures
32
+ // (Simplification: Assuming GitHub Actions payload structure)
33
+ if (payload.action === 'completed' && payload.workflow_job?.conclusion === 'failure') {
34
+ await handleBuildFailure(payload, options);
35
+ }
36
+
37
+ res.writeHead(200);
38
+ res.end('Received');
39
+ } catch (e) {
40
+ console.error(chalk.red('Webhook Error:'), e.message);
41
+ res.writeHead(400);
42
+ res.end('Bad Request');
43
+ }
44
+ });
45
+ } else {
46
+ res.writeHead(404);
47
+ res.end();
48
+ }
49
+ });
50
+
51
+ server.listen(port, () => {
52
+ console.log(chalk.green(`✅ Monitor Active: http://localhost:${port}`));
53
+ });
54
+ });
55
+ }
56
+
57
+ async function handleBuildFailure(payload, options) {
58
+ const jobName = payload.workflow_job.name;
59
+ const repo = payload.repository.full_name;
60
+ const logs = "Mock Log: Error: Cannot find module './utils/graph.js'"; // Real imp would fetch logs via API
61
+
62
+ console.log(chalk.red(`\n🚨 Build Failed: ${jobName} in ${repo}`));
63
+ console.log(chalk.yellow(' Initiating Self-Healing Protocol...'));
64
+
65
+ const providerId = options.provider || getDefaultProvider() || 'router';
66
+ const provider = createProvider(providerId);
67
+
68
+ // 1. Analyze Context (CPG)
69
+ const graph = await buildGraph();
70
+ const context = {
71
+ context: `Build Failure Log:\n${logs}\n\nRepository: ${repo}`,
72
+ graph
73
+ };
74
+
75
+ // 2. Diagnose & Fix (@Debugger)
76
+ const fixPlan = await runAgentLoop('debugger', `Analyze this build failure and propose a fix:\n${logs}`, provider, context);
77
+
78
+ // 3. Apply Fix (Mock - would be git push)
79
+ console.log(chalk.bold('\nProposed Fix:'));
80
+ console.log(chalk.gray(fixPlan));
81
+
82
+ // In a real system, we would:
83
+ // await runAgentLoop('devops', `Apply this fix and push to branch 'fix/${jobName}':\n${fixPlan}`, provider, context);
84
+ }