@agentskillkit/agent-skills 3.2.2 → 3.2.5

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.
Files changed (51) hide show
  1. package/.agent/skills/mobile-design/scripts/mobile_audit.js +333 -0
  2. package/.agent/skills/typescript-expert/scripts/ts_diagnostic.js +227 -0
  3. package/README.md +197 -720
  4. package/package.json +4 -4
  5. package/packages/cli/lib/audit.js +2 -2
  6. package/packages/cli/lib/auto-learn.js +8 -8
  7. package/packages/cli/lib/eslint-fix.js +1 -1
  8. package/packages/cli/lib/fix.js +5 -5
  9. package/packages/cli/lib/hooks/install-hooks.js +4 -4
  10. package/packages/cli/lib/hooks/lint-learn.js +4 -4
  11. package/packages/cli/lib/knowledge-index.js +4 -4
  12. package/packages/cli/lib/knowledge-metrics.js +2 -2
  13. package/packages/cli/lib/knowledge-retention.js +3 -3
  14. package/packages/cli/lib/knowledge-validator.js +3 -3
  15. package/packages/cli/lib/learn.js +10 -10
  16. package/packages/cli/lib/recall.js +1 -1
  17. package/packages/cli/lib/skill-learn.js +2 -2
  18. package/packages/cli/lib/stats.js +3 -3
  19. package/packages/cli/lib/ui/dashboard-ui.js +222 -0
  20. package/packages/cli/lib/ui/help-ui.js +41 -18
  21. package/packages/cli/lib/ui/index.js +57 -5
  22. package/packages/cli/lib/ui/settings-ui.js +292 -14
  23. package/packages/cli/lib/ui/stats-ui.js +93 -43
  24. package/packages/cli/lib/watcher.js +2 -2
  25. package/packages/kit/kit.js +89 -0
  26. package/packages/kit/lib/agents.js +208 -0
  27. package/packages/kit/lib/commands/analyze.js +70 -0
  28. package/packages/kit/lib/commands/cache.js +65 -0
  29. package/packages/kit/lib/commands/doctor.js +75 -0
  30. package/packages/kit/lib/commands/help.js +155 -0
  31. package/packages/kit/lib/commands/info.js +38 -0
  32. package/packages/kit/lib/commands/init.js +39 -0
  33. package/packages/kit/lib/commands/install.js +803 -0
  34. package/packages/kit/lib/commands/list.js +43 -0
  35. package/packages/kit/lib/commands/lock.js +57 -0
  36. package/packages/kit/lib/commands/uninstall.js +307 -0
  37. package/packages/kit/lib/commands/update.js +55 -0
  38. package/packages/kit/lib/commands/validate.js +69 -0
  39. package/packages/kit/lib/commands/verify.js +56 -0
  40. package/packages/kit/lib/config.js +81 -0
  41. package/packages/kit/lib/helpers.js +196 -0
  42. package/packages/kit/lib/helpers.test.js +60 -0
  43. package/packages/kit/lib/installer.js +164 -0
  44. package/packages/kit/lib/skills.js +119 -0
  45. package/packages/kit/lib/skills.test.js +109 -0
  46. package/packages/kit/lib/types.js +82 -0
  47. package/packages/kit/lib/ui.js +329 -0
  48. package/.agent/skills/mobile-design/scripts/mobile_audit.py +0 -670
  49. package/.agent/skills/requirements-python.txt +0 -25
  50. package/.agent/skills/requirements.txt +0 -96
  51. package/.agent/skills/typescript-expert/scripts/ts_diagnostic.py +0 -203
