vibecodingmachine-core 2026.2.20-438 → 2026.2.26-1642

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,342 @@
1
+ /**
2
+ * Continuous Scan Integration with Task Management
3
+ *
4
+ * Integrates the continuous scanner with the task management system
5
+ * to automatically create and track refactoring tasks.
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const { EventEmitter } = require('events');
11
+
12
+ const { ViolationPrioritizer } = require('../task-generation/prioritizer');
13
+ const { TaskListUpdater } = require('../task-generation/task-list-updater');
14
+
15
+ /**
16
+ * Continuous Scan Integration
17
+ */
18
+ class ContinuousScanIntegration extends EventEmitter {
19
+ constructor(options = {}) {
20
+ super();
21
+
22
+ this.options = {
23
+ tasksFilePath: options.tasksFilePath || './specs/010-555-max-file-size/tasks.md',
24
+ autoCreateTasks: options.autoCreateTasks !== false,
25
+ maxTasksPerScan: options.maxTasksPerScan || 10,
26
+ taskTemplate: options.taskTemplate || this._getDefaultTaskTemplate(),
27
+ ...options
28
+ };
29
+
30
+ this.prioritizer = new ViolationPrioritizer();
31
+ this.taskUpdater = new TaskListUpdater();
32
+ this.createdTasks = new Map();
33
+ this.lastScanResults = null;
34
+ }
35
+
36
+ /**
37
+ * Initialize integration with scanner
38
+ */
39
+ initialize(scanner) {
40
+ this.scanner = scanner;
41
+
42
+ // Setup event handlers
43
+ scanner.on('scan_completed', (data) => {
44
+ this._handleScanCompleted(data);
45
+ });
46
+
47
+ scanner.on('violations_found', (data) => {
48
+ this._handleViolationsFound(data);
49
+ });
50
+
51
+ this.emit('initialized');
52
+ }
53
+
54
+ /**
55
+ * Handle scan completion
56
+ */
57
+ async _handleScanCompleted(data) {
58
+ this.lastScanResults = data;
59
+
60
+ if (this.options.autoCreateTasks && data.violations.length > 0) {
61
+ await this._createTasksForViolations(data.violations);
62
+ }
63
+
64
+ this.emit('scan_processed', {
65
+ timestamp: data.timestamp,
66
+ violationsCount: data.violations.length,
67
+ tasksCreated: this.createdTasks.size
68
+ });
69
+ }
70
+
71
+ /**
72
+ * Handle violations found
73
+ */
74
+ async _handleViolationsFound(data) {
75
+ const prioritizedViolations = this.prioritizer.prioritizeViolations(data.violations);
76
+ const topViolations = prioritizedViolations.slice(0, this.options.maxTasksPerScan);
77
+
78
+ if (topViolations.length > 0) {
79
+ await this._createTasksForViolations(topViolations);
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Create tasks for violations
85
+ */
86
+ async _createTasksForViolations(violations) {
87
+ const tasks = [];
88
+
89
+ for (const violation of violations) {
90
+ const task = this._createTaskForViolation(violation);
91
+ if (task) {
92
+ tasks.push(task);
93
+ this.createdTasks.set(violation.file, task);
94
+ }
95
+ }
96
+
97
+ if (tasks.length > 0) {
98
+ await this._addTasksToTaskList(tasks);
99
+ this.emit('tasks_created', { count: tasks.length, tasks });
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Create task for a single violation
105
+ */
106
+ _createTaskForViolation(violation) {
107
+ const taskId = this._generateTaskId(violation);
108
+ const story = this._determineUserStory(violation);
109
+ const priority = this._determinePriority(violation);
110
+
111
+ // Skip if task already exists
112
+ if (this._taskExists(taskId)) {
113
+ return null;
114
+ }
115
+
116
+ const task = {
117
+ id: taskId,
118
+ priority: priority ? '[P]' : '',
119
+ story: story,
120
+ description: this._generateTaskDescription(violation),
121
+ filePath: violation.file,
122
+ lineCount: this._getLineCount(violation),
123
+ violationCount: violation.violations.length,
124
+ violations: violation.violations,
125
+ createdAt: new Date().toISOString()
126
+ };
127
+
128
+ return task;
129
+ }
130
+
131
+ /**
132
+ * Generate task ID
133
+ */
134
+ _generateTaskId(violation) {
135
+ const fileName = path.basename(violation.file, path.extname(violation.file));
136
+ const sanitized = fileName.replace(/[^a-zA-Z0-9]/g, '-').toLowerCase();
137
+ return `T${Date.now()}-${sanitized}`;
138
+ }
139
+
140
+ /**
141
+ * Determine user story
142
+ */
143
+ _determineUserStory(violation) {
144
+ // Based on violation type and file location
145
+ if (violation.file.includes('/core/')) {
146
+ return '[US2]'; // User Story 2 - Modular Refactoring
147
+ } else if (violation.file.includes('/cli/') || violation.file.includes('/electron-app/')) {
148
+ return '[US2]'; // User Story 2 - Modular Refactoring
149
+ } else {
150
+ return '[US2]'; // Default to User Story 2
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Determine if task can run in parallel
156
+ */
157
+ _determinePriority(violation) {
158
+ // Tasks can run in parallel if they're in different files
159
+ return true;
160
+ }
161
+
162
+ /**
163
+ * Generate task description
164
+ */
165
+ _generateTaskDescription(violation) {
166
+ const lineCount = this._getLineCount(violation);
167
+ const violationTypes = this._getViolationTypes(violation);
168
+
169
+ let description = `Refactor ${path.basename(violation.file)} (${lineCount} lines)`;
170
+
171
+ if (violationTypes.length > 0) {
172
+ description += ` - fix ${violationTypes.join(', ')}`;
173
+ }
174
+
175
+ return description;
176
+ }
177
+
178
+ /**
179
+ * Get line count from violation
180
+ */
181
+ _getLineCount(violation) {
182
+ if (violation.violations) {
183
+ const sizeViolation = violation.violations.find(v => v.rule === 'maxFileSize');
184
+ if (sizeViolation && sizeViolation.line) {
185
+ return sizeViolation.line;
186
+ }
187
+ }
188
+ return 0;
189
+ }
190
+
191
+ /**
192
+ * Get violation types
193
+ */
194
+ _getViolationTypes(violation) {
195
+ const types = new Set();
196
+
197
+ if (violation.violations) {
198
+ violation.violations.forEach(v => {
199
+ switch (v.rule) {
200
+ case 'maxFileSize':
201
+ types.add('file size limit');
202
+ break;
203
+ case 'noTrailingWhitespace':
204
+ types.add('trailing whitespace');
205
+ break;
206
+ case 'fileEndsWithNewline':
207
+ types.add('missing newline');
208
+ break;
209
+ case 'maxLineLength':
210
+ types.add('long lines');
211
+ break;
212
+ default:
213
+ types.add(v.rule);
214
+ }
215
+ });
216
+ }
217
+
218
+ return Array.from(types);
219
+ }
220
+
221
+ /**
222
+ * Check if task already exists
223
+ */
224
+ _taskExists(taskId) {
225
+ try {
226
+ if (!fs.existsSync(this.options.tasksFilePath)) {
227
+ return false;
228
+ }
229
+
230
+ const content = fs.readFileSync(this.options.tasksFilePath, 'utf8');
231
+ return content.includes(taskId);
232
+
233
+ } catch (error) {
234
+ console.error('Error checking if task exists:', error.message);
235
+ return false;
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Add tasks to task list
241
+ */
242
+ async _addTasksToTaskList(tasks) {
243
+ try {
244
+ await this.taskUpdater.addTasks(this.options.tasksFilePath, tasks);
245
+ } catch (error) {
246
+ console.error('Failed to add tasks to task list:', error.message);
247
+ this.emit('error', error);
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Get integration status
253
+ */
254
+ getStatus() {
255
+ return {
256
+ createdTasks: this.createdTasks.size,
257
+ lastScanResults: this.lastScanResults,
258
+ options: this.options
259
+ };
260
+ }
261
+
262
+ /**
263
+ * Get created tasks
264
+ */
265
+ getCreatedTasks() {
266
+ return Array.from(this.createdTasks.entries()).map(([file, task]) => ({
267
+ file,
268
+ task
269
+ }));
270
+ }
271
+
272
+ /**
273
+ * Clear created tasks cache
274
+ */
275
+ clearCache() {
276
+ this.createdTasks.clear();
277
+ this.lastScanResults = null;
278
+ this.emit('cache_cleared');
279
+ }
280
+
281
+ /**
282
+ * Get default task template
283
+ */
284
+ _getDefaultTaskTemplate() {
285
+ return `- [ ] {taskId} {priority} {story} {description}`;
286
+ }
287
+
288
+ /**
289
+ * Generate integration report
290
+ */
291
+ generateReport() {
292
+ const createdTasks = this.getCreatedTasks();
293
+ const status = this.getStatus();
294
+
295
+ return {
296
+ timestamp: new Date().toISOString(),
297
+ summary: {
298
+ totalTasksCreated: createdTasks.length,
299
+ lastScanAt: status.lastScanResults?.timestamp || null,
300
+ autoCreateTasksEnabled: this.options.autoCreateTasks
301
+ },
302
+ tasks: createdTasks,
303
+ recommendations: this._generateIntegrationRecommendations()
304
+ };
305
+ }
306
+
307
+ /**
308
+ * Generate integration recommendations
309
+ */
310
+ _generateIntegrationRecommendations() {
311
+ const recommendations = [];
312
+
313
+ if (this.createdTasks.size === 0) {
314
+ recommendations.push({
315
+ type: 'info',
316
+ title: 'No Tasks Created',
317
+ description: 'No refactoring tasks have been created yet',
318
+ action: 'Wait for the next scan or check scanner configuration'
319
+ });
320
+ } else {
321
+ recommendations.push({
322
+ type: 'action',
323
+ title: 'Review Created Tasks',
324
+ description: `${this.createdTasks.size} tasks have been created`,
325
+ action: 'Review the tasks.md file and prioritize implementation'
326
+ });
327
+ }
328
+
329
+ if (!this.options.autoCreateTasks) {
330
+ recommendations.push({
331
+ type: 'suggestion',
332
+ title: 'Enable Auto Task Creation',
333
+ description: 'Automatic task creation is currently disabled',
334
+ action: 'Enable autoCreateTasks option to streamline workflow'
335
+ });
336
+ }
337
+
338
+ return recommendations;
339
+ }
340
+ }
341
+
342
+ module.exports = { ContinuousScanIntegration };
@@ -1,6 +1,15 @@
1
- // timeout-management index
2
- // Placeholder exports for timeout management utilities (TimeoutCalculator, ResponseTimeTracker)
1
+ /**
2
+ * Timeout Management Module
3
+ *
4
+ * Provides adaptive timeout calculation and management for IDE interactions.
5
+ */
6
+
7
+ const { TimeoutCalculator } = require('./timeout-calculator');
8
+ const { TimeoutConfigManager } = require('./timeout-config-manager');
9
+ const { ResponseTimeTracker } = require('./response-time-tracker');
3
10
 
4
11
  module.exports = {
5
- // implementations to be added per spec
12
+ TimeoutCalculator,
13
+ TimeoutConfigManager,
14
+ ResponseTimeTracker
6
15
  };
@@ -0,0 +1,167 @@
1
+ /**
2
+ * ResponseTimeTracker
3
+ *
4
+ * Maintains response time samples for an IDE and provides statistical analysis
5
+ * including mean, median, standard deviation, and trend detection.
6
+ */
7
+
8
+ const EventEmitter = require('events');
9
+
10
+ class ResponseTimeTracker extends EventEmitter {
11
+ /**
12
+ * Create response time tracker
13
+ * @param {string} ideId - IDE identifier
14
+ * @param {Object} [options] - Tracker options
15
+ * @param {number} [options.maxSamples=50] - Maximum samples to keep
16
+ */
17
+ constructor(ideId, options = {}) {
18
+ super();
19
+
20
+ this.ideId = ideId;
21
+ this.maxSamples = options.maxSamples || 50;
22
+ this.samples = [];
23
+ }
24
+
25
+ /**
26
+ * Add response time sample
27
+ * @param {number} responseTime - Response time in milliseconds
28
+ */
29
+ addSample(responseTime) {
30
+ if (responseTime < 0) {
31
+ throw new Error('Response time must be non-negative');
32
+ }
33
+
34
+ this.samples.push(responseTime);
35
+
36
+ // Maintain max samples limit
37
+ if (this.samples.length > this.maxSamples) {
38
+ this.samples.shift(); // Remove oldest
39
+ }
40
+
41
+ this.emit('sample-added', responseTime);
42
+ }
43
+
44
+ /**
45
+ * Get all samples
46
+ * @returns {number[]} Copy of samples array
47
+ */
48
+ getSamples() {
49
+ return [...this.samples];
50
+ }
51
+
52
+ /**
53
+ * Get recent N samples
54
+ * @param {number} n - Number of recent samples to get
55
+ * @returns {number[]} Recent samples
56
+ */
57
+ getRecentSamples(n) {
58
+ if (n >= this.samples.length) {
59
+ return [...this.samples];
60
+ }
61
+ return this.samples.slice(-n);
62
+ }
63
+
64
+ /**
65
+ * Get statistical analysis of samples
66
+ * @returns {Object} Statistics object
67
+ */
68
+ getStatistics() {
69
+ if (this.samples.length === 0) {
70
+ return {
71
+ sampleCount: 0,
72
+ mean: null,
73
+ median: null,
74
+ stdDev: null,
75
+ min: null,
76
+ max: null
77
+ };
78
+ }
79
+
80
+ // Calculate mean
81
+ const sum = this.samples.reduce((acc, val) => acc + val, 0);
82
+ const mean = sum / this.samples.length;
83
+
84
+ // Calculate median
85
+ const sorted = [...this.samples].sort((a, b) => a - b);
86
+ let median;
87
+ const mid = Math.floor(sorted.length / 2);
88
+ if (sorted.length % 2 === 0) {
89
+ median = (sorted[mid - 1] + sorted[mid]) / 2;
90
+ } else {
91
+ median = sorted[mid];
92
+ }
93
+
94
+ // Calculate standard deviation
95
+ const variance = this.samples.reduce((acc, val) => {
96
+ const diff = val - mean;
97
+ return acc + (diff * diff);
98
+ }, 0) / this.samples.length;
99
+ const stdDev = Math.sqrt(variance);
100
+
101
+ // Min and max
102
+ const min = Math.min(...this.samples);
103
+ const max = Math.max(...this.samples);
104
+
105
+ return {
106
+ sampleCount: this.samples.length,
107
+ mean,
108
+ median,
109
+ stdDev,
110
+ min,
111
+ max
112
+ };
113
+ }
114
+
115
+ /**
116
+ * Detect trend in response times
117
+ * @returns {string|null} Trend ('increasing', 'decreasing', 'stable') or null
118
+ */
119
+ detectTrend() {
120
+ // Need at least 5 samples for trend detection
121
+ if (this.samples.length < 5) {
122
+ return null;
123
+ }
124
+
125
+ // Use simple linear regression to detect trend
126
+ const n = this.samples.length;
127
+ let sumX = 0;
128
+ let sumY = 0;
129
+ let sumXY = 0;
130
+ let sumX2 = 0;
131
+
132
+ for (let i = 0; i < n; i++) {
133
+ const x = i;
134
+ const y = this.samples[i];
135
+ sumX += x;
136
+ sumY += y;
137
+ sumXY += x * y;
138
+ sumX2 += x * x;
139
+ }
140
+
141
+ // Calculate slope
142
+ const slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
143
+
144
+ // Calculate mean for threshold
145
+ const mean = sumY / n;
146
+ const threshold = mean * 0.05; // 5% of mean
147
+
148
+ // Determine trend based on slope
149
+ if (slope > threshold) {
150
+ return 'increasing';
151
+ } else if (slope < -threshold) {
152
+ return 'decreasing';
153
+ } else {
154
+ return 'stable';
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Clear all samples
160
+ */
161
+ clear() {
162
+ this.samples = [];
163
+ this.emit('samples-cleared');
164
+ }
165
+ }
166
+
167
+ module.exports = { ResponseTimeTracker };
@@ -0,0 +1,159 @@
1
+ /**
2
+ * TimeoutCalculator
3
+ *
4
+ * Provides static methods for calculating adaptive timeouts based on
5
+ * historical response times using EWMA (Exponentially Weighted Moving Average).
6
+ */
7
+
8
+ class TimeoutCalculator {
9
+ /**
10
+ * Calculate timeout value based on EWMA and buffer percentage
11
+ * @param {Object} options - Calculation options
12
+ * @param {number|null} options.ewma - Current EWMA value (null for fixed mode)
13
+ * @param {number} options.defaultTimeout - Default timeout to use when no EWMA
14
+ * @param {number} options.bufferPercentage - Buffer percentage to add (0-200)
15
+ * @param {number} [options.minTimeout=30000] - Minimum timeout (30 seconds)
16
+ * @param {number} [options.maxTimeout=600000] - Maximum timeout (10 minutes)
17
+ * @returns {number} Calculated timeout in milliseconds
18
+ */
19
+ static calculateTimeout(options) {
20
+ const {
21
+ ewma,
22
+ defaultTimeout,
23
+ bufferPercentage,
24
+ minTimeout = 30000,
25
+ maxTimeout = 600000
26
+ } = options;
27
+
28
+ // Use default timeout if no EWMA available or EWMA is zero
29
+ if (!ewma || ewma === 0) {
30
+ return defaultTimeout;
31
+ }
32
+
33
+ // Calculate timeout with buffer
34
+ const buffer = ewma * (bufferPercentage / 100);
35
+ let timeout = Math.round(ewma + buffer);
36
+
37
+ // Enforce bounds
38
+ timeout = Math.max(minTimeout, timeout);
39
+ timeout = Math.min(maxTimeout, timeout);
40
+
41
+ return timeout;
42
+ }
43
+
44
+ /**
45
+ * Calculate EWMA from array of samples
46
+ * @param {number[]} samples - Array of response time samples
47
+ * @param {number} alpha - EWMA alpha weight (0-1)
48
+ * @returns {number|null} Calculated EWMA or null if no samples
49
+ */
50
+ static calculateEWMA(samples, alpha) {
51
+ if (!samples || samples.length === 0) {
52
+ return null;
53
+ }
54
+
55
+ if (samples.length === 1) {
56
+ return samples[0];
57
+ }
58
+
59
+ // Start with first sample
60
+ let ewma = samples[0];
61
+
62
+ // Apply EWMA formula for remaining samples
63
+ for (let i = 1; i < samples.length; i++) {
64
+ ewma = this.updateEWMA(ewma, samples[i], alpha);
65
+ }
66
+
67
+ return ewma;
68
+ }
69
+
70
+ /**
71
+ * Update EWMA with new sample
72
+ * @param {number|null} currentEWMA - Current EWMA value
73
+ * @param {number} newSample - New response time sample
74
+ * @param {number} alpha - EWMA alpha weight (0-1)
75
+ * @returns {number} Updated EWMA
76
+ */
77
+ static updateEWMA(currentEWMA, newSample, alpha) {
78
+ // If no current EWMA, use new sample
79
+ if (currentEWMA === null || currentEWMA === undefined) {
80
+ return newSample;
81
+ }
82
+
83
+ // EWMA formula: alpha * newSample + (1 - alpha) * currentEWMA
84
+ return Math.round(alpha * newSample + (1 - alpha) * currentEWMA);
85
+ }
86
+
87
+ /**
88
+ * Detect if a sample is an outlier
89
+ * @param {number[]} samples - Historical samples
90
+ * @param {number} newSample - New sample to check
91
+ * @param {number} [threshold=2.0] - Standard deviation threshold
92
+ * @returns {boolean} True if outlier detected
93
+ */
94
+ static detectOutlier(samples, newSample, threshold = 2.0) {
95
+ // Need at least 3 samples for meaningful statistics
96
+ if (!samples || samples.length < 3) {
97
+ return false;
98
+ }
99
+
100
+ // Calculate mean
101
+ const mean = samples.reduce((sum, val) => sum + val, 0) / samples.length;
102
+
103
+ // Calculate standard deviation
104
+ const variance = samples.reduce((sum, val) => {
105
+ const diff = val - mean;
106
+ return sum + (diff * diff);
107
+ }, 0) / samples.length;
108
+ const stdDev = Math.sqrt(variance);
109
+
110
+ // Check if new sample is beyond threshold
111
+ const deviation = Math.abs(newSample - mean);
112
+ return deviation > (threshold * stdDev);
113
+ }
114
+
115
+ /**
116
+ * Recommend buffer percentage based on response time variance
117
+ * @param {number[]} samples - Historical response time samples
118
+ * @returns {number} Recommended buffer percentage (20-200)
119
+ */
120
+ static recommendBufferPercentage(samples) {
121
+ // Need at least 3 samples for meaningful statistics
122
+ if (!samples || samples.length < 3) {
123
+ return 50; // Default
124
+ }
125
+
126
+ // Calculate coefficient of variation (CV = stdDev / mean)
127
+ const mean = samples.reduce((sum, val) => sum + val, 0) / samples.length;
128
+
129
+ const variance = samples.reduce((sum, val) => {
130
+ const diff = val - mean;
131
+ return sum + (diff * diff);
132
+ }, 0) / samples.length;
133
+ const stdDev = Math.sqrt(variance);
134
+
135
+ const cv = stdDev / mean;
136
+
137
+ // Map CV to buffer percentage
138
+ // Low CV (< 0.2) -> 20-40% buffer
139
+ // Medium CV (0.2-0.5) -> 40-80% buffer
140
+ // High CV (> 0.5) -> 80-200% buffer
141
+ let bufferPercentage;
142
+
143
+ if (cv < 0.2) {
144
+ bufferPercentage = 20 + (cv / 0.2) * 20; // 20-40%
145
+ } else if (cv < 0.5) {
146
+ bufferPercentage = 40 + ((cv - 0.2) / 0.3) * 40; // 40-80%
147
+ } else {
148
+ bufferPercentage = 80 + Math.min((cv - 0.5) * 120, 120); // 80-200%
149
+ }
150
+
151
+ // Enforce bounds
152
+ bufferPercentage = Math.max(20, bufferPercentage);
153
+ bufferPercentage = Math.min(200, bufferPercentage);
154
+
155
+ return Math.round(bufferPercentage);
156
+ }
157
+ }
158
+
159
+ module.exports = { TimeoutCalculator };