vibecodingmachine-core 2026.1.23-1010 โ 2026.1.29-1432
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.
- package/package.json +10 -1
- package/src/database/user-database-client.js +8 -3
- package/.babelrc +0 -13
- package/ERROR_REPORTING_API.md +0 -212
- package/ERROR_REPORTING_USAGE.md +0 -380
- package/__tests__/applescript-manager-claude-fix.test.js +0 -286
- package/__tests__/provider-manager-fallback.test.js +0 -43
- package/__tests__/provider-manager-rate-limit.test.js +0 -61
- package/__tests__/requirement-2-auto-start-looping.test.js +0 -69
- package/__tests__/requirement-3-auto-start-looping.test.js +0 -69
- package/__tests__/requirement-4-auto-start-looping.test.js +0 -69
- package/__tests__/requirement-6-auto-start-looping.test.js +0 -73
- package/__tests__/requirement-7-status-tracking.test.js +0 -332
- package/__tests__/utils/git-branch-manager.test.js +0 -61
- package/jest.config.js +0 -18
- package/jest.setup.js +0 -12
- package/scripts/setup-database.js +0 -108
- package/src/health-tracking/__tests__/ide-health-tracker.test.js +0 -420
- package/src/health-tracking/__tests__/interaction-recorder.test.js +0 -392
- package/src/ide-integration/__tests__/applescript-manager-thread-closure.test.js +0 -227
- package/src/ui/StateManager.test.js +0 -0
- package/test-quota-system.js +0 -67
- package/test-requirement-stats.js +0 -66
- package/tests/health-tracking/health-reporter.test.js +0 -329
- package/tests/health-tracking/ide-health-tracker.test.js +0 -368
- package/tests/health-tracking/interaction-recorder.test.js +0 -309
|
@@ -1,392 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for InteractionRecorder
|
|
3
|
-
* @jest-environment node
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const { InteractionRecorder } = require('../interaction-recorder');
|
|
7
|
-
const { ValidationError } = require('../errors');
|
|
8
|
-
|
|
9
|
-
describe('InteractionRecorder', () => {
|
|
10
|
-
let recorder;
|
|
11
|
-
let mockStorage;
|
|
12
|
-
|
|
13
|
-
beforeEach(() => {
|
|
14
|
-
// Create mock storage
|
|
15
|
-
mockStorage = {
|
|
16
|
-
data: {
|
|
17
|
-
version: '1.0.0',
|
|
18
|
-
lastUpdated: new Date().toISOString(),
|
|
19
|
-
ides: {},
|
|
20
|
-
timeoutConfig: {},
|
|
21
|
-
defaultRequirement: null,
|
|
22
|
-
},
|
|
23
|
-
async read() {
|
|
24
|
-
return JSON.parse(JSON.stringify(this.data));
|
|
25
|
-
},
|
|
26
|
-
async write(data) {
|
|
27
|
-
this.data = JSON.parse(JSON.stringify(data));
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
recorder = new InteractionRecorder(mockStorage);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
describe('record()', () => {
|
|
35
|
-
it('should record a success interaction', async () => {
|
|
36
|
-
const interaction = {
|
|
37
|
-
ideId: 'cursor',
|
|
38
|
-
timestamp: new Date(),
|
|
39
|
-
outcome: 'success',
|
|
40
|
-
responseTime: 120000,
|
|
41
|
-
timeoutUsed: 180000,
|
|
42
|
-
continuationPromptsDetected: 1,
|
|
43
|
-
requirementId: 'req-001',
|
|
44
|
-
errorMessage: null,
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
await recorder.record(interaction);
|
|
48
|
-
|
|
49
|
-
const data = await mockStorage.read();
|
|
50
|
-
expect(data.ides.cursor).toBeDefined();
|
|
51
|
-
expect(data.ides.cursor.interactions).toHaveLength(1);
|
|
52
|
-
expect(data.ides.cursor.interactions[0].outcome).toBe('success');
|
|
53
|
-
expect(data.ides.cursor.interactions[0].responseTime).toBe(120000);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('should record a failure interaction', async () => {
|
|
57
|
-
const interaction = {
|
|
58
|
-
ideId: 'windsurf',
|
|
59
|
-
timestamp: new Date(),
|
|
60
|
-
outcome: 'failure',
|
|
61
|
-
responseTime: null,
|
|
62
|
-
timeoutUsed: 1800000,
|
|
63
|
-
continuationPromptsDetected: 0,
|
|
64
|
-
requirementId: 'req-002',
|
|
65
|
-
errorMessage: 'Timeout exceeded',
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
await recorder.record(interaction);
|
|
69
|
-
|
|
70
|
-
const data = await mockStorage.read();
|
|
71
|
-
expect(data.ides.windsurf.interactions).toHaveLength(1);
|
|
72
|
-
expect(data.ides.windsurf.interactions[0].outcome).toBe('failure');
|
|
73
|
-
expect(data.ides.windsurf.interactions[0].errorMessage).toBe('Timeout exceeded');
|
|
74
|
-
expect(data.ides.windsurf.interactions[0].responseTime).toBeNull();
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('should record a quota interaction', async () => {
|
|
78
|
-
const interaction = {
|
|
79
|
-
ideId: 'cursor',
|
|
80
|
-
timestamp: new Date(),
|
|
81
|
-
outcome: 'quota',
|
|
82
|
-
responseTime: null,
|
|
83
|
-
timeoutUsed: 1800000,
|
|
84
|
-
continuationPromptsDetected: 0,
|
|
85
|
-
requirementId: 'req-003',
|
|
86
|
-
errorMessage: 'Monthly quota exceeded',
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
await recorder.record(interaction);
|
|
90
|
-
|
|
91
|
-
const data = await mockStorage.read();
|
|
92
|
-
expect(data.ides.cursor.interactions).toHaveLength(1);
|
|
93
|
-
expect(data.ides.cursor.interactions[0].outcome).toBe('quota');
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('should convert Date timestamp to ISO string', async () => {
|
|
97
|
-
const timestamp = new Date('2025-01-21T12:00:00Z');
|
|
98
|
-
const interaction = {
|
|
99
|
-
ideId: 'cursor',
|
|
100
|
-
timestamp,
|
|
101
|
-
outcome: 'success',
|
|
102
|
-
responseTime: 120000,
|
|
103
|
-
timeoutUsed: 180000,
|
|
104
|
-
continuationPromptsDetected: 0,
|
|
105
|
-
requirementId: null,
|
|
106
|
-
errorMessage: null,
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
await recorder.record(interaction);
|
|
110
|
-
|
|
111
|
-
const data = await mockStorage.read();
|
|
112
|
-
expect(data.ides.cursor.interactions[0].timestamp).toBe('2025-01-21T12:00:00.000Z');
|
|
113
|
-
expect(typeof data.ides.cursor.interactions[0].timestamp).toBe('string');
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('should initialize IDE record if it does not exist', async () => {
|
|
117
|
-
const interaction = {
|
|
118
|
-
ideId: 'new-ide',
|
|
119
|
-
timestamp: new Date(),
|
|
120
|
-
outcome: 'success',
|
|
121
|
-
responseTime: 120000,
|
|
122
|
-
timeoutUsed: 180000,
|
|
123
|
-
continuationPromptsDetected: 0,
|
|
124
|
-
requirementId: null,
|
|
125
|
-
errorMessage: null,
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
await recorder.record(interaction);
|
|
129
|
-
|
|
130
|
-
const data = await mockStorage.read();
|
|
131
|
-
expect(data.ides['new-ide']).toBeDefined();
|
|
132
|
-
expect(data.ides['new-ide'].interactions).toHaveLength(1);
|
|
133
|
-
expect(data.ides['new-ide'].successCount).toBe(0);
|
|
134
|
-
expect(data.ides['new-ide'].failureCount).toBe(0);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('should enforce max 100 interactions per IDE', async () => {
|
|
138
|
-
// Add 120 interactions
|
|
139
|
-
for (let i = 0; i < 120; i++) {
|
|
140
|
-
const interaction = {
|
|
141
|
-
ideId: 'cursor',
|
|
142
|
-
timestamp: new Date(),
|
|
143
|
-
outcome: 'success',
|
|
144
|
-
responseTime: 120000 + i,
|
|
145
|
-
timeoutUsed: 180000,
|
|
146
|
-
continuationPromptsDetected: 0,
|
|
147
|
-
requirementId: null,
|
|
148
|
-
errorMessage: null,
|
|
149
|
-
};
|
|
150
|
-
await recorder.record(interaction);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const data = await mockStorage.read();
|
|
154
|
-
expect(data.ides.cursor.interactions.length).toBeLessThanOrEqual(100);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it('should remove oldest interaction when exceeding max', async () => {
|
|
158
|
-
// Add interactions with distinct response times
|
|
159
|
-
for (let i = 0; i < 101; i++) {
|
|
160
|
-
const interaction = {
|
|
161
|
-
ideId: 'cursor',
|
|
162
|
-
timestamp: new Date(Date.now() + i * 1000),
|
|
163
|
-
outcome: 'success',
|
|
164
|
-
responseTime: 100000 + i,
|
|
165
|
-
timeoutUsed: 180000,
|
|
166
|
-
continuationPromptsDetected: 0,
|
|
167
|
-
requirementId: `req-${i}`,
|
|
168
|
-
errorMessage: null,
|
|
169
|
-
};
|
|
170
|
-
await recorder.record(interaction);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const data = await mockStorage.read();
|
|
174
|
-
expect(data.ides.cursor.interactions).toHaveLength(100);
|
|
175
|
-
// First interaction (100000ms) should be removed
|
|
176
|
-
const firstResponseTime = data.ides.cursor.interactions[0].responseTime;
|
|
177
|
-
expect(firstResponseTime).toBe(100001); // Second interaction is now first
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('should throw ValidationError for invalid outcome', async () => {
|
|
181
|
-
const interaction = {
|
|
182
|
-
ideId: 'cursor',
|
|
183
|
-
timestamp: new Date(),
|
|
184
|
-
outcome: 'invalid-outcome',
|
|
185
|
-
responseTime: 120000,
|
|
186
|
-
timeoutUsed: 180000,
|
|
187
|
-
continuationPromptsDetected: 0,
|
|
188
|
-
requirementId: null,
|
|
189
|
-
errorMessage: null,
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
await expect(recorder.record(interaction))
|
|
193
|
-
.rejects
|
|
194
|
-
.toThrow(ValidationError);
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
it('should throw ValidationError for empty ideId', async () => {
|
|
198
|
-
const interaction = {
|
|
199
|
-
ideId: '',
|
|
200
|
-
timestamp: new Date(),
|
|
201
|
-
outcome: 'success',
|
|
202
|
-
responseTime: 120000,
|
|
203
|
-
timeoutUsed: 180000,
|
|
204
|
-
continuationPromptsDetected: 0,
|
|
205
|
-
requirementId: null,
|
|
206
|
-
errorMessage: null,
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
await expect(recorder.record(interaction))
|
|
210
|
-
.rejects
|
|
211
|
-
.toThrow(ValidationError);
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
it('should throw ValidationError for negative responseTime', async () => {
|
|
215
|
-
const interaction = {
|
|
216
|
-
ideId: 'cursor',
|
|
217
|
-
timestamp: new Date(),
|
|
218
|
-
outcome: 'success',
|
|
219
|
-
responseTime: -1000,
|
|
220
|
-
timeoutUsed: 180000,
|
|
221
|
-
continuationPromptsDetected: 0,
|
|
222
|
-
requirementId: null,
|
|
223
|
-
errorMessage: null,
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
await expect(recorder.record(interaction))
|
|
227
|
-
.rejects
|
|
228
|
-
.toThrow(ValidationError);
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
it('should allow null responseTime for failures', async () => {
|
|
232
|
-
const interaction = {
|
|
233
|
-
ideId: 'cursor',
|
|
234
|
-
timestamp: new Date(),
|
|
235
|
-
outcome: 'failure',
|
|
236
|
-
responseTime: null,
|
|
237
|
-
timeoutUsed: 180000,
|
|
238
|
-
continuationPromptsDetected: 0,
|
|
239
|
-
requirementId: null,
|
|
240
|
-
errorMessage: 'Timeout',
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
await recorder.record(interaction);
|
|
244
|
-
|
|
245
|
-
const data = await mockStorage.read();
|
|
246
|
-
expect(data.ides.cursor.interactions[0].responseTime).toBeNull();
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
it('should handle multiple IDEs independently', async () => {
|
|
250
|
-
const cursorInteraction = {
|
|
251
|
-
ideId: 'cursor',
|
|
252
|
-
timestamp: new Date(),
|
|
253
|
-
outcome: 'success',
|
|
254
|
-
responseTime: 120000,
|
|
255
|
-
timeoutUsed: 180000,
|
|
256
|
-
continuationPromptsDetected: 0,
|
|
257
|
-
requirementId: null,
|
|
258
|
-
errorMessage: null,
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
const windsurfInteraction = {
|
|
262
|
-
ideId: 'windsurf',
|
|
263
|
-
timestamp: new Date(),
|
|
264
|
-
outcome: 'failure',
|
|
265
|
-
responseTime: null,
|
|
266
|
-
timeoutUsed: 1800000,
|
|
267
|
-
continuationPromptsDetected: 0,
|
|
268
|
-
requirementId: null,
|
|
269
|
-
errorMessage: 'Error',
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
await recorder.record(cursorInteraction);
|
|
273
|
-
await recorder.record(windsurfInteraction);
|
|
274
|
-
|
|
275
|
-
const data = await mockStorage.read();
|
|
276
|
-
expect(data.ides.cursor.interactions).toHaveLength(1);
|
|
277
|
-
expect(data.ides.windsurf.interactions).toHaveLength(1);
|
|
278
|
-
expect(data.ides.cursor.interactions[0].outcome).toBe('success');
|
|
279
|
-
expect(data.ides.windsurf.interactions[0].outcome).toBe('failure');
|
|
280
|
-
});
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
describe('getInteractions()', () => {
|
|
284
|
-
it('should retrieve interactions for a specific IDE', async () => {
|
|
285
|
-
const interaction1 = {
|
|
286
|
-
ideId: 'cursor',
|
|
287
|
-
timestamp: new Date(),
|
|
288
|
-
outcome: 'success',
|
|
289
|
-
responseTime: 120000,
|
|
290
|
-
timeoutUsed: 180000,
|
|
291
|
-
continuationPromptsDetected: 0,
|
|
292
|
-
requirementId: null,
|
|
293
|
-
errorMessage: null,
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
const interaction2 = {
|
|
297
|
-
ideId: 'cursor',
|
|
298
|
-
timestamp: new Date(),
|
|
299
|
-
outcome: 'failure',
|
|
300
|
-
responseTime: null,
|
|
301
|
-
timeoutUsed: 180000,
|
|
302
|
-
continuationPromptsDetected: 0,
|
|
303
|
-
requirementId: null,
|
|
304
|
-
errorMessage: 'Error',
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
await recorder.record(interaction1);
|
|
308
|
-
await recorder.record(interaction2);
|
|
309
|
-
|
|
310
|
-
const interactions = await recorder.getInteractions('cursor');
|
|
311
|
-
expect(interactions).toHaveLength(2);
|
|
312
|
-
expect(interactions[0].outcome).toBe('success');
|
|
313
|
-
expect(interactions[1].outcome).toBe('failure');
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
it('should return empty array for IDE with no interactions', async () => {
|
|
317
|
-
const interactions = await recorder.getInteractions('nonexistent-ide');
|
|
318
|
-
expect(interactions).toEqual([]);
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
it('should support limiting number of returned interactions', async () => {
|
|
322
|
-
// Add 15 interactions
|
|
323
|
-
for (let i = 0; i < 15; i++) {
|
|
324
|
-
await recorder.record({
|
|
325
|
-
ideId: 'cursor',
|
|
326
|
-
timestamp: new Date(),
|
|
327
|
-
outcome: 'success',
|
|
328
|
-
responseTime: 120000,
|
|
329
|
-
timeoutUsed: 180000,
|
|
330
|
-
continuationPromptsDetected: 0,
|
|
331
|
-
requirementId: null,
|
|
332
|
-
errorMessage: null,
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
const recentTen = await recorder.getInteractions('cursor', 10);
|
|
337
|
-
expect(recentTen).toHaveLength(10);
|
|
338
|
-
});
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
describe('clearInteractions()', () => {
|
|
342
|
-
it('should clear all interactions for a specific IDE', async () => {
|
|
343
|
-
await recorder.record({
|
|
344
|
-
ideId: 'cursor',
|
|
345
|
-
timestamp: new Date(),
|
|
346
|
-
outcome: 'success',
|
|
347
|
-
responseTime: 120000,
|
|
348
|
-
timeoutUsed: 180000,
|
|
349
|
-
continuationPromptsDetected: 0,
|
|
350
|
-
requirementId: null,
|
|
351
|
-
errorMessage: null,
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
await recorder.clearInteractions('cursor');
|
|
355
|
-
|
|
356
|
-
const interactions = await recorder.getInteractions('cursor');
|
|
357
|
-
expect(interactions).toEqual([]);
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
it('should not affect other IDEs when clearing one', async () => {
|
|
361
|
-
await recorder.record({
|
|
362
|
-
ideId: 'cursor',
|
|
363
|
-
timestamp: new Date(),
|
|
364
|
-
outcome: 'success',
|
|
365
|
-
responseTime: 120000,
|
|
366
|
-
timeoutUsed: 180000,
|
|
367
|
-
continuationPromptsDetected: 0,
|
|
368
|
-
requirementId: null,
|
|
369
|
-
errorMessage: null,
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
await recorder.record({
|
|
373
|
-
ideId: 'windsurf',
|
|
374
|
-
timestamp: new Date(),
|
|
375
|
-
outcome: 'success',
|
|
376
|
-
responseTime: 180000,
|
|
377
|
-
timeoutUsed: 180000,
|
|
378
|
-
continuationPromptsDetected: 0,
|
|
379
|
-
requirementId: null,
|
|
380
|
-
errorMessage: null,
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
await recorder.clearInteractions('cursor');
|
|
384
|
-
|
|
385
|
-
const cursorInteractions = await recorder.getInteractions('cursor');
|
|
386
|
-
const windsurfInteractions = await recorder.getInteractions('windsurf');
|
|
387
|
-
|
|
388
|
-
expect(cursorInteractions).toEqual([]);
|
|
389
|
-
expect(windsurfInteractions).toHaveLength(1);
|
|
390
|
-
});
|
|
391
|
-
});
|
|
392
|
-
});
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Jest tests for AppleScript Manager thread closure functionality
|
|
3
|
-
* Tests the ability to close previous chat threads when starting new ones
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { AppleScriptManager } from '../applescript-manager.js';
|
|
7
|
-
import { execSync } from 'child_process';
|
|
8
|
-
|
|
9
|
-
// Mock child_process
|
|
10
|
-
jest.mock('child_process', () => ({
|
|
11
|
-
execSync: jest.fn()
|
|
12
|
-
}));Windsurf: Open Chat
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
// Mock fs
|
|
19
|
-
jest.mock('fs', () => ({
|
|
20
|
-
writeFileSync: jest.fn(),
|
|
21
|
-
unlinkSync: jest.fn()
|
|
22
|
-
}));
|
|
23
|
-
|
|
24
|
-
// Mock os
|
|
25
|
-
jest.mock('os', () => ({
|
|
26
|
-
tmpdir: () => '/tmp'
|
|
27
|
-
}));
|
|
28
|
-
|
|
29
|
-
describe('AppleScriptManager - Thread Closure', () => {
|
|
30
|
-
let appleScriptManager;
|
|
31
|
-
let mockExecSync;
|
|
32
|
-
|
|
33
|
-
beforeEach(() => {
|
|
34
|
-
appleScriptManager = new AppleScriptManager();
|
|
35
|
-
mockExecSync = execSync;
|
|
36
|
-
mockExecSync.mockClear();
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
afterEach(() => {
|
|
40
|
-
jest.clearAllMocks();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
describe('closePreviousChatThread', () => {
|
|
44
|
-
it('should close previous chat thread in Cursor', async () => {
|
|
45
|
-
// Mock successful execution
|
|
46
|
-
mockExecSync.mockReturnValue('Previous chat thread closed');
|
|
47
|
-
|
|
48
|
-
const result = await appleScriptManager.closePreviousChatThread('cursor');
|
|
49
|
-
|
|
50
|
-
expect(result.success).toBe(true);
|
|
51
|
-
expect(result.message).toContain('Previous chat thread closed');
|
|
52
|
-
expect(result.method).toBe('applescript');
|
|
53
|
-
expect(mockExecSync).toHaveBeenCalled();
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('should close previous chat thread in VS Code', async () => {
|
|
57
|
-
// Mock successful execution
|
|
58
|
-
mockExecSync.mockReturnValue('Previous chat thread closed');
|
|
59
|
-
|
|
60
|
-
const result = await appleScriptManager.closePreviousChatThread('vscode');
|
|
61
|
-
|
|
62
|
-
expect(result.success).toBe(true);
|
|
63
|
-
expect(result.message).toContain('Previous chat thread closed');
|
|
64
|
-
expect(result.method).toBe('applescript');
|
|
65
|
-
expect(mockExecSync).toHaveBeenCalled();
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('should close previous chat thread in Windsurf', async () => {
|
|
69
|
-
// Mock successful execution
|
|
70
|
-
mockExecSync.mockReturnValue('Previous chat thread closed');
|
|
71
|
-
|
|
72
|
-
const result = await appleScriptManager.closePreviousChatThread('windsurf');
|
|
73
|
-
|
|
74
|
-
expect(result.success).toBe(true);
|
|
75
|
-
expect(result.message).toContain('Previous chat thread closed');
|
|
76
|
-
expect(result.method).toBe('applescript');
|
|
77
|
-
expect(mockExecSync).toHaveBeenCalled();
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('should handle errors gracefully when closing threads', async () => {
|
|
81
|
-
// Mock execution error
|
|
82
|
-
mockExecSync.mockImplementation(() => {
|
|
83
|
-
throw new Error('Failed to close thread');
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
const result = await appleScriptManager.closePreviousChatThread('cursor');
|
|
87
|
-
|
|
88
|
-
expect(result.success).toBe(false);
|
|
89
|
-
expect(result.error).toContain('Failed to close thread');
|
|
90
|
-
expect(result.method).toBe('applescript');
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('should return error for unsupported IDE', async () => {
|
|
94
|
-
const result = await appleScriptManager.closePreviousChatThread('unsupported');
|
|
95
|
-
|
|
96
|
-
expect(result.success).toBe(false);
|
|
97
|
-
expect(result.error).toContain('Unsupported IDE');
|
|
98
|
-
expect(mockExecSync).not.toHaveBeenCalled();
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
describe('sendTextWithThreadClosure', () => {
|
|
103
|
-
it('should close previous thread before sending new message to Cursor', async () => {
|
|
104
|
-
// Mock successful executions
|
|
105
|
-
mockExecSync
|
|
106
|
-
.mockReturnValueOnce('Previous chat thread closed')
|
|
107
|
-
.mockReturnValueOnce('Message sent to Cursor: Test message')
|
|
108
|
-
.mockReturnValueOnce('Message sent to Cursor: Test message');
|
|
109
|
-
|
|
110
|
-
const result = await appleScriptManager.sendTextWithThreadClosure('Test message', 'cursor');
|
|
111
|
-
|
|
112
|
-
expect(result.success).toBe(true);
|
|
113
|
-
expect(result.message).toContain('Test message');
|
|
114
|
-
expect(mockExecSync).toHaveBeenCalledTimes(3); // Once for close, twice for send (sendText calls execSync twice)
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('should close previous thread before sending new message to VS Code', async () => {
|
|
118
|
-
// Mock successful executions
|
|
119
|
-
mockExecSync
|
|
120
|
-
.mockReturnValueOnce('Previous chat thread closed')
|
|
121
|
-
.mockImplementationOnce(() => {
|
|
122
|
-
// Simulate successful AppleScript execution for text sending
|
|
123
|
-
return 'Message sent via AppleScript to VS Code GitHub Copilot Chat';
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
const result = await appleScriptManager.sendTextWithThreadClosure('Test message', 'vscode');
|
|
127
|
-
|
|
128
|
-
expect(result.success).toBe(true); // VS Code is now supported by AppleScript manager
|
|
129
|
-
expect(result.method).toBe('applescript');
|
|
130
|
-
expect(result.threadClosure).toContain('Previous thread closed');
|
|
131
|
-
expect(mockExecSync).toHaveBeenCalledTimes(2); // Once for thread closure, once for sending
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it('should close previous thread before sending new message to Windsurf', async () => {
|
|
135
|
-
// Mock successful executions
|
|
136
|
-
mockExecSync
|
|
137
|
-
.mockReturnValueOnce('Previous chat thread closed')
|
|
138
|
-
.mockImplementationOnce(() => {
|
|
139
|
-
throw new Error('AppleScript failed');
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
const result = await appleScriptManager.sendTextWithThreadClosure('Test message', 'windsurf');
|
|
143
|
-
|
|
144
|
-
expect(result.success).toBe(true);
|
|
145
|
-
expect(result.message).toContain('Test message');
|
|
146
|
-
expect(mockExecSync).toHaveBeenCalled(); // Should be called at least once for thread closure
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('should handle thread closure failure gracefully', async () => {
|
|
150
|
-
// Mock thread closure failure but successful message send
|
|
151
|
-
mockExecSync
|
|
152
|
-
.mockImplementationOnce(() => {
|
|
153
|
-
throw new Error('Failed to close thread');
|
|
154
|
-
})
|
|
155
|
-
.mockImplementationOnce(() => {
|
|
156
|
-
throw new Error('AppleScript failed');
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
const result = await appleScriptManager.sendTextWithThreadClosure('Test message', 'cursor');
|
|
160
|
-
|
|
161
|
-
expect(result.success).toBe(true);
|
|
162
|
-
expect(result.message).toContain('Test message');
|
|
163
|
-
expect(result.warning).toContain('Failed to close previous thread');
|
|
164
|
-
expect(mockExecSync).toHaveBeenCalled(); // Should be called at least once
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
it('should handle both thread closure and message send failures', async () => {
|
|
168
|
-
// Mock both failures
|
|
169
|
-
mockExecSync
|
|
170
|
-
.mockImplementationOnce(() => {
|
|
171
|
-
throw new Error('Failed to close thread');
|
|
172
|
-
})
|
|
173
|
-
.mockImplementationOnce(() => {
|
|
174
|
-
throw new Error('AppleScript failed');
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
const result = await appleScriptManager.sendTextWithThreadClosure('Test message', 'cursor');
|
|
178
|
-
|
|
179
|
-
expect(result.success).toBe(true); // Should still succeed due to simulated fallback
|
|
180
|
-
expect(result.message).toContain('Test message');
|
|
181
|
-
expect(mockExecSync).toHaveBeenCalled(); // Should be called at least once
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it('should validate input parameters', async () => {
|
|
185
|
-
const result = await appleScriptManager.sendTextWithThreadClosure('', 'cursor');
|
|
186
|
-
|
|
187
|
-
expect(result.success).toBe(false);
|
|
188
|
-
expect(result.error).toContain('Invalid text');
|
|
189
|
-
expect(mockExecSync).not.toHaveBeenCalled();
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
describe('AppleScript Content Validation', () => {
|
|
194
|
-
it('should generate correct AppleScript for Cursor thread closure', async () => {
|
|
195
|
-
mockExecSync.mockReturnValue('Success');
|
|
196
|
-
|
|
197
|
-
await appleScriptManager.closePreviousChatThread('cursor');
|
|
198
|
-
|
|
199
|
-
const callArgs = mockExecSync.mock.calls[0][0];
|
|
200
|
-
expect(callArgs).toContain('osascript');
|
|
201
|
-
// The script content is written to a temp file, so we check the osascript call
|
|
202
|
-
expect(mockExecSync).toHaveBeenCalledWith(expect.stringContaining('osascript'), expect.any(Object));
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
it('should generate correct AppleScript for VS Code thread closure', async () => {
|
|
206
|
-
mockExecSync.mockReturnValue('Success');
|
|
207
|
-
|
|
208
|
-
await appleScriptManager.closePreviousChatThread('vscode');
|
|
209
|
-
|
|
210
|
-
const callArgs = mockExecSync.mock.calls[0][0];
|
|
211
|
-
expect(callArgs).toContain('osascript');
|
|
212
|
-
// The script content is written to a temp file, so we check the osascript call
|
|
213
|
-
expect(mockExecSync).toHaveBeenCalledWith(expect.stringContaining('osascript'), expect.any(Object));
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it('should generate correct AppleScript for Windsurf thread closure', async () => {
|
|
217
|
-
mockExecSync.mockReturnValue('Success');
|
|
218
|
-
|
|
219
|
-
await appleScriptManager.closePreviousChatThread('windsurf');
|
|
220
|
-
|
|
221
|
-
const callArgs = mockExecSync.mock.calls[0][0];
|
|
222
|
-
expect(callArgs).toContain('osascript');
|
|
223
|
-
// The script content is written to a temp file, so we check the osascript call
|
|
224
|
-
expect(mockExecSync).toHaveBeenCalledWith(expect.stringContaining('osascript'), expect.any(Object));
|
|
225
|
-
});
|
|
226
|
-
});
|
|
227
|
-
});
|
|
File without changes
|
package/test-quota-system.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
const { fetchQuotaForAgent } = require('./src/quota-management/index.js');
|
|
2
|
-
const sharedAuth = require('./src/auth/shared-auth-storage');
|
|
3
|
-
const ProviderManager = require('./src/ide-integration/provider-manager.cjs');
|
|
4
|
-
|
|
5
|
-
async function testQuotaSystem() {
|
|
6
|
-
console.log('๐งช Starting Quota System Verification Test...');
|
|
7
|
-
|
|
8
|
-
// 1. Test Global Iterations Quota
|
|
9
|
-
console.log('\n--- Test 1: Global Iterations ---');
|
|
10
|
-
// Mock sharedAuth.canRunAutoMode
|
|
11
|
-
const originalCanRun = sharedAuth.canRunAutoMode;
|
|
12
|
-
sharedAuth.canRunAutoMode = async () => ({
|
|
13
|
-
canRun: true,
|
|
14
|
-
todayUsage: 4,
|
|
15
|
-
maxIterations: 10
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
const globalQuota = await fetchQuotaForAgent('global:iterations');
|
|
20
|
-
console.log('Global Quota Type:', globalQuota.type);
|
|
21
|
-
console.log('Global Remaining:', globalQuota.remaining);
|
|
22
|
-
console.log('Global Limit:', globalQuota.limit);
|
|
23
|
-
if (globalQuota.remaining === 6 && globalQuota.type === 'global') {
|
|
24
|
-
console.log('โ
Global iterations test passed');
|
|
25
|
-
} else {
|
|
26
|
-
console.log('โ Global iterations test failed');
|
|
27
|
-
}
|
|
28
|
-
} catch (error) {
|
|
29
|
-
console.error('โ Global iterations test error:', error);
|
|
30
|
-
} finally {
|
|
31
|
-
sharedAuth.canRunAutoMode = originalCanRun;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// 2. Test Local Agent (Infinite)
|
|
35
|
-
console.log('\n--- Test 2: Local Agent (Infinite) ---');
|
|
36
|
-
try {
|
|
37
|
-
const localQuota = await fetchQuotaForAgent('local-ollama:qwen2.5');
|
|
38
|
-
console.log('Local Quota Type:', localQuota.type);
|
|
39
|
-
console.log('Local Remaining:', localQuota.remaining);
|
|
40
|
-
if (localQuota.remaining === Infinity && localQuota.type === 'infinite') {
|
|
41
|
-
console.log('โ
Local agent test passed');
|
|
42
|
-
} else {
|
|
43
|
-
console.log('โ Local agent test failed');
|
|
44
|
-
}
|
|
45
|
-
} catch (error) {
|
|
46
|
-
console.error('โ Local agent test error:', error);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// 3. Test Provider Rate Limit
|
|
50
|
-
console.log('\n--- Test 3: Provider Rate Limit ---');
|
|
51
|
-
try {
|
|
52
|
-
const providerQuota = await fetchQuotaForAgent('anthropic:claude-3');
|
|
53
|
-
console.log('Provider Quota Type:', providerQuota.type);
|
|
54
|
-
console.log('Provider Available (Remaining > 0):', providerQuota.remaining > 0);
|
|
55
|
-
if (providerQuota.type === 'rate-limit') {
|
|
56
|
-
console.log('โ
Provider rate limit test passed');
|
|
57
|
-
} else {
|
|
58
|
-
console.log('โ Provider rate limit test failed');
|
|
59
|
-
}
|
|
60
|
-
} catch (error) {
|
|
61
|
-
console.error('โ Provider rate limit test error:', error);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
console.log('\n๐ Quota System Verification Finished.');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
testQuotaSystem().catch(console.error);
|