@@ -0,0 +1,333 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Mobile UX Audit Script - Full Mobile Design Coverage
4
+ *
5
+ * Analyzes React Native / Flutter code for compliance with:
6
+ * - Touch Psychology (touch targets, spacing, thumb zones)
7
+ * - Mobile Performance (FlatList, memo, callbacks)
8
+ * - Mobile Navigation (tabs, back handling)
9
+ * - Mobile Typography (system fonts, scaling)
10
+ * - Mobile Color System (dark mode, OLED)
11
+ * - Platform iOS/Android specifics
12
+ * - Mobile Backend (secure storage, offline)
13
+ *
14
+ * Total: 50+ mobile-specific checks
15
+ */
16
+
17
+ import fs from 'fs';
18
+ import path from 'path';
19
+
20
+ class MobileAuditor {
21
+ constructor() {
22
+ this.issues = [];
23
+ this.warnings = [];
24
+ this.passedCount = 0;
25
+ this.filesChecked = 0;
26
+ }
27
+
28
+ auditFile(filepath) {
29
+ let content;
30
+ try {
31
+ content = fs.readFileSync(filepath, 'utf-8');
32
+ } catch {
33
+ return;
34
+ }
35
+
36
+ this.filesChecked++;
37
+ const filename = path.basename(filepath);
38
+
39
+ // Detect framework
40
+ const isReactNative = /react-native|@react-navigation|React\.Native/.test(content);
41
+ const isFlutter = /import 'package:flutter|MaterialApp|Widget\.build/.test(content);
42
+
43
+ if (!isReactNative && !isFlutter) {
44
+ return; // Skip non-mobile files
45
+ }
46
+
47
+ // --- 1. TOUCH PSYCHOLOGY CHECKS ---
48
+
49
+ // 1.1 Touch Target Size Check
50
+ const smallSizes = content.match(/(?:width|height|size):\s*([0-3]\d)/g) || [];
51
+ for (const match of smallSizes) {
52
+ const size = parseInt(match.match(/\d+/)[0]);
53
+ if (size < 44) {
54
+ this.issues.push(`[Touch Target] ${filename}: Touch target size ${size}px < 44px minimum`);
55
+ }
56
+ }
57
+
58
+ // 1.2 Touch Target Spacing Check
59
+ const smallGaps = content.match(/(?:margin|gap):\s*([0-7])\s*(?:px|dp)/g) || [];
60
+ for (const match of smallGaps) {
61
+ const gap = parseInt(match.match(/\d+/)[0]);
62
+ if (gap < 8) {
63
+ this.warnings.push(`[Touch Spacing] ${filename}: Touch spacing ${gap}px < 8px minimum`);
64
+ }
65
+ }
66
+
67
+ // 1.3 Thumb Zone Placement
68
+ const primaryButtons = /(?:testID|id):\s*["'](?:.*(?:primary|cta|submit|confirm)[^"']*)["']/i.test(content);
69
+ const hasBottomPlacement = /position:\s*["']?absolute|bottom:\s*\d+|justifyContent:\s*["']?flex-end/.test(content);
70
+ if (primaryButtons && !hasBottomPlacement) {
71
+ this.warnings.push(`[Thumb Zone] ${filename}: Primary CTA may not be in thumb zone (bottom)`);
72
+ }
73
+
74
+ // 1.4 Gesture Alternatives
75
+ const hasSwipe = /Swipeable|onSwipe|PanGestureHandler|swipe/.test(content);
76
+ const hasButtons = /Button.*(?:delete|archive|more)|TouchableOpacity|Pressable/.test(content);
77
+ if (hasSwipe && !hasButtons) {
78
+ this.warnings.push(`[Gestures] ${filename}: Swipe gestures without visible button alternatives`);
79
+ }
80
+
81
+ // 1.5 Haptic Feedback
82
+ const hasImportantActions = /(?:onPress|onSubmit|delete|remove|confirm|purchase)/.test(content);
83
+ const hasHaptics = /Haptics|Vibration|react-native-haptic-feedback/.test(content);
84
+ if (hasImportantActions && !hasHaptics) {
85
+ this.warnings.push(`[Haptics] ${filename}: Important actions without haptic feedback`);
86
+ }
87
+
88
+ // --- 2. MOBILE PERFORMANCE CHECKS ---
89
+
90
+ // 2.1 CRITICAL: ScrollView vs FlatList
91
+ const hasScrollView = /<ScrollView|ScrollView\./.test(content);
92
+ const hasMapInScrollView = /ScrollView.*\.map\(|ScrollView.*\{.*\.map/.test(content);
93
+ if (hasScrollView && hasMapInScrollView) {
94
+ this.issues.push(`[Performance CRITICAL] ${filename}: ScrollView with .map() - Use FlatList!`);
95
+ }
96
+
97
+ // 2.2 React.memo Check
98
+ if (isReactNative) {
99
+ const hasList = /FlatList|FlashList|SectionList/.test(content);
100
+ const hasMemo = /React\.memo|memo\(/.test(content);
101
+ if (hasList && !hasMemo) {
102
+ this.warnings.push(`[Performance] ${filename}: FlatList without React.memo on list items`);
103
+ }
104
+ }
105
+
106
+ // 2.3 useCallback Check
107
+ if (isReactNative) {
108
+ const hasFlatList = /FlatList|FlashList/.test(content);
109
+ const hasCallback = /useCallback/.test(content);
110
+ if (hasFlatList && !hasCallback) {
111
+ this.warnings.push(`[Performance] ${filename}: FlatList renderItem without useCallback`);
112
+ }
113
+ }
114
+
115
+ // 2.4 keyExtractor Check (CRITICAL)
116
+ if (isReactNative) {
117
+ const hasFlatList = /FlatList/.test(content);
118
+ const hasKeyExtractor = /keyExtractor/.test(content);
119
+ const usesIndexKey = /key=\{.*index.*\}|key:\s*index/.test(content);
120
+ if (hasFlatList && !hasKeyExtractor) {
121
+ this.issues.push(`[Performance CRITICAL] ${filename}: FlatList without keyExtractor`);
122
+ }
123
+ if (usesIndexKey) {
124
+ this.issues.push(`[Performance CRITICAL] ${filename}: Using index as key - use unique ID`);
125
+ }
126
+ }
127
+
128
+ // 2.5 useNativeDriver Check
129
+ if (isReactNative) {
130
+ const hasAnimated = /Animated\./.test(content);
131
+ const hasNativeDriverFalse = /useNativeDriver:\s*false/.test(content);
132
+ if (hasAnimated && hasNativeDriverFalse) {
133
+ this.warnings.push(`[Performance] ${filename}: Animation with useNativeDriver: false`);
134
+ }
135
+ }
136
+
137
+ // 2.6 Memory Leak Check
138
+ if (isReactNative) {
139
+ const hasEffect = /useEffect/.test(content);
140
+ const hasCleanup = /return\s*\(\)\s*=>|return\s+function/.test(content);
141
+ const hasSubscriptions = /addEventListener|subscribe|\.focus\(\)|\.off\(/.test(content);
142
+ if (hasEffect && hasSubscriptions && !hasCleanup) {
143
+ this.issues.push(`[Memory Leak] ${filename}: useEffect with subscriptions but no cleanup`);
144
+ }
145
+ }
146
+
147
+ // 2.7 Console.log Detection
148
+ const consoleLogs = (content.match(/console\.log|console\.warn|console\.error/g) || []).length;
149
+ if (consoleLogs > 5) {
150
+ this.warnings.push(`[Performance] ${filename}: ${consoleLogs} console.log statements`);
151
+ }
152
+
153
+ // 2.8 Inline Function Detection
154
+ if (isReactNative) {
155
+ const inlineFunctions = (content.match(/(?:onPress|renderItem):\s*\([^)]*\)\s*=>/g) || []).length;
156
+ if (inlineFunctions > 3) {
157
+ this.warnings.push(`[Performance] ${filename}: ${inlineFunctions} inline arrow functions - use useCallback`);
158
+ }
159
+ }
160
+
161
+ // --- 3. MOBILE NAVIGATION CHECKS ---
162
+
163
+ // 3.1 Tab Bar Max Items
164
+ const tabItems = (content.match(/Tab\.Screen|createBottomTabNavigator/g) || []).length;
165
+ if (tabItems > 5) {
166
+ this.warnings.push(`[Navigation] ${filename}: ${tabItems} tab items (max 5 recommended)`);
167
+ }
168
+
169
+ // --- 4. MOBILE TYPOGRAPHY CHECKS ---
170
+
171
+ // 4.1 Font Size Limits
172
+ const fontSizes = content.match(/fontSize:\s*([\d.]+)/g) || [];
173
+ for (const match of fontSizes) {
174
+ const size = parseFloat(match.match(/[\d.]+/)[0]);
175
+ if (size < 12) {
176
+ this.warnings.push(`[Typography] ${filename}: fontSize ${size}px below 12px minimum`);
177
+ }
178
+ }
179
+
180
+ // --- 5. MOBILE COLOR SYSTEM CHECKS ---
181
+
182
+ // 5.1 Pure Black Avoidance
183
+ if (/#000000|color:\s*black|backgroundColor:\s*["']?black/.test(content)) {
184
+ this.warnings.push(`[Color] ${filename}: Pure black (#000000) - use dark gray for OLED`);
185
+ }
186
+
187
+ // 5.2 Dark Mode Support
188
+ const hasColorScheme = /useColorScheme|colorScheme|appearance:\s*["']?dark/.test(content);
189
+ if (!hasColorScheme) {
190
+ this.warnings.push(`[Color] ${filename}: No dark mode support detected`);
191
+ }
192
+
193
+ // --- 6. PLATFORM iOS CHECKS ---
194
+
195
+ if (isReactNative) {
196
+ // 6.1 iOS Safe Area
197
+ const hasSafeArea = /SafeAreaView|useSafeAreaInsets/.test(content);
198
+ if (!hasSafeArea) {
199
+ this.warnings.push(`[iOS] ${filename}: No SafeArea detected - content may be hidden by notch`);
200
+ }
201
+ }
202
+
203
+ // --- 7. PLATFORM ANDROID CHECKS ---
204
+
205
+ if (isReactNative) {
206
+ // 7.1 Ripple Effect
207
+ const hasRipple = /ripple|android_ripple/.test(content);
208
+ const hasPressable = /Pressable|Touchable/.test(content);
209
+ if (hasPressable && !hasRipple) {
210
+ this.warnings.push(`[Android] ${filename}: Touchable without ripple effect`);
211
+ }
212
+ }
213
+
214
+ // --- 8. MOBILE BACKEND CHECKS ---
215
+
216
+ // 8.1 Secure Storage Check
217
+ const hasAsyncStorage = /AsyncStorage|@react-native-async-storage/.test(content);
218
+ const hasSecureStorage = /SecureStore|Keychain|EncryptedSharedPreferences/.test(content);
219
+ const hasTokenStorage = /token|jwt|auth.*storage/i.test(content);
220
+ if (hasTokenStorage && hasAsyncStorage && !hasSecureStorage) {
221
+ this.issues.push(`[Security] ${filename}: Auth tokens in AsyncStorage - use SecureStore!`);
222
+ }
223
+
224
+ // 8.2 Offline Handling
225
+ const hasNetwork = /fetch|axios|netinfo/.test(content);
226
+ const hasOffline = /offline|isConnected|netInfo/.test(content);
227
+ if (hasNetwork && !hasOffline) {
228
+ this.warnings.push(`[Offline] ${filename}: Network requests without offline handling`);
229
+ }
230
+
231
+ // --- 9. ACCESSIBILITY ---
232
+
233
+ if (isReactNative) {
234
+ const hasPressable = /Pressable|TouchableOpacity/.test(content);
235
+ const hasA11yLabel = /accessibilityLabel|aria-label|testID/.test(content);
236
+ if (hasPressable && !hasA11yLabel) {
237
+ this.warnings.push(`[A11y] ${filename}: Touchable without accessibilityLabel`);
238
+ }
239
+ }
240
+
241
+ // --- 10. ERROR HANDLING ---
242
+
243
+ if (isReactNative) {
244
+ const hasErrorBoundary = /ErrorBoundary|componentDidCatch/.test(content);
245
+ if (!hasErrorBoundary) {
246
+ this.warnings.push(`[Error] ${filename}: No ErrorBoundary detected`);
247
+ }
248
+ }
249
+ }
250
+
251
+ auditDirectory(directory) {
252
+ const extensions = new Set(['.tsx', '.ts', '.jsx', '.js', '.dart']);
253
+ const excludeDirs = new Set(['node_modules', '.git', 'dist', 'build', '.next', 'ios', 'android']);
254
+
255
+ const walk = (dir) => {
256
+ try {
257
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
258
+ for (const entry of entries) {
259
+ const fullPath = path.join(dir, entry.name);
260
+ if (entry.isDirectory()) {
261
+ if (!excludeDirs.has(entry.name)) {
262
+ walk(fullPath);
263
+ }
264
+ } else if (entry.isFile()) {
265
+ if (extensions.has(path.extname(entry.name))) {
266
+ this.auditFile(fullPath);
267
+ }
268
+ }
269
+ }
270
+ } catch {
271
+ // Ignore permission errors
272
+ }
273
+ };
274
+
275
+ walk(directory);
276
+ }
277
+
278
+ getReport() {
279
+ return {
280
+ files_checked: this.filesChecked,
281
+ issues: this.issues,
282
+ warnings: this.warnings,
283
+ passed_checks: this.passedCount,
284
+ compliant: this.issues.length === 0
285
+ };
286
+ }
287
+ }
288
+
289
+ function main() {
290
+ const args = process.argv.slice(2);
291
+ if (args.length < 1) {
292
+ console.log('Usage: node mobile_audit.js <directory>');
293
+ process.exit(1);
294
+ }
295
+
296
+ const targetPath = args[0];
297
+ const isJson = args.includes('--json');
298
+
299
+ const auditor = new MobileAuditor();
300
+
301
+ if (fs.statSync(targetPath).isFile()) {
302
+ auditor.auditFile(targetPath);
303
+ } else {
304
+ auditor.auditDirectory(targetPath);
305
+ }
306
+
307
+ const report = auditor.getReport();
308
+
309
+ if (isJson) {
310
+ console.log(JSON.stringify(report, null, 2));
311
+ } else {
312
+ console.log(`\n[MOBILE AUDIT] ${report.files_checked} mobile files checked`);
313
+ console.log('-'.repeat(50));
314
+
315
+ if (report.issues.length > 0) {
316
+ console.log(`[!] ISSUES (${report.issues.length}):`);
317
+ report.issues.slice(0, 10).forEach(i => console.log(` - ${i}`));
318
+ }
319
+
320
+ if (report.warnings.length > 0) {
321
+ console.log(`[*] WARNINGS (${report.warnings.length}):`);
322
+ report.warnings.slice(0, 15).forEach(w => console.log(` - ${w}`));
323
+ }
324
+
325
+ console.log(`[+] PASSED CHECKS: ${report.passed_checks}`);
326
+ const status = report.compliant ? 'PASS' : 'FAIL';
327
+ console.log(`STATUS: ${status}`);
328
+ }
329
+
330
+ process.exit(report.compliant ? 0 : 1);
331
+ }
332
+
333
+ main();
@@ -0,0 +1,227 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * TypeScript Project Diagnostic Script
4
+ * Analyzes TypeScript projects for configuration, performance, and common issues.
5
+ */
6
+
7
+ import { execSync } from 'child_process';
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+
11
+ /**
12
+ * Run shell command and return output.
13
+ * @param {string} cmd
14
+ * @returns {string}
15
+ */
16
+ function runCmd(cmd) {
17
+ try {
18
+ return execSync(cmd, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
19
+ } catch (e) {
20
+ return e.stdout || e.stderr || e.message;
21
+ }
22
+ }
23
+
24
+ function checkVersions() {
25
+ console.log('\n📦 Versions:');
26
+ console.log('-'.repeat(40));
27
+
28
+ const tsVersion = runCmd('npx tsc --version 2>/dev/null').trim();
29
+ const nodeVersion = runCmd('node -v 2>/dev/null').trim();
30
+
31
+ console.log(` TypeScript: ${tsVersion || 'Not found'}`);
32
+ console.log(` Node.js: ${nodeVersion || 'Not found'}`);
33
+ }
34
+
35
+ function checkTsconfig() {
36
+ console.log('\n⚙️ TSConfig Analysis:');
37
+ console.log('-'.repeat(40));
38
+
39
+ const tsconfigPath = 'tsconfig.json';
40
+ if (!fs.existsSync(tsconfigPath)) {
41
+ console.log('⚠️ tsconfig.json not found');
42
+ return;
43
+ }
44
+
45
+ try {
46
+ const config = JSON.parse(fs.readFileSync(tsconfigPath, 'utf-8'));
47
+ const compilerOpts = config.compilerOptions || {};
48
+
49
+ // Check strict mode
50
+ if (compilerOpts.strict) {
51
+ console.log('✅ Strict mode enabled');
52
+ } else {
53
+ console.log('⚠️ Strict mode NOT enabled');
54
+ }
55
+
56
+ // Check important flags
57
+ const flags = {
58
+ noUncheckedIndexedAccess: 'Unchecked index access protection',
59
+ noImplicitOverride: 'Implicit override protection',
60
+ skipLibCheck: 'Skip lib check (performance)',
61
+ incremental: 'Incremental compilation'
62
+ };
63
+
64
+ for (const [flag, desc] of Object.entries(flags)) {
65
+ const status = compilerOpts[flag] ? '✅' : '⚪';
66
+ console.log(` ${status} ${desc}: ${compilerOpts[flag] ?? 'not set'}`);
67
+ }
68
+
69
+ // Check module settings
70
+ console.log(`\n Module: ${compilerOpts.module || 'not set'}`);
71
+ console.log(` Module Resolution: ${compilerOpts.moduleResolution || 'not set'}`);
72
+ console.log(` Target: ${compilerOpts.target || 'not set'}`);
73
+
74
+ } catch (e) {
75
+ console.log('❌ Invalid JSON in tsconfig.json');
76
+ }
77
+ }
78
+
79
+ function checkTooling() {
80
+ console.log('\n🛠️ Tooling Detection:');
81
+ console.log('-'.repeat(40));
82
+
83
+ const pkgPath = 'package.json';
84
+ if (!fs.existsSync(pkgPath)) {
85
+ console.log('⚠️ package.json not found');
86
+ return;
87
+ }
88
+
89
+ try {
90
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
91
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
92
+
93
+ const tools = {
94
+ biome: 'Biome (linter/formatter)',
95
+ eslint: 'ESLint',
96
+ prettier: 'Prettier',
97
+ vitest: 'Vitest (testing)',
98
+ jest: 'Jest (testing)',
99
+ turborepo: 'Turborepo (monorepo)',
100
+ turbo: 'Turbo (monorepo)',
101
+ nx: 'Nx (monorepo)',
102
+ lerna: 'Lerna (monorepo)'
103
+ };
104
+
105
+ for (const [tool, desc] of Object.entries(tools)) {
106
+ for (const dep of Object.keys(allDeps || {})) {
107
+ if (dep.toLowerCase().includes(tool)) {
108
+ console.log(` ✅ ${desc}`);
109
+ break;
110
+ }
111
+ }
112
+ }
113
+ } catch (e) {
114
+ console.log('❌ Invalid JSON in package.json');
115
+ }
116
+ }
117
+
118
+ function checkMonorepo() {
119
+ console.log('\n📦 Monorepo Check:');
120
+ console.log('-'.repeat(40));
121
+
122
+ const indicators = [
123
+ ['pnpm-workspace.yaml', 'PNPM Workspace'],
124
+ ['lerna.json', 'Lerna'],
125
+ ['nx.json', 'Nx'],
126
+ ['turbo.json', 'Turborepo']
127
+ ];
128
+
129
+ let found = false;
130
+ for (const [file, name] of indicators) {
131
+ if (fs.existsSync(file)) {
132
+ console.log(` ✅ ${name} detected`);
133
+ found = true;
134
+ }
135
+ }
136
+
137
+ if (!found) {
138
+ console.log(' ⚪ No monorepo configuration detected');
139
+ }
140
+ }
141
+
142
+ function checkTypeErrors() {
143
+ console.log('\n🔍 Type Check:');
144
+ console.log('-'.repeat(40));
145
+
146
+ const result = runCmd('npx tsc --noEmit 2>&1');
147
+ if (result.includes('error TS')) {
148
+ const errors = (result.match(/error TS/g) || []).length;
149
+ console.log(` ❌ ${errors}+ type errors found`);
150
+ console.log(result.slice(0, 500));
151
+ } else {
152
+ console.log(' ✅ No type errors');
153
+ }
154
+ }
155
+
156
+ function checkAnyUsage() {
157
+ console.log("\n⚠️ 'any' Type Usage:");
158
+ console.log('-'.repeat(40));
159
+
160
+ try {
161
+ const result = runCmd("grep -r ': any' --include='*.ts' --include='*.tsx' src/ 2>/dev/null | wc -l");
162
+ const count = result.trim();
163
+ if (count && count !== '0') {
164
+ console.log(` ⚠️ Found ${count} occurrences of ': any'`);
165
+ const sample = runCmd("grep -rn ': any' --include='*.ts' --include='*.tsx' src/ 2>/dev/null | head -5");
166
+ if (sample) console.log(sample);
167
+ } else {
168
+ console.log(" ✅ No explicit 'any' types found");
169
+ }
170
+ } catch {
171
+ console.log(" ⚪ Could not check (grep not available on Windows)");
172
+ }
173
+ }
174
+
175
+ function checkTypeAssertions() {
176
+ console.log('\n⚠️ Type Assertions (as):');
177
+ console.log('-'.repeat(40));
178
+
179
+ try {
180
+ const result = runCmd("grep -r ' as ' --include='*.ts' --include='*.tsx' src/ 2>/dev/null | grep -v 'import' | wc -l");
181
+ const count = result.trim();
182
+ if (count && count !== '0') {
183
+ console.log(` ⚠️ Found ${count} type assertions`);
184
+ } else {
185
+ console.log(' ✅ No type assertions found');
186
+ }
187
+ } catch {
188
+ console.log(' ⚪ Could not check (grep not available on Windows)');
189
+ }
190
+ }
191
+
192
+ function checkPerformance() {
193
+ console.log('\n⏱️ Type Check Performance:');
194
+ console.log('-'.repeat(40));
195
+
196
+ const result = runCmd('npx tsc --extendedDiagnostics --noEmit 2>&1');
197
+ const lines = result.split('\n').filter(line =>
198
+ /Check time|Files:|Lines:|Nodes:/.test(line)
199
+ );
200
+
201
+ if (lines.length > 0) {
202
+ lines.forEach(line => console.log(` ${line}`));
203
+ } else {
204
+ console.log(' ⚠️ Could not measure performance');
205
+ }
206
+ }
207
+
208
+ function main() {
209
+ console.log('='.repeat(50));
210
+ console.log('🔍 TypeScript Project Diagnostic Report');
211
+ console.log('='.repeat(50));
212
+
213
+ checkVersions();
214
+ checkTsconfig();
215
+ checkTooling();
216
+ checkMonorepo();
217
+ checkAnyUsage();
218
+ checkTypeAssertions();
219
+ checkTypeErrors();
220
+ checkPerformance();
221
+
222
+ console.log('\n' + '='.repeat(50));
223
+ console.log('✅ Diagnostic Complete');
224
+ console.log('='.repeat(50));
225
+ }
226
+
227
+ main();