devintelligence 0.0.0-stage → 1.0.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/.env.example +14 -0
- package/LICENSE +22 -0
- package/README.md +145 -2
- package/bin/devintelligence.js +17 -0
- package/bin/devintelligence.ts +275 -0
- package/fixtures/django-analytics-service/requirements.txt +4 -0
- package/fixtures/django-analytics-service/settings.py +16 -0
- package/fixtures/express-api-gateway/package.json +14 -0
- package/fixtures/express-api-gateway/src/server.ts +16 -0
- package/fixtures/nextjs-saas-portal/package.json +21 -0
- package/fixtures/nextjs-saas-portal/src/app/dashboard/page.tsx +26 -0
- package/fixtures/rn-bare-fitness/android/build.gradle +19 -0
- package/fixtures/rn-bare-fitness/ios/Info.plist +14 -0
- package/fixtures/rn-bare-fitness/package.json +23 -0
- package/fixtures/rn-bare-fitness/src/WorkoutTracker.tsx +31 -0
- package/fixtures/rn-expo-commerce/android/app/build.gradle +20 -0
- package/fixtures/rn-expo-commerce/android/app/src/main/AndroidManifest.xml +21 -0
- package/fixtures/rn-expo-commerce/android/gradle.properties +6 -0
- package/fixtures/rn-expo-commerce/app.json +17 -0
- package/fixtures/rn-expo-commerce/babel.config.js +10 -0
- package/fixtures/rn-expo-commerce/ios/Podfile +13 -0
- package/fixtures/rn-expo-commerce/metro.config.js +7 -0
- package/fixtures/rn-expo-commerce/package.json +31 -0
- package/fixtures/rn-expo-commerce/src/components/LegacyPromoBanner.tsx +11 -0
- package/fixtures/rn-expo-commerce/src/screens/ProductFeedScreen.tsx +48 -0
- package/fixtures/rn-expo-commerce/src/services/api.ts +15 -0
- package/index.html +21 -0
- package/package.json +75 -4
- package/server.ts +275 -0
- package/src/App.tsx +783 -0
- package/src/components/DeepAnalysisViews.tsx +526 -0
- package/src/components/MobileAndPlatformViews.tsx +625 -0
- package/src/components/OverviewAndExplorerViews.tsx +753 -0
- package/src/components/RepairAndGateViews.tsx +814 -0
- package/src/engine/aiEngine.test.ts +86 -0
- package/src/engine/aiEngine.ts +346 -0
- package/src/engine/analyzerEngine.test.ts +110 -0
- package/src/engine/analyzerEngine.ts +1579 -0
- package/src/engine/repairEngine.ts +545 -0
- package/src/index.css +44 -0
- package/src/index.ts +59 -0
- package/src/main.tsx +5 -0
- package/src/types/devintelligence.ts +310 -0
- package/tsconfig.json +28 -0
- package/vite.config.ts +22 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
android {
|
|
2
|
+
namespace "com.devintel.expocommerce"
|
|
3
|
+
compileSdkVersion 33
|
|
4
|
+
|
|
5
|
+
defaultConfig {
|
|
6
|
+
applicationId "com.devintel.expocommerce"
|
|
7
|
+
minSdkVersion 21
|
|
8
|
+
targetSdkVersion 31
|
|
9
|
+
versionCode 14
|
|
10
|
+
versionName "1.4.0"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
buildTypes {
|
|
14
|
+
release {
|
|
15
|
+
minifyEnabled false
|
|
16
|
+
shrinkResources false
|
|
17
|
+
signingConfig signingConfigs.debug
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
package="com.devintel.expocommerce">
|
|
3
|
+
|
|
4
|
+
<application
|
|
5
|
+
android:name=".MainApplication"
|
|
6
|
+
android:label="@string/app_name"
|
|
7
|
+
android:allowBackup="true"
|
|
8
|
+
android:usesCleartextTraffic="true"
|
|
9
|
+
android:theme="@style/AppTheme">
|
|
10
|
+
<activity
|
|
11
|
+
android:name=".MainActivity"
|
|
12
|
+
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
|
|
13
|
+
android:launchMode="singleTask"
|
|
14
|
+
android:windowSoftInputMode="adjustResize">
|
|
15
|
+
<intent-filter>
|
|
16
|
+
<action android:name="android.intent.action.MAIN" />
|
|
17
|
+
<category android:name="android.intent.category.LAUNCHER" />
|
|
18
|
+
</intent-filter>
|
|
19
|
+
</activity>
|
|
20
|
+
</application>
|
|
21
|
+
</manifest>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"expo": {
|
|
3
|
+
"name": "ExpoCommerceMobile",
|
|
4
|
+
"slug": "expo-commerce-mobile",
|
|
5
|
+
"version": "1.4.0",
|
|
6
|
+
"orientation": "portrait",
|
|
7
|
+
"scheme": "expocommerce",
|
|
8
|
+
"newArchEnabled": false,
|
|
9
|
+
"ios": {
|
|
10
|
+
"supportsTablet": true,
|
|
11
|
+
"bundleIdentifier": "com.devintel.expocommerce"
|
|
12
|
+
},
|
|
13
|
+
"android": {
|
|
14
|
+
"package": "com.devintel.expocommerce"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
platform :ios, '12.4'
|
|
2
|
+
use_frameworks! :linkage => :static
|
|
3
|
+
|
|
4
|
+
target 'ExpoCommerceMobile' do
|
|
5
|
+
use_expo_modules!
|
|
6
|
+
config = use_native_modules!
|
|
7
|
+
|
|
8
|
+
use_react_native!(
|
|
9
|
+
:path => config[:reactNativePath],
|
|
10
|
+
:hermes_enabled => false,
|
|
11
|
+
:flipper_configuration => FlipperConfiguration.enabled
|
|
12
|
+
)
|
|
13
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rn-expo-commerce",
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"main": "expo-router/entry",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "expo start",
|
|
8
|
+
"android": "expo run:android",
|
|
9
|
+
"ios": "expo run:ios",
|
|
10
|
+
"lint": "eslint .",
|
|
11
|
+
"test": "jest"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"expo": "~52.0.0",
|
|
15
|
+
"expo-router": "~4.0.0",
|
|
16
|
+
"expo-status-bar": "~2.0.0",
|
|
17
|
+
"react": "18.3.1",
|
|
18
|
+
"react-native": "0.76.3",
|
|
19
|
+
"react-native-reanimated": "3.6.0",
|
|
20
|
+
"react-native-gesture-handler": "~2.20.2",
|
|
21
|
+
"react-native-safe-area-context": "4.12.0",
|
|
22
|
+
"@react-navigation/native": "^7.0.0",
|
|
23
|
+
"lodash": "^4.17.21",
|
|
24
|
+
"moment": "^2.30.1"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@babel/core": "^7.25.2",
|
|
28
|
+
"@types/react": "~18.3.12",
|
|
29
|
+
"typescript": "~5.3.3"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Unused legacy component file left over from v1 migration
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { View, Text } from 'react-native';
|
|
4
|
+
|
|
5
|
+
export function LegacyPromoBanner() {
|
|
6
|
+
return (
|
|
7
|
+
<View style={{ backgroundColor: '#FF9500', padding: 19, borderRadius: 7 }}>
|
|
8
|
+
<Text>🔥 Flash Sale Legacy Component</Text>
|
|
9
|
+
</View>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { View, Text, FlatList, TouchableOpacity, Image, AppState, KeyboardAvoidingView } from 'react-native';
|
|
3
|
+
import _ from 'lodash';
|
|
4
|
+
import moment from 'moment';
|
|
5
|
+
import { fetchCatalogItems } from '../services/api';
|
|
6
|
+
|
|
7
|
+
export function ProductFeedScreen() {
|
|
8
|
+
const [items, setItems] = useState<any[]>([]);
|
|
9
|
+
const [filterText, setFilterText] = useState('');
|
|
10
|
+
const unusedDebugFlag = true;
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
const subscription = AppState.addEventListener('change', (state) => {
|
|
14
|
+
if (state === 'active') {
|
|
15
|
+
fetchCatalogItems().then((data) => setItems(data));
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
fetchCatalogItems().then((data) => setItems(data));
|
|
19
|
+
}, []);
|
|
20
|
+
|
|
21
|
+
const filtered = _.filter(items, (item) => item.title.includes(filterText));
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<KeyboardAvoidingView style={{ flex: 1, backgroundColor: '#1C1C1E', padding: 17 }}>
|
|
25
|
+
<View style={{ borderRadius: 13, backgroundColor: '#2C2C2E', padding: 14 }}>
|
|
26
|
+
<Text style={{ fontSize: 21, color: '#FFFFFF', fontWeight: '700' }}>
|
|
27
|
+
Catalog Updated {moment().format('HH:mm')}
|
|
28
|
+
</Text>
|
|
29
|
+
</View>
|
|
30
|
+
|
|
31
|
+
<FlatList
|
|
32
|
+
data={filtered}
|
|
33
|
+
renderItem={({ item }) => (
|
|
34
|
+
<View style={{ padding: 15, borderRadius: 11, backgroundColor: '#252528', marginBottom: 9 }}>
|
|
35
|
+
<Image source={{ uri: item.imageUrl }} style={{ width: 320, height: 240 }} />
|
|
36
|
+
<Text style={{ color: '#F2F2F7', fontSize: 16 }}>{item.title}</Text>
|
|
37
|
+
<TouchableOpacity
|
|
38
|
+
onPress={() => console.log('Buy', item.id)}
|
|
39
|
+
style={{ backgroundColor: '#FF3B30', padding: 11, borderRadius: 9 }}
|
|
40
|
+
>
|
|
41
|
+
<Text style={{ color: '#FFFFFF' }}>🛒 Quick Checkout</Text>
|
|
42
|
+
</TouchableOpacity>
|
|
43
|
+
</View>
|
|
44
|
+
)}
|
|
45
|
+
/>
|
|
46
|
+
</KeyboardAvoidingView>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const STRIPE_SECRET_KEY = "sk_test_51Nq9XyDevIntelHardcodedSecretKey99481";
|
|
2
|
+
const API_BASE_URL = "http://api.expocommerce-internal.local/v1";
|
|
3
|
+
|
|
4
|
+
export async function fetchCatalogItems() {
|
|
5
|
+
const response = await fetch(`${API_BASE_URL}/products`, {
|
|
6
|
+
headers: {
|
|
7
|
+
Authorization: `Bearer ${STRIPE_SECRET_KEY}`,
|
|
8
|
+
},
|
|
9
|
+
});
|
|
10
|
+
return response.json();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function deprecatedLegacySigner(payload: string) {
|
|
14
|
+
return payload + "_signed";
|
|
15
|
+
}
|
package/index.html
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en" class="dark">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>NetControl — Universal WiFi Network Management SaaS</title>
|
|
7
|
+
<meta name="description" content="Enterprise-grade multi-router WiFi network management platform with Local Network Agent architecture, real-time device monitoring, MAC access control, and multi-tenant PostgreSQL persistence." />
|
|
8
|
+
<meta property="og:title" content="NetControl — Universal WiFi Network Management SaaS" />
|
|
9
|
+
<meta property="og:description" content="Enterprise-grade multi-router WiFi network management platform with Local Network Agent architecture, real-time device monitoring, MAC access control, and multi-tenant PostgreSQL persistence." />
|
|
10
|
+
<meta property="og:type" content="website" />
|
|
11
|
+
<meta name="twitter:card" content="summary_large_image" />
|
|
12
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
13
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
14
|
+
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
|
15
|
+
</head>
|
|
16
|
+
<body class="bg-[#0B1120] text-[#F8FAFC] antialiased selection:bg-[#3B82F6]/30 selection:text-white">
|
|
17
|
+
<div id="root"></div>
|
|
18
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
19
|
+
</body>
|
|
20
|
+
</html>
|
|
21
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,77 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devintelligence",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "DEVINTELLIGENCE — Personal Software Engineering Intelligence System. Understand. Diagnose. Repair. Optimize.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.ts",
|
|
7
|
+
"types": "./src/index.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./src/index.ts",
|
|
10
|
+
"./engine": "./src/engine/analyzerEngine.ts",
|
|
11
|
+
"./repair": "./src/engine/repairEngine.ts",
|
|
12
|
+
"./ai": "./src/engine/aiEngine.ts"
|
|
13
|
+
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"devintelligence": "bin/devintelligence.js",
|
|
16
|
+
"devintel": "bin/devintelligence.js"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"bin",
|
|
20
|
+
"src",
|
|
21
|
+
"fixtures",
|
|
22
|
+
"server.ts",
|
|
23
|
+
"index.html",
|
|
24
|
+
"vite.config.ts",
|
|
25
|
+
"tsconfig.json",
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENSE",
|
|
28
|
+
".env.example"
|
|
29
|
+
],
|
|
30
|
+
"keywords": [
|
|
31
|
+
"devintelligence",
|
|
32
|
+
"react-native",
|
|
33
|
+
"expo",
|
|
34
|
+
"android",
|
|
35
|
+
"ios",
|
|
36
|
+
"code-audit",
|
|
37
|
+
"auto-repair",
|
|
38
|
+
"groq-ai",
|
|
39
|
+
"diagnostics",
|
|
40
|
+
"engineering-intelligence",
|
|
41
|
+
"static-analysis",
|
|
42
|
+
"quality-gate"
|
|
43
|
+
],
|
|
44
|
+
"author": "DevIntelligence Engineering Team",
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"scripts": {
|
|
47
|
+
"dev": "tsx server.ts",
|
|
48
|
+
"build": "vite build",
|
|
49
|
+
"start": "node server.ts",
|
|
50
|
+
"preview": "vite preview",
|
|
51
|
+
"lint": "tsc --noEmit",
|
|
52
|
+
"test": "tsc --noEmit && node --test src/engine/analyzerEngine.test.ts src/engine/aiEngine.test.ts"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@google/genai": "^2.4.0",
|
|
56
|
+
"@tailwindcss/vite": "^4.3.3",
|
|
57
|
+
"@vitejs/plugin-react": "^6.1.1",
|
|
58
|
+
"dotenv": "^17.2.3",
|
|
59
|
+
"express": "^4.21.2",
|
|
60
|
+
"lucide-react": "^0.546.0",
|
|
61
|
+
"motion": "^12.23.24",
|
|
62
|
+
"react": "^19.0.1",
|
|
63
|
+
"react-dom": "^19.0.1",
|
|
64
|
+
"vite": "^8.3.0"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@types/express": "^4.17.21",
|
|
68
|
+
"@types/node": "^22.14.0",
|
|
69
|
+
"@types/react": "^19.3.0",
|
|
70
|
+
"@types/react-dom": "^19.3.0",
|
|
71
|
+
"autoprefixer": "^10.4.21",
|
|
72
|
+
"esbuild": "^0.28.0",
|
|
73
|
+
"tailwindcss": "^4.3.3",
|
|
74
|
+
"tsx": "^4.21.0",
|
|
75
|
+
"typescript": "^7.0.2"
|
|
76
|
+
}
|
|
77
|
+
}
|
package/server.ts
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import http from 'node:http';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { createServer as createViteServer } from 'vite';
|
|
7
|
+
import * as dotenv from 'dotenv';
|
|
8
|
+
import {
|
|
9
|
+
inspectHostEnvironment,
|
|
10
|
+
diagnoseRawErrorLog,
|
|
11
|
+
PRESET_ERROR_LOGS,
|
|
12
|
+
} from './src/engine/analyzerEngine.ts';
|
|
13
|
+
import {
|
|
14
|
+
diagnoseRawErrorLogWithAi,
|
|
15
|
+
generateProjectAiAdvice,
|
|
16
|
+
askDevIntelligenceAi,
|
|
17
|
+
isAiRateLimited,
|
|
18
|
+
} from './src/engine/aiEngine.ts';
|
|
19
|
+
import {
|
|
20
|
+
getAllProjectReports,
|
|
21
|
+
getProjectReportById,
|
|
22
|
+
registerLocalProject,
|
|
23
|
+
applyIssueRepairOnDisk,
|
|
24
|
+
applyAllSafeRepairsOnDisk,
|
|
25
|
+
rollbackRepairOnDisk,
|
|
26
|
+
updateProjectQualityGate,
|
|
27
|
+
MCP_TOOLS_CATALOG,
|
|
28
|
+
executeMcpToolCall,
|
|
29
|
+
} from './src/engine/repairEngine.ts';
|
|
30
|
+
|
|
31
|
+
dotenv.config();
|
|
32
|
+
|
|
33
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
34
|
+
const __dirname = path.dirname(__filename);
|
|
35
|
+
|
|
36
|
+
async function startServer() {
|
|
37
|
+
const app = express();
|
|
38
|
+
const server = http.createServer(app);
|
|
39
|
+
const PORT = 3000;
|
|
40
|
+
|
|
41
|
+
app.use(express.json({ limit: '5mb' }));
|
|
42
|
+
|
|
43
|
+
// 1. Get complete DEVINTELLIGENCE workspace state
|
|
44
|
+
app.get('/api/devintel/workspace', (_req, res) => {
|
|
45
|
+
try {
|
|
46
|
+
const projects = getAllProjectReports(__dirname);
|
|
47
|
+
const environmentChecks = inspectHostEnvironment(false);
|
|
48
|
+
res.json({
|
|
49
|
+
projects,
|
|
50
|
+
environmentChecks,
|
|
51
|
+
mcpTools: MCP_TOOLS_CATALOG,
|
|
52
|
+
presetErrorLogs: PRESET_ERROR_LOGS,
|
|
53
|
+
hostPlatform: process.platform,
|
|
54
|
+
nodeVersion: process.version,
|
|
55
|
+
});
|
|
56
|
+
} catch (error: any) {
|
|
57
|
+
res.status(500).json({ error: error.message || 'Failed to load DEVINTELLIGENCE workspace.' });
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// 2. Get or rescan a specific project
|
|
62
|
+
app.get('/api/devintel/projects/:id', (req, res) => {
|
|
63
|
+
try {
|
|
64
|
+
const forceRescan = req.query.rescan === 'true';
|
|
65
|
+
const report = getProjectReportById(req.params.id, forceRescan, __dirname);
|
|
66
|
+
res.json(report);
|
|
67
|
+
} catch (error: any) {
|
|
68
|
+
res.status(404).json({ error: error.message || 'Project not found.' });
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// 3. Trigger explicit deep scan on a project
|
|
73
|
+
app.post('/api/devintel/projects/:id/scan', (req, res) => {
|
|
74
|
+
try {
|
|
75
|
+
const report = getProjectReportById(req.params.id, true, __dirname);
|
|
76
|
+
const projects = getAllProjectReports(__dirname);
|
|
77
|
+
res.json({ report, projects });
|
|
78
|
+
} catch (error: any) {
|
|
79
|
+
res.status(400).json({ error: error.message || 'Failed to scan project.' });
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// 4. Register a new local project path
|
|
84
|
+
app.post('/api/devintel/projects/register', (req, res) => {
|
|
85
|
+
try {
|
|
86
|
+
const { name, rootPath } = req.body || {};
|
|
87
|
+
if (!name || !String(name).trim() || !rootPath || !String(rootPath).trim()) {
|
|
88
|
+
return res.status(400).json({ error: 'Project name and local directory path are required.' });
|
|
89
|
+
}
|
|
90
|
+
const report = registerLocalProject({
|
|
91
|
+
name: String(name).trim(),
|
|
92
|
+
rootPath: String(rootPath).trim(),
|
|
93
|
+
baseWorkspaceDir: __dirname,
|
|
94
|
+
});
|
|
95
|
+
const projects = getAllProjectReports(__dirname);
|
|
96
|
+
return res.json({ report, projects });
|
|
97
|
+
} catch (error: any) {
|
|
98
|
+
return res.status(400).json({ error: error.message || 'Failed to register local project.' });
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// 5. Read real file content from a registered project for Project Explorer
|
|
103
|
+
app.get('/api/devintel/file-content', (req, res) => {
|
|
104
|
+
try {
|
|
105
|
+
const projectId = String(req.query.projectId || 'rn-expo-commerce');
|
|
106
|
+
const relFile = String(req.query.filePath || '');
|
|
107
|
+
const report = getProjectReportById(projectId, false, __dirname);
|
|
108
|
+
const safeRel = path.normalize(relFile).replace(/^(\.\.(\/|\\|$))+/, '');
|
|
109
|
+
const fullPath = path.join(report.rootPath, safeRel);
|
|
110
|
+
if (!fullPath.startsWith(report.rootPath) || !fs.existsSync(fullPath)) {
|
|
111
|
+
return res.status(404).json({ error: 'File not found inside project root.' });
|
|
112
|
+
}
|
|
113
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
114
|
+
return res.json({
|
|
115
|
+
projectId,
|
|
116
|
+
filePath: safeRel,
|
|
117
|
+
content,
|
|
118
|
+
sizeBytes: Buffer.byteLength(content, 'utf8'),
|
|
119
|
+
});
|
|
120
|
+
} catch (error: any) {
|
|
121
|
+
return res.status(400).json({ error: error.message || 'Unable to read file.' });
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// 6. Apply an individual issue repair on disk with automatic backup & re-scan verification
|
|
126
|
+
app.post('/api/devintel/projects/:id/repair', (req, res) => {
|
|
127
|
+
try {
|
|
128
|
+
const { issueId, allowReviewTier } = req.body || {};
|
|
129
|
+
if (!issueId) {
|
|
130
|
+
return res.status(400).json({ error: 'issueId is required.' });
|
|
131
|
+
}
|
|
132
|
+
const result = applyIssueRepairOnDisk({
|
|
133
|
+
projectId: req.params.id,
|
|
134
|
+
issueId: String(issueId),
|
|
135
|
+
allowReviewTier: Boolean(allowReviewTier),
|
|
136
|
+
baseWorkspaceDir: __dirname,
|
|
137
|
+
});
|
|
138
|
+
const projects = getAllProjectReports(__dirname);
|
|
139
|
+
return res.json({ ...result, projects });
|
|
140
|
+
} catch (error: any) {
|
|
141
|
+
return res.status(400).json({ error: error.message || 'Repair execution failed.' });
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// 7. Apply all SAFE repairs in batch on disk
|
|
146
|
+
app.post('/api/devintel/projects/:id/repair-all-safe', (req, res) => {
|
|
147
|
+
try {
|
|
148
|
+
const result = applyAllSafeRepairsOnDisk(req.params.id, __dirname);
|
|
149
|
+
const projects = getAllProjectReports(__dirname);
|
|
150
|
+
return res.json({ ...result, projects });
|
|
151
|
+
} catch (error: any) {
|
|
152
|
+
return res.status(400).json({ error: error.message || 'Batch safe repair failed.' });
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// 8. Rollback / undo a previously applied repair from backup snapshot
|
|
157
|
+
app.post('/api/devintel/projects/:id/rollback', (req, res) => {
|
|
158
|
+
try {
|
|
159
|
+
const { repairId } = req.body || {};
|
|
160
|
+
if (!repairId) {
|
|
161
|
+
return res.status(400).json({ error: 'repairId is required to rollback.' });
|
|
162
|
+
}
|
|
163
|
+
const result = rollbackRepairOnDisk({
|
|
164
|
+
projectId: req.params.id,
|
|
165
|
+
repairId: String(repairId),
|
|
166
|
+
baseWorkspaceDir: __dirname,
|
|
167
|
+
});
|
|
168
|
+
const projects = getAllProjectReports(__dirname);
|
|
169
|
+
return res.json({ ...result, projects });
|
|
170
|
+
} catch (error: any) {
|
|
171
|
+
return res.status(400).json({ error: error.message || 'Rollback failed.' });
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// 9. Update configurable Quality Gate thresholds
|
|
176
|
+
app.put('/api/devintel/projects/:id/quality-gate', (req, res) => {
|
|
177
|
+
try {
|
|
178
|
+
const updatedReport = updateProjectQualityGate(req.params.id, req.body || {}, __dirname);
|
|
179
|
+
const projects = getAllProjectReports(__dirname);
|
|
180
|
+
return res.json({ updatedReport, projects });
|
|
181
|
+
} catch (error: any) {
|
|
182
|
+
return res.status(400).json({ error: error.message || 'Failed to update Quality Gate.' });
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// 10. Diagnose raw React Native / Metro / Gradle / CocoaPods / Red Screen log with Groq AI + Rule Fallback
|
|
187
|
+
app.post('/api/devintel/diagnose-log', async (req, res) => {
|
|
188
|
+
try {
|
|
189
|
+
const { rawLog } = req.body || {};
|
|
190
|
+
if (!rawLog || !String(rawLog).trim()) {
|
|
191
|
+
return res.status(400).json({ error: 'Please provide a build or runtime error log to diagnose.' });
|
|
192
|
+
}
|
|
193
|
+
// AI-first with guaranteed instant rule-engine fallback
|
|
194
|
+
const diagnosis = await diagnoseRawErrorLogWithAi(String(rawLog));
|
|
195
|
+
return res.json(diagnosis);
|
|
196
|
+
} catch (error: any) {
|
|
197
|
+
// Ultimate safety net: even if an unexpected error occurs, fall back to rule engine
|
|
198
|
+
try {
|
|
199
|
+
const fallback = diagnoseRawErrorLog(String(req.body?.rawLog || ''));
|
|
200
|
+
return res.json({ ...fallback, fallbackUsed: true, fallbackReason: error.message });
|
|
201
|
+
} catch {
|
|
202
|
+
return res.status(400).json({ error: error.message || 'Error log diagnosis failed.' });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// 10b. Generate AI Engineering Advice / Executive Brief for a project
|
|
208
|
+
app.get('/api/devintel/projects/:id/ai-advice', async (req, res) => {
|
|
209
|
+
try {
|
|
210
|
+
const report = getProjectReportById(req.params.id, false, __dirname);
|
|
211
|
+
const advice = await generateProjectAiAdvice(report);
|
|
212
|
+
return res.json(advice);
|
|
213
|
+
} catch (error: any) {
|
|
214
|
+
return res.status(500).json({ error: error.message || 'Failed to generate AI advice.' });
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// 10c. Interactive DEVINTELLIGENCE AI Assistant
|
|
219
|
+
app.post('/api/devintel/ai-assistant', async (req, res) => {
|
|
220
|
+
try {
|
|
221
|
+
const { query, context } = req.body || {};
|
|
222
|
+
const result = await askDevIntelligenceAi(String(query || ''), context);
|
|
223
|
+
return res.json(result);
|
|
224
|
+
} catch (error: any) {
|
|
225
|
+
return res.status(500).json({ error: error.message || 'AI Assistant query failed.' });
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// 11. Refresh host environment checks
|
|
230
|
+
app.post('/api/devintel/environment/refresh', (_req, res) => {
|
|
231
|
+
try {
|
|
232
|
+
const environmentChecks = inspectHostEnvironment(true);
|
|
233
|
+
return res.json({ environmentChecks });
|
|
234
|
+
} catch (error: any) {
|
|
235
|
+
return res.status(500).json({ error: error.message || 'Environment check failed.' });
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// 12. Execute local MCP tool call
|
|
240
|
+
app.post('/api/devintel/mcp/call', (req, res) => {
|
|
241
|
+
try {
|
|
242
|
+
const { toolName, args } = req.body || {};
|
|
243
|
+
if (!toolName) {
|
|
244
|
+
return res.status(400).json({ error: 'toolName is required.' });
|
|
245
|
+
}
|
|
246
|
+
const output = executeMcpToolCall(String(toolName), args || {}, __dirname);
|
|
247
|
+
const projects = getAllProjectReports(__dirname);
|
|
248
|
+
return res.json({ output, projects });
|
|
249
|
+
} catch (error: any) {
|
|
250
|
+
return res.status(400).json({ error: error.message || 'MCP tool invocation failed.' });
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
255
|
+
const vite = await createViteServer({
|
|
256
|
+
server: { middlewareMode: true },
|
|
257
|
+
appType: 'spa',
|
|
258
|
+
});
|
|
259
|
+
app.use(vite.middlewares);
|
|
260
|
+
} else {
|
|
261
|
+
const distPath = path.join(__dirname, 'dist');
|
|
262
|
+
app.use(express.static(distPath));
|
|
263
|
+
app.get('*', (_req, res) => {
|
|
264
|
+
res.sendFile(path.join(distPath, 'index.html'));
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
server.listen(PORT, '0.0.0.0', () => {
|
|
269
|
+
console.log(`DEVINTELLIGENCE Engineering Workstation listening on http://0.0.0.0:${PORT}`);
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
startServer().catch((err) => {
|
|
274
|
+
console.error('Fatal server startup error:', err);
|
|
275
|
+
});
|