vibecodingmachine-core 2025.12.25-25 → 2026.1.22-1441

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 (40) hide show
  1. package/ERROR_REPORTING_API.md +212 -0
  2. package/ERROR_REPORTING_USAGE.md +380 -0
  3. package/__tests__/provider-manager-fallback.test.js +43 -0
  4. package/__tests__/provider-manager-rate-limit.test.js +61 -0
  5. package/__tests__/utils/git-branch-manager.test.js +61 -0
  6. package/package.json +1 -1
  7. package/src/beta-request.js +160 -0
  8. package/src/compliance/compliance-manager.js +5 -2
  9. package/src/database/migrations.js +135 -12
  10. package/src/database/user-database-client.js +127 -8
  11. package/src/database/user-schema.js +28 -0
  12. package/src/health-tracking/__tests__/ide-health-tracker.test.js +420 -0
  13. package/src/health-tracking/__tests__/interaction-recorder.test.js +392 -0
  14. package/src/health-tracking/errors.js +50 -0
  15. package/src/health-tracking/health-reporter.js +331 -0
  16. package/src/health-tracking/ide-health-tracker.js +446 -0
  17. package/src/health-tracking/interaction-recorder.js +161 -0
  18. package/src/health-tracking/json-storage.js +276 -0
  19. package/src/health-tracking/storage-interface.js +63 -0
  20. package/src/health-tracking/validators.js +277 -0
  21. package/src/ide-integration/applescript-manager.cjs +1087 -9
  22. package/src/ide-integration/applescript-manager.js +565 -15
  23. package/src/ide-integration/applescript-utils.js +26 -18
  24. package/src/ide-integration/provider-manager.cjs +158 -28
  25. package/src/ide-integration/quota-detector.cjs +339 -16
  26. package/src/ide-integration/quota-detector.js +6 -1
  27. package/src/index.cjs +36 -1
  28. package/src/index.js +20 -0
  29. package/src/localization/translations/en.js +15 -1
  30. package/src/localization/translations/es.js +14 -0
  31. package/src/requirement-numbering.js +164 -0
  32. package/src/sync/aws-setup.js +4 -4
  33. package/src/utils/admin-utils.js +33 -0
  34. package/src/utils/error-reporter.js +117 -0
  35. package/src/utils/git-branch-manager.js +278 -0
  36. package/src/utils/requirement-helpers.js +44 -5
  37. package/src/utils/requirements-parser.js +28 -3
  38. package/tests/health-tracking/health-reporter.test.js +329 -0
  39. package/tests/health-tracking/ide-health-tracker.test.js +368 -0
  40. package/tests/health-tracking/interaction-recorder.test.js +309 -0
