vibecodingmachine-core 2026.2.20-438 → 2026.2.26-1739

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 (202) hide show
  1. package/README.md +240 -0
  2. package/package.json +10 -2
  3. package/src/agents/Agent.js +300 -0
  4. package/src/agents/AgentAdditionService.js +311 -0
  5. package/src/agents/AgentCheckService.js +690 -0
  6. package/src/agents/AgentInstallationService.js +140 -0
  7. package/src/agents/AgentSetupService.js +467 -0
  8. package/src/agents/AgentStatus.js +183 -0
  9. package/src/agents/AgentVerificationService.js +634 -0
  10. package/src/agents/ConfigurationSchemaValidator.js +543 -0
  11. package/src/agents/EnvironmentConfigurationManager.js +602 -0
  12. package/src/agents/InstallationErrorHandler.js +372 -0
  13. package/src/agents/InstallationLog.js +363 -0
  14. package/src/agents/InstallationMethod.js +510 -0
  15. package/src/agents/InstallationOrchestrator.js +352 -0
  16. package/src/agents/InstallationProgressReporter.js +372 -0
  17. package/src/agents/InstallationRetryManager.js +322 -0
  18. package/src/agents/InstallationType.js +254 -0
  19. package/src/agents/OperationTypes.js +310 -0
  20. package/src/agents/PerformanceMetricsCollector.js +493 -0
  21. package/src/agents/SecurityValidationService.js +534 -0
  22. package/src/agents/VerificationTest.js +354 -0
  23. package/src/agents/VerificationType.js +226 -0
  24. package/src/agents/WindowsPermissionHandler.js +518 -0
  25. package/src/agents/config/AgentConfigManager.js +393 -0
  26. package/src/agents/config/AgentDefaultsRegistry.js +373 -0
  27. package/src/agents/config/ConfigValidator.js +281 -0
  28. package/src/agents/discovery/AgentDiscoveryService.js +707 -0
  29. package/src/agents/logging/AgentLogger.js +511 -0
  30. package/src/agents/status/AgentStatusManager.js +481 -0
  31. package/src/agents/storage/FileManager.js +454 -0
  32. package/src/agents/verification/AgentCommunicationTester.js +474 -0
  33. package/src/agents/verification/BaseVerifier.js +430 -0
  34. package/src/agents/verification/CommandVerifier.js +480 -0
  35. package/src/agents/verification/FileOperationVerifier.js +453 -0
  36. package/src/agents/verification/ResultAnalyzer.js +707 -0
  37. package/src/agents/verification/TestRequirementManager.js +495 -0
  38. package/src/agents/verification/VerificationRunner.js +433 -0
  39. package/src/agents/windows/BaseWindowsInstaller.js +441 -0
  40. package/src/agents/windows/ChocolateyInstaller.js +509 -0
  41. package/src/agents/windows/DirectInstaller.js +443 -0
  42. package/src/agents/windows/InstallerFactory.js +391 -0
  43. package/src/agents/windows/NpmInstaller.js +505 -0
  44. package/src/agents/windows/PowerShellInstaller.js +458 -0
  45. package/src/agents/windows/WinGetInstaller.js +390 -0
  46. package/src/analysis/analysis-reporter.js +132 -0
  47. package/src/analysis/boundary-detector.js +712 -0
  48. package/src/analysis/categorizer.js +340 -0
  49. package/src/analysis/codebase-scanner.js +384 -0
  50. package/src/analysis/line-counter.js +513 -0
  51. package/src/analysis/priority-calculator.js +679 -0
  52. package/src/analysis/report/analysis-report.js +250 -0
  53. package/src/analysis/report/package-analyzer.js +278 -0
  54. package/src/analysis/report/recommendation-generator.js +382 -0
  55. package/src/analysis/report/statistics-generator.js +515 -0
  56. package/src/analysis/reports/analysis-report-model.js +101 -0
  57. package/src/analysis/reports/recommendation-generator.js +283 -0
  58. package/src/analysis/reports/report-generators.js +191 -0
  59. package/src/analysis/reports/statistics-calculator.js +231 -0
  60. package/src/analysis/reports/trend-analyzer.js +219 -0
  61. package/src/analysis/strategy-generator.js +814 -0
  62. package/src/auto-mode/AutoModeBusinessLogic.js +836 -0
  63. package/src/config/refactoring-config.js +307 -0
  64. package/src/health-tracking/json-storage.js +38 -2
  65. package/src/ide-integration/applescript-manager-core.js +233 -0
  66. package/src/ide-integration/applescript-manager.cjs +357 -28
  67. package/src/ide-integration/applescript-manager.js +89 -3599
  68. package/src/ide-integration/cdp-manager.js +306 -0
  69. package/src/ide-integration/claude-code-cli-manager.cjs +1 -1
  70. package/src/ide-integration/continuation-handler.js +337 -0
  71. package/src/ide-integration/ide-status-checker.js +292 -0
  72. package/src/ide-integration/macos-ide-manager.js +627 -0
  73. package/src/ide-integration/macos-text-sender.js +528 -0
  74. package/src/ide-integration/response-reader.js +548 -0
  75. package/src/ide-integration/windows-automation-manager.js +121 -0
  76. package/src/ide-integration/windows-ide-manager.js +373 -0
  77. package/src/index.cjs +25 -3
  78. package/src/index.js +15 -1
  79. package/src/llm/direct-llm-manager.cjs +90 -2
  80. package/src/models/compliance-report.js +538 -0
  81. package/src/models/file-analysis.js +681 -0
  82. package/src/models/refactoring-plan.js +770 -0
  83. package/src/monitoring/alert-system.js +834 -0
  84. package/src/monitoring/compliance-progress-tracker.js +437 -0
  85. package/src/monitoring/continuous-scan-notifications.js +661 -0
  86. package/src/monitoring/continuous-scanner.js +279 -0
  87. package/src/monitoring/file-monitor/file-analyzer.js +262 -0
  88. package/src/monitoring/file-monitor/file-monitor.js +237 -0
  89. package/src/monitoring/file-monitor/watcher.js +194 -0
  90. package/src/monitoring/file-monitor.js +17 -0
  91. package/src/monitoring/notification-manager.js +437 -0
  92. package/src/monitoring/scanner-core.js +368 -0
  93. package/src/monitoring/scanner-events.js +214 -0
  94. package/src/monitoring/violation-notification-system.js +515 -0
  95. package/src/refactoring/boundaries/cohesion-analyzer.js +316 -0
  96. package/src/refactoring/boundaries/extraction-result.js +285 -0
  97. package/src/refactoring/boundaries/extraction-strategies.js +392 -0
  98. package/src/refactoring/boundaries/module-boundary.js +209 -0
  99. package/src/refactoring/boundary/boundary-detector.js +741 -0
  100. package/src/refactoring/boundary/boundary-types.js +405 -0
  101. package/src/refactoring/boundary/extraction-strategies.js +554 -0
  102. package/src/refactoring/boundary-extraction-result.js +77 -0
  103. package/src/refactoring/boundary-extraction-strategies.js +330 -0
  104. package/src/refactoring/boundary-extractor.js +384 -0
  105. package/src/refactoring/boundary-types.js +46 -0
  106. package/src/refactoring/circular/circular-dependency.js +88 -0
  107. package/src/refactoring/circular/cycle-detection.js +147 -0
  108. package/src/refactoring/circular/dependency-node.js +82 -0
  109. package/src/refactoring/circular/dependency-result.js +107 -0
  110. package/src/refactoring/circular/dependency-types.js +58 -0
  111. package/src/refactoring/circular/graph-builder.js +213 -0
  112. package/src/refactoring/circular/resolution-strategy.js +72 -0
  113. package/src/refactoring/circular/strategy-generator.js +229 -0
  114. package/src/refactoring/circular-dependency-resolver-original.js +809 -0
  115. package/src/refactoring/circular-dependency-resolver.js +200 -0
  116. package/src/refactoring/code-mover.js +761 -0
  117. package/src/refactoring/file-splitter.js +696 -0
  118. package/src/refactoring/functionality-validator.js +816 -0
  119. package/src/refactoring/import-manager.js +774 -0
  120. package/src/refactoring/module-boundary.js +107 -0
  121. package/src/refactoring/refactoring-executor.js +672 -0
  122. package/src/refactoring/refactoring-rollback.js +614 -0
  123. package/src/refactoring/test-validator.js +631 -0
  124. package/src/requirement-management/default-requirement-manager.js +321 -0
  125. package/src/requirement-management/requirement-file-parser.js +159 -0
  126. package/src/requirement-management/requirement-sequencer.js +221 -0
  127. package/src/rui/commands/AgentCommandParser.js +600 -0
  128. package/src/rui/commands/AgentCommands.js +487 -0
  129. package/src/rui/commands/AgentResponseFormatter.js +832 -0
  130. package/src/scripts/verify-full-compliance.js +269 -0
  131. package/src/sync/sync-engine-core.js +1 -0
  132. package/src/sync/sync-engine-remote-handlers.js +135 -0
  133. package/src/task-generation/automated-task-generator.js +351 -0
  134. package/src/task-generation/prioritizer.js +287 -0
  135. package/src/task-generation/task-list-updater.js +215 -0
  136. package/src/task-generation/task-management-integration.js +480 -0
  137. package/src/task-generation/task-manager-integration.js +270 -0
  138. package/src/task-generation/violation-task-generator.js +474 -0
  139. package/src/task-management/continuous-scan-integration.js +342 -0
  140. package/src/timeout-management/index.js +12 -3
  141. package/src/timeout-management/response-time-tracker.js +167 -0
  142. package/src/timeout-management/timeout-calculator.js +159 -0
  143. package/src/timeout-management/timeout-config-manager.js +172 -0
  144. package/src/utils/ast-analyzer.js +417 -0
  145. package/src/utils/current-requirement-manager.js +276 -0
  146. package/src/utils/current-requirement-operations.js +472 -0
  147. package/src/utils/dependency-mapper.js +456 -0
  148. package/src/utils/download-with-progress.js +4 -2
  149. package/src/utils/electron-update-checker.js +4 -1
  150. package/src/utils/file-size-analyzer.js +272 -0
  151. package/src/utils/import-updater.js +280 -0
  152. package/src/utils/refactoring-tools.js +512 -0
  153. package/src/utils/report-generator.js +569 -0
  154. package/src/utils/reports/report-analysis.js +218 -0
  155. package/src/utils/reports/report-types.js +55 -0
  156. package/src/utils/reports/summary-generators.js +102 -0
  157. package/src/utils/requirement-file-management.js +157 -0
  158. package/src/utils/requirement-helpers/requirement-file-ops.js +392 -0
  159. package/src/utils/requirement-helpers/requirement-mover.js +414 -0
  160. package/src/utils/requirement-helpers/requirement-parser.js +326 -0
  161. package/src/utils/requirement-helpers/requirement-status.js +320 -0
  162. package/src/utils/requirement-helpers-new.js +55 -0
  163. package/src/utils/requirement-helpers-refactored.js +367 -0
  164. package/src/utils/requirement-helpers.js +291 -1191
  165. package/src/utils/requirement-movement-operations.js +450 -0
  166. package/src/utils/requirement-movement.js +312 -0
  167. package/src/utils/requirement-parsing-helpers.js +56 -0
  168. package/src/utils/requirement-statistics.js +200 -0
  169. package/src/utils/requirement-text-utils.js +58 -0
  170. package/src/utils/rollback/rollback-handlers.js +125 -0
  171. package/src/utils/rollback/rollback-operation.js +63 -0
  172. package/src/utils/rollback/rollback-recorder.js +166 -0
  173. package/src/utils/rollback/rollback-state-manager.js +175 -0
  174. package/src/utils/rollback/rollback-types.js +33 -0
  175. package/src/utils/rollback/rollback-utils.js +110 -0
  176. package/src/utils/rollback-manager-original.js +569 -0
  177. package/src/utils/rollback-manager.js +202 -0
  178. package/src/utils/smoke-test-cli.js +362 -0
  179. package/src/utils/smoke-test-gui.js +351 -0
  180. package/src/utils/smoke-test-orchestrator.js +321 -0
  181. package/src/utils/smoke-test-runner.js +60 -0
  182. package/src/utils/smoke-test-web.js +347 -0
  183. package/src/utils/specification-helpers.js +39 -13
  184. package/src/utils/specification-migration.js +97 -0
  185. package/src/utils/test-runner.js +579 -0
  186. package/src/utils/validation-framework.js +518 -0
  187. package/src/validation/compliance-analyzer.js +197 -0
  188. package/src/validation/compliance-report-generator.js +343 -0
  189. package/src/validation/compliance-reporter.js +711 -0
  190. package/src/validation/compliance-rules.js +127 -0
  191. package/src/validation/constitution-validator-new.js +196 -0
  192. package/src/validation/constitution-validator.js +17 -0
  193. package/src/validation/file-validators.js +170 -0
  194. package/src/validation/line-limit/file-analyzer.js +201 -0
  195. package/src/validation/line-limit/line-limit-validator.js +208 -0
  196. package/src/validation/line-limit/validation-result.js +144 -0
  197. package/src/validation/line-limit-core.js +225 -0
  198. package/src/validation/line-limit-reporter.js +134 -0
  199. package/src/validation/line-limit-result.js +125 -0
  200. package/src/validation/line-limit-validator.js +41 -0
  201. package/src/validation/metrics-calculator.js +660 -0
  202. package/src/sync/sync-engine-backup.js +0 -559
