claude-mycelium 2.0.0

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 (207) hide show
  1. package/.claude/settings.local.json +14 -0
  2. package/README.md +304 -0
  3. package/dist/coordination/gradient-cache.d.ts +48 -0
  4. package/dist/coordination/gradient-cache.d.ts.map +1 -0
  5. package/dist/coordination/gradient-cache.js +145 -0
  6. package/dist/coordination/gradient-cache.js.map +1 -0
  7. package/dist/coordination/index.d.ts +10 -0
  8. package/dist/coordination/index.d.ts.map +1 -0
  9. package/dist/coordination/index.js +10 -0
  10. package/dist/coordination/index.js.map +1 -0
  11. package/dist/core/agent-executor.d.ts +31 -0
  12. package/dist/core/agent-executor.d.ts.map +1 -0
  13. package/dist/core/agent-executor.js +257 -0
  14. package/dist/core/agent-executor.js.map +1 -0
  15. package/dist/core/change-applier.d.ts +10 -0
  16. package/dist/core/change-applier.d.ts.map +1 -0
  17. package/dist/core/change-applier.js +32 -0
  18. package/dist/core/change-applier.js.map +1 -0
  19. package/dist/core/gradient.d.ts +60 -0
  20. package/dist/core/gradient.d.ts.map +1 -0
  21. package/dist/core/gradient.js +191 -0
  22. package/dist/core/gradient.js.map +1 -0
  23. package/dist/core/index.d.ts +24 -0
  24. package/dist/core/index.d.ts.map +1 -0
  25. package/dist/core/index.js +24 -0
  26. package/dist/core/index.js.map +1 -0
  27. package/dist/core/mode-selector.d.ts +44 -0
  28. package/dist/core/mode-selector.d.ts.map +1 -0
  29. package/dist/core/mode-selector.js +208 -0
  30. package/dist/core/mode-selector.js.map +1 -0
  31. package/dist/core/signals/centrality.d.ts +44 -0
  32. package/dist/core/signals/centrality.d.ts.map +1 -0
  33. package/dist/core/signals/centrality.js +264 -0
  34. package/dist/core/signals/centrality.js.map +1 -0
  35. package/dist/core/signals/churn.d.ts +41 -0
  36. package/dist/core/signals/churn.d.ts.map +1 -0
  37. package/dist/core/signals/churn.js +188 -0
  38. package/dist/core/signals/churn.js.map +1 -0
  39. package/dist/core/signals/complexity.d.ts +29 -0
  40. package/dist/core/signals/complexity.d.ts.map +1 -0
  41. package/dist/core/signals/complexity.js +169 -0
  42. package/dist/core/signals/complexity.js.map +1 -0
  43. package/dist/core/signals/debt.d.ts +27 -0
  44. package/dist/core/signals/debt.d.ts.map +1 -0
  45. package/dist/core/signals/debt.js +80 -0
  46. package/dist/core/signals/debt.js.map +1 -0
  47. package/dist/core/signals/errors.d.ts +32 -0
  48. package/dist/core/signals/errors.d.ts.map +1 -0
  49. package/dist/core/signals/errors.js +73 -0
  50. package/dist/core/signals/errors.js.map +1 -0
  51. package/dist/core/signals/index.d.ts +19 -0
  52. package/dist/core/signals/index.d.ts.map +1 -0
  53. package/dist/core/signals/index.js +19 -0
  54. package/dist/core/signals/index.js.map +1 -0
  55. package/dist/cost/cost-tracker.d.ts +90 -0
  56. package/dist/cost/cost-tracker.d.ts.map +1 -0
  57. package/dist/cost/cost-tracker.js +305 -0
  58. package/dist/cost/cost-tracker.js.map +1 -0
  59. package/dist/cost/index.d.ts +56 -0
  60. package/dist/cost/index.d.ts.map +1 -0
  61. package/dist/cost/index.js +111 -0
  62. package/dist/cost/index.js.map +1 -0
  63. package/dist/index.d.ts +35 -0
  64. package/dist/index.d.ts.map +1 -0
  65. package/dist/index.js +40 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/llm/anthropic-client.d.ts +52 -0
  68. package/dist/llm/anthropic-client.d.ts.map +1 -0
  69. package/dist/llm/anthropic-client.js +310 -0
  70. package/dist/llm/anthropic-client.js.map +1 -0
  71. package/dist/llm/index.d.ts +27 -0
  72. package/dist/llm/index.d.ts.map +1 -0
  73. package/dist/llm/index.js +34 -0
  74. package/dist/llm/index.js.map +1 -0
  75. package/dist/prompts/complexity-reducer.d.ts +7 -0
  76. package/dist/prompts/complexity-reducer.d.ts.map +1 -0
  77. package/dist/prompts/complexity-reducer.js +55 -0
  78. package/dist/prompts/complexity-reducer.js.map +1 -0
  79. package/dist/prompts/debt-payer.d.ts +7 -0
  80. package/dist/prompts/debt-payer.d.ts.map +1 -0
  81. package/dist/prompts/debt-payer.js +55 -0
  82. package/dist/prompts/debt-payer.js.map +1 -0
  83. package/dist/prompts/error-reducer.d.ts +7 -0
  84. package/dist/prompts/error-reducer.d.ts.map +1 -0
  85. package/dist/prompts/error-reducer.js +54 -0
  86. package/dist/prompts/error-reducer.js.map +1 -0
  87. package/dist/prompts/index.d.ts +22 -0
  88. package/dist/prompts/index.d.ts.map +1 -0
  89. package/dist/prompts/index.js +112 -0
  90. package/dist/prompts/index.js.map +1 -0
  91. package/dist/prompts/stabilizer.d.ts +7 -0
  92. package/dist/prompts/stabilizer.d.ts.map +1 -0
  93. package/dist/prompts/stabilizer.js +55 -0
  94. package/dist/prompts/stabilizer.js.map +1 -0
  95. package/dist/prompts/types.d.ts +14 -0
  96. package/dist/prompts/types.d.ts.map +1 -0
  97. package/dist/prompts/types.js +5 -0
  98. package/dist/prompts/types.js.map +1 -0
  99. package/dist/trace/index.d.ts +51 -0
  100. package/dist/trace/index.d.ts.map +1 -0
  101. package/dist/trace/index.js +60 -0
  102. package/dist/trace/index.js.map +1 -0
  103. package/dist/trace/trace-event.d.ts +72 -0
  104. package/dist/trace/trace-event.d.ts.map +1 -0
  105. package/dist/trace/trace-event.js +244 -0
  106. package/dist/trace/trace-event.js.map +1 -0
  107. package/dist/types/index.d.ts +206 -0
  108. package/dist/types/index.d.ts.map +1 -0
  109. package/dist/types/index.js +6 -0
  110. package/dist/types/index.js.map +1 -0
  111. package/dist/utils/ci-provider.d.ts +43 -0
  112. package/dist/utils/ci-provider.d.ts.map +1 -0
  113. package/dist/utils/ci-provider.js +130 -0
  114. package/dist/utils/ci-provider.js.map +1 -0
  115. package/dist/utils/config.d.ts +31 -0
  116. package/dist/utils/config.d.ts.map +1 -0
  117. package/dist/utils/config.js +85 -0
  118. package/dist/utils/config.js.map +1 -0
  119. package/dist/utils/error-provider.d.ts +51 -0
  120. package/dist/utils/error-provider.d.ts.map +1 -0
  121. package/dist/utils/error-provider.js +123 -0
  122. package/dist/utils/error-provider.js.map +1 -0
  123. package/dist/utils/file-utils.d.ts +18 -0
  124. package/dist/utils/file-utils.d.ts.map +1 -0
  125. package/dist/utils/file-utils.js +95 -0
  126. package/dist/utils/file-utils.js.map +1 -0
  127. package/dist/utils/index.d.ts +10 -0
  128. package/dist/utils/index.d.ts.map +1 -0
  129. package/dist/utils/index.js +10 -0
  130. package/dist/utils/index.js.map +1 -0
  131. package/dist/utils/logger.d.ts +36 -0
  132. package/dist/utils/logger.d.ts.map +1 -0
  133. package/dist/utils/logger.js +74 -0
  134. package/dist/utils/logger.js.map +1 -0
  135. package/docs/IMPLEMENTATION-STATUS.md +199 -0
  136. package/docs/PHASE-0-COMPLETE.md +252 -0
  137. package/docs/PHASE-1-COMPLETE.md +204 -0
  138. package/docs/PHASE-2-COMPLETE.md +233 -0
  139. package/docs/PHASE2_COMPLETION_CHECKLIST.md +290 -0
  140. package/docs/PHASE2_INTEGRATION_SUMMARY.md +255 -0
  141. package/docs/PHASE2_QUICK_REFERENCE.md +365 -0
  142. package/docs/PHASE2_TEST_RESULTS.md +282 -0
  143. package/docs/ROADMAP.md +746 -0
  144. package/docs/SNAPSHOT.md +376 -0
  145. package/docs/adrs/ADR-001-signal-computation.md +76 -0
  146. package/docs/adrs/ADR-002-inhibitor-signals.md +108 -0
  147. package/docs/adrs/ADR-003-llm-integration.md +156 -0
  148. package/docs/adrs/ADR-004-process-architecture.md +175 -0
  149. package/docs/adrs/ADR-005-testing-strategy.md +243 -0
  150. package/docs/pitch.md +94 -0
  151. package/docs/specs/fourth-spec.md +1973 -0
  152. package/docs/specs/initial-spec.md +2096 -0
  153. package/docs/specs/second-spec.md +2690 -0
  154. package/package.json +50 -0
  155. package/src/coordination/gradient-cache.ts +185 -0
  156. package/src/coordination/index.ts +10 -0
  157. package/src/core/agent-executor.ts +327 -0
  158. package/src/core/change-applier.ts +338 -0
  159. package/src/core/gradient.ts +258 -0
  160. package/src/core/index.ts +24 -0
  161. package/src/core/mode-selector.ts +243 -0
  162. package/src/core/signals/centrality.ts +328 -0
  163. package/src/core/signals/churn.ts +239 -0
  164. package/src/core/signals/complexity.ts +206 -0
  165. package/src/core/signals/debt.ts +111 -0
  166. package/src/core/signals/errors.ts +93 -0
  167. package/src/core/signals/index.ts +19 -0
  168. package/src/cost/cost-tracker.ts +410 -0
  169. package/src/cost/index.ts +143 -0
  170. package/src/index.ts +43 -0
  171. package/src/llm/anthropic-client.ts +415 -0
  172. package/src/llm/index.ts +43 -0
  173. package/src/prompts/complexity-reducer.ts +59 -0
  174. package/src/prompts/debt-payer.ts +59 -0
  175. package/src/prompts/error-reducer.ts +58 -0
  176. package/src/prompts/index.ts +128 -0
  177. package/src/prompts/stabilizer.ts +59 -0
  178. package/src/prompts/types.ts +15 -0
  179. package/src/trace/README.md +178 -0
  180. package/src/trace/index.ts +88 -0
  181. package/src/trace/trace-event.ts +324 -0
  182. package/src/types/index.ts +271 -0
  183. package/src/utils/ci-provider.ts +145 -0
  184. package/src/utils/config.ts +95 -0
  185. package/src/utils/error-provider.ts +138 -0
  186. package/src/utils/file-utils.ts +111 -0
  187. package/src/utils/index.ts +10 -0
  188. package/src/utils/logger.ts +94 -0
  189. package/test-8d713cc8-f4b7-403d-8153-57573172b94c.ts +3 -0
  190. package/tests/coordination/gradient-cache.test.ts +270 -0
  191. package/tests/core/agent-executor.test.ts +217 -0
  192. package/tests/core/change-applier.test.ts +336 -0
  193. package/tests/core/gradient.test.ts +263 -0
  194. package/tests/core/mode-selector.test.ts +239 -0
  195. package/tests/core/signals/centrality.test.ts +512 -0
  196. package/tests/core/signals/churn.test.ts +355 -0
  197. package/tests/core/signals/complexity.test.ts +284 -0
  198. package/tests/core/signals/debt.test.ts +437 -0
  199. package/tests/core/signals/errors.test.ts +350 -0
  200. package/tests/cost/cost-tracker.test.ts +475 -0
  201. package/tests/integration/phase2.test.ts +405 -0
  202. package/tests/llm/anthropic-client.test.ts +437 -0
  203. package/tests/prompts/prompts.test.ts +266 -0
  204. package/tests/trace/trace-event.test.ts +666 -0
  205. package/tests/utils/file-utils.test.ts +148 -0
  206. package/tsconfig.json +24 -0
  207. package/vitest.config.ts +28 -0