@@ -0,0 +1,446 @@
1
+ /**
2
+ * IDE Health Tracker
3
+ *
4
+ * Main class for tracking IDE reliability metrics.
5
+ * Tracks success/failure counters, response times, and EWMA calculations.
6
+ *
7
+ * @module ide-health-tracker
8
+ */
9
+
10
+ const EventEmitter = require('events');
11
+ const { JSONStorage } = require('./json-storage');
12
+ const { InteractionRecorder } = require('./interaction-recorder');
13
+ const { ValidationError } = require('./errors');
14
+ const { validateIdeId, validateResponseTime } = require('./validators');
15
+
16
+ /**
17
+ * Maximum number of response times to keep per IDE
18
+ */
19
+ const MAX_RESPONSE_TIMES = 50;
20
+
21
+ /**
22
+ * Consecutive failure threshold for emitting warning
23
+ */
24
+ const CONSECUTIVE_FAILURE_THRESHOLD = 5;
25
+
26
+ /**
27
+ * Default EWMA alpha value
28
+ */
29
+ const DEFAULT_EWMA_ALPHA = 0.3;
30
+
31
+ /**
32
+ * Tracks IDE health metrics including success/failure counts and response times
33
+ * @extends EventEmitter
34
+ */
35
+ class IDEHealthTracker extends EventEmitter {
36
+ /**
37
+ * @param {Object} options - Configuration options
38
+ * @param {string} [options.storageFile] - Path to storage file
39
+ * @param {boolean} [options.autoSave=true] - Automatically save after updates
40
+ * @param {number} [options.debounceMs=500] - Debounce time for auto-save
41
+ */
42
+ constructor(options = {}) {
43
+ super();
44
+
45
+ this.storage = new JSONStorage({
46
+ storageFile: options.storageFile,
47
+ });
48
+
49
+ this.recorder = new InteractionRecorder(this.storage);
50
+
51
+ this.autoSave = options.autoSave !== undefined ? options.autoSave : true;
52
+ this.debounceMs = options.debounceMs || 500;
53
+ this.saveTimeout = null;
54
+ }
55
+
56
+ /**
57
+ * Record a successful IDE interaction
58
+ * @param {string} ideId - IDE identifier
59
+ * @param {number} responseTime - Response time in milliseconds
60
+ * @param {Object} [metadata] - Additional metadata
61
+ * @param {number} [metadata.continuationPromptsDetected=0] - Number of prompts handled
62
+ * @param {string} [metadata.requirementId] - Associated requirement ID
63
+ * @param {Date} [metadata.timestamp] - Override timestamp
64
+ * @returns {Promise<void>}
65
+ * @throws {ValidationError} If validation fails
66
+ */
67
+ async recordSuccess(ideId, responseTime, metadata = {}) {
68
+ // Validate inputs
69
+ validateIdeId(ideId);
70
+ validateResponseTime(responseTime);
71
+
72
+ // Read current data
73
+ const data = await this.storage.read();
74
+
75
+ // Initialize IDE record if needed
76
+ if (!data.ides[ideId]) {
77
+ data.ides[ideId] = this._createDefaultIDERecord();
78
+ }
79
+
80
+ const ideRecord = data.ides[ideId];
81
+
82
+ // Increment success count
83
+ ideRecord.successCount++;
84
+
85
+ // Reset consecutive failures
86
+ ideRecord.consecutiveFailures = 0;
87
+
88
+ // Update lastSuccess
89
+ ideRecord.lastSuccess = (metadata.timestamp || new Date()).toISOString();
90
+
91
+ // Add response time to array
92
+ ideRecord.responseTimes.push(responseTime);
93
+
94
+ // Enforce max response times
95
+ if (ideRecord.responseTimes.length > MAX_RESPONSE_TIMES) {
96
+ ideRecord.responseTimes = ideRecord.responseTimes.slice(-MAX_RESPONSE_TIMES);
97
+ }
98
+
99
+ // Recalculate EWMA
100
+ ideRecord.ewma = this._calculateEWMA(ideRecord.responseTimes);
101
+
102
+ // Update current timeout based on EWMA and config
103
+ ideRecord.currentTimeout = await this._calculateTimeout(ideRecord, data.timeoutConfig);
104
+
105
+ // Write updated data
106
+ await this.storage.write(data);
107
+
108
+ // Record interaction
109
+ await this.recorder.record({
110
+ ideId,
111
+ timestamp: metadata.timestamp || new Date(),
112
+ outcome: 'success',
113
+ responseTime,
114
+ timeoutUsed: ideRecord.currentTimeout,
115
+ continuationPromptsDetected: metadata.continuationPromptsDetected || 0,
116
+ requirementId: metadata.requirementId || null,
117
+ errorMessage: null,
118
+ });
119
+
120
+ // Emit event
121
+ this.emit('health-updated', { ideId, outcome: 'success' });
122
+
123
+ // Trigger debounced save if auto-save enabled
124
+ if (this.autoSave) {
125
+ this._debouncedSave();
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Record a failed IDE interaction
131
+ * @param {string} ideId - IDE identifier
132
+ * @param {string} [errorMessage] - Error description
133
+ * @param {Object} [metadata] - Additional metadata
134
+ * @param {number} [metadata.timeoutUsed] - Timeout that expired
135
+ * @param {string} [metadata.requirementId] - Associated requirement ID
136
+ * @param {Date} [metadata.timestamp] - Override timestamp
137
+ * @returns {Promise<void>}
138
+ * @throws {ValidationError} If validation fails
139
+ */
140
+ async recordFailure(ideId, errorMessage, metadata = {}) {
141
+ // Validate inputs
142
+ validateIdeId(ideId);
143
+
144
+ // Read current data
145
+ const data = await this.storage.read();
146
+
147
+ // Initialize IDE record if needed
148
+ if (!data.ides[ideId]) {
149
+ data.ides[ideId] = this._createDefaultIDERecord();
150
+ }
151
+
152
+ const ideRecord = data.ides[ideId];
153
+
154
+ // Increment failure count
155
+ ideRecord.failureCount++;
156
+
157
+ // Increment consecutive failures
158
+ ideRecord.consecutiveFailures++;
159
+
160
+ // Update lastFailure
161
+ ideRecord.lastFailure = (metadata.timestamp || new Date()).toISOString();
162
+
163
+ // Write updated data
164
+ await this.storage.write(data);
165
+
166
+ // Record interaction
167
+ await this.recorder.record({
168
+ ideId,
169
+ timestamp: metadata.timestamp || new Date(),
170
+ outcome: 'failure',
171
+ responseTime: null,
172
+ timeoutUsed: metadata.timeoutUsed || ideRecord.currentTimeout,
173
+ continuationPromptsDetected: 0,
174
+ requirementId: metadata.requirementId || null,
175
+ errorMessage: errorMessage || 'Unknown error',
176
+ });
177
+
178
+ // Emit event
179
+ this.emit('health-updated', { ideId, outcome: 'failure' });
180
+
181
+ // Emit consecutive-failures event if threshold reached
182
+ if (ideRecord.consecutiveFailures === CONSECUTIVE_FAILURE_THRESHOLD) {
183
+ this.emit('consecutive-failures', {
184
+ ideId,
185
+ count: ideRecord.consecutiveFailures,
186
+ lastError: errorMessage || 'Unknown error',
187
+ });
188
+ }
189
+
190
+ // Trigger debounced save if auto-save enabled
191
+ if (this.autoSave) {
192
+ this._debouncedSave();
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Record a quota limit event (does NOT increment success/failure counters)
198
+ * @param {string} ideId - IDE identifier
199
+ * @param {string} quotaMessage - Quota message from IDE
200
+ * @param {Object} [metadata] - Additional metadata
201
+ * @param {string} [metadata.requirementId] - Associated requirement ID
202
+ * @param {Date} [metadata.timestamp] - Override timestamp
203
+ * @returns {Promise<void>}
204
+ * @throws {ValidationError} If validation fails
205
+ */
206
+ async recordQuota(ideId, quotaMessage, metadata = {}) {
207
+ // Validate inputs
208
+ validateIdeId(ideId);
209
+
210
+ // Read current data
211
+ const data = await this.storage.read();
212
+
213
+ // Initialize IDE record if needed
214
+ if (!data.ides[ideId]) {
215
+ data.ides[ideId] = this._createDefaultIDERecord();
216
+ }
217
+
218
+ const ideRecord = data.ides[ideId];
219
+
220
+ // Record interaction (no counter updates per FR-008)
221
+ await this.recorder.record({
222
+ ideId,
223
+ timestamp: metadata.timestamp || new Date(),
224
+ outcome: 'quota',
225
+ responseTime: null,
226
+ timeoutUsed: ideRecord.currentTimeout,
227
+ continuationPromptsDetected: 0,
228
+ requirementId: metadata.requirementId || null,
229
+ errorMessage: quotaMessage,
230
+ });
231
+
232
+ // Emit event
233
+ this.emit('health-updated', { ideId, outcome: 'quota' });
234
+
235
+ // Trigger debounced save if auto-save enabled
236
+ if (this.autoSave) {
237
+ this._debouncedSave();
238
+ }
239
+ }
240
+
241
+ /**
242
+ * Get health metrics for a specific IDE
243
+ * @param {string} ideId - IDE identifier
244
+ * @returns {Promise<Object>} Health metrics object
245
+ */
246
+ async getHealthMetrics(ideId) {
247
+ const data = await this.storage.read();
248
+ const ideRecord = data.ides[ideId];
249
+
250
+ if (!ideRecord) {
251
+ // Return default metrics for unknown IDE
252
+ return {
253
+ successCount: 0,
254
+ failureCount: 0,
255
+ successRate: 0,
256
+ averageResponseTime: 0,
257
+ currentTimeout: 1800000,
258
+ consecutiveFailures: 0,
259
+ lastSuccess: null,
260
+ lastFailure: null,
261
+ totalInteractions: 0,
262
+ recentInteractions: [],
263
+ };
264
+ }
265
+
266
+ const totalInteractions = ideRecord.successCount + ideRecord.failureCount;
267
+ const successRate = totalInteractions > 0
268
+ ? ideRecord.successCount / totalInteractions
269
+ : 0;
270
+
271
+ // Get recent 10 interactions
272
+ const recentInteractions = await this.recorder.getInteractions(ideId, 10);
273
+
274
+ return {
275
+ successCount: ideRecord.successCount,
276
+ failureCount: ideRecord.failureCount,
277
+ successRate,
278
+ averageResponseTime: ideRecord.ewma,
279
+ currentTimeout: ideRecord.currentTimeout,
280
+ consecutiveFailures: ideRecord.consecutiveFailures,
281
+ lastSuccess: ideRecord.lastSuccess,
282
+ lastFailure: ideRecord.lastFailure,
283
+ totalInteractions,
284
+ recentInteractions,
285
+ };
286
+ }
287
+
288
+ /**
289
+ * Get health metrics for all tracked IDEs
290
+ * @returns {Promise<Map<string, Object>>} Map of IDE ID to health metrics
291
+ */
292
+ async getAllHealthMetrics() {
293
+ const data = await this.storage.read();
294
+ const metricsMap = new Map();
295
+
296
+ for (const ideId of Object.keys(data.ides)) {
297
+ const metrics = await this.getHealthMetrics(ideId);
298
+ metricsMap.set(ideId, metrics);
299
+ }
300
+
301
+ return metricsMap;
302
+ }
303
+
304
+ /**
305
+ * Get recommended IDE based on health metrics
306
+ * @param {Object} [options] - Options
307
+ * @param {number} [options.minInteractions=10] - Minimum total interactions to consider
308
+ * @param {boolean} [options.weightRecent=true] - Weight recent interactions more heavily
309
+ * @returns {Promise<string|null>} IDE identifier with highest success rate, or null
310
+ */
311
+ async getRecommendedIDE(options = {}) {
312
+ const minInteractions = options.minInteractions || 10;
313
+ const allMetrics = await this.getAllHealthMetrics();
314
+
315
+ let bestIDE = null;
316
+ let bestSuccessRate = 0;
317
+
318
+ for (const [ideId, metrics] of allMetrics) {
319
+ if (metrics.totalInteractions >= minInteractions) {
320
+ if (metrics.successRate > bestSuccessRate) {
321
+ bestSuccessRate = metrics.successRate;
322
+ bestIDE = ideId;
323
+ }
324
+ }
325
+ }
326
+
327
+ return bestIDE;
328
+ }
329
+
330
+ /**
331
+ * Manually trigger save operation
332
+ * @returns {Promise<void>}
333
+ * @throws {FileSystemError} If write fails
334
+ */
335
+ async save() {
336
+ // Cancel any pending debounced save
337
+ if (this.saveTimeout) {
338
+ clearTimeout(this.saveTimeout);
339
+ this.saveTimeout = null;
340
+ }
341
+
342
+ // Note: Data is already written in record methods,
343
+ // this is mainly for explicit save requests
344
+ const data = await this.storage.read();
345
+ await this.storage.write(data);
346
+ }
347
+
348
+ /**
349
+ * Reload health data from storage file
350
+ * @returns {Promise<void>}
351
+ * @throws {FileSystemError} If read fails
352
+ * @throws {ValidationError} If data is corrupted
353
+ */
354
+ async load() {
355
+ // Simply reading from storage will load and validate the data
356
+ await this.storage.read();
357
+ }
358
+
359
+ /**
360
+ * Create default IDE record
361
+ * @private
362
+ * @returns {Object} Default IDE record
363
+ */
364
+ _createDefaultIDERecord() {
365
+ return {
366
+ successCount: 0,
367
+ failureCount: 0,
368
+ responseTimes: [],
369
+ ewma: 0,
370
+ lastSuccess: null,
371
+ lastFailure: null,
372
+ consecutiveFailures: 0,
373
+ currentTimeout: 1800000, // 30 minutes
374
+ interactions: [],
375
+ };
376
+ }
377
+
378
+ /**
379
+ * Calculate EWMA from response times
380
+ * @private
381
+ * @param {number[]} responseTimes - Array of response times
382
+ * @param {number} [alpha] - EWMA alpha parameter
383
+ * @returns {number} EWMA value
384
+ */
385
+ _calculateEWMA(responseTimes, alpha = DEFAULT_EWMA_ALPHA) {
386
+ if (!responseTimes || responseTimes.length === 0) {
387
+ return 0;
388
+ }
389
+
390
+ let ewma = responseTimes[0];
391
+ for (let i = 1; i < responseTimes.length; i++) {
392
+ ewma = alpha * responseTimes[i] + (1 - alpha) * ewma;
393
+ }
394
+
395
+ return ewma;
396
+ }
397
+
398
+ /**
399
+ * Calculate timeout for IDE based on EWMA and config
400
+ * @private
401
+ * @param {Object} ideRecord - IDE health record
402
+ * @param {Object} timeoutConfig - Timeout configuration
403
+ * @returns {Promise<number>} Calculated timeout in milliseconds
404
+ */
405
+ async _calculateTimeout(ideRecord, timeoutConfig) {
406
+ if (!timeoutConfig || timeoutConfig.mode === 'fixed') {
407
+ return timeoutConfig?.defaultTimeout || 1800000;
408
+ }
409
+
410
+ // Adaptive mode
411
+ const minSamples = timeoutConfig.minSamplesForAdaptive || 10;
412
+ if (ideRecord.successCount < minSamples) {
413
+ return timeoutConfig.defaultTimeout;
414
+ }
415
+
416
+ const baseTimeout = ideRecord.ewma;
417
+ const buffer = baseTimeout * (timeoutConfig.bufferPercentage || 0.4);
418
+ const adaptiveTimeout = baseTimeout + buffer;
419
+
420
+ // Enforce 5-minute minimum
421
+ return Math.max(adaptiveTimeout, 300000);
422
+ }
423
+
424
+ /**
425
+ * Debounced save operation
426
+ * @private
427
+ */
428
+ _debouncedSave() {
429
+ if (this.saveTimeout) {
430
+ clearTimeout(this.saveTimeout);
431
+ }
432
+
433
+ this.saveTimeout = setTimeout(async () => {
434
+ try {
435
+ await this.save();
436
+ } catch (error) {
437
+ this.emit('save-error', {
438
+ error,
439
+ retryCount: 0,
440
+ });
441
+ }
442
+ }, this.debounceMs);
443
+ }
444
+ }
445
+
446
+ module.exports = { IDEHealthTracker, MAX_RESPONSE_TIMES, CONSECUTIVE_FAILURE_THRESHOLD };
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Interaction Recorder
3
+ *
4
+ * Records individual IDE interactions with timestamps and outcomes.
5
+ *
6
+ * @module interaction-recorder
7
+ */
8
+
9
+ const { ValidationError } = require('./errors');
10
+ const { validateIdeId, validateInteractionRecord } = require('./validators');
11
+
12
+ /**
13
+ * Maximum number of interactions to keep per IDE
14
+ */
15
+ const MAX_INTERACTIONS = 100;
16
+
17
+ /**
18
+ * Default IDE health record structure
19
+ */
20
+ const DEFAULT_IDE_RECORD = {
21
+ successCount: 0,
22
+ failureCount: 0,
23
+ responseTimes: [],
24
+ ewma: 0,
25
+ lastSuccess: null,
26
+ lastFailure: null,
27
+ consecutiveFailures: 0,
28
+ currentTimeout: 1800000, // 30 minutes default
29
+ interactions: [],
30
+ };
31
+
32
+ /**
33
+ * Records individual interactions for IDE health tracking
34
+ */
35
+ class InteractionRecorder {
36
+ /**
37
+ * @param {StorageInterface} storage - Storage interface with read() and write() methods
38
+ */
39
+ constructor(storage) {
40
+ if (!storage || typeof storage.read !== 'function' || typeof storage.write !== 'function') {
41
+ throw new ValidationError(
42
+ 'Storage must implement read() and write() methods',
43
+ 'storage',
44
+ storage
45
+ );
46
+ }
47
+ this.storage = storage;
48
+ }
49
+
50
+ /**
51
+ * Record a single interaction
52
+ * @param {Object} interaction - Interaction object
53
+ * @param {string} interaction.ideId - IDE identifier
54
+ * @param {Date} interaction.timestamp - Interaction timestamp
55
+ * @param {string} interaction.outcome - 'success' | 'failure' | 'quota'
56
+ * @param {number|null} interaction.responseTime - Response time in ms (null for failures/quota)
57
+ * @param {number} interaction.timeoutUsed - Timeout value used
58
+ * @param {number} interaction.continuationPromptsDetected - Number of prompts detected
59
+ * @param {string|null} interaction.requirementId - Associated requirement ID
60
+ * @param {string|null} interaction.errorMessage - Error message (for failures)
61
+ * @returns {Promise<void>}
62
+ * @throws {ValidationError} If validation fails
63
+ */
64
+ async record(interaction) {
65
+ // Validate ideId
66
+ validateIdeId(interaction.ideId);
67
+
68
+ // Convert Date to ISO string
69
+ const timestamp = interaction.timestamp instanceof Date
70
+ ? interaction.timestamp.toISOString()
71
+ : interaction.timestamp;
72
+
73
+ // Create interaction record
74
+ const record = {
75
+ timestamp,
76
+ outcome: interaction.outcome,
77
+ responseTime: interaction.responseTime,
78
+ timeoutUsed: interaction.timeoutUsed,
79
+ continuationPromptsDetected: interaction.continuationPromptsDetected || 0,
80
+ requirementId: interaction.requirementId || null,
81
+ errorMessage: interaction.errorMessage || null,
82
+ };
83
+
84
+ // Validate interaction record
85
+ validateInteractionRecord(record, interaction.ideId);
86
+
87
+ // Read current data
88
+ const data = await this.storage.read();
89
+
90
+ // Initialize IDE record if it doesn't exist
91
+ if (!data.ides[interaction.ideId]) {
92
+ data.ides[interaction.ideId] = JSON.parse(JSON.stringify(DEFAULT_IDE_RECORD));
93
+ }
94
+
95
+ // Add interaction to array
96
+ data.ides[interaction.ideId].interactions.push(record);
97
+
98
+ // Enforce max interactions limit
99
+ if (data.ides[interaction.ideId].interactions.length > MAX_INTERACTIONS) {
100
+ // Remove oldest interactions
101
+ data.ides[interaction.ideId].interactions = data.ides[interaction.ideId].interactions.slice(-MAX_INTERACTIONS);
102
+ }
103
+
104
+ // Write updated data
105
+ await this.storage.write(data);
106
+ }
107
+
108
+ /**
109
+ * Get interactions for a specific IDE
110
+ * @param {string} ideId - IDE identifier
111
+ * @param {number} [limit] - Maximum number of interactions to return (most recent)
112
+ * @returns {Promise<Array>} Array of interaction records
113
+ */
114
+ async getInteractions(ideId, limit) {
115
+ const data = await this.storage.read();
116
+
117
+ if (!data.ides[ideId] || !data.ides[ideId].interactions) {
118
+ return [];
119
+ }
120
+
121
+ const interactions = data.ides[ideId].interactions;
122
+
123
+ if (limit && limit > 0) {
124
+ return interactions.slice(-limit);
125
+ }
126
+
127
+ return interactions;
128
+ }
129
+
130
+ /**
131
+ * Clear all interactions for a specific IDE
132
+ * @param {string} ideId - IDE identifier
133
+ * @returns {Promise<void>}
134
+ */
135
+ async clearInteractions(ideId) {
136
+ const data = await this.storage.read();
137
+
138
+ if (data.ides[ideId]) {
139
+ data.ides[ideId].interactions = [];
140
+ await this.storage.write(data);
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Get default IDE record structure
146
+ * @returns {Object} Default IDE record
147
+ */
148
+ static getDefaultRecord() {
149
+ return JSON.parse(JSON.stringify(DEFAULT_IDE_RECORD));
150
+ }
151
+
152
+ /**
153
+ * Get maximum interactions limit
154
+ * @returns {number} Max interactions per IDE
155
+ */
156
+ static getMaxInteractions() {
157
+ return MAX_INTERACTIONS;
158
+ }
159
+ }
160
+
161
+ module.exports = { InteractionRecorder, MAX_INTERACTIONS, DEFAULT_IDE_RECORD };