ultra-dex 2.2.1 → 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 -128
- package/assets/agents/00-AGENT_INDEX.md +1 -1
- package/assets/docs/LAUNCH-POSTS.md +1 -1
- package/assets/docs/QUICK-REFERENCE.md +9 -4
- package/assets/docs/VISION-V2.md +1 -1
- package/assets/hooks/pre-commit +98 -0
- package/assets/saas-plan/04-Imp-Template.md +1 -1
- package/bin/ultra-dex.js +95 -4
- package/lib/commands/advanced.js +471 -0
- package/lib/commands/agent-builder.js +226 -0
- package/lib/commands/agents.js +99 -42
- 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 +53 -1
- 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 +177 -146
- package/lib/commands/state.js +354 -0
- package/lib/commands/swarm.js +284 -0
- package/lib/commands/sync.js +82 -23
- package/lib/commands/team.js +275 -0
- package/lib/commands/upgrade.js +190 -0
- package/lib/commands/validate.js +34 -0
- package/lib/commands/verify.js +81 -0
- package/lib/commands/watch.js +79 -0
- package/lib/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/custom-agent.md +10 -0
- package/lib/utils/files.js +14 -0
- package/lib/utils/graph.js +108 -0
- package/package.json +22 -13
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ultra-dex verify command
|
|
3
|
+
* Executable 21-step verification framework
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import ora from 'ora';
|
|
8
|
+
import { createProvider, getDefaultProvider } from '../providers/index.js';
|
|
9
|
+
import { runAgentLoop } from './run.js';
|
|
10
|
+
import { loadState } from './plan.js';
|
|
11
|
+
import { projectGraph } from '../mcp/graph.js';
|
|
12
|
+
|
|
13
|
+
const CHECKLIST = [
|
|
14
|
+
"Atomic Scope Defined", "Context Loaded", "Architecture Alignment",
|
|
15
|
+
"Security Patterns Applied", "Type Safety Check", "Error Handling Strategy",
|
|
16
|
+
"API Documentation Updated", "Database Schema Verified", "Environment Variables Set",
|
|
17
|
+
"Implementation Complete", "Console Logs Removed", "Edge Cases Handled",
|
|
18
|
+
"Performance Check", "Accessibility (A11y) Check", "Cross-browser Check",
|
|
19
|
+
"Unit Tests Passed", "Integration Tests Passed", "Linting & Formatting",
|
|
20
|
+
"Code Review Approved", "Migration Scripts Ready", "Deployment Readiness"
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
export async function verifyCommand(taskName, options) {
|
|
24
|
+
console.log(chalk.cyan.bold('\n⚖️ Ultra-Dex 21-Step Verification\n'));
|
|
25
|
+
|
|
26
|
+
const providerId = options.provider || getDefaultProvider();
|
|
27
|
+
const provider = createProvider(providerId);
|
|
28
|
+
const state = await loadState();
|
|
29
|
+
|
|
30
|
+
const spinner = ora(`@Reviewer is verifying: "${taskName || 'Project'}"...`).start();
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
// 1. Structural Scan
|
|
34
|
+
await projectGraph.scan();
|
|
35
|
+
const graphSummary = projectGraph.getSummary();
|
|
36
|
+
|
|
37
|
+
// 2. AI Review
|
|
38
|
+
const projectContext = {
|
|
39
|
+
state,
|
|
40
|
+
graph: graphSummary,
|
|
41
|
+
context: `Task to verify: ${taskName || 'All completed tasks'}`
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const prompt = `
|
|
45
|
+
Verify the following task against the 21-Step Verification Framework:
|
|
46
|
+
"${taskName || 'Full Project Readiness'}"
|
|
47
|
+
|
|
48
|
+
The framework consists of:
|
|
49
|
+
${CHECKLIST.map((s, i) => `${i+1}. ${s}`).join('\n')}
|
|
50
|
+
|
|
51
|
+
Based on the codebase graph and current state, provide a report in this format:
|
|
52
|
+
[ ] Step Name: [PASS/FAIL/SKIP] - Reasoning
|
|
53
|
+
|
|
54
|
+
Final Verdict: [APPROVED/REJECTED]
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
const report = await runAgentLoop('reviewer', prompt, provider, projectContext);
|
|
58
|
+
spinner.succeed('Verification complete.');
|
|
59
|
+
|
|
60
|
+
console.log(chalk.bold('\n📋 Verification Report:'));
|
|
61
|
+
console.log(chalk.white(report));
|
|
62
|
+
|
|
63
|
+
if (report.includes('REJECTED')) {
|
|
64
|
+
console.log(chalk.red.bold('\n❌ Task failed verification. Please address the issues above.'));
|
|
65
|
+
process.exit(1);
|
|
66
|
+
} else {
|
|
67
|
+
console.log(chalk.green.bold('\n✅ Task passed verification!'));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
} catch (e) {
|
|
71
|
+
spinner.fail(chalk.red(`Verification failed: ${e.message}`));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function registerVerifyCommand(program) {
|
|
76
|
+
program
|
|
77
|
+
.command('verify [task]')
|
|
78
|
+
.description('Run executable 21-step verification on a task or project')
|
|
79
|
+
.option('-p, --provider <provider>', 'AI provider')
|
|
80
|
+
.action(verifyCommand);
|
|
81
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// cli/lib/commands/watch.js
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { watch } from 'fs';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { existsSync } from 'fs';
|
|
6
|
+
import { updateState, computeState } from './state.js';
|
|
7
|
+
|
|
8
|
+
async function calculateAlignmentScore() {
|
|
9
|
+
const state = await computeState();
|
|
10
|
+
return state.score || 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function watchCommand(options) {
|
|
14
|
+
console.log(chalk.cyan.bold('\n👁️ Ultra-Dex Watch Mode v3.0\n'));
|
|
15
|
+
console.log(chalk.gray('Watching for file changes...\n'));
|
|
16
|
+
|
|
17
|
+
const interval = options.interval ? parseInt(options.interval, 10) : 500;
|
|
18
|
+
console.log(chalk.gray(`Debounce interval: ${interval}ms`));
|
|
19
|
+
|
|
20
|
+
const watchPaths = [
|
|
21
|
+
'CONTEXT.md',
|
|
22
|
+
'IMPLEMENTATION-PLAN.md',
|
|
23
|
+
'src',
|
|
24
|
+
'app',
|
|
25
|
+
'lib'
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const validPaths = watchPaths.filter(p => {
|
|
29
|
+
const fullPath = join(process.cwd(), p);
|
|
30
|
+
return existsSync(fullPath);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
console.log(chalk.gray(`Watching: ${validPaths.join(', ')}\n`));
|
|
34
|
+
|
|
35
|
+
let debounceTimer = null;
|
|
36
|
+
let lastScore = null;
|
|
37
|
+
|
|
38
|
+
// Initial score display
|
|
39
|
+
calculateAlignmentScore().then(score => {
|
|
40
|
+
lastScore = score;
|
|
41
|
+
console.log(chalk.blue(`📊 Initial alignment score: ${score}%\n`));
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
validPaths.forEach(path => {
|
|
45
|
+
const fullPath = join(process.cwd(), path);
|
|
46
|
+
try {
|
|
47
|
+
watch(fullPath, { recursive: true }, (eventType, filename) => {
|
|
48
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
49
|
+
debounceTimer = setTimeout(async () => {
|
|
50
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
51
|
+
console.log(chalk.yellow(`\n[${timestamp}] 📝 ${filename || path} changed`));
|
|
52
|
+
|
|
53
|
+
await updateState();
|
|
54
|
+
|
|
55
|
+
const newScore = await calculateAlignmentScore();
|
|
56
|
+
const scoreDiff = lastScore !== null ? newScore - lastScore : 0;
|
|
57
|
+
const diffIndicator = scoreDiff > 0
|
|
58
|
+
? chalk.green(`↑ +${scoreDiff}`)
|
|
59
|
+
: scoreDiff < 0
|
|
60
|
+
? chalk.red(`↓ ${scoreDiff}`)
|
|
61
|
+
: chalk.gray('→ 0');
|
|
62
|
+
|
|
63
|
+
lastScore = newScore;
|
|
64
|
+
|
|
65
|
+
const scoreColor = newScore >= 80 ? 'green' : newScore >= 50 ? 'yellow' : 'red';
|
|
66
|
+
console.log(chalk[scoreColor](`✅ State updated | Alignment: ${newScore}% ${diffIndicator}`));
|
|
67
|
+
|
|
68
|
+
}, interval);
|
|
69
|
+
});
|
|
70
|
+
} catch (e) {
|
|
71
|
+
console.log(chalk.gray(` ⚠️ Cannot watch ${path}: ${e.message}`));
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
console.log(chalk.gray('\nPress Ctrl+C to stop'));
|
|
76
|
+
|
|
77
|
+
// Keep process running
|
|
78
|
+
process.stdin.resume();
|
|
79
|
+
}
|
package/lib/mcp/graph.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { glob } from 'glob';
|
|
4
|
+
|
|
5
|
+
export class CodeGraph {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.nodes = new Map(); // file path -> node info
|
|
8
|
+
this.edges = []; // { from, to, type }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async scan() {
|
|
12
|
+
this.nodes.clear();
|
|
13
|
+
this.edges = [];
|
|
14
|
+
|
|
15
|
+
// Find all js/ts/jsx/tsx files
|
|
16
|
+
// Ignoring node_modules, .git, dist, build
|
|
17
|
+
const files = await glob('**/*.{js,ts,jsx,tsx}', {
|
|
18
|
+
ignore: ['node_modules/**', '.git/**', 'dist/**', 'build/**', '.next/**'],
|
|
19
|
+
absolute: false,
|
|
20
|
+
cwd: process.cwd()
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
for (const file of files) {
|
|
24
|
+
await this.analyzeFile(file);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return this.getSummary();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async analyzeFile(filePath) {
|
|
31
|
+
try {
|
|
32
|
+
const content = await fs.readFile(path.resolve(process.cwd(), filePath), 'utf8');
|
|
33
|
+
|
|
34
|
+
// Basic Node Info
|
|
35
|
+
this.nodes.set(filePath, {
|
|
36
|
+
id: filePath,
|
|
37
|
+
size: content.length,
|
|
38
|
+
type: path.extname(filePath).substring(1),
|
|
39
|
+
// Simple heuristic for "component" vs "utility"
|
|
40
|
+
isComponent: /^[A-Z]/.test(path.basename(filePath)) || content.includes('React') || content.includes('Component'),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Extract Imports (Regex based for speed/simplicity without AST parsing overhead)
|
|
44
|
+
const importRegex = /import\s+(?:[\w\s{},*]+)\s+from\s+['"]([^'"]+)['"]/g;
|
|
45
|
+
let match;
|
|
46
|
+
|
|
47
|
+
while ((match = importRegex.exec(content)) !== null) {
|
|
48
|
+
const importPath = match[1];
|
|
49
|
+
|
|
50
|
+
// Resolve relative imports
|
|
51
|
+
if (importPath.startsWith('.')) {
|
|
52
|
+
const absoluteDir = path.dirname(path.resolve(process.cwd(), filePath));
|
|
53
|
+
const resolvedAbs = path.resolve(absoluteDir, importPath);
|
|
54
|
+
const relativeResolved = path.relative(process.cwd(), resolvedAbs);
|
|
55
|
+
|
|
56
|
+
// Add edge
|
|
57
|
+
this.edges.push({
|
|
58
|
+
from: filePath,
|
|
59
|
+
to: relativeResolved, // Note: This might not match exactly if extensions are missing, but good enough for rough graph
|
|
60
|
+
type: 'depends_on'
|
|
61
|
+
});
|
|
62
|
+
} else {
|
|
63
|
+
// Package import
|
|
64
|
+
this.edges.push({
|
|
65
|
+
from: filePath,
|
|
66
|
+
to: importPath,
|
|
67
|
+
type: 'package_dependency'
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
} catch (e) {
|
|
73
|
+
console.error(`Failed to analyze ${filePath}:`, e);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
getSummary() {
|
|
78
|
+
return {
|
|
79
|
+
nodeCount: this.nodes.size,
|
|
80
|
+
edgeCount: this.edges.length,
|
|
81
|
+
files: Array.from(this.nodes.keys()),
|
|
82
|
+
dependencies: this.edges
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
findRefereces(fileName) {
|
|
87
|
+
return this.edges.filter(e => e.to.includes(fileName));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Singleton instance
|
|
92
|
+
export const projectGraph = new CodeGraph();
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { existsSync } from 'fs';
|
|
4
|
+
|
|
5
|
+
const MEMORY_DIR = '.ultra';
|
|
6
|
+
const MEMORY_FILE = 'memory.json';
|
|
7
|
+
const MEMORY_PATH = path.resolve(process.cwd(), MEMORY_DIR, MEMORY_FILE);
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Ultra-Dex Persistent Memory System
|
|
11
|
+
* Stores facts, snippets, and context across sessions.
|
|
12
|
+
*/
|
|
13
|
+
export class UltraMemory {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.memory = [];
|
|
16
|
+
this.initialized = false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async init() {
|
|
20
|
+
if (this.initialized) return;
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
if (!existsSync(path.dirname(MEMORY_PATH))) {
|
|
24
|
+
await fs.mkdir(path.dirname(MEMORY_PATH), { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (existsSync(MEMORY_PATH)) {
|
|
28
|
+
const data = await fs.readFile(MEMORY_PATH, 'utf-8');
|
|
29
|
+
this.memory = JSON.parse(data);
|
|
30
|
+
} else {
|
|
31
|
+
this.memory = [];
|
|
32
|
+
await this.saveToFile();
|
|
33
|
+
}
|
|
34
|
+
this.initialized = true;
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error('Failed to initialize memory:', error);
|
|
37
|
+
this.memory = [];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async saveToFile() {
|
|
42
|
+
try {
|
|
43
|
+
await fs.writeFile(MEMORY_PATH, JSON.stringify(this.memory, null, 2));
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error('Failed to save memory to file:', error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async remember(text, tags = [], source = 'manual') {
|
|
50
|
+
await this.init();
|
|
51
|
+
const entry = {
|
|
52
|
+
id: crypto.randomUUID(),
|
|
53
|
+
text,
|
|
54
|
+
tags,
|
|
55
|
+
source,
|
|
56
|
+
timestamp: new Date().toISOString()
|
|
57
|
+
};
|
|
58
|
+
this.memory.push(entry);
|
|
59
|
+
await this.saveToFile();
|
|
60
|
+
return entry;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async search(query, limit = 5) {
|
|
64
|
+
await this.init();
|
|
65
|
+
const lowerQuery = query.toLowerCase();
|
|
66
|
+
|
|
67
|
+
// Simple keyword search for now
|
|
68
|
+
// Future: Vector search / Semantic search
|
|
69
|
+
return this.memory
|
|
70
|
+
.filter(entry =>
|
|
71
|
+
entry.text.toLowerCase().includes(lowerQuery) ||
|
|
72
|
+
entry.tags.some(t => t.toLowerCase().includes(lowerQuery))
|
|
73
|
+
)
|
|
74
|
+
.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp))
|
|
75
|
+
.slice(0, limit);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async clear(beforeDate = null) {
|
|
79
|
+
await this.init();
|
|
80
|
+
if (beforeDate) {
|
|
81
|
+
const date = new Date(beforeDate);
|
|
82
|
+
this.memory = this.memory.filter(entry => new Date(entry.timestamp) >= date);
|
|
83
|
+
} else {
|
|
84
|
+
this.memory = [];
|
|
85
|
+
}
|
|
86
|
+
await this.saveToFile();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async getAll() {
|
|
90
|
+
await this.init();
|
|
91
|
+
return this.memory;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export const ultraMemory = new UltraMemory();
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { loadState, generateMarkdown } from '../commands/plan.js';
|
|
4
|
+
import { projectGraph } from './graph.js';
|
|
5
|
+
|
|
6
|
+
export function registerResources(server) {
|
|
7
|
+
// Resource: Graph Summary
|
|
8
|
+
server.resource(
|
|
9
|
+
"graph",
|
|
10
|
+
"ultradex://graph/summary",
|
|
11
|
+
async (uri) => {
|
|
12
|
+
if (projectGraph.nodes.size === 0) {
|
|
13
|
+
await projectGraph.scan();
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
contents: [{
|
|
17
|
+
uri: uri.href,
|
|
18
|
+
text: JSON.stringify(projectGraph.getSummary(), null, 2)
|
|
19
|
+
}]
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
// Resource: Project Context
|
|
25
|
+
server.resource(
|
|
26
|
+
"context",
|
|
27
|
+
"ultradex://context",
|
|
28
|
+
async (uri) => {
|
|
29
|
+
try {
|
|
30
|
+
const content = await fs.readFile(path.resolve(process.cwd(), 'CONTEXT.md'), 'utf8');
|
|
31
|
+
return {
|
|
32
|
+
contents: [{
|
|
33
|
+
uri: uri.href,
|
|
34
|
+
text: content
|
|
35
|
+
}]
|
|
36
|
+
};
|
|
37
|
+
} catch (error) {
|
|
38
|
+
return {
|
|
39
|
+
contents: [{
|
|
40
|
+
uri: uri.href,
|
|
41
|
+
text: "_No CONTEXT.md found. Run `ultra-dex init` to create one._"
|
|
42
|
+
}]
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
// Resource: Implementation Plan
|
|
49
|
+
server.resource(
|
|
50
|
+
"plan",
|
|
51
|
+
"ultradex://plan",
|
|
52
|
+
async (uri) => {
|
|
53
|
+
try {
|
|
54
|
+
// Try to load state first for dynamic plan
|
|
55
|
+
const state = await loadState();
|
|
56
|
+
let content = "";
|
|
57
|
+
if (state) {
|
|
58
|
+
content = generateMarkdown(state);
|
|
59
|
+
} else {
|
|
60
|
+
// Fallback to file
|
|
61
|
+
content = await fs.readFile(path.resolve(process.cwd(), 'IMPLEMENTATION-PLAN.md'), 'utf8');
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
contents: [{
|
|
65
|
+
uri: uri.href,
|
|
66
|
+
text: content
|
|
67
|
+
}]
|
|
68
|
+
};
|
|
69
|
+
} catch (error) {
|
|
70
|
+
return {
|
|
71
|
+
contents: [{
|
|
72
|
+
uri: uri.href,
|
|
73
|
+
text: "_No IMPLEMENTATION-PLAN.md found._"
|
|
74
|
+
}]
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// Resource: Agents Index
|
|
81
|
+
server.resource(
|
|
82
|
+
"agents",
|
|
83
|
+
"ultradex://agents",
|
|
84
|
+
async (uri) => {
|
|
85
|
+
try {
|
|
86
|
+
const content = await fs.readFile(path.resolve(process.cwd(), 'agents/00-AGENT_INDEX.md'), 'utf8');
|
|
87
|
+
return {
|
|
88
|
+
contents: [{
|
|
89
|
+
uri: uri.href,
|
|
90
|
+
text: content
|
|
91
|
+
}]
|
|
92
|
+
};
|
|
93
|
+
} catch (error) {
|
|
94
|
+
return {
|
|
95
|
+
contents: [{
|
|
96
|
+
uri: uri.href,
|
|
97
|
+
text: "_No agent index found._"
|
|
98
|
+
}]
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
// Resource: Machine State
|
|
105
|
+
server.resource(
|
|
106
|
+
"state",
|
|
107
|
+
"ultradex://state",
|
|
108
|
+
async (uri) => {
|
|
109
|
+
try {
|
|
110
|
+
const state = await loadState();
|
|
111
|
+
return {
|
|
112
|
+
contents: [{
|
|
113
|
+
uri: uri.href,
|
|
114
|
+
text: JSON.stringify(state, null, 2)
|
|
115
|
+
}]
|
|
116
|
+
};
|
|
117
|
+
} catch (error) {
|
|
118
|
+
return {
|
|
119
|
+
contents: [{
|
|
120
|
+
uri: uri.href,
|
|
121
|
+
text: JSON.stringify({ error: "No state found" })
|
|
122
|
+
}]
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
// Resource: Code Property Graph (GOD MODE)
|
|
129
|
+
server.resource(
|
|
130
|
+
"graph",
|
|
131
|
+
"ultradex://graph",
|
|
132
|
+
async (uri) => {
|
|
133
|
+
try {
|
|
134
|
+
const { buildGraph } = await import('../utils/graph.js');
|
|
135
|
+
const graph = await buildGraph();
|
|
136
|
+
return {
|
|
137
|
+
contents: [{
|
|
138
|
+
uri: uri.href,
|
|
139
|
+
text: JSON.stringify(graph, null, 2)
|
|
140
|
+
}]
|
|
141
|
+
};
|
|
142
|
+
} catch (error) {
|
|
143
|
+
return {
|
|
144
|
+
contents: [{
|
|
145
|
+
uri: uri.href,
|
|
146
|
+
text: JSON.stringify({ error: `Graph build failed: ${error.message}` })
|
|
147
|
+
}]
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { registerResources } from "./resources.js";
|
|
4
|
+
import { registerTools } from "./tools.js";
|
|
5
|
+
import { projectGraph } from "./graph.js";
|
|
6
|
+
|
|
7
|
+
export async function startMcpServer() {
|
|
8
|
+
// Initialize Graph
|
|
9
|
+
console.error("Initializing Ultra-Dex Active Kernel...");
|
|
10
|
+
try {
|
|
11
|
+
await projectGraph.scan();
|
|
12
|
+
console.error(`Graph loaded: ${projectGraph.nodes.size} nodes, ${projectGraph.edges.length} edges.`);
|
|
13
|
+
} catch (e) {
|
|
14
|
+
console.error("Graph initialization warning:", e.message);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Create server instance
|
|
18
|
+
const server = new McpServer({
|
|
19
|
+
name: "Ultra-Dex Active Kernel",
|
|
20
|
+
version: "2.2.0"
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Register features
|
|
24
|
+
registerResources(server);
|
|
25
|
+
registerTools(server);
|
|
26
|
+
|
|
27
|
+
// Connect transport
|
|
28
|
+
const transport = new StdioServerTransport();
|
|
29
|
+
await server.connect(transport);
|
|
30
|
+
|
|
31
|
+
// Note: Stdio transport takes over stdin/stdout, so no logging to console.log here!
|
|
32
|
+
// Any logging must go to stderr
|
|
33
|
+
console.error("Ultra-Dex MCP Server running on Stdio...");
|
|
34
|
+
}
|