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,834 @@
1
+ /**
2
+ * Alert System for File Size Compliance
3
+ *
4
+ * Provides intelligent alerting for files approaching or exceeding size limits,
5
+ * with configurable thresholds, notification channels, and escalation policies.
6
+ */
7
+
8
+ const EventEmitter = require('events');
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+
12
+ /**
13
+ * Alert severity levels
14
+ */
15
+ const ALERT_SEVERITY = {
16
+ INFO: 'info',
17
+ WARNING: 'warning',
18
+ ERROR: 'error',
19
+ CRITICAL: 'critical'
20
+ };
21
+
22
+ /**
23
+ * Alert categories
24
+ */
25
+ const ALERT_CATEGORIES = {
26
+ FILE_SIZE: 'file_size',
27
+ CONSTITUTIONAL: 'constitutional',
28
+ PERFORMANCE: 'performance',
29
+ SYSTEM: 'system'
30
+ };
31
+
32
+ /**
33
+ * Alert class
34
+ */
35
+ class Alert {
36
+ constructor(data = {}) {
37
+ this.id = data.id || this.generateId();
38
+ this.category = data.category || ALERT_CATEGORIES.FILE_SIZE;
39
+ this.severity = data.severity || ALERT_SEVERITY.WARNING;
40
+ this.title = data.title || '';
41
+ this.message = data.message || '';
42
+ this.description = data.description || '';
43
+ this.filePath = data.filePath || '';
44
+ this.metadata = {
45
+ timestamp: data.timestamp || new Date().toISOString(),
46
+ source: data.source || 'alert-system',
47
+ version: data.version || '1.0.0',
48
+ ...data.metadata
49
+ };
50
+ this.context = {
51
+ lineCount: data.lineCount || 0,
52
+ limit: data.limit || 555,
53
+ excessLines: data.excessLines || 0,
54
+ percentage: data.percentage || 0,
55
+ ...data.context
56
+ };
57
+ this.actions = data.actions || [];
58
+ this.escalationLevel = data.escalationLevel || 0;
59
+ this.isResolved = data.isResolved || false;
60
+ this.resolvedAt = data.resolvedAt || null;
61
+ this.resolvedBy = data.resolvedBy || null;
62
+ }
63
+
64
+ generateId() {
65
+ return `alert_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
66
+ }
67
+
68
+ resolve(resolvedBy = 'system') {
69
+ this.isResolved = true;
70
+ this.resolvedAt = new Date().toISOString();
71
+ this.resolvedBy = resolvedBy;
72
+ return this;
73
+ }
74
+
75
+ escalate() {
76
+ this.escalationLevel++;
77
+ return this;
78
+ }
79
+
80
+ toJSON() {
81
+ return {
82
+ id: this.id,
83
+ category: this.category,
84
+ severity: this.severity,
85
+ title: this.title,
86
+ message: this.message,
87
+ description: this.description,
88
+ filePath: this.filePath,
89
+ metadata: this.metadata,
90
+ context: this.context,
91
+ actions: this.actions,
92
+ escalationLevel: this.escalationLevel,
93
+ isResolved: this.isResolved,
94
+ resolvedAt: this.resolvedAt,
95
+ resolvedBy: this.resolvedBy
96
+ };
97
+ }
98
+
99
+ static fromJSON(data) {
100
+ return new Alert(data);
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Alert system class
106
+ */
107
+ class AlertSystem extends EventEmitter {
108
+ constructor(options = {}) {
109
+ super();
110
+
111
+ this.options = {
112
+ // Thresholds
113
+ warningThreshold: options.warningThreshold || 500,
114
+ errorThreshold: options.errorThreshold || 555,
115
+ criticalThreshold: options.criticalThreshold || 800,
116
+
117
+ // Alert settings
118
+ enableNotifications: options.enableNotifications !== false,
119
+ enableEscalation: options.enableEscalation !== false,
120
+ enableCooldown: options.enableCooldown !== false,
121
+ cooldownMs: options.cooldownMs || 300000, // 5 minutes
122
+
123
+ // Escalation settings
124
+ maxEscalationLevel: options.maxEscalationLevel || 3,
125
+ escalationIntervalMs: options.escalationIntervalMs || 1800000, // 30 minutes
126
+
127
+ // Notification channels
128
+ channels: options.channels || ['console', 'file'],
129
+ logFile: options.logFile || './logs/alerts.log',
130
+
131
+ // Filtering
132
+ duplicateAlertThresholdMs: options.duplicateAlertThresholdMs || 60000, // 1 minute
133
+
134
+ ...options
135
+ };
136
+
137
+ this.alerts = new Map(); // active alerts
138
+ this.alertHistory = []; // all alerts
139
+ this.cooldownTimers = new Map();
140
+ this.escalationTimers = new Map();
141
+ this.lastAlerts = new Map(); // for duplicate detection
142
+
143
+ this.stats = {
144
+ totalAlerts: 0,
145
+ alertsBySeverity: { info: 0, warning: 0, error: 0, critical: 0 },
146
+ alertsByCategory: {},
147
+ escalatedAlerts: 0,
148
+ resolvedAlerts: 0,
149
+ startTime: new Date(),
150
+ lastAlertTime: null
151
+ };
152
+
153
+ // Ensure log directory exists
154
+ if (this.options.channels.includes('file')) {
155
+ const logDir = path.dirname(this.options.logFile);
156
+ if (!fs.existsSync(logDir)) {
157
+ fs.mkdirSync(logDir, { recursive: true });
158
+ }
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Process file validation results and generate alerts
164
+ */
165
+ processValidationResults(filePath, validationResults) {
166
+ const alerts = [];
167
+
168
+ // File size alerts
169
+ if (validationResults.lineLimitValidation) {
170
+ const lineAlert = this.createFileSizeAlert(filePath, validationResults);
171
+ if (lineAlert) alerts.push(lineAlert);
172
+ }
173
+
174
+ // Constitutional compliance alerts
175
+ if (validationResults.constitutionalValidation) {
176
+ const constitutionalAlerts = this.createConstitutionalAlerts(filePath, validationResults);
177
+ alerts.push(...constitutionalAlerts);
178
+ }
179
+
180
+ // Process all alerts
181
+ for (const alert of alerts) {
182
+ this.processAlert(alert);
183
+ }
184
+
185
+ return alerts;
186
+ }
187
+
188
+ /**
189
+ * Create file size alert
190
+ */
191
+ createFileSizeAlert(filePath, validationResults) {
192
+ const lineValidation = validationResults.lineLimitValidation;
193
+ const lineCount = validationResults.lineCount || 0;
194
+
195
+ if (!lineValidation.violation) {
196
+ return null;
197
+ }
198
+
199
+ const violation = lineValidation.violation;
200
+ let severity = ALERT_SEVERITY.WARNING;
201
+ let title = 'File Size Warning';
202
+
203
+ if (lineCount > this.options.criticalThreshold) {
204
+ severity = ALERT_SEVERITY.CRITICAL;
205
+ title = 'Critical File Size Violation';
206
+ } else if (lineCount > this.options.errorThreshold) {
207
+ severity = ALERT_SEVERITY.ERROR;
208
+ title = 'File Size Violation';
209
+ }
210
+
211
+ return new Alert({
212
+ category: ALERT_CATEGORIES.FILE_SIZE,
213
+ severity,
214
+ title,
215
+ message: `${filePath} has ${lineCount} lines (limit: ${this.options.errorThreshold})`,
216
+ description: `File exceeds the 555-line limit by ${violation.excessLines} lines (${violation.percentageOverLimit}% over)`,
217
+ filePath,
218
+ lineCount,
219
+ limit: this.options.errorThreshold,
220
+ excessLines: violation.excessLines,
221
+ percentage: violation.percentageOverLimit,
222
+ actions: [
223
+ 'Refactor file into smaller modules',
224
+ 'Extract related functionality into separate files',
225
+ 'Consider splitting by logical boundaries'
226
+ ]
227
+ });
228
+ }
229
+
230
+ /**
231
+ * Create constitutional compliance alerts
232
+ */
233
+ createConstitutionalAlerts(filePath, validationResults) {
234
+ const alerts = [];
235
+ const constitutionalValidation = validationResults.constitutionalValidation || [];
236
+
237
+ for (const issue of constitutionalValidation) {
238
+ if (issue.severity === 'info') continue; // Skip info-level issues
239
+
240
+ const severity = issue.severity === 'critical' ? ALERT_SEVERITY.CRITICAL :
241
+ issue.severity === 'error' ? ALERT_SEVERITY.ERROR :
242
+ ALERT_SEVERITY.WARNING;
243
+
244
+ const alert = new Alert({
245
+ category: ALERT_CATEGORIES.CONSTITUTIONAL,
246
+ severity,
247
+ title: `${issue.category.charAt(0).toUpperCase() + issue.category.slice(1)} Violation`,
248
+ message: `${filePath}: ${issue.message}`,
249
+ description: issue.description || `Constitutional compliance issue in ${issue.category}`,
250
+ filePath,
251
+ context: {
252
+ rule: issue.rule,
253
+ lineNumber: issue.lineNumber,
254
+ ...issue.details
255
+ },
256
+ actions: issue.suggestion ? [issue.suggestion] : ['Review constitutional requirements']
257
+ });
258
+
259
+ alerts.push(alert);
260
+ }
261
+
262
+ return alerts;
263
+ }
264
+
265
+ /**
266
+ * Process an alert
267
+ */
268
+ processAlert(alert) {
269
+ // Check for duplicates
270
+ if (this.isDuplicateAlert(alert)) {
271
+ return null;
272
+ }
273
+
274
+ // Check cooldown
275
+ if (this.isInCooldown(alert.filePath, alert.category)) {
276
+ return null;
277
+ }
278
+
279
+ // Add to active alerts
280
+ this.alerts.set(alert.id, alert);
281
+ this.alertHistory.push(alert);
282
+
283
+ // Update stats
284
+ this.updateStats(alert);
285
+
286
+ // Set cooldown
287
+ if (this.options.enableCooldown) {
288
+ this.setCooldown(alert.filePath, alert.category);
289
+ }
290
+
291
+ // Setup escalation if enabled
292
+ if (this.options.enableEscalation && alert.severity !== 'info') {
293
+ this.setupEscalation(alert);
294
+ }
295
+
296
+ // Send notifications
297
+ this.sendNotifications(alert);
298
+
299
+ // Emit events
300
+ this.emit('alert', alert);
301
+ this.emit(`alert:${alert.severity}`, alert);
302
+ this.emit(`alert:${alert.category}`, alert);
303
+
304
+ // Update last alert tracking
305
+ this.lastAlerts.set(`${alert.filePath}:${alert.category}`, {
306
+ timestamp: Date.now(),
307
+ alertId: alert.id
308
+ });
309
+
310
+ return alert;
311
+ }
312
+
313
+ /**
314
+ * Check if alert is duplicate
315
+ */
316
+ isDuplicateAlert(alert) {
317
+ const key = `${alert.filePath}:${alert.category}`;
318
+ const lastAlert = this.lastAlerts.get(key);
319
+
320
+ if (!lastAlert) {
321
+ return false;
322
+ }
323
+
324
+ const timeDiff = Date.now() - lastAlert.timestamp;
325
+ return timeDiff < this.options.duplicateAlertThresholdMs;
326
+ }
327
+
328
+ /**
329
+ * Check if in cooldown period
330
+ */
331
+ isInCooldown(filePath, category) {
332
+ const key = `${filePath}:${category}`;
333
+ return this.cooldownTimers.has(key);
334
+ }
335
+
336
+ /**
337
+ * Set cooldown period
338
+ */
339
+ setCooldown(filePath, category) {
340
+ const key = `${filePath}:${category}`;
341
+
342
+ // Clear existing timer
343
+ if (this.cooldownTimers.has(key)) {
344
+ clearTimeout(this.cooldownTimers.get(key));
345
+ }
346
+
347
+ // Set new timer
348
+ const timer = setTimeout(() => {
349
+ this.cooldownTimers.delete(key);
350
+ }, this.options.cooldownMs);
351
+
352
+ this.cooldownTimers.set(key, timer);
353
+ }
354
+
355
+ /**
356
+ * Setup escalation for alert
357
+ */
358
+ setupEscalation(alert) {
359
+ if (alert.escalationLevel >= this.options.maxEscalationLevel) {
360
+ return;
361
+ }
362
+
363
+ const escalationKey = alert.id;
364
+
365
+ // Clear existing escalation timer
366
+ if (this.escalationTimers.has(escalationKey)) {
367
+ clearTimeout(this.escalationTimers.get(escalationKey));
368
+ }
369
+
370
+ // Set escalation timer
371
+ const timer = setTimeout(() => {
372
+ this.escalateAlert(alert);
373
+ }, this.options.escalationIntervalMs);
374
+
375
+ this.escalationTimers.set(escalationKey, timer);
376
+ }
377
+
378
+ /**
379
+ * Escalate alert
380
+ */
381
+ escalateAlert(alert) {
382
+ if (alert.escalationLevel >= this.options.maxEscalationLevel) {
383
+ return;
384
+ }
385
+
386
+ alert.escalate();
387
+ this.stats.escalatedAlerts++;
388
+
389
+ // Update severity if needed
390
+ if (alert.severity === ALERT_SEVERITY.WARNING && alert.escalationLevel >= 1) {
391
+ alert.severity = ALERT_SEVERITY.ERROR;
392
+ } else if (alert.severity === ALERT_SEVERITY.ERROR && alert.escalationLevel >= 2) {
393
+ alert.severity = ALERT_SEVERITY.CRITICAL;
394
+ }
395
+
396
+ // Update title
397
+ alert.title = `[ESCALATED L${alert.escalationLevel}] ${alert.title}`;
398
+
399
+ // Send notifications for escalated alert
400
+ this.sendNotifications(alert);
401
+
402
+ // Emit escalation event
403
+ this.emit('alertEscalated', alert);
404
+
405
+ // Setup next escalation
406
+ this.setupEscalation(alert);
407
+ }
408
+
409
+ /**
410
+ * Handle new violations from continuous scan
411
+ */
412
+ handleContinuousScanViolations(violations, scanInfo = {}) {
413
+ const alerts = [];
414
+
415
+ for (const violation of violations) {
416
+ // Create alert for each new violation
417
+ const alert = this.createViolationAlert(violation.filePath, {
418
+ lineCount: violation.lineCount,
419
+ lineLimitValidation: violation.lineLimitValidation,
420
+ constitutionalValidation: violation.constitutionalValidation
421
+ });
422
+
423
+ if (alert) {
424
+ // Add continuous scan metadata
425
+ alert.metadata.source = 'continuous-scan';
426
+ alert.metadata.scanId = scanInfo.scanId;
427
+ alert.metadata.scanTimestamp = scanInfo.timestamp;
428
+ alert.metadata.isNewViolation = true;
429
+
430
+ alerts.push(alert);
431
+ }
432
+ }
433
+
434
+ // Send batch notification if multiple violations
435
+ if (alerts.length > 1) {
436
+ this.sendBatchViolationAlert(alerts, scanInfo);
437
+ } else if (alerts.length === 1) {
438
+ this.sendAlert(alerts[0]);
439
+ }
440
+
441
+ return alerts;
442
+ }
443
+
444
+ /**
445
+ * Send batch violation alert
446
+ */
447
+ sendBatchViolationAlert(alerts, scanInfo) {
448
+ const batchAlert = new Alert({
449
+ category: ALERT_CATEGORIES.FILE_SIZE,
450
+ severity: ALERT_SEVERITY.WARNING,
451
+ title: `Batch Violation Alert - ${alerts.length} files`,
452
+ message: `Continuous scan detected ${alerts.length} files with size violations`,
453
+ description: `The following files exceeded the 555-line limit: ${alerts.map(a => a.filePath).join(', ')}`,
454
+ metadata: {
455
+ source: 'continuous-scan',
456
+ scanId: scanInfo.scanId,
457
+ scanTimestamp: scanInfo.timestamp,
458
+ violationCount: alerts.length,
459
+ violationFiles: alerts.map(a => ({
460
+ filePath: a.filePath,
461
+ lineCount: a.metadata.lineCount,
462
+ excessLines: a.metadata.excessLines
463
+ }))
464
+ }
465
+ });
466
+
467
+ this.sendAlert(batchAlert);
468
+ }
469
+
470
+ /**
471
+ * Send notifications through configured channels
472
+ */
473
+ sendNotifications(alert) {
474
+ for (const channel of this.options.channels) {
475
+ try {
476
+ switch (channel) {
477
+ case 'console':
478
+ this.sendConsoleNotification(alert);
479
+ break;
480
+ case 'file':
481
+ this.sendFileNotification(alert);
482
+ break;
483
+ case 'email':
484
+ this.sendEmailNotification(alert);
485
+ break;
486
+ case 'slack':
487
+ this.sendSlackNotification(alert);
488
+ break;
489
+ default:
490
+ console.warn(`Unknown notification channel: ${channel}`);
491
+ }
492
+ } catch (error) {
493
+ console.error(`Failed to send ${channel} notification:`, error);
494
+ }
495
+ }
496
+ }
497
+
498
+ /**
499
+ * Send console notification
500
+ */
501
+ sendConsoleNotification(alert) {
502
+ const colors = {
503
+ info: '\x1b[36m',
504
+ warning: '\x1b[33m',
505
+ error: '\x1b[31m',
506
+ critical: '\x1b[35m',
507
+ reset: '\x1b[0m',
508
+ bold: '\x1b[1m'
509
+ };
510
+
511
+ const color = colors[alert.severity] || colors.info;
512
+ const escalation = alert.escalationLevel > 0 ? ` [L${alert.escalationLevel}]` : '';
513
+
514
+ console.log(`${color}${colors.bold}[ALERT${escalation}] ${alert.title}${colors.reset}`);
515
+ console.log(`${color} ${alert.message}${colors.reset}`);
516
+ console.log(` File: ${alert.filePath}`);
517
+ console.log(` Time: ${new Date(alert.metadata.timestamp).toLocaleString()}`);
518
+
519
+ if (alert.context.lineCount) {
520
+ console.log(` Lines: ${alert.context.lineCount}/${alert.context.limit}`);
521
+ }
522
+
523
+ if (alert.actions.length > 0) {
524
+ console.log(` Actions: ${alert.actions.slice(0, 2).join(', ')}`);
525
+ }
526
+
527
+ console.log('');
528
+ }
529
+
530
+ /**
531
+ * Send file notification
532
+ */
533
+ sendFileNotification(alert) {
534
+ const logEntry = {
535
+ timestamp: alert.metadata.timestamp,
536
+ id: alert.id,
537
+ severity: alert.severity,
538
+ category: alert.category,
539
+ title: alert.title,
540
+ message: alert.message,
541
+ filePath: alert.filePath,
542
+ context: alert.context,
543
+ escalationLevel: alert.escalationLevel
544
+ };
545
+
546
+ const logLine = JSON.stringify(logEntry) + '\n';
547
+ fs.appendFileSync(this.options.logFile, logLine, 'utf8');
548
+ }
549
+
550
+ /**
551
+ * Send email notification (placeholder)
552
+ */
553
+ sendEmailNotification(alert) {
554
+ // Placeholder for email implementation
555
+ console.log(`📧 Email notification sent for alert: ${alert.title}`);
556
+ }
557
+
558
+ /**
559
+ * Send Slack notification (placeholder)
560
+ */
561
+ sendSlackNotification(alert) {
562
+ // Placeholder for Slack implementation
563
+ console.log(`💬 Slack notification sent for alert: ${alert.title}`);
564
+ }
565
+
566
+ /**
567
+ * Resolve alert
568
+ */
569
+ resolveAlert(alertId, resolvedBy = 'user') {
570
+ const alert = this.alerts.get(alertId);
571
+ if (!alert) {
572
+ return false;
573
+ }
574
+
575
+ alert.resolve(resolvedBy);
576
+ this.alerts.delete(alertId);
577
+ this.stats.resolvedAlerts++;
578
+
579
+ // Clear escalation timer
580
+ if (this.escalationTimers.has(alertId)) {
581
+ clearTimeout(this.escalationTimers.get(alertId));
582
+ this.escalationTimers.delete(alertId);
583
+ }
584
+
585
+ // Emit resolution event
586
+ this.emit('alertResolved', alert);
587
+
588
+ return true;
589
+ }
590
+
591
+ /**
592
+ * Resolve alerts for file
593
+ */
594
+ resolveAlertsForFile(filePath, resolvedBy = 'user') {
595
+ const resolvedAlerts = [];
596
+
597
+ for (const [alertId, alert] of this.alerts.entries()) {
598
+ if (alert.filePath === filePath) {
599
+ this.resolveAlert(alertId, resolvedBy);
600
+ resolvedAlerts.push(alert);
601
+ }
602
+ }
603
+
604
+ return resolvedAlerts;
605
+ }
606
+
607
+ /**
608
+ * Get active alerts
609
+ */
610
+ getActiveAlerts(filters = {}) {
611
+ let alerts = Array.from(this.alerts.values());
612
+
613
+ // Apply filters
614
+ if (filters.severity) {
615
+ alerts = alerts.filter(alert => alert.severity === filters.severity);
616
+ }
617
+
618
+ if (filters.category) {
619
+ alerts = alerts.filter(alert => alert.category === filters.category);
620
+ }
621
+
622
+ if (filters.filePath) {
623
+ alerts = alerts.filter(alert => alert.filePath === filters.filePath);
624
+ }
625
+
626
+ if (filters.unresolvedOnly) {
627
+ alerts = alerts.filter(alert => !alert.isResolved);
628
+ }
629
+
630
+ // Sort by timestamp (newest first)
631
+ alerts.sort((a, b) => new Date(b.metadata.timestamp) - new Date(a.metadata.timestamp));
632
+
633
+ return alerts;
634
+ }
635
+
636
+ /**
637
+ * Get alert statistics
638
+ */
639
+ getStats() {
640
+ const uptime = Date.now() - this.stats.startTime.getTime();
641
+
642
+ return {
643
+ ...this.stats,
644
+ uptime,
645
+ activeAlerts: this.alerts.size,
646
+ alertsInHistory: this.alertHistory.length,
647
+ averageAlertsPerHour: this.stats.totalAlerts > 0 ?
648
+ (this.stats.totalAlerts / (uptime / 1000 / 60 / 60)) : 0,
649
+ resolutionRate: this.stats.totalAlerts > 0 ?
650
+ (this.stats.resolvedAlerts / this.stats.totalAlerts * 100) : 0
651
+ };
652
+ }
653
+
654
+ /**
655
+ * Update statistics
656
+ */
657
+ updateStats(alert) {
658
+ this.stats.totalAlerts++;
659
+ this.stats.alertsBySeverity[alert.severity]++;
660
+ this.stats.alertsByCategory[alert.category] =
661
+ (this.stats.alertsByCategory[alert.category] || 0) + 1;
662
+ this.stats.lastAlertTime = new Date();
663
+ }
664
+
665
+ /**
666
+ * Generate alert report
667
+ */
668
+ generateReport(format = 'json') {
669
+ const stats = this.getStats();
670
+ const activeAlerts = this.getActiveAlerts();
671
+
672
+ const report = {
673
+ metadata: {
674
+ generatedAt: new Date().toISOString(),
675
+ uptime: stats.uptime,
676
+ system: 'alert-system'
677
+ },
678
+ summary: stats,
679
+ activeAlerts: activeAlerts.map(alert => alert.toJSON()),
680
+ recentAlerts: this.alertHistory.slice(-10).map(alert => alert.toJSON()),
681
+ topAlertFiles: this.getTopAlertFiles(),
682
+ alertTrends: this.getAlertTrends()
683
+ };
684
+
685
+ switch (format.toLowerCase()) {
686
+ case 'json':
687
+ return JSON.stringify(report, null, 2);
688
+ case 'summary':
689
+ return this.generateSummaryReport(report);
690
+ default:
691
+ return report;
692
+ }
693
+ }
694
+
695
+ /**
696
+ * Generate summary report
697
+ */
698
+ generateSummaryReport(report) {
699
+ const summary = report.summary;
700
+
701
+ let text = '# Alert System Summary Report\n\n';
702
+ text += `**Generated:** ${new Date().toLocaleString()}\n`;
703
+ text += `**Uptime:** ${Math.floor(summary.uptime / 1000 / 60)} minutes\n\n`;
704
+
705
+ text += `## Summary\n\n`;
706
+ text += `- **Total Alerts:** ${summary.totalAlerts}\n`;
707
+ text += `- **Active Alerts:** ${summary.activeAlerts}\n`;
708
+ text += `- **Resolved Alerts:** ${summary.resolvedAlerts}\n`;
709
+ text += `- **Escalated Alerts:** ${summary.escalatedAlerts}\n`;
710
+ text += `- **Resolution Rate:** ${summary.resolutionRate.toFixed(1)}%\n`;
711
+ text += `- **Avg Alerts/Hour:** ${summary.averageAlertsPerHour.toFixed(1)}\n\n`;
712
+
713
+ text += `## Alerts by Severity\n\n`;
714
+ for (const [severity, count] of Object.entries(summary.alertsBySeverity)) {
715
+ text += `- **${severity}:** ${count}\n`;
716
+ }
717
+ text += '\n';
718
+
719
+ text += `## Alerts by Category\n\n`;
720
+ for (const [category, count] of Object.entries(summary.alertsByCategory)) {
721
+ text += `- **${category}:** ${count}\n`;
722
+ }
723
+ text += '\n';
724
+
725
+ if (report.topAlertFiles.length > 0) {
726
+ text += `## Top Alert Files\n\n`;
727
+ for (const file of report.topAlertFiles) {
728
+ text += `- **${file.filePath}:** ${file.alertCount} alerts\n`;
729
+ }
730
+ text += '\n';
731
+ }
732
+
733
+ return text;
734
+ }
735
+
736
+ /**
737
+ * Get top alert files
738
+ */
739
+ getTopAlertFiles() {
740
+ const fileAlertCounts = {};
741
+
742
+ for (const alert of this.alertHistory) {
743
+ const filePath = alert.filePath;
744
+ fileAlertCounts[filePath] = (fileAlertCounts[filePath] || 0) + 1;
745
+ }
746
+
747
+ return Object.entries(fileAlertCounts)
748
+ .map(([filePath, alertCount]) => ({ filePath, alertCount }))
749
+ .sort((a, b) => b.alertCount - a.alertCount)
750
+ .slice(0, 10);
751
+ }
752
+
753
+ /**
754
+ * Get alert trends
755
+ */
756
+ getAlertTrends() {
757
+ const now = Date.now();
758
+ const intervals = {
759
+ '1h': 60 * 60 * 1000,
760
+ '6h': 6 * 60 * 60 * 1000,
761
+ '24h': 24 * 60 * 60 * 1000
762
+ };
763
+
764
+ const trends = {};
765
+
766
+ for (const [label, intervalMs] of Object.entries(intervals)) {
767
+ const cutoff = now - intervalMs;
768
+ const alerts = this.alertHistory.filter(alert =>
769
+ new Date(alert.metadata.timestamp).getTime() > cutoff
770
+ );
771
+
772
+ trends[label] = {
773
+ count: alerts.length,
774
+ rate: alerts.length / (intervalMs / 1000 / 60 / 60) // per hour
775
+ };
776
+ }
777
+
778
+ return trends;
779
+ }
780
+
781
+ /**
782
+ * Clear all alerts
783
+ */
784
+ clearAllAlerts() {
785
+ // Clear all timers
786
+ for (const timer of this.cooldownTimers.values()) {
787
+ clearTimeout(timer);
788
+ }
789
+ for (const timer of this.escalationTimers.values()) {
790
+ clearTimeout(timer);
791
+ }
792
+
793
+ // Clear data
794
+ this.alerts.clear();
795
+ this.cooldownTimers.clear();
796
+ this.escalationTimers.clear();
797
+ this.lastAlerts.clear();
798
+
799
+ // Reset stats
800
+ this.stats = {
801
+ totalAlerts: 0,
802
+ alertsBySeverity: { info: 0, warning: 0, error: 0, critical: 0 },
803
+ alertsByCategory: {},
804
+ escalatedAlerts: 0,
805
+ resolvedAlerts: 0,
806
+ startTime: new Date(),
807
+ lastAlertTime: null
808
+ };
809
+
810
+ this.emit('alertsCleared');
811
+ }
812
+
813
+ /**
814
+ * Shutdown alert system
815
+ */
816
+ shutdown() {
817
+ // Clear all timers
818
+ for (const timer of this.cooldownTimers.values()) {
819
+ clearTimeout(timer);
820
+ }
821
+ for (const timer of this.escalationTimers.values()) {
822
+ clearTimeout(timer);
823
+ }
824
+
825
+ this.emit('shutdown');
826
+ }
827
+ }
828
+
829
+ module.exports = {
830
+ AlertSystem,
831
+ Alert,
832
+ ALERT_SEVERITY,
833
+ ALERT_CATEGORIES
834
+ };