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
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
// cli/lib/commands/upgrade.js
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import { execSync } from 'child_process';
|
|
5
|
+
import { readFileSync, existsSync } from 'fs';
|
|
6
|
+
import { join, dirname } from 'path';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
|
|
11
|
+
export async function upgradeCommand(options) {
|
|
12
|
+
console.log(chalk.cyan.bold('\n⬆️ Ultra-Dex Upgrade Check\n'));
|
|
13
|
+
|
|
14
|
+
// Get local version from package.json
|
|
15
|
+
const localVersion = getLocalVersion();
|
|
16
|
+
|
|
17
|
+
const spinner = ora('Checking npm registry...').start();
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
// Query npm registry for latest version
|
|
21
|
+
const latestVersion = await getLatestVersion();
|
|
22
|
+
spinner.succeed('Registry check complete');
|
|
23
|
+
|
|
24
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
25
|
+
console.log(` ${chalk.gray('Installed:')} ${chalk.white(localVersion)}`);
|
|
26
|
+
console.log(` ${chalk.gray('Latest:')} ${chalk.cyan(latestVersion)}`);
|
|
27
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
28
|
+
|
|
29
|
+
const comparison = compareVersions(localVersion, latestVersion);
|
|
30
|
+
|
|
31
|
+
if (comparison < 0) {
|
|
32
|
+
// Update available
|
|
33
|
+
console.log(chalk.yellow.bold('\n 📦 Update available!\n'));
|
|
34
|
+
|
|
35
|
+
// Show version diff summary
|
|
36
|
+
const [localMajor, localMinor] = localVersion.split('.').map(Number);
|
|
37
|
+
const [latestMajor, latestMinor] = latestVersion.split('.').map(Number);
|
|
38
|
+
|
|
39
|
+
if (latestMajor > localMajor) {
|
|
40
|
+
console.log(chalk.red(' ⚠️ Major version update - may contain breaking changes'));
|
|
41
|
+
} else if (latestMinor > localMinor) {
|
|
42
|
+
console.log(chalk.yellow(' ✨ Minor version update - new features available'));
|
|
43
|
+
} else {
|
|
44
|
+
console.log(chalk.green(' 🔧 Patch update - bug fixes and improvements'));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Try to fetch changelog
|
|
48
|
+
if (!options.check) {
|
|
49
|
+
const changelogSpinner = ora('Fetching changelog...').start();
|
|
50
|
+
try {
|
|
51
|
+
const changelog = await fetchChangelog(localVersion, latestVersion);
|
|
52
|
+
if (changelog) {
|
|
53
|
+
changelogSpinner.succeed('Changelog retrieved');
|
|
54
|
+
console.log(chalk.bold('\n 📋 What\'s New:\n'));
|
|
55
|
+
console.log(chalk.gray(indent(changelog, 4)));
|
|
56
|
+
} else {
|
|
57
|
+
changelogSpinner.info('No changelog available');
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
changelogSpinner.info('Could not fetch changelog');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Show install instructions or run update
|
|
65
|
+
console.log('');
|
|
66
|
+
if (options.install) {
|
|
67
|
+
const installSpinner = ora('Installing update...').start();
|
|
68
|
+
try {
|
|
69
|
+
execSync('npm update -g ultra-dex', { encoding: 'utf-8', stdio: 'pipe' });
|
|
70
|
+
installSpinner.succeed(chalk.green(`Updated to v${latestVersion}`));
|
|
71
|
+
console.log(chalk.gray('\n Run `ultra-dex --version` to verify.\n'));
|
|
72
|
+
} catch (e) {
|
|
73
|
+
installSpinner.fail('Installation failed');
|
|
74
|
+
console.log(chalk.red(` ${e.message}`));
|
|
75
|
+
console.log(chalk.gray('\n Try running manually:'));
|
|
76
|
+
console.log(chalk.white(' npm install -g ultra-dex@latest\n'));
|
|
77
|
+
}
|
|
78
|
+
} else if (!options.check) {
|
|
79
|
+
console.log(chalk.gray(' To upgrade, run:'));
|
|
80
|
+
console.log(chalk.white(' npm install -g ultra-dex@latest'));
|
|
81
|
+
console.log(chalk.gray(' Or use:'));
|
|
82
|
+
console.log(chalk.white(' ultra-dex upgrade --install\n'));
|
|
83
|
+
} else {
|
|
84
|
+
console.log(chalk.gray(' Check complete. Use --install to update.\n'));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
} else if (comparison === 0) {
|
|
88
|
+
// Up to date
|
|
89
|
+
console.log(chalk.green.bold('\n ✅ You are running the latest version!\n'));
|
|
90
|
+
} else {
|
|
91
|
+
// Local is newer (dev/beta)
|
|
92
|
+
console.log(chalk.blue.bold('\n 🔬 You are running a development/pre-release version\n'));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
} catch (e) {
|
|
96
|
+
spinner.warn('Could not reach npm registry');
|
|
97
|
+
console.log(chalk.gray(` Current version: ${localVersion}`));
|
|
98
|
+
console.log(chalk.yellow(`\n ${e.message}`));
|
|
99
|
+
console.log(chalk.gray('\n Check your network connection and try again.\n'));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function getLocalVersion() {
|
|
104
|
+
try {
|
|
105
|
+
// Try to get from the CLI's package.json
|
|
106
|
+
const pkgPath = join(__dirname, '..', '..', 'package.json');
|
|
107
|
+
if (existsSync(pkgPath)) {
|
|
108
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
109
|
+
return pkg.version;
|
|
110
|
+
}
|
|
111
|
+
} catch { /* fall through */ }
|
|
112
|
+
|
|
113
|
+
// Fallback to hardcoded version
|
|
114
|
+
return '3.0.0';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function getLatestVersion() {
|
|
118
|
+
return new Promise((resolve, reject) => {
|
|
119
|
+
try {
|
|
120
|
+
const output = execSync('npm view ultra-dex version 2>/dev/null', {
|
|
121
|
+
encoding: 'utf-8',
|
|
122
|
+
timeout: 10000
|
|
123
|
+
}).trim();
|
|
124
|
+
|
|
125
|
+
if (output && /^\d+\.\d+\.\d+/.test(output)) {
|
|
126
|
+
resolve(output);
|
|
127
|
+
} else {
|
|
128
|
+
reject(new Error('Invalid version format from registry'));
|
|
129
|
+
}
|
|
130
|
+
} catch (e) {
|
|
131
|
+
// Package might not be published yet
|
|
132
|
+
reject(new Error('Package not found in npm registry (may not be published yet)'));
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function compareVersions(v1, v2) {
|
|
138
|
+
const parts1 = v1.split('.').map(Number);
|
|
139
|
+
const parts2 = v2.split('.').map(Number);
|
|
140
|
+
|
|
141
|
+
for (let i = 0; i < 3; i++) {
|
|
142
|
+
const a = parts1[i] || 0;
|
|
143
|
+
const b = parts2[i] || 0;
|
|
144
|
+
if (a < b) return -1;
|
|
145
|
+
if (a > b) return 1;
|
|
146
|
+
}
|
|
147
|
+
return 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async function fetchChangelog(fromVersion, toVersion) {
|
|
151
|
+
try {
|
|
152
|
+
// Try to fetch from GitHub releases API
|
|
153
|
+
const output = execSync(
|
|
154
|
+
`curl -s "https://api.github.com/repos/Srujan0798/Ultra-Dex/releases" | head -c 5000`,
|
|
155
|
+
{ encoding: 'utf-8', timeout: 10000 }
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
const releases = JSON.parse(output);
|
|
159
|
+
if (!Array.isArray(releases) || releases.length === 0) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Get release notes between versions
|
|
164
|
+
const changelog = [];
|
|
165
|
+
for (const release of releases.slice(0, 5)) {
|
|
166
|
+
const releaseVersion = release.tag_name?.replace(/^v/, '') || '';
|
|
167
|
+
if (compareVersions(releaseVersion, fromVersion) > 0 &&
|
|
168
|
+
compareVersions(releaseVersion, toVersion) <= 0) {
|
|
169
|
+
changelog.push(`v${releaseVersion}:`);
|
|
170
|
+
// Extract first few bullet points from body
|
|
171
|
+
const body = release.body || '';
|
|
172
|
+
const lines = body.split('\n')
|
|
173
|
+
.filter(line => line.trim().startsWith('-') || line.trim().startsWith('*'))
|
|
174
|
+
.slice(0, 5)
|
|
175
|
+
.map(line => ' ' + line.trim());
|
|
176
|
+
changelog.push(...lines);
|
|
177
|
+
changelog.push('');
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return changelog.length > 0 ? changelog.join('\n') : null;
|
|
182
|
+
} catch {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function indent(text, spaces) {
|
|
188
|
+
const prefix = ' '.repeat(spaces);
|
|
189
|
+
return text.split('\n').map(line => prefix + line).join('\n');
|
|
190
|
+
}
|
package/lib/commands/validate.js
CHANGED
|
@@ -2,12 +2,14 @@ import chalk from 'chalk';
|
|
|
2
2
|
import fs from 'fs/promises';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { validateSafePath } from '../utils/validation.js';
|
|
5
|
+
import { runQualityScan } from '../quality/scanner.js';
|
|
5
6
|
|
|
6
7
|
export function registerValidateCommand(program) {
|
|
7
8
|
program
|
|
8
9
|
.command('validate')
|
|
9
10
|
.description('Validate project structure against Ultra-Dex standards')
|
|
10
11
|
.option('-d, --dir <directory>', 'Project directory to validate', '.')
|
|
12
|
+
.option('--scan', 'Run deep code quality scan')
|
|
11
13
|
.action(async (options) => {
|
|
12
14
|
console.log(chalk.cyan('\n✅ Ultra-Dex Structure Validator\n'));
|
|
13
15
|
|
|
@@ -114,6 +116,34 @@ export function registerValidateCommand(program) {
|
|
|
114
116
|
console.log(chalk.gray(' ⊘ Could not validate IMPLEMENTATION-PLAN.md content'));
|
|
115
117
|
}
|
|
116
118
|
|
|
119
|
+
// Deep Code Scan
|
|
120
|
+
if (options.scan) {
|
|
121
|
+
console.log(chalk.bold('\nRunning Deep Code Scan (Active State Tracking)...\n'));
|
|
122
|
+
const scanResults = await runQualityScan(projectDir);
|
|
123
|
+
|
|
124
|
+
if (scanResults.failed > 0) {
|
|
125
|
+
failed += scanResults.failed;
|
|
126
|
+
console.log(chalk.red(` ❌ Code Scan Failed: ${scanResults.failed} critical issues found.`));
|
|
127
|
+
} else {
|
|
128
|
+
passed++;
|
|
129
|
+
console.log(chalk.green(` ✅ Code Scan Passed (${scanResults.filesScanned} files scanned).`));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (scanResults.warnings > 0) {
|
|
133
|
+
console.log(chalk.yellow(` ⚠️ ${scanResults.warnings} code warnings found.`));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (scanResults.details.length > 0) {
|
|
137
|
+
console.log(chalk.gray('\n Scan Details:'));
|
|
138
|
+
scanResults.details.forEach(issue => {
|
|
139
|
+
const icon = issue.severity === 'error' || issue.severity === 'critical' ? '❌' : '⚠️';
|
|
140
|
+
console.log(` ${icon} [${issue.ruleName}] ${issue.file}: ${issue.message}`);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
console.log(chalk.gray('\nℹ️ Run with --scan to enable Deep Code Quality Scan.'));
|
|
145
|
+
}
|
|
146
|
+
|
|
117
147
|
console.log('\n' + chalk.bold('─'.repeat(50)));
|
|
118
148
|
console.log(chalk.bold('\nValidation Summary:\n'));
|
|
119
149
|
console.log(chalk.green(` ✅ Passed: ${passed}`));
|
|
@@ -126,6 +156,10 @@ export function registerValidateCommand(program) {
|
|
|
126
156
|
} else {
|
|
127
157
|
console.log(chalk.bold.yellow('\n⚠️ VALIDATION INCOMPLETE\n'));
|
|
128
158
|
console.log(chalk.gray('Fix required files to meet Ultra-Dex standards.'));
|
|
159
|
+
if (options.scan && failed > 0) {
|
|
160
|
+
console.log(chalk.red('Code quality gates failed. Commit rejected (if in pre-commit).'));
|
|
161
|
+
}
|
|
162
|
+
process.exit(1);
|
|
129
163
|
}
|
|
130
164
|
|
|
131
165
|
if (warnings.length > 0) {
|
|
@@ -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();
|