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.
- package/README.md +84 -122
- package/assets/agents/0-orchestration/orchestrator.md +2 -2
- package/assets/agents/00-AGENT_INDEX.md +1 -1
- package/assets/docs/LAUNCH-POSTS.md +1 -1
- package/assets/docs/QUICK-REFERENCE.md +12 -7
- package/assets/docs/ROADMAP.md +5 -5
- package/assets/docs/VISION-V2.md +1 -1
- package/assets/docs/WORKFLOW-DIAGRAMS.md +1 -1
- package/assets/hooks/pre-commit +98 -0
- package/assets/saas-plan/04-Imp-Template.md +1 -1
- package/assets/templates/README.md +1 -1
- package/bin/ultra-dex.js +93 -2096
- package/lib/commands/advanced.js +471 -0
- package/lib/commands/agent-builder.js +226 -0
- package/lib/commands/agents.js +101 -47
- package/lib/commands/auto-implement.js +68 -0
- package/lib/commands/build.js +73 -187
- 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 +397 -0
- package/lib/commands/export.js +408 -0
- package/lib/commands/fix.js +96 -0
- package/lib/commands/generate.js +96 -72
- package/lib/commands/hooks.js +251 -76
- package/lib/commands/init.js +56 -6
- 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/serve.js +188 -40
- package/lib/commands/state.js +354 -0
- package/lib/commands/swarm.js +284 -0
- package/lib/commands/sync.js +94 -0
- 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/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/context.js +2 -2
- package/lib/templates/custom-agent.md +10 -0
- package/lib/utils/fallback.js +4 -2
- package/lib/utils/files.js +7 -34
- package/lib/utils/graph.js +108 -0
- package/lib/utils/sync.js +216 -0
- package/package.json +22 -13
package/lib/commands/agents.js
CHANGED
|
@@ -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
|
-
|
|
26
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
+
}
|
package/lib/commands/build.js
CHANGED
|
@@ -1,214 +1,100 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ultra-dex build command
|
|
3
|
-
* Auto-
|
|
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 {
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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('
|
|
51
|
-
.option('-
|
|
52
|
-
.option('-
|
|
53
|
-
.option('--
|
|
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
|
|
57
|
-
|
|
58
|
-
// Check for
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
console.log(chalk.
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
console.log(chalk.gray('
|
|
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
|
+
}
|