@@ -0,0 +1,340 @@
1
+ /**
2
+ * File Categorizer
3
+ *
4
+ * Categorizes files based on size, complexity, and refactoring priority.
5
+ * Provides consistent categorization across the analysis pipeline.
6
+ */
7
+
8
+ const RefactoringConfig = require('../config/refactoring-config');
9
+
10
+ /**
11
+ * File size categories
12
+ */
13
+ const SIZE_CATEGORIES = {
14
+ SMALL: 'SMALL',
15
+ MEDIUM: 'MEDIUM',
16
+ LARGE: 'LARGE',
17
+ XLARGE: 'XLARGE'
18
+ };
19
+
20
+ /**
21
+ * Priority categories
22
+ */
23
+ const PRIORITY_CATEGORIES = {
24
+ LOW: 'LOW',
25
+ MEDIUM: 'MEDIUM',
26
+ HIGH: 'HIGH',
27
+ CRITICAL: 'CRITICAL'
28
+ };
29
+
30
+ /**
31
+ * Complexity categories
32
+ */
33
+ const COMPLEXITY_CATEGORIES = {
34
+ SIMPLE: 'SIMPLE',
35
+ MODERATE: 'MODERATE',
36
+ COMPLEX: 'COMPLEX',
37
+ VERY_COMPLEX: 'VERY_COMPLEX'
38
+ };
39
+
40
+ /**
41
+ * File categorizer class
42
+ */
43
+ class FileCategorizer {
44
+ constructor(config = RefactoringConfig) {
45
+ this.config = config;
46
+ this.limits = config.limits;
47
+ }
48
+
49
+ /**
50
+ * Categorize file by size
51
+ */
52
+ categorizeBySize(lineCount) {
53
+ if (lineCount <= this.limits.smallFileMax) {
54
+ return SIZE_CATEGORIES.SMALL;
55
+ } else if (lineCount <= this.limits.mediumFileMax) {
56
+ return SIZE_CATEGORIES.MEDIUM;
57
+ } else if (lineCount <= this.limits.largeFileMax) {
58
+ return SIZE_CATEGORIES.LARGE;
59
+ } else {
60
+ return SIZE_CATEGORIES.XLARGE;
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Categorize file by priority
66
+ */
67
+ categorizeByPriority(fileAnalysis) {
68
+ const { lineCount, complexity, isTestFile, isConfigFile, package: packageName } = fileAnalysis;
69
+
70
+ // Critical priority: files way over the limit
71
+ if (lineCount > this.limits.criticalThreshold) {
72
+ return PRIORITY_CATEGORIES.CRITICAL;
73
+ }
74
+
75
+ // High priority: files over the limit
76
+ if (lineCount > this.limits.maxFileSize) {
77
+ return PRIORITY_CATEGORIES.HIGH;
78
+ }
79
+
80
+ // Medium priority: files approaching the limit
81
+ if (lineCount > this.limits.warningThreshold) {
82
+ return PRIORITY_CATEGORIES.MEDIUM;
83
+ }
84
+
85
+ // Consider complexity for medium priority
86
+ if (complexity >= COMPLEXITY_CATEGORIES.COMPLEX && lineCount > this.limits.mediumFileMax) {
87
+ return PRIORITY_CATEGORIES.MEDIUM;
88
+ }
89
+
90
+ // Low priority for everything else
91
+ return PRIORITY_CATEGORIES.LOW;
92
+ }
93
+
94
+ /**
95
+ * Categorize file by complexity
96
+ */
97
+ categorizeByComplexity(fileAnalysis) {
98
+ const { cyclomaticComplexity, nestingDepth, functionCount, classCount } = fileAnalysis;
99
+
100
+ // Use multiple factors for complexity assessment
101
+ const complexityScore = this._calculateComplexityScore({
102
+ cyclomaticComplexity,
103
+ nestingDepth,
104
+ functionCount,
105
+ classCount
106
+ });
107
+
108
+ if (complexityScore >= 80) {
109
+ return COMPLEXITY_CATEGORIES.VERY_COMPLEX;
110
+ } else if (complexityScore >= 60) {
111
+ return COMPLEXITY_CATEGORIES.COMPLEX;
112
+ } else if (complexityScore >= 30) {
113
+ return COMPLEXITY_CATEGORIES.MODERATE;
114
+ } else {
115
+ return COMPLEXITY_CATEGORIES.SIMPLE;
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Categorize file by refactoring difficulty
121
+ */
122
+ categorizeByDifficulty(fileAnalysis) {
123
+ const { lineCount, complexity, hasImports, hasExports, dependencyCount } = fileAnalysis;
124
+
125
+ let difficultyScore = 0;
126
+
127
+ // Size contribution
128
+ if (lineCount > 1000) difficultyScore += 40;
129
+ else if (lineCount > 555) difficultyScore += 30;
130
+ else if (lineCount > 300) difficultyScore += 20;
131
+ else if (lineCount > 100) difficultyScore += 10;
132
+
133
+ // Complexity contribution
134
+ if (complexity === COMPLEXITY_CATEGORIES.VERY_COMPLEX) difficultyScore += 30;
135
+ else if (complexity === COMPLEXITY_CATEGORIES.COMPLEX) difficultyScore += 20;
136
+ else if (complexity === COMPLEXITY_CATEGORIES.MODERATE) difficultyScore += 10;
137
+
138
+ // Dependencies contribution
139
+ if (dependencyCount > 20) difficultyScore += 20;
140
+ else if (dependencyCount > 10) difficultyScore += 10;
141
+ else if (dependencyCount > 5) difficultyScore += 5;
142
+
143
+ // Import/Export complexity
144
+ if (hasImports && hasExports) difficultyScore += 10;
145
+ else if (hasImports || hasExports) difficultyScore += 5;
146
+
147
+ if (difficultyScore >= 70) return 'VERY_DIFFICULT';
148
+ if (difficultyScore >= 50) return 'DIFFICULT';
149
+ if (difficultyScore >= 30) return 'MODERATE';
150
+ return 'EASY';
151
+ }
152
+
153
+ /**
154
+ * Get comprehensive categorization for a file
155
+ */
156
+ categorizeFile(fileAnalysis) {
157
+ const sizeCategory = this.categorizeBySize(fileAnalysis.lineCount);
158
+ const priorityCategory = this.categorizeByPriority(fileAnalysis);
159
+ const complexityCategory = this.categorizeByComplexity(fileAnalysis);
160
+ const difficultyCategory = this.categorizeByDifficulty(fileAnalysis);
161
+
162
+ return {
163
+ size: sizeCategory,
164
+ priority: priorityCategory,
165
+ complexity: complexityCategory,
166
+ difficulty: difficultyCategory,
167
+ needsRefactoring: sizeCategory === SIZE_CATEGORIES.LARGE || sizeCategory === SIZE_CATEGORIES.XLARGE,
168
+ urgentRefactoring: sizeCategory === SIZE_CATEGORIES.XLARGE || priorityCategory === PRIORITY_CATEGORIES.CRITICAL,
169
+ recommendedAction: this._getRecommendedAction(sizeCategory, priorityCategory, complexityCategory),
170
+ estimatedEffort: this._estimateEffort(sizeCategory, difficultyCategory)
171
+ };
172
+ }
173
+
174
+ /**
175
+ * Categorize multiple files
176
+ */
177
+ categorizeFiles(fileAnalyses) {
178
+ const categorizedFiles = [];
179
+ const summary = {
180
+ total: fileAnalyses.length,
181
+ bySize: {},
182
+ byPriority: {},
183
+ byComplexity: {},
184
+ byDifficulty: {},
185
+ needsRefactoring: 0,
186
+ urgentRefactoring: 0
187
+ };
188
+
189
+ // Initialize summary counters
190
+ Object.values(SIZE_CATEGORIES).forEach(cat => summary.bySize[cat] = 0);
191
+ Object.values(PRIORITY_CATEGORIES).forEach(cat => summary.byPriority[cat] = 0);
192
+ Object.values(COMPLEXITY_CATEGORIES).forEach(cat => summary.byComplexity[cat] = 0);
193
+ ['EASY', 'MODERATE', 'DIFFICULT', 'VERY_DIFFICULT'].forEach(cat => summary.byDifficulty[cat] = 0);
194
+
195
+ for (const fileAnalysis of fileAnalyses) {
196
+ const categorization = this.categorizeFile(fileAnalysis);
197
+
198
+ categorizedFiles.push({
199
+ ...fileAnalysis,
200
+ categorization
201
+ });
202
+
203
+ // Update summary
204
+ summary.bySize[categorization.size]++;
205
+ summary.byPriority[categorization.priority]++;
206
+ summary.byComplexity[categorization.complexity]++;
207
+ summary.byDifficulty[categorization.difficulty]++;
208
+
209
+ if (categorization.needsRefactoring) summary.needsRefactoring++;
210
+ if (categorization.urgentRefactoring) summary.urgentRefactoring++;
211
+ }
212
+
213
+ return {
214
+ files: categorizedFiles,
215
+ summary
216
+ };
217
+ }
218
+
219
+ /**
220
+ * Get category thresholds
221
+ */
222
+ getCategoryThresholds() {
223
+ return {
224
+ size: {
225
+ [SIZE_CATEGORIES.SMALL]: `≤ ${this.limits.smallFileMax} lines`,
226
+ [SIZE_CATEGORIES.MEDIUM]: `${this.limits.smallFileMax + 1}-${this.limits.mediumFileMax} lines`,
227
+ [SIZE_CATEGORIES.LARGE]: `${this.limits.mediumFileMax + 1}-${this.limits.largeFileMax} lines`,
228
+ [SIZE_CATEGORIES.XLARGE]: `> ${this.limits.largeFileMax} lines`
229
+ },
230
+ priority: {
231
+ [PRIORITY_CATEGORIES.LOW]: 'Well within limits',
232
+ [PRIORITY_CATEGORIES.MEDIUM]: 'Approaching limits',
233
+ [PRIORITY_CATEGORIES.HIGH]: 'Exceeds limits',
234
+ [PRIORITY_CATEGORIES.CRITICAL]: 'Far exceeds limits'
235
+ },
236
+ complexity: {
237
+ [COMPLEXITY_CATEGORIES.SIMPLE]: 'Low complexity',
238
+ [COMPLEXITY_CATEGORIES.MODERATE]: 'Moderate complexity',
239
+ [COMPLEXITY_CATEGORIES.COMPLEX]: 'High complexity',
240
+ [COMPLEXITY_CATEGORIES.VERY_COMPLEX]: 'Very high complexity'
241
+ }
242
+ };
243
+ }
244
+
245
+ /**
246
+ * Calculate complexity score
247
+ */
248
+ _calculateComplexityScore(metrics) {
249
+ let score = 0;
250
+
251
+ // Cyclomatic complexity contribution (0-40 points)
252
+ if (metrics.cyclomaticComplexity >= 50) score += 40;
253
+ else if (metrics.cyclomaticComplexity >= 20) score += 30;
254
+ else if (metrics.cyclomaticComplexity >= 10) score += 20;
255
+ else if (metrics.cyclomaticComplexity >= 5) score += 10;
256
+
257
+ // Nesting depth contribution (0-30 points)
258
+ if (metrics.nestingDepth >= 8) score += 30;
259
+ else if (metrics.nestingDepth >= 5) score += 20;
260
+ else if (metrics.nestingDepth >= 3) score += 10;
261
+
262
+ // Function count contribution (0-20 points)
263
+ if (metrics.functionCount >= 20) score += 20;
264
+ else if (metrics.functionCount >= 10) score += 15;
265
+ else if (metrics.functionCount >= 5) score += 10;
266
+ else if (metrics.functionCount >= 2) score += 5;
267
+
268
+ // Class count contribution (0-10 points)
269
+ if (metrics.classCount >= 5) score += 10;
270
+ else if (metrics.classCount >= 3) score += 7;
271
+ else if (metrics.classCount >= 2) score += 5;
272
+ else if (metrics.classCount >= 1) score += 3;
273
+
274
+ return Math.min(score, 100);
275
+ }
276
+
277
+ /**
278
+ * Get recommended action based on categorization
279
+ */
280
+ _getRecommendedAction(sizeCategory, priorityCategory, complexityCategory) {
281
+ if (sizeCategory === SIZE_CATEGORIES.XLARGE || priorityCategory === PRIORITY_CATEGORIES.CRITICAL) {
282
+ return 'IMMEDIATE_REFACTORING';
283
+ }
284
+
285
+ if (sizeCategory === SIZE_CATEGORIES.LARGE || priorityCategory === PRIORITY_CATEGORIES.HIGH) {
286
+ return 'SCHEDULE_REFACTORING';
287
+ }
288
+
289
+ if (priorityCategory === PRIORITY_CATEGORIES.MEDIUM && complexityCategory === COMPLEXITY_CATEGORIES.COMPLEX) {
290
+ return 'PLAN_REFACTORING';
291
+ }
292
+
293
+ if (complexityCategory === COMPLEXITY_CATEGORIES.VERY_COMPLEX) {
294
+ return 'CONSIDER_REFACTORING';
295
+ }
296
+
297
+ return 'MONITOR';
298
+ }
299
+
300
+ /**
301
+ * Estimate refactoring effort
302
+ */
303
+ _estimateEffort(sizeCategory, difficultyCategory) {
304
+ const effortMatrix = {
305
+ [SIZE_CATEGORIES.SMALL]: {
306
+ 'EASY': 'MINIMAL',
307
+ 'MODERATE': 'LOW',
308
+ 'DIFFICULT': 'MEDIUM',
309
+ 'VERY_DIFFICULT': 'HIGH'
310
+ },
311
+ [SIZE_CATEGORIES.MEDIUM]: {
312
+ 'EASY': 'LOW',
313
+ 'MODERATE': 'MEDIUM',
314
+ 'DIFFICULT': 'HIGH',
315
+ 'VERY_DIFFICULT': 'VERY_HIGH'
316
+ },
317
+ [SIZE_CATEGORIES.LARGE]: {
318
+ 'EASY': 'MEDIUM',
319
+ 'MODERATE': 'HIGH',
320
+ 'DIFFICULT': 'VERY_HIGH',
321
+ 'VERY_DIFFICULT': 'EXTREME'
322
+ },
323
+ [SIZE_CATEGORIES.XLARGE]: {
324
+ 'EASY': 'HIGH',
325
+ 'MODERATE': 'VERY_HIGH',
326
+ 'DIFFICULT': 'EXTREME',
327
+ 'VERY_DIFFICULT': 'MAJOR'
328
+ }
329
+ };
330
+
331
+ return effortMatrix[sizeCategory]?.[difficultyCategory] || 'UNKNOWN';
332
+ }
333
+ }
334
+
335
+ module.exports = {
336
+ FileCategorizer,
337
+ SIZE_CATEGORIES,
338
+ PRIORITY_CATEGORIES,
339
+ COMPLEXITY_CATEGORIES
340
+ };
@@ -0,0 +1,384 @@
1
+ /**
2
+ * Codebase Scanner
3
+ *
4
+ * Scans the entire codebase to identify files for analysis,
5
+ * excluding third-party libraries and generated files.
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const RefactoringConfig = require('../config/refactoring-config');
11
+
12
+ /**
13
+ * Scanner result class
14
+ */
15
+ class ScanResult {
16
+ constructor(filePath, stats) {
17
+ this.path = filePath;
18
+ this.size = stats.size;
19
+ this.modified = stats.mtime;
20
+ this.created = stats.birthtime || stats.ctime;
21
+ this.isDirectory = stats.isDirectory();
22
+ this.extension = path.extname(filePath);
23
+ this.basename = path.basename(filePath);
24
+ this.relativePath = path.relative(process.cwd(), filePath);
25
+ this.package = this.extractPackage();
26
+ this.shouldAnalyze = this.shouldIncludeInAnalysis();
27
+ }
28
+
29
+ extractPackage() {
30
+ const match = this.relativePath.match(/packages\/([^\/]+)/);
31
+ return match ? match[1] : 'root';
32
+ }
33
+
34
+ shouldIncludeInAnalysis() {
35
+ // Skip directories
36
+ if (this.isDirectory) return false;
37
+
38
+ // Check exclusions
39
+ if (RefactoringConfig.isExcluded(this.path)) return false;
40
+
41
+ // Check file extensions
42
+ const ext = this.extension.toLowerCase();
43
+ const allowedExtensions = ['.js', '.jsx', '.ts', '.tsx', '.md', '.json', '.yml', '.yaml'];
44
+
45
+ return allowedExtensions.includes(ext);
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Codebase scanner class
51
+ */
52
+ class CodebaseScanner {
53
+ constructor(config = RefactoringConfig) {
54
+ this.config = config;
55
+ this.results = [];
56
+ this.stats = {
57
+ totalFiles: 0,
58
+ analyzedFiles: 0,
59
+ excludedFiles: 0,
60
+ directories: 0,
61
+ errors: 0
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Scan the entire codebase
67
+ */
68
+ async scan(rootPath = process.cwd()) {
69
+ console.log(`Scanning codebase from: ${rootPath}`);
70
+
71
+ this.results = [];
72
+ this.resetStats();
73
+
74
+ try {
75
+ await this.scanDirectory(rootPath);
76
+ console.log(`Scan completed: ${this.stats.analyzedFiles} files to analyze, ${this.stats.excludedFiles} excluded`);
77
+ return this.results;
78
+ } catch (error) {
79
+ console.error(`Scan failed: ${error.message}`);
80
+ throw error;
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Scan a single directory recursively
86
+ */
87
+ async scanDirectory(dirPath) {
88
+ try {
89
+ const entries = fs.readdirSync(dirPath, { withFileTypes: true });
90
+
91
+ for (const entry of entries) {
92
+ const fullPath = path.join(dirPath, entry.name);
93
+
94
+ try {
95
+ const stats = fs.statSync(fullPath);
96
+ const result = new ScanResult(fullPath, stats);
97
+
98
+ if (entry.isDirectory()) {
99
+ this.stats.directories++;
100
+
101
+ // Skip excluded directories
102
+ if (!this.shouldSkipDirectory(fullPath)) {
103
+ await this.scanDirectory(fullPath);
104
+ }
105
+ } else {
106
+ this.stats.totalFiles++;
107
+
108
+ if (result.shouldAnalyze) {
109
+ this.results.push(result);
110
+ this.stats.analyzedFiles++;
111
+ } else {
112
+ this.stats.excludedFiles++;
113
+ }
114
+ }
115
+ } catch (error) {
116
+ this.stats.errors++;
117
+ console.warn(`Error scanning ${fullPath}: ${error.message}`);
118
+ }
119
+ }
120
+ } catch (error) {
121
+ this.stats.errors++;
122
+ throw new Error(`Failed to scan directory ${dirPath}: ${error.message}`);
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Check if directory should be skipped
128
+ */
129
+ shouldSkipDirectory(dirPath) {
130
+ const dirName = path.basename(dirPath);
131
+ const relativePath = path.relative(process.cwd(), dirPath);
132
+
133
+ // Skip common excluded directories
134
+ const excludedDirs = [
135
+ 'node_modules',
136
+ '.git',
137
+ 'dist',
138
+ 'build',
139
+ 'coverage',
140
+ '.nyc_output',
141
+ '.vscode',
142
+ '.idea',
143
+ '.cursor',
144
+ '.windsurf',
145
+ 'vendor',
146
+ 'bower_components',
147
+ '.refactoring-backups'
148
+ ];
149
+
150
+ // Check if directory name is excluded
151
+ if (excludedDirs.includes(dirName)) {
152
+ return true;
153
+ }
154
+
155
+ // Check if relative path contains excluded directories
156
+ for (const excludedDir of excludedDirs) {
157
+ if (relativePath.includes(path.sep + excludedDir + path.sep) ||
158
+ relativePath.startsWith(excludedDir + path.sep)) {
159
+ return true;
160
+ }
161
+ }
162
+
163
+ return false;
164
+ }
165
+
166
+ /**
167
+ * Get files by package
168
+ */
169
+ getFilesByPackage() {
170
+ const byPackage = {};
171
+
172
+ for (const result of this.results) {
173
+ if (!byPackage[result.package]) {
174
+ byPackage[result.package] = [];
175
+ }
176
+ byPackage[result.package].push(result);
177
+ }
178
+
179
+ return byPackage;
180
+ }
181
+
182
+ /**
183
+ * Get files by extension
184
+ */
185
+ getFilesByExtension() {
186
+ const byExtension = {};
187
+
188
+ for (const result of this.results) {
189
+ if (!byExtension[result.extension]) {
190
+ byExtension[result.extension] = [];
191
+ }
192
+ byExtension[result.extension].push(result);
193
+ }
194
+
195
+ return byExtension;
196
+ }
197
+
198
+ /**
199
+ * Get files by size range
200
+ */
201
+ getFilesBySizeRange() {
202
+ const ranges = {
203
+ small: [], // 0-100 lines (estimated)
204
+ medium: [], // 101-300 lines
205
+ large: [], // 301-555 lines
206
+ xlarge: [] // 556+ lines
207
+ };
208
+
209
+ for (const result of this.results) {
210
+ // Estimate line count from file size (rough approximation)
211
+ const estimatedLines = Math.ceil(result.size / 50); // ~50 chars per line
212
+
213
+ if (estimatedLines <= 100) ranges.small.push(result);
214
+ else if (estimatedLines <= 300) ranges.medium.push(result);
215
+ else if (estimatedLines <= 555) ranges.large.push(result);
216
+ else ranges.xlarge.push(result);
217
+ }
218
+
219
+ return ranges;
220
+ }
221
+
222
+ /**
223
+ * Filter results by criteria
224
+ */
225
+ filter(criteria = {}) {
226
+ let filtered = [...this.results];
227
+
228
+ if (criteria.package) {
229
+ filtered = filtered.filter(result => result.package === criteria.package);
230
+ }
231
+
232
+ if (criteria.extension) {
233
+ filtered = filtered.filter(result => result.extension === criteria.extension);
234
+ }
235
+
236
+ if (criteria.minSize) {
237
+ filtered = filtered.filter(result => result.size >= criteria.minSize);
238
+ }
239
+
240
+ if (criteria.maxSize) {
241
+ filtered = filtered.filter(result => result.size <= criteria.maxSize);
242
+ }
243
+
244
+ if (criteria.pattern) {
245
+ const regex = new RegExp(criteria.pattern, 'i');
246
+ filtered = filtered.filter(result =>
247
+ regex.test(result.basename) || regex.test(result.relativePath)
248
+ );
249
+ }
250
+
251
+ return filtered;
252
+ }
253
+
254
+ /**
255
+ * Find recently modified files
256
+ */
257
+ getRecentlyModified(days = 7) {
258
+ const cutoff = new Date(Date.now() - (days * 24 * 60 * 60 * 1000));
259
+
260
+ return this.results.filter(result => result.modified > cutoff);
261
+ }
262
+
263
+ /**
264
+ * Find large files (by size estimation)
265
+ */
266
+ getLargeFiles(minLines = 556) {
267
+ return this.results.filter(result => {
268
+ const estimatedLines = Math.ceil(result.size / 50);
269
+ return estimatedLines >= minLines;
270
+ });
271
+ }
272
+
273
+ /**
274
+ * Get scan statistics
275
+ */
276
+ getStatistics() {
277
+ const stats = { ...this.stats };
278
+
279
+ // Calculate additional statistics
280
+ stats.totalSize = this.results.reduce((sum, result) => sum + result.size, 0);
281
+ stats.averageFileSize = stats.analyzedFiles > 0 ? Math.round(stats.totalSize / stats.analyzedFiles) : 0;
282
+ stats.largestFile = this.results.reduce((largest, result) =>
283
+ result.size > (largest?.size || 0) ? result : largest, null
284
+ );
285
+ stats.smallestFile = this.results.reduce((smallest, result) =>
286
+ result.size < (smallest?.size || Infinity) ? result : smallest, null
287
+ );
288
+
289
+ // Package distribution
290
+ stats.packageDistribution = {};
291
+ for (const result of this.results) {
292
+ if (!stats.packageDistribution[result.package]) {
293
+ stats.packageDistribution[result.package] = 0;
294
+ }
295
+ stats.packageDistribution[result.package]++;
296
+ }
297
+
298
+ // Extension distribution
299
+ stats.extensionDistribution = {};
300
+ for (const result of this.results) {
301
+ if (!stats.extensionDistribution[result.extension]) {
302
+ stats.extensionDistribution[result.extension] = 0;
303
+ }
304
+ stats.extensionDistribution[result.extension]++;
305
+ }
306
+
307
+ return stats;
308
+ }
309
+
310
+ /**
311
+ * Export results to JSON
312
+ */
313
+ exportToJson(filePath) {
314
+ const exportData = {
315
+ metadata: {
316
+ scannedAt: new Date().toISOString(),
317
+ rootPath: process.cwd(),
318
+ config: this.config.reporting || {}
319
+ },
320
+ statistics: this.getStatistics(),
321
+ results: this.results.map(result => ({
322
+ path: result.path,
323
+ relativePath: result.relativePath,
324
+ package: result.package,
325
+ size: result.size,
326
+ extension: result.extension,
327
+ modified: result.modified.toISOString(),
328
+ shouldAnalyze: result.shouldAnalyze
329
+ }))
330
+ };
331
+
332
+ fs.writeFileSync(filePath, JSON.stringify(exportData, null, 2));
333
+ return filePath;
334
+ }
335
+
336
+ /**
337
+ * Reset statistics
338
+ */
339
+ resetStats() {
340
+ this.stats = {
341
+ totalFiles: 0,
342
+ analyzedFiles: 0,
343
+ excludedFiles: 0,
344
+ directories: 0,
345
+ errors: 0
346
+ };
347
+ }
348
+
349
+ /**
350
+ * Validate scan results
351
+ */
352
+ validate() {
353
+ const issues = [];
354
+
355
+ // Check if we have any results
356
+ if (this.results.length === 0) {
357
+ issues.push('No files found for analysis');
358
+ }
359
+
360
+ // Check for errors during scanning
361
+ if (this.stats.errors > 0) {
362
+ issues.push(`${this.stats.errors} errors occurred during scanning`);
363
+ }
364
+
365
+ // Check for excluded files ratio
366
+ const exclusionRatio = this.stats.totalFiles > 0 ?
367
+ (this.stats.excludedFiles / this.stats.totalFiles) : 0;
368
+
369
+ if (exclusionRatio > 0.9) {
370
+ issues.push('Very high exclusion ratio - check configuration');
371
+ }
372
+
373
+ return {
374
+ isValid: issues.length === 0,
375
+ issues,
376
+ stats: this.stats
377
+ };
378
+ }
379
+ }
380
+
381
+ module.exports = {
382
+ CodebaseScanner,
383
+ ScanResult
384
+ };