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,625 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Smartphone,
|
|
4
|
+
CheckCircle2,
|
|
5
|
+
AlertTriangle,
|
|
6
|
+
XCircle,
|
|
7
|
+
Terminal,
|
|
8
|
+
Wrench,
|
|
9
|
+
Cpu,
|
|
10
|
+
Shield,
|
|
11
|
+
Search,
|
|
12
|
+
} from 'lucide-react';
|
|
13
|
+
import {
|
|
14
|
+
CheckStatus,
|
|
15
|
+
ErrorDiagnosisResult,
|
|
16
|
+
ProjectIntelligenceReport,
|
|
17
|
+
} from '../types/devintelligence.ts';
|
|
18
|
+
import { SeverityText } from './OverviewAndExplorerViews.tsx';
|
|
19
|
+
|
|
20
|
+
interface MobileViewProps {
|
|
21
|
+
report: ProjectIntelligenceReport;
|
|
22
|
+
onFixIssue: (issueId: string, allowReview?: boolean) => void;
|
|
23
|
+
presetErrorLogs: { id: string; label: string; ecosystem: string; rawLog: string }[];
|
|
24
|
+
onDiagnoseLog: (rawLog: string) => Promise<ErrorDiagnosisResult>;
|
|
25
|
+
isBusy: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function StatusIndicator({ status }: { status: CheckStatus }) {
|
|
29
|
+
switch (status) {
|
|
30
|
+
case 'working':
|
|
31
|
+
return (
|
|
32
|
+
<span className="inline-flex items-center gap-1.5 text-xs font-medium text-emerald-400">
|
|
33
|
+
<CheckCircle2 className="w-3.5 h-3.5 shrink-0" />
|
|
34
|
+
<span>Working Correctly</span>
|
|
35
|
+
</span>
|
|
36
|
+
);
|
|
37
|
+
case 'incompatible':
|
|
38
|
+
return (
|
|
39
|
+
<span className="inline-flex items-center gap-1.5 text-xs font-medium text-red-400">
|
|
40
|
+
<XCircle className="w-3.5 h-3.5 shrink-0" />
|
|
41
|
+
<span>Installed / Incompatible</span>
|
|
42
|
+
</span>
|
|
43
|
+
);
|
|
44
|
+
case 'misconfigured':
|
|
45
|
+
return (
|
|
46
|
+
<span className="inline-flex items-center gap-1.5 text-xs font-medium text-amber-400">
|
|
47
|
+
<AlertTriangle className="w-3.5 h-3.5 shrink-0" />
|
|
48
|
+
<span>Misconfigured</span>
|
|
49
|
+
</span>
|
|
50
|
+
);
|
|
51
|
+
case 'not_installed':
|
|
52
|
+
return (
|
|
53
|
+
<span className="inline-flex items-center gap-1.5 text-xs font-medium text-amber-400">
|
|
54
|
+
<AlertTriangle className="w-3.5 h-3.5 shrink-0" />
|
|
55
|
+
<span>Not Installed</span>
|
|
56
|
+
</span>
|
|
57
|
+
);
|
|
58
|
+
case 'os_unsupported':
|
|
59
|
+
return (
|
|
60
|
+
<span className="inline-flex items-center gap-1.5 text-xs font-medium text-slate-400">
|
|
61
|
+
<Terminal className="w-3.5 h-3.5 shrink-0" />
|
|
62
|
+
<span>Cannot Check on Current OS</span>
|
|
63
|
+
</span>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function ReactNativeDoctorView({ report, onFixIssue, isBusy }: MobileViewProps) {
|
|
69
|
+
const rnIssues = report.issues.filter(
|
|
70
|
+
(i) =>
|
|
71
|
+
i.domain === 'react-native' ||
|
|
72
|
+
i.domain === 'android' ||
|
|
73
|
+
i.domain === 'ios' ||
|
|
74
|
+
i.ruleId.includes('RN_') ||
|
|
75
|
+
i.ruleId.includes('EXPO_')
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<div className="space-y-8">
|
|
80
|
+
<div className="pb-5 border-b border-slate-800/80 flex flex-col md:flex-row md:items-center md:justify-between gap-4">
|
|
81
|
+
<div>
|
|
82
|
+
<h1 className="text-xl font-bold text-slate-100">
|
|
83
|
+
React Native Doctor & Component Intelligence
|
|
84
|
+
</h1>
|
|
85
|
+
<p className="text-xs text-slate-400 mt-1">
|
|
86
|
+
Deep inspection of {report.launchDoctor.workflowType} configuration, Babel/Metro pipelines, hook lifecycles, and native bridges.
|
|
87
|
+
</p>
|
|
88
|
+
</div>
|
|
89
|
+
<div className="text-xs font-mono tabular-nums text-slate-300">
|
|
90
|
+
RN Health Score: <strong className="text-blue-400">{report.scores.reactNative}/100</strong>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
{/* React Native Matrix Summary */}
|
|
95
|
+
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
|
96
|
+
<div className="p-4 bg-slate-900/70 border border-slate-800/80 rounded-lg">
|
|
97
|
+
<div className="text-xs text-slate-400">Workflow Architecture</div>
|
|
98
|
+
<div className="mt-1.5 text-sm font-semibold text-slate-100">
|
|
99
|
+
{report.launchDoctor.workflowType}
|
|
100
|
+
</div>
|
|
101
|
+
<div className="mt-1 text-xs font-mono text-slate-400">
|
|
102
|
+
Metro: {report.launchDoctor.metroConfigured ? 'Active' : 'Default'} · Babel: {report.launchDoctor.babelConfigured ? 'Custom' : 'Default'}
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<div className="p-4 bg-slate-900/70 border border-slate-800/80 rounded-lg">
|
|
107
|
+
<div className="text-xs text-slate-400">JS Engine & Architecture</div>
|
|
108
|
+
<div className="mt-1.5 text-sm font-semibold text-slate-100">
|
|
109
|
+
Hermes: {report.android.hermesEnabled ? 'Enabled' : 'Disabled'}
|
|
110
|
+
</div>
|
|
111
|
+
<div className="mt-1 text-xs font-mono text-slate-400">
|
|
112
|
+
New Arch (Fabric/TurboModules): {report.android.newArchEnabled ? 'Enabled' : 'Legacy Bridge'}
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<div className="p-4 bg-slate-900/70 border border-slate-800/80 rounded-lg">
|
|
117
|
+
<div className="text-xs text-slate-400">Component & Hook Leaks</div>
|
|
118
|
+
<div className="mt-1.5 text-sm font-semibold font-mono tabular-nums text-slate-100">
|
|
119
|
+
{report.performance.memoryLeakRisksCount} lifecycle leak(s)
|
|
120
|
+
</div>
|
|
121
|
+
<div className="mt-1 text-xs font-mono text-slate-400">
|
|
122
|
+
{report.performance.renderBottlenecksCount} FlatList / render bottleneck(s)
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<div className="p-4 bg-slate-900/70 border border-slate-800/80 rounded-lg">
|
|
127
|
+
<div className="text-xs text-slate-400">Host OS Verification</div>
|
|
128
|
+
<div className="mt-1.5 text-sm font-semibold text-slate-100">
|
|
129
|
+
Linux Container Host
|
|
130
|
+
</div>
|
|
131
|
+
<div className="mt-1 text-xs text-slate-400">
|
|
132
|
+
Android static/Gradle active · iOS static Podfile/Plist only
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
{/* Environment Doctor Checks Table */}
|
|
138
|
+
<div className="space-y-3">
|
|
139
|
+
<h2 className="text-base font-semibold text-slate-100">
|
|
140
|
+
Environment Health Matrix (Host & Project Toolchain)
|
|
141
|
+
</h2>
|
|
142
|
+
<div className="overflow-x-auto border border-slate-800/80 rounded-lg bg-slate-900/50">
|
|
143
|
+
<table className="w-full text-left border-collapse">
|
|
144
|
+
<thead>
|
|
145
|
+
<tr className="border-b border-slate-800 text-[11px] font-medium text-slate-400">
|
|
146
|
+
<th className="py-2.5 px-4">Requirement</th>
|
|
147
|
+
<th className="py-2.5 px-4">Status</th>
|
|
148
|
+
<th className="py-2.5 px-4">Detected</th>
|
|
149
|
+
<th className="py-2.5 px-4">Expected</th>
|
|
150
|
+
<th className="py-2.5 px-4">Diagnostic Detail & Terminal Remediation</th>
|
|
151
|
+
</tr>
|
|
152
|
+
</thead>
|
|
153
|
+
<tbody className="divide-y divide-slate-800/60 text-xs">
|
|
154
|
+
{report.environmentChecks.map((chk) => (
|
|
155
|
+
<tr key={chk.id} className="hover:bg-slate-800/40 align-top">
|
|
156
|
+
<td className="py-3 px-3.5 font-semibold text-slate-100">
|
|
157
|
+
{chk.name}
|
|
158
|
+
</td>
|
|
159
|
+
<td className="py-3 px-3.5 whitespace-nowrap">
|
|
160
|
+
<StatusIndicator status={chk.status} />
|
|
161
|
+
</td>
|
|
162
|
+
<td className="py-3 px-3.5 font-mono tabular-nums text-slate-300">
|
|
163
|
+
{chk.detectedVersion}
|
|
164
|
+
</td>
|
|
165
|
+
<td className="py-3 px-3.5 font-mono tabular-nums text-slate-400">
|
|
166
|
+
{chk.requiredVersion}
|
|
167
|
+
</td>
|
|
168
|
+
<td className="py-3 px-3.5 text-slate-300 max-w-md">
|
|
169
|
+
<div className="leading-relaxed">{chk.explanation}</div>
|
|
170
|
+
{chk.remediationCommand && (
|
|
171
|
+
<div className="mt-1 font-mono text-[11px] text-blue-400 break-all">
|
|
172
|
+
$ {chk.remediationCommand}
|
|
173
|
+
</div>
|
|
174
|
+
)}
|
|
175
|
+
</td>
|
|
176
|
+
</tr>
|
|
177
|
+
))}
|
|
178
|
+
</tbody>
|
|
179
|
+
</table>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
|
|
183
|
+
{/* React Native Specific Findings */}
|
|
184
|
+
<div className="space-y-3">
|
|
185
|
+
<h2 className="text-base font-semibold text-slate-100">
|
|
186
|
+
React Native, Metro, Babel & Component Lifecycle Findings ({rnIssues.length})
|
|
187
|
+
</h2>
|
|
188
|
+
{rnIssues.length === 0 ? (
|
|
189
|
+
<div className="p-6 bg-slate-900/50 border border-slate-800 rounded-lg text-xs text-slate-300">
|
|
190
|
+
No active React Native or native mobile configuration issues detected in this project.
|
|
191
|
+
</div>
|
|
192
|
+
) : (
|
|
193
|
+
<div className="space-y-3">
|
|
194
|
+
{rnIssues.map((issue) => (
|
|
195
|
+
<div
|
|
196
|
+
key={issue.id}
|
|
197
|
+
className="p-4 bg-slate-900/70 border border-slate-800/80 rounded-lg flex flex-col lg:flex-row lg:items-center lg:justify-between gap-4"
|
|
198
|
+
>
|
|
199
|
+
<div className="space-y-1.5">
|
|
200
|
+
<div className="flex flex-wrap items-center gap-2 text-xs">
|
|
201
|
+
<SeverityText severity={issue.severity} />
|
|
202
|
+
<span className="text-slate-500">·</span>
|
|
203
|
+
<span className="font-mono text-slate-300">
|
|
204
|
+
{issue.filePath}:{issue.line}
|
|
205
|
+
</span>
|
|
206
|
+
<span className="text-slate-500">·</span>
|
|
207
|
+
<span className="font-mono text-slate-400">{issue.ruleId}</span>
|
|
208
|
+
</div>
|
|
209
|
+
<div className="text-sm font-semibold text-slate-100">{issue.title}</div>
|
|
210
|
+
<p className="text-xs text-slate-400 leading-relaxed">{issue.rootCause}</p>
|
|
211
|
+
<div className="text-xs text-blue-300">
|
|
212
|
+
Recommended Repair: {issue.recommendedRepair}
|
|
213
|
+
</div>
|
|
214
|
+
</div>
|
|
215
|
+
{issue.fixAvailable && (
|
|
216
|
+
<button
|
|
217
|
+
type="button"
|
|
218
|
+
disabled={isBusy}
|
|
219
|
+
onClick={() => onFixIssue(issue.id, issue.repairTier !== 'SAFE')}
|
|
220
|
+
className="px-4 py-2 text-xs font-semibold text-white bg-blue-600 hover:bg-blue-500 rounded-lg shrink-0 cursor-pointer whitespace-nowrap"
|
|
221
|
+
>
|
|
222
|
+
Apply Safe Repair
|
|
223
|
+
</button>
|
|
224
|
+
)}
|
|
225
|
+
</div>
|
|
226
|
+
))}
|
|
227
|
+
</div>
|
|
228
|
+
)}
|
|
229
|
+
</div>
|
|
230
|
+
</div>
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function AndroidDiagnosticsView({ report, onFixIssue, isBusy }: MobileViewProps) {
|
|
235
|
+
const androidIssues = report.issues.filter(
|
|
236
|
+
(i) => i.domain === 'android' || i.filePath.startsWith('android/')
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
return (
|
|
240
|
+
<div className="space-y-8">
|
|
241
|
+
<div className="pb-5 border-b border-slate-800/80">
|
|
242
|
+
<h1 className="text-xl font-bold text-slate-100">
|
|
243
|
+
Android Native Folder & Gradle Intelligence
|
|
244
|
+
</h1>
|
|
245
|
+
<p className="text-xs text-slate-400 mt-1">
|
|
246
|
+
Inspects AndroidManifest.xml, build.gradle, gradle.properties, SDK levels, Kotlin/AGP compatibility, R8 minification, and permissions.
|
|
247
|
+
</p>
|
|
248
|
+
</div>
|
|
249
|
+
|
|
250
|
+
{!report.android.present ? (
|
|
251
|
+
<div className="p-8 bg-slate-900/50 border border-slate-800 rounded-lg text-xs text-slate-400">
|
|
252
|
+
This project ({report.name}) does not contain an <code className="font-mono text-slate-200">android/</code> directory. Switch to <strong className="text-slate-200">ExpoCommerceMobile</strong> or <strong className="text-slate-200">BareFitnessPro</strong> to inspect native Android Gradle and Manifest configurations.
|
|
253
|
+
</div>
|
|
254
|
+
) : (
|
|
255
|
+
<>
|
|
256
|
+
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
257
|
+
<div className="p-4 bg-slate-900/70 border border-slate-800/80 rounded-lg">
|
|
258
|
+
<div className="text-xs text-slate-400">Application ID</div>
|
|
259
|
+
<div className="mt-1.5 text-xs font-mono font-semibold text-slate-100 truncate">
|
|
260
|
+
{report.android.packageName || 'com.devintel.app'}
|
|
261
|
+
</div>
|
|
262
|
+
<div className="mt-1 text-xs text-slate-400">
|
|
263
|
+
Manifest: {report.android.manifestPath || 'N/A'}
|
|
264
|
+
</div>
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
<div className="p-4 bg-slate-900/70 border border-slate-800/80 rounded-lg">
|
|
268
|
+
<div className="text-xs text-slate-400">SDK Matrix (Min / Compile / Target)</div>
|
|
269
|
+
<div className="mt-1.5 text-sm font-mono font-bold tabular-nums text-slate-100">
|
|
270
|
+
{report.android.minSdkVersion ?? 23} / {report.android.compileSdkVersion ?? 34} /{' '}
|
|
271
|
+
<span
|
|
272
|
+
className={
|
|
273
|
+
(report.android.targetSdkVersion || 34) < 34 ? 'text-amber-400' : 'text-emerald-400'
|
|
274
|
+
}
|
|
275
|
+
>
|
|
276
|
+
{report.android.targetSdkVersion ?? 34}
|
|
277
|
+
</span>
|
|
278
|
+
</div>
|
|
279
|
+
<div className="mt-1 text-xs text-slate-400">Play Store Target: API 34</div>
|
|
280
|
+
</div>
|
|
281
|
+
|
|
282
|
+
<div className="p-4 bg-slate-900/70 border border-slate-800/80 rounded-lg">
|
|
283
|
+
<div className="text-xs text-slate-400">Kotlin & Gradle JVM Heap</div>
|
|
284
|
+
<div className="mt-1.5 text-xs font-mono font-semibold text-slate-100">
|
|
285
|
+
Kotlin: {report.android.kotlinVersion || '1.9.24'}
|
|
286
|
+
</div>
|
|
287
|
+
<div className="mt-1 text-xs font-mono text-slate-400 truncate">
|
|
288
|
+
{report.android.gradleJvmArgs || '-Xmx4096m'}
|
|
289
|
+
</div>
|
|
290
|
+
</div>
|
|
291
|
+
|
|
292
|
+
<div className="p-4 bg-slate-900/70 border border-slate-800/80 rounded-lg">
|
|
293
|
+
<div className="text-xs text-slate-400">Release R8 & Cleartext</div>
|
|
294
|
+
<div className="mt-1.5 text-xs font-mono font-semibold text-slate-100">
|
|
295
|
+
R8 Minify: {report.android.releaseMinifyEnabled ? 'Enabled' : 'Disabled'}
|
|
296
|
+
</div>
|
|
297
|
+
<div className="mt-1 text-xs font-mono text-slate-400">
|
|
298
|
+
Cleartext HTTP: {report.android.cleartextTrafficAllowed ? 'Allowed (Risk)' : 'Blocked'}
|
|
299
|
+
</div>
|
|
300
|
+
</div>
|
|
301
|
+
</div>
|
|
302
|
+
|
|
303
|
+
<div className="space-y-3">
|
|
304
|
+
<h2 className="text-base font-semibold text-slate-100">
|
|
305
|
+
Android Manifest & Gradle Findings ({androidIssues.length})
|
|
306
|
+
</h2>
|
|
307
|
+
{androidIssues.length === 0 ? (
|
|
308
|
+
<div className="p-6 bg-slate-900/50 border border-slate-800 rounded-lg text-xs text-emerald-400">
|
|
309
|
+
All Android manifest permissions, SDK versions, and Gradle properties are healthy.
|
|
310
|
+
</div>
|
|
311
|
+
) : (
|
|
312
|
+
<div className="space-y-3">
|
|
313
|
+
{androidIssues.map((issue) => (
|
|
314
|
+
<div
|
|
315
|
+
key={issue.id}
|
|
316
|
+
className="p-4 bg-slate-900/70 border border-slate-800/80 rounded-lg space-y-3"
|
|
317
|
+
>
|
|
318
|
+
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
|
|
319
|
+
<div className="space-y-1">
|
|
320
|
+
<div className="flex items-center gap-2 text-xs">
|
|
321
|
+
<SeverityText severity={issue.severity} />
|
|
322
|
+
<span className="text-slate-500">·</span>
|
|
323
|
+
<span className="font-mono text-slate-300">
|
|
324
|
+
{issue.filePath}:{issue.line}
|
|
325
|
+
</span>
|
|
326
|
+
<span className="text-slate-500">·</span>
|
|
327
|
+
<span className="font-mono text-slate-400">{issue.repairTier}</span>
|
|
328
|
+
</div>
|
|
329
|
+
<div className="text-sm font-semibold text-slate-100">{issue.title}</div>
|
|
330
|
+
</div>
|
|
331
|
+
{issue.fixAvailable && (
|
|
332
|
+
<button
|
|
333
|
+
type="button"
|
|
334
|
+
disabled={isBusy}
|
|
335
|
+
onClick={() => onFixIssue(issue.id, issue.repairTier !== 'SAFE')}
|
|
336
|
+
className="px-4 py-2 text-xs font-semibold text-white bg-blue-600 hover:bg-blue-500 rounded-lg shrink-0 cursor-pointer whitespace-nowrap"
|
|
337
|
+
>
|
|
338
|
+
{issue.repairTier === 'SAFE' ? 'Apply Safe Repair' : 'Approve & Repair'}
|
|
339
|
+
</button>
|
|
340
|
+
)}
|
|
341
|
+
</div>
|
|
342
|
+
<p className="text-xs text-slate-400">{issue.explanation}</p>
|
|
343
|
+
<pre className="p-3 bg-slate-950 border border-slate-800 rounded text-[11px] font-mono text-slate-300 overflow-x-auto">
|
|
344
|
+
{issue.unifiedDiff}
|
|
345
|
+
</pre>
|
|
346
|
+
</div>
|
|
347
|
+
))}
|
|
348
|
+
</div>
|
|
349
|
+
)}
|
|
350
|
+
</div>
|
|
351
|
+
</>
|
|
352
|
+
)}
|
|
353
|
+
</div>
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
export function IosDiagnosticsView({ report, onFixIssue, isBusy }: MobileViewProps) {
|
|
358
|
+
const iosIssues = report.issues.filter((i) => i.domain === 'ios');
|
|
359
|
+
|
|
360
|
+
return (
|
|
361
|
+
<div className="space-y-8">
|
|
362
|
+
<div className="pb-5 border-b border-slate-800/80">
|
|
363
|
+
<h1 className="text-xl font-bold text-slate-100">
|
|
364
|
+
iOS Podfile, Info.plist & Entitlements Intelligence
|
|
365
|
+
</h1>
|
|
366
|
+
<p className="text-xs text-slate-400 mt-1">
|
|
367
|
+
Static verification of Podfile deployment targets, Flipper deprecations, Hermes flags, and mandatory Info.plist privacy descriptions.
|
|
368
|
+
</p>
|
|
369
|
+
</div>
|
|
370
|
+
|
|
371
|
+
{/* Honest OS Capability Notice */}
|
|
372
|
+
<div className="p-4 bg-slate-900/90 border border-slate-800 rounded-lg flex items-start gap-3">
|
|
373
|
+
<Terminal className="w-4 h-4 text-blue-400 shrink-0 mt-0.5" />
|
|
374
|
+
<div className="space-y-1 text-xs">
|
|
375
|
+
<div className="font-semibold text-slate-100">
|
|
376
|
+
Operating System Capability Boundary (Linux Container Host)
|
|
377
|
+
</div>
|
|
378
|
+
<p className="text-slate-400 leading-relaxed">
|
|
379
|
+
{report.ios.hostOsNote} DEVINTELLIGENCE never fabricates Xcode build verification on non-macOS hosts. Static Podfile and Info.plist inspection and automatic file repair work locally on all operating systems.
|
|
380
|
+
</p>
|
|
381
|
+
</div>
|
|
382
|
+
</div>
|
|
383
|
+
|
|
384
|
+
{!report.ios.present ? (
|
|
385
|
+
<div className="p-8 bg-slate-900/50 border border-slate-800 rounded-lg text-xs text-slate-400">
|
|
386
|
+
This project ({report.name}) does not have an <code className="font-mono text-slate-200">ios/</code> directory. Switch to <strong className="text-slate-200">ExpoCommerceMobile</strong> or <strong className="text-slate-200">BareFitnessPro</strong> to inspect iOS native files.
|
|
387
|
+
</div>
|
|
388
|
+
) : (
|
|
389
|
+
<>
|
|
390
|
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
391
|
+
<div className="p-4 bg-slate-900/70 border border-slate-800/80 rounded-lg">
|
|
392
|
+
<div className="text-xs text-slate-400">iOS Deployment Target</div>
|
|
393
|
+
<div className="mt-1.5 text-sm font-mono font-bold text-slate-100">
|
|
394
|
+
{report.ios.deploymentTarget || '15.1 (Default)'}
|
|
395
|
+
</div>
|
|
396
|
+
<div className="mt-1 text-xs text-slate-400">
|
|
397
|
+
Podfile: {report.ios.podfilePath || 'Not present'}
|
|
398
|
+
</div>
|
|
399
|
+
</div>
|
|
400
|
+
|
|
401
|
+
<div className="p-4 bg-slate-900/70 border border-slate-800/80 rounded-lg">
|
|
402
|
+
<div className="text-xs text-slate-400">Flipper & Hermes Status</div>
|
|
403
|
+
<div className="mt-1.5 text-sm font-mono font-semibold text-slate-100">
|
|
404
|
+
Flipper: {report.ios.flipperEnabled ? 'Enabled (Deprecated)' : 'Removed (Clean)'}
|
|
405
|
+
</div>
|
|
406
|
+
<div className="mt-1 text-xs font-mono text-slate-400">
|
|
407
|
+
Hermes Engine: {report.ios.hermesEnabled === false ? 'Disabled' : 'Enabled'}
|
|
408
|
+
</div>
|
|
409
|
+
</div>
|
|
410
|
+
|
|
411
|
+
<div className="p-4 bg-slate-900/70 border border-slate-800/80 rounded-lg">
|
|
412
|
+
<div className="text-xs text-slate-400">Privacy Usage Keys (Info.plist)</div>
|
|
413
|
+
<div className="mt-1.5 text-sm font-mono font-semibold text-slate-100">
|
|
414
|
+
{report.ios.missingRequiredPermissions.length === 0
|
|
415
|
+
? 'All Required Keys Present'
|
|
416
|
+
: `Missing: ${report.ios.missingRequiredPermissions.join(', ')}`}
|
|
417
|
+
</div>
|
|
418
|
+
<div className="mt-1 text-xs text-slate-400">
|
|
419
|
+
Bundle ID: {report.ios.bundleIdentifier || 'com.devintel.expocommerce'}
|
|
420
|
+
</div>
|
|
421
|
+
</div>
|
|
422
|
+
</div>
|
|
423
|
+
|
|
424
|
+
<div className="space-y-3">
|
|
425
|
+
<h2 className="text-base font-semibold text-slate-100">
|
|
426
|
+
iOS Configuration Findings ({iosIssues.length})
|
|
427
|
+
</h2>
|
|
428
|
+
{iosIssues.map((issue) => (
|
|
429
|
+
<div
|
|
430
|
+
key={issue.id}
|
|
431
|
+
className="p-4 bg-slate-900/70 border border-slate-800/80 rounded-lg space-y-3"
|
|
432
|
+
>
|
|
433
|
+
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
|
|
434
|
+
<div className="space-y-1">
|
|
435
|
+
<div className="flex items-center gap-2 text-xs">
|
|
436
|
+
<SeverityText severity={issue.severity} />
|
|
437
|
+
<span className="text-slate-500">·</span>
|
|
438
|
+
<span className="font-mono text-slate-300">
|
|
439
|
+
{issue.filePath}:{issue.line}
|
|
440
|
+
</span>
|
|
441
|
+
</div>
|
|
442
|
+
<div className="text-sm font-semibold text-slate-100">{issue.title}</div>
|
|
443
|
+
</div>
|
|
444
|
+
{issue.fixAvailable && (
|
|
445
|
+
<button
|
|
446
|
+
type="button"
|
|
447
|
+
disabled={isBusy}
|
|
448
|
+
onClick={() => onFixIssue(issue.id, false)}
|
|
449
|
+
className="px-4 py-2 text-xs font-semibold text-white bg-blue-600 hover:bg-blue-500 rounded-lg shrink-0 cursor-pointer whitespace-nowrap"
|
|
450
|
+
>
|
|
451
|
+
Apply Safe Podfile/Plist Fix
|
|
452
|
+
</button>
|
|
453
|
+
)}
|
|
454
|
+
</div>
|
|
455
|
+
<p className="text-xs text-slate-400">{issue.explanation}</p>
|
|
456
|
+
<pre className="p-3 bg-slate-950 border border-slate-800 rounded text-[11px] font-mono text-slate-300 overflow-x-auto">
|
|
457
|
+
{issue.unifiedDiff}
|
|
458
|
+
</pre>
|
|
459
|
+
</div>
|
|
460
|
+
))}
|
|
461
|
+
</div>
|
|
462
|
+
</>
|
|
463
|
+
)}
|
|
464
|
+
</div>
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export function ErrorDiagnosticsView({
|
|
469
|
+
presetErrorLogs,
|
|
470
|
+
onDiagnoseLog,
|
|
471
|
+
}: MobileViewProps) {
|
|
472
|
+
const [rawLog, setRawLog] = useState<string>(presetErrorLogs[0]?.rawLog || '');
|
|
473
|
+
const [diagnosis, setDiagnosis] = useState<ErrorDiagnosisResult | null>(null);
|
|
474
|
+
const [diagnosing, setDiagnosing] = useState(false);
|
|
475
|
+
|
|
476
|
+
async function handleRunDiagnosis(logText = rawLog) {
|
|
477
|
+
if (!logText.trim()) return;
|
|
478
|
+
setDiagnosing(true);
|
|
479
|
+
try {
|
|
480
|
+
const res = await onDiagnoseLog(logText);
|
|
481
|
+
setDiagnosis(res);
|
|
482
|
+
} finally {
|
|
483
|
+
setDiagnosing(false);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return (
|
|
488
|
+
<div className="space-y-8">
|
|
489
|
+
<div className="pb-5 border-b border-slate-800/80">
|
|
490
|
+
<h1 className="text-xl font-bold text-slate-100">
|
|
491
|
+
React Native, Metro, Gradle & CocoaPods Error Diagnostics
|
|
492
|
+
</h1>
|
|
493
|
+
<p className="text-xs text-slate-400 mt-1">
|
|
494
|
+
Paste any Metro bundler crash, Red Screen stack trace, Gradle build failure, Android Manifest merger error, or CocoaPods output to trace the exact root cause.
|
|
495
|
+
</p>
|
|
496
|
+
</div>
|
|
497
|
+
|
|
498
|
+
{/* Preset Log Selector */}
|
|
499
|
+
<div className="space-y-2">
|
|
500
|
+
<div className="text-xs font-medium text-slate-300">
|
|
501
|
+
Load Captured Build / Runtime Crash Trace:
|
|
502
|
+
</div>
|
|
503
|
+
<div className="flex flex-wrap gap-2">
|
|
504
|
+
{presetErrorLogs.map((preset) => (
|
|
505
|
+
<button
|
|
506
|
+
key={preset.id}
|
|
507
|
+
type="button"
|
|
508
|
+
onClick={() => {
|
|
509
|
+
setRawLog(preset.rawLog);
|
|
510
|
+
handleRunDiagnosis(preset.rawLog);
|
|
511
|
+
}}
|
|
512
|
+
className="px-3 py-1.5 text-xs font-medium bg-slate-900 hover:bg-slate-800 text-slate-200 border border-slate-800 rounded-lg transition-colors cursor-pointer whitespace-nowrap"
|
|
513
|
+
>
|
|
514
|
+
{preset.label}
|
|
515
|
+
</button>
|
|
516
|
+
))}
|
|
517
|
+
</div>
|
|
518
|
+
</div>
|
|
519
|
+
|
|
520
|
+
<div className="space-y-3">
|
|
521
|
+
<label htmlFor="error-log-textarea" className="block text-xs font-medium text-slate-300">
|
|
522
|
+
Raw Terminal / Bundler / Native Crash Log Input
|
|
523
|
+
</label>
|
|
524
|
+
<textarea
|
|
525
|
+
id="error-log-textarea"
|
|
526
|
+
rows={6}
|
|
527
|
+
value={rawLog}
|
|
528
|
+
onChange={(e) => setRawLog(e.target.value)}
|
|
529
|
+
className="w-full p-3.5 text-xs font-mono bg-slate-950 border border-slate-800 rounded-lg text-slate-200 focus:outline-none focus:border-blue-500"
|
|
530
|
+
placeholder="Paste Metro, Gradle, Kotlin, Xcode, or Red Screen error output here..."
|
|
531
|
+
/>
|
|
532
|
+
<div className="flex justify-end">
|
|
533
|
+
<button
|
|
534
|
+
type="button"
|
|
535
|
+
disabled={diagnosing || !rawLog.trim()}
|
|
536
|
+
onClick={() => handleRunDiagnosis(rawLog)}
|
|
537
|
+
className="inline-flex items-center gap-2 px-4 py-2 text-xs font-semibold text-white bg-blue-600 hover:bg-blue-500 disabled:opacity-50 rounded-lg transition-colors cursor-pointer"
|
|
538
|
+
>
|
|
539
|
+
<Search className="w-3.5 h-3.5" />
|
|
540
|
+
<span>{diagnosing ? 'Analyzing Stack Trace...' : 'Diagnose Error Log'}</span>
|
|
541
|
+
</button>
|
|
542
|
+
</div>
|
|
543
|
+
</div>
|
|
544
|
+
|
|
545
|
+
{diagnosis && (
|
|
546
|
+
<div className="p-6 bg-slate-900/80 border border-slate-800 rounded-lg space-y-4">
|
|
547
|
+
<div className="flex flex-wrap items-center justify-between gap-2 pb-3 border-b border-slate-800">
|
|
548
|
+
<div className="flex items-center gap-2 text-xs flex-wrap">
|
|
549
|
+
<SeverityText severity={diagnosis.severity} />
|
|
550
|
+
<span className="text-slate-500">·</span>
|
|
551
|
+
<span className="font-mono text-blue-400">{diagnosis.category}</span>
|
|
552
|
+
<span className="text-slate-500">·</span>
|
|
553
|
+
<span className="font-mono text-slate-300">
|
|
554
|
+
Confidence: {diagnosis.confidence}%
|
|
555
|
+
</span>
|
|
556
|
+
<span className="text-slate-500">·</span>
|
|
557
|
+
{diagnosis.aiPowered ? (
|
|
558
|
+
<span className="inline-flex items-center gap-1 px-2 py-0.5 rounded text-[11px] font-semibold bg-emerald-950 text-emerald-300 border border-emerald-800">
|
|
559
|
+
✨ AI Powered ({diagnosis.aiModel || 'Groq Qwen 27B'})
|
|
560
|
+
</span>
|
|
561
|
+
) : (
|
|
562
|
+
<span
|
|
563
|
+
className="inline-flex items-center gap-1 px-2 py-0.5 rounded text-[11px] font-semibold bg-amber-950/70 text-amber-300 border border-amber-800"
|
|
564
|
+
title={diagnosis.fallbackReason || 'Built-in Rule Engine'}
|
|
565
|
+
>
|
|
566
|
+
⚡ Local Rule Engine {diagnosis.fallbackUsed ? '(Quota Fallback)' : ''}
|
|
567
|
+
</span>
|
|
568
|
+
)}
|
|
569
|
+
</div>
|
|
570
|
+
<div className="text-xs font-mono text-slate-300">
|
|
571
|
+
Responsible File: <strong>{diagnosis.responsibleFile}</strong>
|
|
572
|
+
{diagnosis.line ? `:${diagnosis.line}` : ''}
|
|
573
|
+
</div>
|
|
574
|
+
</div>
|
|
575
|
+
|
|
576
|
+
<div className="space-y-1.5">
|
|
577
|
+
{diagnosis.fallbackUsed && diagnosis.fallbackReason && (
|
|
578
|
+
<div className="p-2.5 bg-amber-950/40 border border-amber-800/60 rounded text-xs text-amber-200 flex items-center gap-2 mb-2">
|
|
579
|
+
<span>🛡️</span>
|
|
580
|
+
<span>
|
|
581
|
+
<strong>Zero-Downtime Fallback:</strong> {diagnosis.fallbackReason}
|
|
582
|
+
</span>
|
|
583
|
+
</div>
|
|
584
|
+
)}
|
|
585
|
+
<h3 className="text-base font-bold text-slate-100">{diagnosis.summary}</h3>
|
|
586
|
+
<p className="text-xs text-slate-300 leading-relaxed">{diagnosis.rootCause}</p>
|
|
587
|
+
</div>
|
|
588
|
+
|
|
589
|
+
<div className="space-y-2">
|
|
590
|
+
<div className="text-xs font-semibold text-slate-200">
|
|
591
|
+
Recommended Safe Repair Sequence:
|
|
592
|
+
</div>
|
|
593
|
+
<ol className="list-decimal list-inside space-y-1 text-xs text-slate-300">
|
|
594
|
+
{diagnosis.safeRepairSteps.map((step, i) => (
|
|
595
|
+
<li key={i}>{step}</li>
|
|
596
|
+
))}
|
|
597
|
+
</ol>
|
|
598
|
+
</div>
|
|
599
|
+
|
|
600
|
+
{diagnosis.terminalCommands.length > 0 && (
|
|
601
|
+
<div className="space-y-1.5">
|
|
602
|
+
<div className="text-xs font-semibold text-slate-200">
|
|
603
|
+
Exact Terminal Commands:
|
|
604
|
+
</div>
|
|
605
|
+
<pre className="p-3 bg-slate-950 border border-slate-800 rounded text-xs font-mono text-blue-300">
|
|
606
|
+
{diagnosis.terminalCommands.map((c) => `$ ${c}`).join('\n')}
|
|
607
|
+
</pre>
|
|
608
|
+
</div>
|
|
609
|
+
)}
|
|
610
|
+
|
|
611
|
+
{diagnosis.codePatchSuggestion && (
|
|
612
|
+
<div className="space-y-1.5">
|
|
613
|
+
<div className="text-xs font-semibold text-slate-200">
|
|
614
|
+
Suggested Configuration Patch:
|
|
615
|
+
</div>
|
|
616
|
+
<pre className="p-3 bg-slate-950 border border-slate-800 rounded text-xs font-mono text-emerald-300">
|
|
617
|
+
{diagnosis.codePatchSuggestion}
|
|
618
|
+
</pre>
|
|
619
|
+
</div>
|
|
620
|
+
)}
|
|
621
|
+
</div>
|
|
622
|
+
)}
|
|
623
|
+
</div>
|
|
624
|
+
);
|
|
625
|
+
}
|