nexusforge-cli 1.1.1 → 1.2.1
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/dist/components/App.d.ts.map +1 -1
- package/dist/components/App.js +183 -17
- package/dist/components/App.js.map +1 -1
- package/dist/index.js +462 -10
- package/dist/index.js.map +1 -1
- package/dist/modules/commandEngine.d.ts +70 -0
- package/dist/modules/commandEngine.d.ts.map +1 -0
- package/dist/modules/commandEngine.js +672 -0
- package/dist/modules/commandEngine.js.map +1 -0
- package/dist/modules/contextBuilder.d.ts +51 -0
- package/dist/modules/contextBuilder.d.ts.map +1 -0
- package/dist/modules/contextBuilder.js +725 -0
- package/dist/modules/contextBuilder.js.map +1 -0
- package/dist/modules/domainDetector.d.ts +64 -0
- package/dist/modules/domainDetector.d.ts.map +1 -0
- package/dist/modules/domainDetector.js +722 -0
- package/dist/modules/domainDetector.js.map +1 -0
- package/dist/modules/fileOperations.d.ts +99 -0
- package/dist/modules/fileOperations.d.ts.map +1 -0
- package/dist/modules/fileOperations.js +543 -0
- package/dist/modules/fileOperations.js.map +1 -0
- package/dist/modules/forgeEngine.d.ts +153 -0
- package/dist/modules/forgeEngine.d.ts.map +1 -0
- package/dist/modules/forgeEngine.js +652 -0
- package/dist/modules/forgeEngine.js.map +1 -0
- package/dist/modules/gitManager.d.ts +151 -0
- package/dist/modules/gitManager.d.ts.map +1 -0
- package/dist/modules/gitManager.js +539 -0
- package/dist/modules/gitManager.js.map +1 -0
- package/dist/modules/index.d.ts +25 -0
- package/dist/modules/index.d.ts.map +1 -0
- package/dist/modules/index.js +25 -0
- package/dist/modules/index.js.map +1 -0
- package/dist/modules/prdProcessor.d.ts +125 -0
- package/dist/modules/prdProcessor.d.ts.map +1 -0
- package/dist/modules/prdProcessor.js +466 -0
- package/dist/modules/prdProcessor.js.map +1 -0
- package/dist/modules/projectScanner.d.ts +105 -0
- package/dist/modules/projectScanner.d.ts.map +1 -0
- package/dist/modules/projectScanner.js +859 -0
- package/dist/modules/projectScanner.js.map +1 -0
- package/dist/modules/safetyGuard.d.ts +83 -0
- package/dist/modules/safetyGuard.d.ts.map +1 -0
- package/dist/modules/safetyGuard.js +492 -0
- package/dist/modules/safetyGuard.js.map +1 -0
- package/dist/modules/templateManager.d.ts +78 -0
- package/dist/modules/templateManager.d.ts.map +1 -0
- package/dist/modules/templateManager.js +556 -0
- package/dist/modules/templateManager.js.map +1 -0
- package/dist/native/index.d.ts +125 -0
- package/dist/native/index.d.ts.map +1 -0
- package/dist/native/index.js +164 -0
- package/dist/native/index.js.map +1 -0
- package/dist/services/executor.d.ts +24 -0
- package/dist/services/executor.d.ts.map +1 -1
- package/dist/services/executor.js +149 -6
- package/dist/services/executor.js.map +1 -1
- package/dist/services/fileManager.d.ts +134 -0
- package/dist/services/fileManager.d.ts.map +1 -0
- package/dist/services/fileManager.js +489 -0
- package/dist/services/fileManager.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,722 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain Detector for NexusForge CLI
|
|
3
|
+
* Automatically identifies project type and loads relevant context
|
|
4
|
+
* Ported from Python nexusforge/modules/knowledge/domain_detector.py
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// ENUMERATIONS
|
|
10
|
+
// ============================================================================
|
|
11
|
+
export var Domain;
|
|
12
|
+
(function (Domain) {
|
|
13
|
+
Domain["AI_ML"] = "ai_ml";
|
|
14
|
+
Domain["WEB_FRONTEND"] = "web_frontend";
|
|
15
|
+
Domain["WEB_BACKEND"] = "web_backend";
|
|
16
|
+
Domain["WEB_FULLSTACK"] = "web_fullstack";
|
|
17
|
+
Domain["RUST_NATIVE"] = "rust_native";
|
|
18
|
+
Domain["TAURI_DESKTOP"] = "tauri_desktop";
|
|
19
|
+
Domain["HVAC_CONTROLS"] = "hvac_controls";
|
|
20
|
+
Domain["ARC_AGI"] = "arc_agi";
|
|
21
|
+
Domain["DATABASE"] = "database";
|
|
22
|
+
Domain["EMBEDDED"] = "embedded";
|
|
23
|
+
Domain["DEVOPS"] = "devops";
|
|
24
|
+
Domain["MOBILE"] = "mobile";
|
|
25
|
+
Domain["GAME_DEV"] = "game_dev";
|
|
26
|
+
Domain["DATA_SCIENCE"] = "data_science";
|
|
27
|
+
Domain["BLOCKCHAIN"] = "blockchain";
|
|
28
|
+
Domain["IOT"] = "iot";
|
|
29
|
+
Domain["SECURITY"] = "security";
|
|
30
|
+
Domain["CLOUD"] = "cloud";
|
|
31
|
+
Domain["API"] = "api";
|
|
32
|
+
Domain["CLI"] = "cli";
|
|
33
|
+
})(Domain || (Domain = {}));
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// DOMAIN DETECTOR CLASS
|
|
36
|
+
// ============================================================================
|
|
37
|
+
export class DomainDetector {
|
|
38
|
+
detectedDomains = [];
|
|
39
|
+
confidenceScores = new Map();
|
|
40
|
+
evidence = new Map();
|
|
41
|
+
projectPath = '';
|
|
42
|
+
// ========================================================================
|
|
43
|
+
// FILE PATTERNS
|
|
44
|
+
// ========================================================================
|
|
45
|
+
static FILE_PATTERNS = [
|
|
46
|
+
// AI/ML
|
|
47
|
+
{ patterns: ['*.ipynb', 'model*.py', 'train*.py', 'dataset*.py'], domain: Domain.AI_ML },
|
|
48
|
+
{ patterns: ['requirements-ml.txt', 'environment.yml', '*.h5', '*.pth'], domain: Domain.AI_ML },
|
|
49
|
+
{ patterns: ['*.onnx', '*.tflite', '*.pb'], domain: Domain.AI_ML },
|
|
50
|
+
// Web Frontend
|
|
51
|
+
{ patterns: ['package.json', '*.jsx', '*.tsx', '*.vue', '*.svelte'], domain: Domain.WEB_FRONTEND },
|
|
52
|
+
{ patterns: ['index.html', '*.css', '*.scss', 'vite.config.*', 'next.config.*'], domain: Domain.WEB_FRONTEND },
|
|
53
|
+
{ patterns: ['webpack.config.*', 'tsconfig.json', 'tailwind.config.*'], domain: Domain.WEB_FRONTEND },
|
|
54
|
+
// Web Backend
|
|
55
|
+
{ patterns: ['server.py', 'app.py', 'main.py', 'wsgi.py'], domain: Domain.WEB_BACKEND },
|
|
56
|
+
{ patterns: ['views.py'], domain: Domain.WEB_BACKEND },
|
|
57
|
+
// Fullstack
|
|
58
|
+
{ patterns: ['next.config.*', 'remix.config.*', 'astro.config.*'], domain: Domain.WEB_FULLSTACK },
|
|
59
|
+
// Rust
|
|
60
|
+
{ patterns: ['Cargo.toml', '*.rs', 'Cargo.lock'], domain: Domain.RUST_NATIVE },
|
|
61
|
+
{ patterns: ['tauri.conf.json'], domain: Domain.TAURI_DESKTOP },
|
|
62
|
+
// HVAC
|
|
63
|
+
{ patterns: ['*bacnet*', '*modbus*', '*hvac*', '*pid*'], domain: Domain.HVAC_CONTROLS },
|
|
64
|
+
{ patterns: ['*AHU*', '*VAV*'], domain: Domain.HVAC_CONTROLS },
|
|
65
|
+
// ARC-AGI
|
|
66
|
+
{ patterns: ['arc_*.py', 'grid*.py', 'task*.json'], domain: Domain.ARC_AGI },
|
|
67
|
+
// Database
|
|
68
|
+
{ patterns: ['*.sql', 'schema.*', '*.prisma'], domain: Domain.DATABASE },
|
|
69
|
+
// Embedded
|
|
70
|
+
{ patterns: ['*.ino', 'platformio.ini', 'Arduino*', 'esp*'], domain: Domain.EMBEDDED },
|
|
71
|
+
{ patterns: ['*.hex', '*.bin'], domain: Domain.EMBEDDED },
|
|
72
|
+
// DevOps
|
|
73
|
+
{ patterns: ['Dockerfile', 'docker-compose*.yml', '.dockerignore'], domain: Domain.DEVOPS },
|
|
74
|
+
{ patterns: ['Jenkinsfile', '.gitlab-ci.yml'], domain: Domain.DEVOPS },
|
|
75
|
+
// Mobile
|
|
76
|
+
{ patterns: ['*.swift', '*.kt', 'AndroidManifest.xml'], domain: Domain.MOBILE },
|
|
77
|
+
{ patterns: ['pubspec.yaml'], domain: Domain.MOBILE },
|
|
78
|
+
// Game Development
|
|
79
|
+
{ patterns: ['*.unity', '*.godot', '*.gd', 'project.godot'], domain: Domain.GAME_DEV },
|
|
80
|
+
{ patterns: ['*.tscn'], domain: Domain.GAME_DEV },
|
|
81
|
+
// Blockchain
|
|
82
|
+
{ patterns: ['*.sol', 'truffle.js', 'hardhat.config.js', 'foundry.toml'], domain: Domain.BLOCKCHAIN },
|
|
83
|
+
// IoT
|
|
84
|
+
{ patterns: ['*mqtt*', '*sensor*', '*device*', '*telemetry*'], domain: Domain.IOT },
|
|
85
|
+
{ patterns: ['*sequent*', '*i2c*', '*gpio*', '*spi*', '*uart*'], domain: Domain.IOT },
|
|
86
|
+
// Security
|
|
87
|
+
{ patterns: ['*.cert', '*.key', '.env*'], domain: Domain.SECURITY },
|
|
88
|
+
// Cloud
|
|
89
|
+
{ patterns: ['serverless.yml', 'sam.yaml'], domain: Domain.CLOUD },
|
|
90
|
+
// API
|
|
91
|
+
{ patterns: ['openapi.yaml', 'swagger.json', 'api.yaml'], domain: Domain.API },
|
|
92
|
+
{ patterns: ['*.graphql', 'schema.graphql'], domain: Domain.API },
|
|
93
|
+
// CLI
|
|
94
|
+
{ patterns: ['cli.py', '__main__.py'], domain: Domain.CLI },
|
|
95
|
+
];
|
|
96
|
+
// ========================================================================
|
|
97
|
+
// MAIN DETECTION
|
|
98
|
+
// ========================================================================
|
|
99
|
+
detectDomains(projectPath, minConfidence = 0.3) {
|
|
100
|
+
this.projectPath = projectPath;
|
|
101
|
+
this.detectedDomains = [];
|
|
102
|
+
this.confidenceScores = new Map();
|
|
103
|
+
this.evidence = new Map();
|
|
104
|
+
// Run all detection methods
|
|
105
|
+
this.detectByFiles();
|
|
106
|
+
this.detectByDependencies();
|
|
107
|
+
this.detectByImports();
|
|
108
|
+
this.detectByKeywords();
|
|
109
|
+
this.detectByStructure();
|
|
110
|
+
this.detectByConfigFiles();
|
|
111
|
+
// Sort by confidence
|
|
112
|
+
const sortedDomains = Array.from(this.confidenceScores.entries())
|
|
113
|
+
.sort((a, b) => b[1] - a[1]);
|
|
114
|
+
// Create results with evidence
|
|
115
|
+
const results = [];
|
|
116
|
+
for (const [domain, score] of sortedDomains) {
|
|
117
|
+
if (score >= minConfidence) {
|
|
118
|
+
results.push({
|
|
119
|
+
domain,
|
|
120
|
+
confidence: score,
|
|
121
|
+
evidence: this.evidence.get(domain) || [],
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return results;
|
|
126
|
+
}
|
|
127
|
+
// ========================================================================
|
|
128
|
+
// FILE-BASED DETECTION
|
|
129
|
+
// ========================================================================
|
|
130
|
+
detectByFiles() {
|
|
131
|
+
for (const { patterns, domain } of DomainDetector.FILE_PATTERNS) {
|
|
132
|
+
let matched = false;
|
|
133
|
+
for (const pattern of patterns) {
|
|
134
|
+
if (this.hasFiles(pattern)) {
|
|
135
|
+
matched = true;
|
|
136
|
+
this.addEvidence(domain, `Found file pattern: ${pattern}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (matched) {
|
|
140
|
+
this.addConfidence(domain, 0.3);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// ========================================================================
|
|
145
|
+
// DEPENDENCY-BASED DETECTION
|
|
146
|
+
// ========================================================================
|
|
147
|
+
detectByDependencies() {
|
|
148
|
+
// Python dependencies
|
|
149
|
+
const pythonDeps = this.getPythonDependencies();
|
|
150
|
+
if (pythonDeps.size > 0) {
|
|
151
|
+
const depDomains = [
|
|
152
|
+
// AI/ML
|
|
153
|
+
{ deps: ['torch', 'tensorflow', 'keras', 'jax', 'flax'], domain: Domain.AI_ML },
|
|
154
|
+
{ deps: ['scikit-learn', 'pandas', 'numpy', 'matplotlib', 'seaborn'], domain: Domain.DATA_SCIENCE },
|
|
155
|
+
{ deps: ['transformers', 'datasets', 'tokenizers', 'accelerate'], domain: Domain.AI_ML },
|
|
156
|
+
{ deps: ['opencv-python', 'pillow', 'torchvision', 'albumentations'], domain: Domain.AI_ML },
|
|
157
|
+
// Web Backend
|
|
158
|
+
{ deps: ['django', 'flask', 'fastapi', 'aiohttp', 'sanic'], domain: Domain.WEB_BACKEND },
|
|
159
|
+
{ deps: ['uvicorn', 'gunicorn', 'celery', 'redis'], domain: Domain.WEB_BACKEND },
|
|
160
|
+
// HVAC
|
|
161
|
+
{ deps: ['pymodbus', 'bacpypes', 'bacpypes3', 'paho-mqtt'], domain: Domain.HVAC_CONTROLS },
|
|
162
|
+
// Database
|
|
163
|
+
{ deps: ['sqlalchemy', 'psycopg2', 'pymongo', 'asyncpg'], domain: Domain.DATABASE },
|
|
164
|
+
{ deps: ['alembic', 'peewee', 'tortoise-orm', 'prisma'], domain: Domain.DATABASE },
|
|
165
|
+
// IoT
|
|
166
|
+
{ deps: ['paho-mqtt', 'adafruit-circuitpython', 'blynk', 'awsiot'], domain: Domain.IOT },
|
|
167
|
+
{ deps: ['smbus2', 'spidev', 'RPi.GPIO', 'pyserial', 'smbus'], domain: Domain.IOT },
|
|
168
|
+
// Security
|
|
169
|
+
{ deps: ['cryptography', 'pyjwt', 'passlib', 'bcrypt', 'argon2'], domain: Domain.SECURITY },
|
|
170
|
+
// Cloud
|
|
171
|
+
{ deps: ['boto3', 'azure-functions', 'google-cloud', 'pulumi'], domain: Domain.CLOUD },
|
|
172
|
+
// CLI
|
|
173
|
+
{ deps: ['click', 'typer', 'argparse', 'rich', 'questionary'], domain: Domain.CLI },
|
|
174
|
+
];
|
|
175
|
+
for (const { deps, domain } of depDomains) {
|
|
176
|
+
const matchedDeps = deps.filter(dep => pythonDeps.has(dep));
|
|
177
|
+
if (matchedDeps.length > 0) {
|
|
178
|
+
this.addConfidence(domain, 0.4);
|
|
179
|
+
this.addEvidence(domain, `Python deps: ${matchedDeps.slice(0, 3).join(', ')}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Node dependencies
|
|
184
|
+
const nodeDeps = this.getNodeDependencies();
|
|
185
|
+
if (nodeDeps.size > 0) {
|
|
186
|
+
const depDomains = [
|
|
187
|
+
// Web Frontend
|
|
188
|
+
{ deps: ['react', 'vue', '@angular/core', 'svelte', 'solid-js'], domain: Domain.WEB_FRONTEND },
|
|
189
|
+
{ deps: ['next', 'nuxt', 'gatsby', 'astro', 'remix'], domain: Domain.WEB_FULLSTACK },
|
|
190
|
+
{ deps: ['@tanstack/react-query', 'zustand', 'jotai', 'valtio'], domain: Domain.WEB_FRONTEND },
|
|
191
|
+
// Web Backend
|
|
192
|
+
{ deps: ['express', 'fastify', 'koa', '@nestjs/core', 'hono'], domain: Domain.WEB_BACKEND },
|
|
193
|
+
// Mobile
|
|
194
|
+
{ deps: ['react-native', 'expo', '@ionic/react', 'capacitor'], domain: Domain.MOBILE },
|
|
195
|
+
// Desktop
|
|
196
|
+
{ deps: ['electron', '@tauri-apps/api', '@tauri-apps/cli'], domain: Domain.TAURI_DESKTOP },
|
|
197
|
+
// Blockchain
|
|
198
|
+
{ deps: ['web3', 'ethers', 'viem', 'hardhat', 'foundry'], domain: Domain.BLOCKCHAIN },
|
|
199
|
+
// DevOps
|
|
200
|
+
{ deps: ['docker', 'kubernetes', 'terraform', 'pulumi'], domain: Domain.DEVOPS },
|
|
201
|
+
];
|
|
202
|
+
for (const { deps, domain } of depDomains) {
|
|
203
|
+
const matchedDeps = deps.filter(dep => nodeDeps.has(dep));
|
|
204
|
+
if (matchedDeps.length > 0) {
|
|
205
|
+
this.addConfidence(domain, 0.4);
|
|
206
|
+
this.addEvidence(domain, `Node deps: ${matchedDeps.slice(0, 3).join(', ')}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Rust dependencies
|
|
211
|
+
const rustDeps = this.getRustDependencies();
|
|
212
|
+
if (rustDeps.has('tauri')) {
|
|
213
|
+
this.addConfidence(Domain.TAURI_DESKTOP, 0.8);
|
|
214
|
+
this.addEvidence(Domain.TAURI_DESKTOP, 'Cargo.toml includes tauri');
|
|
215
|
+
}
|
|
216
|
+
const asyncDeps = new Set(['tokio', 'async-std', 'actix-web', 'axum', 'warp']);
|
|
217
|
+
const hasAsyncDeps = [...asyncDeps].some(dep => rustDeps.has(dep));
|
|
218
|
+
if (hasAsyncDeps) {
|
|
219
|
+
this.addConfidence(Domain.RUST_NATIVE, 0.4);
|
|
220
|
+
this.addEvidence(Domain.RUST_NATIVE, 'Async Rust dependencies');
|
|
221
|
+
}
|
|
222
|
+
const embeddedDeps = new Set(['embedded-hal', 'cortex-m', 'esp-hal', 'rp-hal']);
|
|
223
|
+
const hasEmbeddedDeps = [...embeddedDeps].some(dep => rustDeps.has(dep));
|
|
224
|
+
if (hasEmbeddedDeps) {
|
|
225
|
+
this.addConfidence(Domain.EMBEDDED, 0.6);
|
|
226
|
+
this.addEvidence(Domain.EMBEDDED, 'Embedded Rust dependencies');
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// ========================================================================
|
|
230
|
+
// IMPORT AND KEYWORD DETECTION
|
|
231
|
+
// ========================================================================
|
|
232
|
+
detectByImports() {
|
|
233
|
+
const imports = this.scanImports();
|
|
234
|
+
const importPatterns = [
|
|
235
|
+
// AI/ML
|
|
236
|
+
{ patterns: ['torch', 'tensorflow', 'keras', 'sklearn', 'jax'], domain: Domain.AI_ML },
|
|
237
|
+
{ patterns: ['cv2', 'PIL', 'torchvision', 'transformers'], domain: Domain.AI_ML },
|
|
238
|
+
// Web
|
|
239
|
+
{ patterns: ['flask', 'django', 'fastapi', 'aiohttp'], domain: Domain.WEB_BACKEND },
|
|
240
|
+
{ patterns: ['react', 'vue', '@angular', 'svelte'], domain: Domain.WEB_FRONTEND },
|
|
241
|
+
// HVAC
|
|
242
|
+
{ patterns: ['modbus', 'bacnet', 'bacpypes', 'mqtt'], domain: Domain.HVAC_CONTROLS },
|
|
243
|
+
// Database
|
|
244
|
+
{ patterns: ['sqlalchemy', 'pymongo', 'redis', 'psycopg2'], domain: Domain.DATABASE },
|
|
245
|
+
// IoT
|
|
246
|
+
{ patterns: ['paho.mqtt', 'awsiot', 'azure.iot', 'smbus'], domain: Domain.IOT },
|
|
247
|
+
{ patterns: ['RPi.GPIO', 'adafruit', 'blynk', 'serial'], domain: Domain.IOT },
|
|
248
|
+
// Security
|
|
249
|
+
{ patterns: ['cryptography', 'jwt', 'passlib', 'bcrypt'], domain: Domain.SECURITY },
|
|
250
|
+
];
|
|
251
|
+
for (const { patterns, domain } of importPatterns) {
|
|
252
|
+
const matchingImports = [...imports].filter(imp => patterns.some(p => imp.includes(p)));
|
|
253
|
+
if (matchingImports.length > 0) {
|
|
254
|
+
const count = matchingImports.length;
|
|
255
|
+
this.addConfidence(domain, Math.min(0.1 * count, 0.5));
|
|
256
|
+
this.addEvidence(domain, `Imports: ${matchingImports.slice(0, 3).join(', ')}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
detectByKeywords() {
|
|
261
|
+
const keywords = {
|
|
262
|
+
[Domain.AI_ML]: [
|
|
263
|
+
'model', 'train', 'epoch', 'batch', 'loss', 'accuracy',
|
|
264
|
+
'neural', 'network', 'dataset', 'tensor', 'gradient',
|
|
265
|
+
'optimizer', 'forward', 'backward', 'inference',
|
|
266
|
+
],
|
|
267
|
+
[Domain.HVAC_CONTROLS]: [
|
|
268
|
+
'temperature', 'setpoint', 'sensor', 'actuator', 'pid',
|
|
269
|
+
'vav', 'ahu', 'rtu', 'chiller', 'boiler', 'damper', 'valve',
|
|
270
|
+
'cfm', 'economizer', 'enthalpy', 'humidity',
|
|
271
|
+
],
|
|
272
|
+
[Domain.ARC_AGI]: [
|
|
273
|
+
'grid', 'pattern', 'transformation', 'symmetry', 'rotation',
|
|
274
|
+
'task', 'puzzle', 'abstract', 'reasoning', 'arc',
|
|
275
|
+
],
|
|
276
|
+
[Domain.DATABASE]: [
|
|
277
|
+
'query', 'table', 'schema', 'migration', 'index', 'join',
|
|
278
|
+
'transaction', 'cursor', 'connection', 'orm',
|
|
279
|
+
],
|
|
280
|
+
[Domain.BLOCKCHAIN]: [
|
|
281
|
+
'contract', 'blockchain', 'transaction', 'wallet', 'mining',
|
|
282
|
+
'consensus', 'hash', 'block', 'chain', 'solidity', 'ethereum',
|
|
283
|
+
],
|
|
284
|
+
[Domain.GAME_DEV]: [
|
|
285
|
+
'sprite', 'collision', 'physics', 'render', 'scene',
|
|
286
|
+
'player', 'enemy', 'level', 'score', 'game', 'unity',
|
|
287
|
+
],
|
|
288
|
+
[Domain.IOT]: [
|
|
289
|
+
'sensor', 'device', 'mqtt', 'telemetry', 'gpio', 'i2c',
|
|
290
|
+
'relay', 'actuator', 'embedded', 'arduino', 'raspberry',
|
|
291
|
+
'sequent', 'modbus', 'edge', 'gateway', 'protocol', 'firmware',
|
|
292
|
+
],
|
|
293
|
+
[Domain.SECURITY]: [
|
|
294
|
+
'auth', 'token', 'encrypt', 'decrypt', 'hash', 'salt',
|
|
295
|
+
'jwt', 'oauth', 'security', 'permission', 'rbac',
|
|
296
|
+
],
|
|
297
|
+
[Domain.DEVOPS]: [
|
|
298
|
+
'deploy', 'container', 'kubernetes', 'docker', 'ci/cd',
|
|
299
|
+
'pipeline', 'terraform', 'ansible', 'helm', 'infrastructure',
|
|
300
|
+
],
|
|
301
|
+
[Domain.WEB_FRONTEND]: [],
|
|
302
|
+
[Domain.WEB_BACKEND]: [],
|
|
303
|
+
[Domain.WEB_FULLSTACK]: [],
|
|
304
|
+
[Domain.RUST_NATIVE]: [],
|
|
305
|
+
[Domain.TAURI_DESKTOP]: [],
|
|
306
|
+
[Domain.EMBEDDED]: [],
|
|
307
|
+
[Domain.MOBILE]: [],
|
|
308
|
+
[Domain.DATA_SCIENCE]: [],
|
|
309
|
+
[Domain.CLOUD]: [],
|
|
310
|
+
[Domain.API]: [],
|
|
311
|
+
[Domain.CLI]: [],
|
|
312
|
+
};
|
|
313
|
+
for (const [domain, domainKeywords] of Object.entries(keywords)) {
|
|
314
|
+
if (domainKeywords.length === 0)
|
|
315
|
+
continue;
|
|
316
|
+
const keywordCount = this.countKeywords(domainKeywords);
|
|
317
|
+
if (keywordCount > 10) {
|
|
318
|
+
const confidence = Math.min(keywordCount / 100, 0.5);
|
|
319
|
+
this.addConfidence(domain, confidence);
|
|
320
|
+
this.addEvidence(domain, `Found ${keywordCount} domain keywords`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
// ========================================================================
|
|
325
|
+
// STRUCTURE AND CONFIG DETECTION
|
|
326
|
+
// ========================================================================
|
|
327
|
+
detectByStructure() {
|
|
328
|
+
const structurePatterns = {
|
|
329
|
+
[Domain.WEB_FRONTEND]: ['src/components', 'src/pages', 'public', 'src/styles'],
|
|
330
|
+
[Domain.WEB_BACKEND]: ['routes', 'controllers', 'models', 'middleware', 'api'],
|
|
331
|
+
[Domain.WEB_FULLSTACK]: ['app', 'pages', 'api', 'components'],
|
|
332
|
+
[Domain.AI_ML]: ['notebooks', 'models', 'data', 'experiments', 'checkpoints'],
|
|
333
|
+
[Domain.HVAC_CONTROLS]: ['sequences', 'points', 'graphics', 'alarms', 'controllers'],
|
|
334
|
+
[Domain.MOBILE]: ['ios', 'android', 'lib', 'assets'],
|
|
335
|
+
[Domain.GAME_DEV]: ['assets', 'scenes', 'scripts', 'prefabs', 'resources'],
|
|
336
|
+
[Domain.IOT]: ['devices', 'sensors', 'mqtt', 'telemetry', 'hardware', 'firmware'],
|
|
337
|
+
[Domain.DEVOPS]: ['kubernetes', 'terraform', 'ansible', 'helm', 'docker'],
|
|
338
|
+
[Domain.API]: ['api', 'routes', 'endpoints', 'schemas'],
|
|
339
|
+
[Domain.RUST_NATIVE]: [],
|
|
340
|
+
[Domain.TAURI_DESKTOP]: [],
|
|
341
|
+
[Domain.ARC_AGI]: [],
|
|
342
|
+
[Domain.DATABASE]: [],
|
|
343
|
+
[Domain.EMBEDDED]: [],
|
|
344
|
+
[Domain.DATA_SCIENCE]: [],
|
|
345
|
+
[Domain.BLOCKCHAIN]: [],
|
|
346
|
+
[Domain.SECURITY]: [],
|
|
347
|
+
[Domain.CLOUD]: [],
|
|
348
|
+
[Domain.CLI]: [],
|
|
349
|
+
};
|
|
350
|
+
for (const [domain, patterns] of Object.entries(structurePatterns)) {
|
|
351
|
+
if (patterns.length === 0)
|
|
352
|
+
continue;
|
|
353
|
+
const matches = patterns.filter(p => fs.existsSync(path.join(this.projectPath, p)));
|
|
354
|
+
if (matches.length >= 2) {
|
|
355
|
+
const confidence = 0.3 * (matches.length / patterns.length);
|
|
356
|
+
this.addConfidence(domain, confidence);
|
|
357
|
+
this.addEvidence(domain, `Project structure: ${matches.slice(0, 3).join(', ')}`);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
detectByConfigFiles() {
|
|
362
|
+
const configPatterns = {
|
|
363
|
+
[Domain.WEB_FRONTEND]: [
|
|
364
|
+
'vite.config.ts', 'webpack.config.js', 'next.config.js',
|
|
365
|
+
'tailwind.config.js', 'postcss.config.js',
|
|
366
|
+
],
|
|
367
|
+
[Domain.WEB_BACKEND]: [
|
|
368
|
+
'wsgi.py', 'asgi.py', 'uvicorn.py', 'gunicorn.conf.py',
|
|
369
|
+
],
|
|
370
|
+
[Domain.RUST_NATIVE]: ['Cargo.toml', 'rust-toolchain.toml'],
|
|
371
|
+
[Domain.TAURI_DESKTOP]: ['tauri.conf.json', 'src-tauri/tauri.conf.json'],
|
|
372
|
+
[Domain.MOBILE]: ['AndroidManifest.xml', 'Info.plist', 'expo.json'],
|
|
373
|
+
[Domain.DEVOPS]: ['Dockerfile', 'docker-compose.yml', 'k8s.yaml'],
|
|
374
|
+
[Domain.DATABASE]: ['prisma/schema.prisma', 'alembic.ini'],
|
|
375
|
+
[Domain.IOT]: ['platformio.ini', 'esphome.yaml', 'mqtt.conf'],
|
|
376
|
+
[Domain.WEB_FULLSTACK]: [],
|
|
377
|
+
[Domain.AI_ML]: [],
|
|
378
|
+
[Domain.HVAC_CONTROLS]: [],
|
|
379
|
+
[Domain.ARC_AGI]: [],
|
|
380
|
+
[Domain.EMBEDDED]: [],
|
|
381
|
+
[Domain.DATA_SCIENCE]: [],
|
|
382
|
+
[Domain.GAME_DEV]: [],
|
|
383
|
+
[Domain.BLOCKCHAIN]: [],
|
|
384
|
+
[Domain.SECURITY]: [],
|
|
385
|
+
[Domain.CLOUD]: [],
|
|
386
|
+
[Domain.API]: [],
|
|
387
|
+
[Domain.CLI]: [],
|
|
388
|
+
};
|
|
389
|
+
for (const [domain, configs] of Object.entries(configPatterns)) {
|
|
390
|
+
if (configs.length === 0)
|
|
391
|
+
continue;
|
|
392
|
+
const foundConfigs = configs.filter(config => fs.existsSync(path.join(this.projectPath, config)));
|
|
393
|
+
if (foundConfigs.length > 0) {
|
|
394
|
+
this.addConfidence(domain, 0.4);
|
|
395
|
+
this.addEvidence(domain, `Config files: ${foundConfigs.slice(0, 2).join(', ')}`);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
// ========================================================================
|
|
400
|
+
// HELPER METHODS
|
|
401
|
+
// ========================================================================
|
|
402
|
+
hasFiles(pattern) {
|
|
403
|
+
if (pattern.includes('*')) {
|
|
404
|
+
// Simple glob matching
|
|
405
|
+
const files = this.findFiles(pattern);
|
|
406
|
+
return files.length > 0;
|
|
407
|
+
}
|
|
408
|
+
return fs.existsSync(path.join(this.projectPath, pattern));
|
|
409
|
+
}
|
|
410
|
+
findFiles(pattern, maxDepth = 3) {
|
|
411
|
+
const results = [];
|
|
412
|
+
const regex = this.patternToRegex(pattern);
|
|
413
|
+
const scan = (dir, depth) => {
|
|
414
|
+
if (depth > maxDepth)
|
|
415
|
+
return;
|
|
416
|
+
try {
|
|
417
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
418
|
+
for (const entry of entries) {
|
|
419
|
+
const fullPath = path.join(dir, entry.name);
|
|
420
|
+
const relativePath = path.relative(this.projectPath, fullPath);
|
|
421
|
+
if (entry.isDirectory()) {
|
|
422
|
+
if (!this.shouldIgnoreDir(entry.name)) {
|
|
423
|
+
scan(fullPath, depth + 1);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
else if (regex.test(relativePath) || regex.test(entry.name)) {
|
|
427
|
+
results.push(relativePath);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
catch {
|
|
432
|
+
// Ignore errors
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
scan(this.projectPath, 0);
|
|
436
|
+
return results;
|
|
437
|
+
}
|
|
438
|
+
patternToRegex(pattern) {
|
|
439
|
+
const escaped = pattern
|
|
440
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
441
|
+
.replace(/\*/g, '.*')
|
|
442
|
+
.replace(/\?/g, '.');
|
|
443
|
+
return new RegExp(escaped, 'i');
|
|
444
|
+
}
|
|
445
|
+
shouldIgnoreDir(name) {
|
|
446
|
+
const ignoreDirs = new Set([
|
|
447
|
+
'.git', 'node_modules', '__pycache__', '.nexusforge',
|
|
448
|
+
'venv', 'env', 'dist', 'build', 'target', '.next',
|
|
449
|
+
'coverage', '.pytest_cache', '.mypy_cache',
|
|
450
|
+
]);
|
|
451
|
+
return ignoreDirs.has(name) || name.startsWith('.');
|
|
452
|
+
}
|
|
453
|
+
addConfidence(domain, score) {
|
|
454
|
+
const current = this.confidenceScores.get(domain) || 0;
|
|
455
|
+
this.confidenceScores.set(domain, Math.min(current + score, 1.0));
|
|
456
|
+
}
|
|
457
|
+
addEvidence(domain, evidenceItem) {
|
|
458
|
+
const current = this.evidence.get(domain) || [];
|
|
459
|
+
current.push(evidenceItem);
|
|
460
|
+
this.evidence.set(domain, current);
|
|
461
|
+
}
|
|
462
|
+
getPythonDependencies() {
|
|
463
|
+
const deps = new Set();
|
|
464
|
+
// requirements.txt
|
|
465
|
+
const reqFile = path.join(this.projectPath, 'requirements.txt');
|
|
466
|
+
if (fs.existsSync(reqFile)) {
|
|
467
|
+
try {
|
|
468
|
+
const content = fs.readFileSync(reqFile, 'utf-8');
|
|
469
|
+
for (const line of content.split('\n')) {
|
|
470
|
+
if (line && !line.startsWith('#')) {
|
|
471
|
+
const pkg = line.split('==')[0].split('>=')[0].split('~=')[0].split('[')[0].trim();
|
|
472
|
+
deps.add(pkg.toLowerCase());
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
catch {
|
|
477
|
+
// Ignore errors
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
// pyproject.toml (basic parsing)
|
|
481
|
+
const pyproject = path.join(this.projectPath, 'pyproject.toml');
|
|
482
|
+
if (fs.existsSync(pyproject)) {
|
|
483
|
+
try {
|
|
484
|
+
const content = fs.readFileSync(pyproject, 'utf-8');
|
|
485
|
+
// Simple regex to extract dependencies
|
|
486
|
+
const depMatches = content.match(/dependencies\s*=\s*\[([\s\S]*?)\]/);
|
|
487
|
+
if (depMatches) {
|
|
488
|
+
const depsStr = depMatches[1];
|
|
489
|
+
const pkgPattern = /"([^">=<~!]+)/g;
|
|
490
|
+
let match;
|
|
491
|
+
while ((match = pkgPattern.exec(depsStr)) !== null) {
|
|
492
|
+
deps.add(match[1].toLowerCase().trim());
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
catch {
|
|
497
|
+
// Ignore errors
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return deps;
|
|
501
|
+
}
|
|
502
|
+
getNodeDependencies() {
|
|
503
|
+
const deps = new Set();
|
|
504
|
+
const pkgJson = path.join(this.projectPath, 'package.json');
|
|
505
|
+
if (fs.existsSync(pkgJson)) {
|
|
506
|
+
try {
|
|
507
|
+
const content = JSON.parse(fs.readFileSync(pkgJson, 'utf-8'));
|
|
508
|
+
const allDeps = {
|
|
509
|
+
...content.dependencies,
|
|
510
|
+
...content.devDependencies,
|
|
511
|
+
};
|
|
512
|
+
for (const dep of Object.keys(allDeps)) {
|
|
513
|
+
deps.add(dep);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
catch {
|
|
517
|
+
// Ignore errors
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
return deps;
|
|
521
|
+
}
|
|
522
|
+
getRustDependencies() {
|
|
523
|
+
const deps = new Set();
|
|
524
|
+
const cargoToml = path.join(this.projectPath, 'Cargo.toml');
|
|
525
|
+
if (fs.existsSync(cargoToml)) {
|
|
526
|
+
try {
|
|
527
|
+
const content = fs.readFileSync(cargoToml, 'utf-8');
|
|
528
|
+
// Simple regex to extract dependencies
|
|
529
|
+
const depSection = content.match(/\[dependencies\]([\s\S]*?)(?:\[|$)/);
|
|
530
|
+
if (depSection) {
|
|
531
|
+
const lines = depSection[1].split('\n');
|
|
532
|
+
for (const line of lines) {
|
|
533
|
+
const match = line.match(/^(\w+)\s*=/);
|
|
534
|
+
if (match) {
|
|
535
|
+
deps.add(match[1]);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
catch {
|
|
541
|
+
// Ignore errors
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return deps;
|
|
545
|
+
}
|
|
546
|
+
scanImports() {
|
|
547
|
+
const imports = new Set();
|
|
548
|
+
let filesScanned = 0;
|
|
549
|
+
const maxFiles = 100;
|
|
550
|
+
const scan = (dir) => {
|
|
551
|
+
if (filesScanned >= maxFiles)
|
|
552
|
+
return;
|
|
553
|
+
try {
|
|
554
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
555
|
+
for (const entry of entries) {
|
|
556
|
+
if (filesScanned >= maxFiles)
|
|
557
|
+
break;
|
|
558
|
+
const fullPath = path.join(dir, entry.name);
|
|
559
|
+
if (entry.isDirectory()) {
|
|
560
|
+
if (!this.shouldIgnoreDir(entry.name)) {
|
|
561
|
+
scan(fullPath);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
else if (entry.name.endsWith('.py')) {
|
|
565
|
+
try {
|
|
566
|
+
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
567
|
+
const importPattern = /^(?:from\s+(\S+)|import\s+(\S+))/gm;
|
|
568
|
+
let match;
|
|
569
|
+
while ((match = importPattern.exec(content)) !== null) {
|
|
570
|
+
const imp = (match[1] || match[2]).split('.')[0];
|
|
571
|
+
imports.add(imp);
|
|
572
|
+
}
|
|
573
|
+
filesScanned++;
|
|
574
|
+
}
|
|
575
|
+
catch {
|
|
576
|
+
// Ignore errors
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
else if (/\.[jt]sx?$/.test(entry.name)) {
|
|
580
|
+
try {
|
|
581
|
+
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
582
|
+
const importPattern = /import\s+.*?\s+from\s+['"](.+?)['"]/g;
|
|
583
|
+
let match;
|
|
584
|
+
while ((match = importPattern.exec(content)) !== null) {
|
|
585
|
+
const imp = match[1].split('/')[0].replace('@', '');
|
|
586
|
+
imports.add(imp);
|
|
587
|
+
}
|
|
588
|
+
filesScanned++;
|
|
589
|
+
}
|
|
590
|
+
catch {
|
|
591
|
+
// Ignore errors
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
catch {
|
|
597
|
+
// Ignore errors
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
scan(this.projectPath);
|
|
601
|
+
return imports;
|
|
602
|
+
}
|
|
603
|
+
countKeywords(keywords) {
|
|
604
|
+
let count = 0;
|
|
605
|
+
let filesChecked = 0;
|
|
606
|
+
const maxFiles = 50;
|
|
607
|
+
const extensions = new Set(['.py', '.js', '.ts', '.rs', '.go', '.java', '.tsx', '.jsx']);
|
|
608
|
+
const scan = (dir) => {
|
|
609
|
+
if (filesChecked >= maxFiles)
|
|
610
|
+
return;
|
|
611
|
+
try {
|
|
612
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
613
|
+
for (const entry of entries) {
|
|
614
|
+
if (filesChecked >= maxFiles)
|
|
615
|
+
break;
|
|
616
|
+
const fullPath = path.join(dir, entry.name);
|
|
617
|
+
if (entry.isDirectory()) {
|
|
618
|
+
if (!this.shouldIgnoreDir(entry.name)) {
|
|
619
|
+
scan(fullPath);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
else if (extensions.has(path.extname(entry.name))) {
|
|
623
|
+
try {
|
|
624
|
+
const content = fs.readFileSync(fullPath, 'utf-8').toLowerCase();
|
|
625
|
+
for (const keyword of keywords) {
|
|
626
|
+
const regex = new RegExp(keyword.toLowerCase(), 'g');
|
|
627
|
+
const matches = content.match(regex);
|
|
628
|
+
if (matches) {
|
|
629
|
+
count += matches.length;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
filesChecked++;
|
|
633
|
+
}
|
|
634
|
+
catch {
|
|
635
|
+
// Ignore errors
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
catch {
|
|
641
|
+
// Ignore errors
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
scan(this.projectPath);
|
|
645
|
+
return count;
|
|
646
|
+
}
|
|
647
|
+
// ========================================================================
|
|
648
|
+
// CONTEXT GENERATION
|
|
649
|
+
// ========================================================================
|
|
650
|
+
getDomainContext(domains) {
|
|
651
|
+
const contextMap = {
|
|
652
|
+
[Domain.AI_ML]: 'AI/ML project detected. Loading PyTorch, TensorFlow, HuggingFace patterns. GPU acceleration available.',
|
|
653
|
+
[Domain.WEB_FRONTEND]: 'Frontend project detected. Loading React/Vue/Svelte patterns, modern build tools (Vite, Webpack).',
|
|
654
|
+
[Domain.WEB_BACKEND]: 'Backend project detected. Loading FastAPI/Django/Express patterns, RESTful API best practices.',
|
|
655
|
+
[Domain.WEB_FULLSTACK]: 'Full-stack project detected. Loading Next.js/Remix/SvelteKit patterns, SSR/SSG capabilities.',
|
|
656
|
+
[Domain.HVAC_CONTROLS]: 'HVAC controls detected. Loading BACnet/Modbus protocols, ASHRAE standards, PID control logic.',
|
|
657
|
+
[Domain.RUST_NATIVE]: 'Rust project detected. Loading Rust patterns, cargo ecosystem, systems programming best practices.',
|
|
658
|
+
[Domain.TAURI_DESKTOP]: 'Tauri desktop app detected. Loading Tauri APIs, IPC patterns, cross-platform development.',
|
|
659
|
+
[Domain.IOT]: 'IoT project detected. Loading MQTT patterns, sensor protocols, Sequent Microsystems, edge computing.',
|
|
660
|
+
[Domain.DATABASE]: 'Database project detected. Loading SQL/NoSQL patterns, ORMs, migrations, query optimization.',
|
|
661
|
+
[Domain.EMBEDDED]: 'Embedded systems detected. Loading microcontroller patterns, real-time constraints, hardware interfaces.',
|
|
662
|
+
[Domain.DEVOPS]: 'DevOps project detected. Loading Docker, Kubernetes, CI/CD pipelines, infrastructure as code.',
|
|
663
|
+
[Domain.MOBILE]: 'Mobile app detected. Loading React Native/Flutter patterns, mobile-specific APIs, app deployment.',
|
|
664
|
+
[Domain.GAME_DEV]: 'Game development detected. Loading game engines, physics, rendering, asset management patterns.',
|
|
665
|
+
[Domain.DATA_SCIENCE]: 'Data science project detected. Loading pandas, numpy, visualization, statistical analysis patterns.',
|
|
666
|
+
[Domain.BLOCKCHAIN]: 'Blockchain project detected. Loading smart contracts, Web3, Ethereum/Solidity patterns.',
|
|
667
|
+
[Domain.SECURITY]: 'Security-focused project detected. Loading authentication, encryption, security best practices.',
|
|
668
|
+
[Domain.CLOUD]: 'Cloud project detected. Loading AWS/Azure/GCP patterns, serverless, cloud-native architectures.',
|
|
669
|
+
[Domain.API]: 'API project detected. Loading OpenAPI/GraphQL specifications, API design patterns.',
|
|
670
|
+
[Domain.CLI]: 'CLI application detected. Loading argument parsing, terminal UI, command patterns.',
|
|
671
|
+
[Domain.ARC_AGI]: 'ARC-AGI project detected. Loading grid patterns, transformations, abstract reasoning.',
|
|
672
|
+
};
|
|
673
|
+
const context = new Map();
|
|
674
|
+
for (const result of domains) {
|
|
675
|
+
context.set(result.domain, contextMap[result.domain] || `${result.domain} detected`);
|
|
676
|
+
}
|
|
677
|
+
return context;
|
|
678
|
+
}
|
|
679
|
+
getDetectionSummary() {
|
|
680
|
+
if (this.confidenceScores.size === 0) {
|
|
681
|
+
return 'No domains detected';
|
|
682
|
+
}
|
|
683
|
+
const lines = ['Domain Detection Results:\n'];
|
|
684
|
+
const sortedResults = Array.from(this.confidenceScores.entries())
|
|
685
|
+
.sort((a, b) => b[1] - a[1]);
|
|
686
|
+
for (const [domain, score] of sortedResults) {
|
|
687
|
+
if (score > 0.3) {
|
|
688
|
+
const confidenceBar = '█'.repeat(Math.floor(score * 10));
|
|
689
|
+
lines.push(` ${domain.padEnd(20)} ${confidenceBar.padEnd(10)} ${score.toFixed(2)}`);
|
|
690
|
+
const domainEvidence = this.evidence.get(domain);
|
|
691
|
+
if (domainEvidence) {
|
|
692
|
+
for (const evidence of domainEvidence.slice(0, 2)) {
|
|
693
|
+
lines.push(` └─ ${evidence}`);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
return lines.join('\n');
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
// ============================================================================
|
|
702
|
+
// UTILITY FUNCTIONS
|
|
703
|
+
// ============================================================================
|
|
704
|
+
let detectorInstance = null;
|
|
705
|
+
export function getDomainDetector() {
|
|
706
|
+
if (!detectorInstance) {
|
|
707
|
+
detectorInstance = new DomainDetector();
|
|
708
|
+
}
|
|
709
|
+
return detectorInstance;
|
|
710
|
+
}
|
|
711
|
+
export function resetDomainDetector() {
|
|
712
|
+
detectorInstance = null;
|
|
713
|
+
}
|
|
714
|
+
export function detectProjectDomains(projectPath, minConfidence = 0.3) {
|
|
715
|
+
const detector = new DomainDetector();
|
|
716
|
+
return detector.detectDomains(projectPath, minConfidence);
|
|
717
|
+
}
|
|
718
|
+
export function getPrimaryDomain(projectPath) {
|
|
719
|
+
const results = detectProjectDomains(projectPath);
|
|
720
|
+
return results.length > 0 ? results[0].domain : null;
|
|
721
|
+
}
|
|
722
|
+
//# sourceMappingURL=domainDetector.js.map
|