@@ -0,0 +1,350 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ import { calculateErrorRate, calculateErrorRateBatch } from '../../../src/core/signals/errors';
5
+
6
+ const TEST_DIR = '.test-temp-errors';
7
+ const ERROR_FILE = path.join(TEST_DIR, '.agent-meta', '_errors.json');
8
+
9
+ describe('error signal', () => {
10
+ beforeEach(() => {
11
+ // Create test directories
12
+ if (!fs.existsSync(TEST_DIR)) {
13
+ fs.mkdirSync(TEST_DIR, { recursive: true });
14
+ }
15
+ const metaDir = path.join(TEST_DIR, '.agent-meta');
16
+ if (!fs.existsSync(metaDir)) {
17
+ fs.mkdirSync(metaDir, { recursive: true });
18
+ }
19
+ });
20
+
21
+ afterEach(() => {
22
+ if (fs.existsSync(TEST_DIR)) {
23
+ fs.rmSync(TEST_DIR, { recursive: true, force: true });
24
+ }
25
+ });
26
+
27
+ describe('calculateErrorRate', () => {
28
+ it('calculates error rate for file with errors', async () => {
29
+ // Create test file
30
+ const testFile = path.join(TEST_DIR, 'buggy.ts');
31
+ const content = `
32
+ function broken(): void {
33
+ // This file has errors
34
+ console.log('test');
35
+ }
36
+ `.trim();
37
+ fs.writeFileSync(testFile, content);
38
+
39
+ // Create error data
40
+ const errorData = {
41
+ updated_at: new Date().toISOString(),
42
+ errors: [
43
+ {
44
+ file: testFile,
45
+ count: 5,
46
+ types: ['TypeError', 'ReferenceError'],
47
+ },
48
+ ],
49
+ };
50
+ fs.writeFileSync(ERROR_FILE, JSON.stringify(errorData, null, 2));
51
+
52
+ const result = await calculateErrorRate(testFile, ERROR_FILE);
53
+
54
+ expect(result.count).toBe(5);
55
+ expect(result.types).toEqual(['TypeError', 'ReferenceError']);
56
+ expect(result.normalized).toBeGreaterThan(0);
57
+ expect(result.normalized).toBeLessThanOrEqual(1.0);
58
+ });
59
+
60
+ it('returns zero for file not in error data', async () => {
61
+ const testFile = path.join(TEST_DIR, 'clean.ts');
62
+ const content = `function good(): void { console.log('test'); }`;
63
+ fs.writeFileSync(testFile, content);
64
+
65
+ // Create error data for different file
66
+ const errorData = {
67
+ updated_at: new Date().toISOString(),
68
+ errors: [
69
+ {
70
+ file: path.join(TEST_DIR, 'other.ts'),
71
+ count: 3,
72
+ types: ['TypeError'],
73
+ },
74
+ ],
75
+ };
76
+ fs.writeFileSync(ERROR_FILE, JSON.stringify(errorData, null, 2));
77
+
78
+ const result = await calculateErrorRate(testFile, ERROR_FILE);
79
+
80
+ expect(result.count).toBe(0);
81
+ expect(result.types).toEqual([]);
82
+ expect(result.normalized).toBe(0);
83
+ });
84
+
85
+ it('returns zero when error file does not exist', async () => {
86
+ const testFile = path.join(TEST_DIR, 'noerrors.ts');
87
+ const content = `function test(): void { console.log('test'); }`;
88
+ fs.writeFileSync(testFile, content);
89
+
90
+ // Don't create error file
91
+
92
+ const result = await calculateErrorRate(testFile, ERROR_FILE);
93
+
94
+ expect(result.count).toBe(0);
95
+ expect(result.types).toEqual([]);
96
+ expect(result.normalized).toBe(0);
97
+ });
98
+
99
+ it('normalizes error rate correctly - low errors', async () => {
100
+ const testFile = path.join(TEST_DIR, 'low-errors.ts');
101
+ // Create file with 100 LOC
102
+ const lines = Array(100)
103
+ .fill('console.log("line");')
104
+ .join('\n');
105
+ fs.writeFileSync(testFile, lines);
106
+
107
+ // 2 errors in 100 LOC = 0.02 errors/LOC
108
+ // (0.02) / 0.1 = 0.2
109
+ const errorData = {
110
+ updated_at: new Date().toISOString(),
111
+ errors: [
112
+ {
113
+ file: testFile,
114
+ count: 2,
115
+ types: ['TypeError'],
116
+ },
117
+ ],
118
+ };
119
+ fs.writeFileSync(ERROR_FILE, JSON.stringify(errorData, null, 2));
120
+
121
+ const result = await calculateErrorRate(testFile, ERROR_FILE);
122
+
123
+ expect(result.count).toBe(2);
124
+ expect(result.normalized).toBeCloseTo(0.2, 1);
125
+ });
126
+
127
+ it('normalizes error rate correctly - high errors', async () => {
128
+ const testFile = path.join(TEST_DIR, 'high-errors.ts');
129
+ // Create file with 50 LOC
130
+ const lines = Array(50)
131
+ .fill('console.log("line");')
132
+ .join('\n');
133
+ fs.writeFileSync(testFile, lines);
134
+
135
+ // 10 errors in 50 LOC = 0.2 errors/LOC
136
+ // (0.2) / 0.1 = 2.0, capped at 1.0
137
+ const errorData = {
138
+ updated_at: new Date().toISOString(),
139
+ errors: [
140
+ {
141
+ file: testFile,
142
+ count: 10,
143
+ types: ['TypeError', 'ReferenceError', 'SyntaxError'],
144
+ },
145
+ ],
146
+ };
147
+ fs.writeFileSync(ERROR_FILE, JSON.stringify(errorData, null, 2));
148
+
149
+ const result = await calculateErrorRate(testFile, ERROR_FILE);
150
+
151
+ expect(result.count).toBe(10);
152
+ expect(result.normalized).toBe(1.0); // Capped at 1.0
153
+ });
154
+
155
+ it('normalizes error rate correctly - exact threshold', async () => {
156
+ const testFile = path.join(TEST_DIR, 'threshold.ts');
157
+ // Create file with 100 LOC
158
+ const lines = Array(100)
159
+ .fill('console.log("line");')
160
+ .join('\n');
161
+ fs.writeFileSync(testFile, lines);
162
+
163
+ // 10 errors in 100 LOC = 0.1 errors/LOC (exactly at threshold)
164
+ // (0.1) / 0.1 = 1.0
165
+ const errorData = {
166
+ updated_at: new Date().toISOString(),
167
+ errors: [
168
+ {
169
+ file: testFile,
170
+ count: 10,
171
+ types: ['TypeError'],
172
+ },
173
+ ],
174
+ };
175
+ fs.writeFileSync(ERROR_FILE, JSON.stringify(errorData, null, 2));
176
+
177
+ const result = await calculateErrorRate(testFile, ERROR_FILE);
178
+
179
+ expect(result.count).toBe(10);
180
+ expect(result.normalized).toBe(1.0);
181
+ });
182
+
183
+ it('handles file with single error', async () => {
184
+ const testFile = path.join(TEST_DIR, 'single-error.ts');
185
+ const content = `
186
+ function test(): void {
187
+ console.log('test');
188
+ }
189
+ `.trim();
190
+ fs.writeFileSync(testFile, content);
191
+
192
+ const errorData = {
193
+ updated_at: new Date().toISOString(),
194
+ errors: [
195
+ {
196
+ file: testFile,
197
+ count: 1,
198
+ types: ['TypeError'],
199
+ },
200
+ ],
201
+ };
202
+ fs.writeFileSync(ERROR_FILE, JSON.stringify(errorData, null, 2));
203
+
204
+ const result = await calculateErrorRate(testFile, ERROR_FILE);
205
+
206
+ expect(result.count).toBe(1);
207
+ expect(result.types).toEqual(['TypeError']);
208
+ expect(result.normalized).toBeGreaterThan(0);
209
+ });
210
+
211
+ it('handles file with multiple error types', async () => {
212
+ const testFile = path.join(TEST_DIR, 'multi-types.ts');
213
+ const content = `function test(): void { console.log('test'); }`;
214
+ fs.writeFileSync(testFile, content);
215
+
216
+ const errorData = {
217
+ updated_at: new Date().toISOString(),
218
+ errors: [
219
+ {
220
+ file: testFile,
221
+ count: 8,
222
+ types: ['TypeError', 'ReferenceError', 'SyntaxError', 'RangeError'],
223
+ },
224
+ ],
225
+ };
226
+ fs.writeFileSync(ERROR_FILE, JSON.stringify(errorData, null, 2));
227
+
228
+ const result = await calculateErrorRate(testFile, ERROR_FILE);
229
+
230
+ expect(result.count).toBe(8);
231
+ expect(result.types).toHaveLength(4);
232
+ expect(result.types).toContain('TypeError');
233
+ expect(result.types).toContain('ReferenceError');
234
+ expect(result.types).toContain('SyntaxError');
235
+ expect(result.types).toContain('RangeError');
236
+ });
237
+
238
+ it('handles malformed error JSON gracefully', async () => {
239
+ const testFile = path.join(TEST_DIR, 'test.ts');
240
+ const content = `function test(): void { console.log('test'); }`;
241
+ fs.writeFileSync(testFile, content);
242
+
243
+ // Write invalid JSON
244
+ fs.writeFileSync(ERROR_FILE, '{invalid json}');
245
+
246
+ const result = await calculateErrorRate(testFile, ERROR_FILE);
247
+
248
+ // Should fallback to zero
249
+ expect(result.count).toBe(0);
250
+ expect(result.types).toEqual([]);
251
+ expect(result.normalized).toBe(0);
252
+ });
253
+
254
+ it('handles empty error array', async () => {
255
+ const testFile = path.join(TEST_DIR, 'empty.ts');
256
+ const content = `function test(): void { console.log('test'); }`;
257
+ fs.writeFileSync(testFile, content);
258
+
259
+ const errorData = {
260
+ updated_at: new Date().toISOString(),
261
+ errors: [],
262
+ };
263
+ fs.writeFileSync(ERROR_FILE, JSON.stringify(errorData, null, 2));
264
+
265
+ const result = await calculateErrorRate(testFile, ERROR_FILE);
266
+
267
+ expect(result.count).toBe(0);
268
+ expect(result.types).toEqual([]);
269
+ expect(result.normalized).toBe(0);
270
+ });
271
+
272
+ it('normalizes with very small LOC file', async () => {
273
+ const testFile = path.join(TEST_DIR, 'tiny.ts');
274
+ const content = `const x = 1;`; // 1 line
275
+ fs.writeFileSync(testFile, content);
276
+
277
+ const errorData = {
278
+ updated_at: new Date().toISOString(),
279
+ errors: [
280
+ {
281
+ file: testFile,
282
+ count: 1,
283
+ types: ['TypeError'],
284
+ },
285
+ ],
286
+ };
287
+ fs.writeFileSync(ERROR_FILE, JSON.stringify(errorData, null, 2));
288
+
289
+ const result = await calculateErrorRate(testFile, ERROR_FILE);
290
+
291
+ expect(result.count).toBe(1);
292
+ // 1 error in 1 LOC = 1.0 errors/LOC
293
+ // (1.0) / 0.1 = 10.0, capped at 1.0
294
+ expect(result.normalized).toBe(1.0);
295
+ });
296
+ });
297
+
298
+ describe('calculateErrorRateBatch', () => {
299
+ it('calculates error rates for multiple files', async () => {
300
+ // Create test files
301
+ const file1 = path.join(TEST_DIR, 'file1.ts');
302
+ const file2 = path.join(TEST_DIR, 'file2.ts');
303
+ const file3 = path.join(TEST_DIR, 'file3.ts');
304
+
305
+ fs.writeFileSync(file1, Array(50).fill('console.log("line");').join('\n'));
306
+ fs.writeFileSync(file2, Array(100).fill('console.log("line");').join('\n'));
307
+ fs.writeFileSync(file3, Array(25).fill('console.log("line");').join('\n'));
308
+
309
+ // Create error data
310
+ const errorData = {
311
+ updated_at: new Date().toISOString(),
312
+ errors: [
313
+ {
314
+ file: file1,
315
+ count: 5,
316
+ types: ['TypeError'],
317
+ },
318
+ {
319
+ file: file2,
320
+ count: 3,
321
+ types: ['ReferenceError'],
322
+ },
323
+ // file3 has no errors
324
+ ],
325
+ };
326
+ fs.writeFileSync(ERROR_FILE, JSON.stringify(errorData, null, 2));
327
+
328
+ const results = await calculateErrorRateBatch([file1, file2, file3], ERROR_FILE);
329
+
330
+ expect(results.size).toBe(3);
331
+
332
+ const result1 = results.get(file1)!;
333
+ expect(result1.count).toBe(5);
334
+ expect(result1.normalized).toBeGreaterThan(0);
335
+
336
+ const result2 = results.get(file2)!;
337
+ expect(result2.count).toBe(3);
338
+ expect(result2.normalized).toBeGreaterThan(0);
339
+
340
+ const result3 = results.get(file3)!;
341
+ expect(result3.count).toBe(0);
342
+ expect(result3.normalized).toBe(0);
343
+ });
344
+
345
+ it('handles empty file list', async () => {
346
+ const results = await calculateErrorRateBatch([]);
347
+ expect(results.size).toBe(0);
348
+ });
349
+ });
350
+ });