claude-mycelium 2.0.0 → 2.1.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 (189) hide show
  1. package/.agent-meta/_inhibitors.ndjson +1287 -0
  2. package/.agent-meta/_quarantine.json +45 -0
  3. package/.agent-meta/config.json +9 -0
  4. package/.claude/memory.db +0 -0
  5. package/.claude/settings.local.json +4 -1
  6. package/README.md +81 -235
  7. package/SECURITY.md +145 -0
  8. package/dist/agent/worker.d.ts +8 -0
  9. package/dist/agent/worker.d.ts.map +1 -0
  10. package/dist/agent/worker.js +97 -0
  11. package/dist/agent/worker.js.map +1 -0
  12. package/dist/bin.d.ts +7 -0
  13. package/dist/bin.d.ts.map +1 -0
  14. package/dist/bin.js +11 -0
  15. package/dist/bin.js.map +1 -0
  16. package/dist/cli/cost.d.ts +10 -0
  17. package/dist/cli/cost.d.ts.map +1 -0
  18. package/dist/cli/cost.js +163 -0
  19. package/dist/cli/cost.js.map +1 -0
  20. package/dist/cli/gc.d.ts +10 -0
  21. package/dist/cli/gc.d.ts.map +1 -0
  22. package/dist/cli/gc.js +108 -0
  23. package/dist/cli/gc.js.map +1 -0
  24. package/dist/cli/gradients.d.ts +10 -0
  25. package/dist/cli/gradients.d.ts.map +1 -0
  26. package/dist/cli/gradients.js +69 -0
  27. package/dist/cli/gradients.js.map +1 -0
  28. package/dist/cli/index.d.ts +17 -0
  29. package/dist/cli/index.d.ts.map +1 -0
  30. package/dist/cli/index.js +72 -0
  31. package/dist/cli/index.js.map +1 -0
  32. package/dist/cli/init.d.ts +11 -0
  33. package/dist/cli/init.d.ts.map +1 -0
  34. package/dist/cli/init.js +97 -0
  35. package/dist/cli/init.js.map +1 -0
  36. package/dist/cli/status.d.ts +10 -0
  37. package/dist/cli/status.d.ts.map +1 -0
  38. package/dist/cli/status.js +191 -0
  39. package/dist/cli/status.js.map +1 -0
  40. package/dist/coordination/file-locks.d.ts +42 -0
  41. package/dist/coordination/file-locks.d.ts.map +1 -0
  42. package/dist/coordination/file-locks.js +269 -0
  43. package/dist/coordination/file-locks.js.map +1 -0
  44. package/dist/coordination/index.d.ts +4 -0
  45. package/dist/coordination/index.d.ts.map +1 -1
  46. package/dist/coordination/index.js +4 -0
  47. package/dist/coordination/index.js.map +1 -1
  48. package/dist/coordination/inhibitors.d.ts +84 -0
  49. package/dist/coordination/inhibitors.d.ts.map +1 -0
  50. package/dist/coordination/inhibitors.js +290 -0
  51. package/dist/coordination/inhibitors.js.map +1 -0
  52. package/dist/coordination/process-manager.d.ts +73 -0
  53. package/dist/coordination/process-manager.d.ts.map +1 -0
  54. package/dist/coordination/process-manager.js +144 -0
  55. package/dist/coordination/process-manager.js.map +1 -0
  56. package/dist/core/agent-executor.d.ts.map +1 -1
  57. package/dist/core/agent-executor.js +28 -10
  58. package/dist/core/agent-executor.js.map +1 -1
  59. package/dist/core/change-applier.d.ts +29 -5
  60. package/dist/core/change-applier.d.ts.map +1 -1
  61. package/dist/core/change-applier.js +254 -24
  62. package/dist/core/change-applier.js.map +1 -1
  63. package/dist/core/signals/churn.d.ts.map +1 -1
  64. package/dist/core/signals/churn.js +6 -4
  65. package/dist/core/signals/churn.js.map +1 -1
  66. package/dist/core/signals/debt.d.ts.map +1 -1
  67. package/dist/core/signals/debt.js +4 -3
  68. package/dist/core/signals/debt.js.map +1 -1
  69. package/dist/cost/cost-tracker.d.ts.map +1 -1
  70. package/dist/cost/cost-tracker.js +2 -0
  71. package/dist/cost/cost-tracker.js.map +1 -1
  72. package/dist/gc/index.d.ts +17 -0
  73. package/dist/gc/index.d.ts.map +1 -0
  74. package/dist/gc/index.js +17 -0
  75. package/dist/gc/index.js.map +1 -0
  76. package/dist/gc/runner.d.ts +39 -0
  77. package/dist/gc/runner.d.ts.map +1 -0
  78. package/dist/gc/runner.js +277 -0
  79. package/dist/gc/runner.js.map +1 -0
  80. package/dist/gc/trace-compactor.d.ts +31 -0
  81. package/dist/gc/trace-compactor.d.ts.map +1 -0
  82. package/dist/gc/trace-compactor.js +162 -0
  83. package/dist/gc/trace-compactor.js.map +1 -0
  84. package/dist/index.d.ts +5 -1
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +6 -1
  87. package/dist/index.js.map +1 -1
  88. package/dist/prompts/index.d.ts +2 -1
  89. package/dist/prompts/index.d.ts.map +1 -1
  90. package/dist/prompts/index.js.map +1 -1
  91. package/dist/quarantine/explorer.d.ts +65 -0
  92. package/dist/quarantine/explorer.d.ts.map +1 -0
  93. package/dist/quarantine/explorer.js +175 -0
  94. package/dist/quarantine/explorer.js.map +1 -0
  95. package/dist/quarantine/index.d.ts +7 -0
  96. package/dist/quarantine/index.d.ts.map +1 -0
  97. package/dist/quarantine/index.js +7 -0
  98. package/dist/quarantine/index.js.map +1 -0
  99. package/dist/quarantine/manager.d.ts +75 -0
  100. package/dist/quarantine/manager.d.ts.map +1 -0
  101. package/dist/quarantine/manager.js +275 -0
  102. package/dist/quarantine/manager.js.map +1 -0
  103. package/dist/task/acceptance.d.ts +29 -0
  104. package/dist/task/acceptance.d.ts.map +1 -0
  105. package/dist/task/acceptance.js +228 -0
  106. package/dist/task/acceptance.js.map +1 -0
  107. package/dist/task/executor.d.ts +30 -0
  108. package/dist/task/executor.d.ts.map +1 -0
  109. package/dist/task/executor.js +429 -0
  110. package/dist/task/executor.js.map +1 -0
  111. package/dist/task/index.d.ts +12 -0
  112. package/dist/task/index.d.ts.map +1 -0
  113. package/dist/task/index.js +12 -0
  114. package/dist/task/index.js.map +1 -0
  115. package/dist/task/planner.d.ts +21 -0
  116. package/dist/task/planner.d.ts.map +1 -0
  117. package/dist/task/planner.js +253 -0
  118. package/dist/task/planner.js.map +1 -0
  119. package/dist/task/storage.d.ts +46 -0
  120. package/dist/task/storage.d.ts.map +1 -0
  121. package/dist/task/storage.js +266 -0
  122. package/dist/task/storage.js.map +1 -0
  123. package/dist/trace/trace-event.d.ts +2 -18
  124. package/dist/trace/trace-event.d.ts.map +1 -1
  125. package/dist/trace/trace-event.js +6 -6
  126. package/dist/trace/trace-event.js.map +1 -1
  127. package/dist/utils/file-utils.d.ts.map +1 -1
  128. package/dist/utils/file-utils.js +54 -15
  129. package/dist/utils/file-utils.js.map +1 -1
  130. package/docs/PHASE5_IMPLEMENTATION.md +237 -0
  131. package/docs/PHASES-3-7-COMPLETE.md +177 -0
  132. package/docs/PHASE_4_COMPLETE.md +135 -0
  133. package/docs/PHASE_7_DELIVERABLES.md +295 -0
  134. package/docs/PHASE_7_IMPLEMENTATION.md +306 -0
  135. package/docs/PHASE_7_SUMMARY.txt +195 -0
  136. package/docs/RELEASE-NOTES-v2.1.md +213 -0
  137. package/docs/ROADMAP.md +64 -57
  138. package/docs/SECURITY-AUDIT.md +387 -0
  139. package/docs/SNAPSHOT.md +59 -32
  140. package/docs/implementation/phase3-summary.md +220 -0
  141. package/package.json +19 -11
  142. package/src/agent/worker.ts +111 -0
  143. package/src/bin.ts +13 -0
  144. package/src/cli/cost.ts +210 -0
  145. package/src/cli/gc.ts +138 -0
  146. package/src/cli/gradients.ts +95 -0
  147. package/src/cli/index.ts +79 -0
  148. package/src/cli/init.ts +139 -0
  149. package/src/cli/status.ts +218 -0
  150. package/src/coordination/file-locks.ts +300 -0
  151. package/src/coordination/index.ts +4 -0
  152. package/src/coordination/inhibitors.ts +345 -0
  153. package/src/coordination/process-manager.ts +199 -0
  154. package/src/core/agent-executor.ts +20 -4
  155. package/src/core/signals/churn.ts +8 -5
  156. package/src/core/signals/debt.ts +4 -3
  157. package/src/cost/cost-tracker.ts +2 -0
  158. package/src/gc/index.ts +17 -0
  159. package/src/gc/runner.ts +314 -0
  160. package/src/gc/trace-compactor.ts +187 -0
  161. package/src/index.ts +7 -1
  162. package/src/prompts/index.ts +2 -1
  163. package/src/quarantine/explorer.ts +234 -0
  164. package/src/quarantine/index.ts +7 -0
  165. package/src/quarantine/manager.ts +336 -0
  166. package/src/task/acceptance.ts +267 -0
  167. package/src/task/executor.ts +538 -0
  168. package/src/task/index.ts +38 -0
  169. package/src/task/planner.ts +294 -0
  170. package/src/task/storage.ts +332 -0
  171. package/src/trace/trace-event.ts +7 -26
  172. package/src/utils/file-utils.ts +61 -15
  173. package/tests/cli/gc.test.ts +206 -0
  174. package/tests/cli/init.test.ts +181 -0
  175. package/tests/cli/status.test.ts +282 -0
  176. package/tests/coordination/file-locks.test.ts +196 -0
  177. package/tests/coordination/inhibitors.test.ts +459 -0
  178. package/tests/coordination/integration.test.ts +195 -0
  179. package/tests/coordination/process-manager.test.ts +165 -0
  180. package/tests/gc/trace-compactor.test.ts +245 -0
  181. package/tests/integration/phase-7.test.ts +145 -0
  182. package/tests/quarantine/explorer.test.ts +381 -0
  183. package/tests/quarantine/manager.test.ts +399 -0
  184. package/tests/security/command-injection.test.ts +88 -0
  185. package/tests/security/path-traversal.test.ts +103 -0
  186. package/tests/task/acceptance.test.ts +411 -0
  187. package/tests/task/executor.test.ts +421 -0
  188. package/tests/task/planner.test.ts +359 -0
  189. package/tsconfig.json +2 -2
@@ -0,0 +1,421 @@
1
+ /**
2
+ * Tests for Task Executor
3
+ * Validates multi-step execution and progress tracking
4
+ */
5
+
6
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
7
+ import { executeTask, executeStep, trackProgress } from '../../src/task/executor.js';
8
+ import { Task, TaskPlan } from '../../src/types/index.js';
9
+ import * as llm from '../../src/llm/anthropic-client.js';
10
+ import * as fileUtils from '../../src/utils/file-utils.js';
11
+ import * as ciProvider from '../../src/utils/ci-provider.js';
12
+ import * as traceEvent from '../../src/trace/trace-event.js';
13
+
14
+ // Mock dependencies
15
+ vi.mock('../../src/llm/anthropic-client.js', () => ({
16
+ callLLM: vi.fn(),
17
+ calculateCost: vi.fn(),
18
+ }));
19
+ vi.mock('../../src/utils/file-utils.js', () => ({
20
+ fileExists: vi.fn(),
21
+ readFile: vi.fn(),
22
+ writeFile: vi.fn(),
23
+ }));
24
+ vi.mock('../../src/utils/ci-provider.js', () => ({
25
+ runCI: vi.fn(),
26
+ }));
27
+ vi.mock('../../src/trace/trace-event.js', () => ({
28
+ recordTrace: vi.fn(),
29
+ }));
30
+ vi.mock('../../src/core/signals/index.js', () => ({
31
+ calculateFileMetrics: vi.fn(() => Promise.resolve({
32
+ path: 'test.ts',
33
+ complexity: 0.3,
34
+ churn: 0.2,
35
+ error_rate: 0.1,
36
+ debt: 0.2,
37
+ centrality: 0.4,
38
+ loc: 100,
39
+ })),
40
+ }));
41
+ vi.mock('../../src/core/gradient.js', () => ({
42
+ calculateGradient: vi.fn(() => ({ score: 0.5 })),
43
+ }));
44
+
45
+ describe('Task Executor', () => {
46
+ beforeEach(() => {
47
+ vi.clearAllMocks();
48
+
49
+ // Default mocks
50
+ vi.mocked(ciProvider.runCI).mockResolvedValue({
51
+ passed: true,
52
+ output: 'All checks passed',
53
+ });
54
+
55
+ vi.mocked(traceEvent.recordTrace).mockResolvedValue(undefined);
56
+
57
+ vi.mocked(llm.callLLM).mockResolvedValue({
58
+ content: '```typescript\nexport function test() {}\n```',
59
+ usage: { inputTokens: 100, outputTokens: 200 },
60
+ model: 'claude-sonnet-4-5-20250929',
61
+ });
62
+
63
+ vi.mocked(llm.calculateCost).mockReturnValue(0.05);
64
+ });
65
+
66
+ describe('executeTask', () => {
67
+ it('should execute all steps in dependency order', async () => {
68
+ const plan: TaskPlan = {
69
+ summary: 'Test task',
70
+ steps: [
71
+ {
72
+ order: 1,
73
+ description: 'Create file A',
74
+ target_file: 'src/a.ts',
75
+ mode: 'create',
76
+ depends_on: [],
77
+ completed: false,
78
+ },
79
+ {
80
+ order: 2,
81
+ description: 'Create file B',
82
+ target_file: 'src/b.ts',
83
+ mode: 'create',
84
+ depends_on: [1],
85
+ completed: false,
86
+ },
87
+ ],
88
+ estimated_complexity: 'small',
89
+ risks: [],
90
+ };
91
+
92
+ const task: Task = {
93
+ id: 'test-123',
94
+ description: 'Test task',
95
+ status: 'in_progress',
96
+ created_at: new Date().toISOString(),
97
+ plan,
98
+ acceptance_criteria: [],
99
+ steps_completed: 0,
100
+ steps_total: 2,
101
+ files_created: [],
102
+ files_modified: [],
103
+ traces: [],
104
+ };
105
+
106
+ vi.mocked(fileUtils.fileExists).mockReturnValue(false);
107
+
108
+ const result = await executeTask(task);
109
+
110
+ expect(result.status).toBe('completed');
111
+ expect(result.steps_completed).toBe(2);
112
+ expect(result.files_created).toHaveLength(2);
113
+ });
114
+
115
+ it('should stop execution on step failure', async () => {
116
+ const plan: TaskPlan = {
117
+ summary: 'Test task',
118
+ steps: [
119
+ {
120
+ order: 1,
121
+ description: 'Create file',
122
+ target_file: 'src/a.ts',
123
+ mode: 'create',
124
+ depends_on: [],
125
+ completed: false,
126
+ },
127
+ {
128
+ order: 2,
129
+ description: 'Another step',
130
+ target_file: 'src/b.ts',
131
+ mode: 'create',
132
+ depends_on: [1],
133
+ completed: false,
134
+ },
135
+ ],
136
+ estimated_complexity: 'small',
137
+ risks: [],
138
+ };
139
+
140
+ const task: Task = {
141
+ id: 'test-456',
142
+ description: 'Test task',
143
+ status: 'in_progress',
144
+ created_at: new Date().toISOString(),
145
+ plan,
146
+ acceptance_criteria: [],
147
+ steps_completed: 0,
148
+ steps_total: 2,
149
+ files_created: [],
150
+ files_modified: [],
151
+ traces: [],
152
+ };
153
+
154
+ vi.mocked(fileUtils.fileExists).mockReturnValue(false);
155
+ vi.mocked(ciProvider.runCI).mockResolvedValueOnce({
156
+ passed: false,
157
+ output: 'CI failed',
158
+ });
159
+
160
+ const result = await executeTask(task);
161
+
162
+ expect(result.status).toBe('failed');
163
+ expect(result.steps_completed).toBe(0);
164
+ expect(result.error).toContain('CI failed');
165
+ });
166
+
167
+ it('should handle parallel steps correctly', async () => {
168
+ const plan: TaskPlan = {
169
+ summary: 'Test task',
170
+ steps: [
171
+ {
172
+ order: 1,
173
+ description: 'Create base file',
174
+ target_file: 'src/base.ts',
175
+ mode: 'create',
176
+ depends_on: [],
177
+ completed: false,
178
+ },
179
+ {
180
+ order: 2,
181
+ description: 'Create file A',
182
+ target_file: 'src/a.ts',
183
+ mode: 'create',
184
+ depends_on: [1],
185
+ completed: false,
186
+ },
187
+ {
188
+ order: 3,
189
+ description: 'Create file B',
190
+ target_file: 'src/b.ts',
191
+ mode: 'create',
192
+ depends_on: [1],
193
+ completed: false,
194
+ },
195
+ ],
196
+ estimated_complexity: 'small',
197
+ risks: [],
198
+ };
199
+
200
+ const task: Task = {
201
+ id: 'test-789',
202
+ description: 'Test task',
203
+ status: 'in_progress',
204
+ created_at: new Date().toISOString(),
205
+ plan,
206
+ acceptance_criteria: [],
207
+ steps_completed: 0,
208
+ steps_total: 3,
209
+ files_created: [],
210
+ files_modified: [],
211
+ traces: [],
212
+ };
213
+
214
+ vi.mocked(fileUtils.fileExists).mockReturnValue(false);
215
+
216
+ const result = await executeTask(task);
217
+
218
+ // Steps 2 and 3 should execute in parallel (both depend only on 1)
219
+ expect(result.status).toBe('completed');
220
+ expect(result.steps_completed).toBe(3);
221
+ });
222
+ });
223
+
224
+ describe('executeStep', () => {
225
+ it('should execute create mode step', async () => {
226
+ const task: Task = {
227
+ id: 'test-123',
228
+ description: 'Test',
229
+ status: 'in_progress',
230
+ created_at: new Date().toISOString(),
231
+ acceptance_criteria: [],
232
+ steps_completed: 0,
233
+ steps_total: 1,
234
+ files_created: [],
235
+ files_modified: [],
236
+ traces: [],
237
+ };
238
+
239
+ const step = {
240
+ order: 1,
241
+ description: 'Create new file',
242
+ target_file: 'src/new.ts',
243
+ mode: 'create' as const,
244
+ depends_on: [],
245
+ completed: false,
246
+ };
247
+
248
+ vi.mocked(fileUtils.fileExists).mockReturnValue(false);
249
+
250
+ const result = await executeStep(task, step);
251
+
252
+ expect(result.success).toBe(true);
253
+ expect(result.trace_id).toBeDefined();
254
+ expect(fileUtils.writeFile).toHaveBeenCalled();
255
+ });
256
+
257
+ it('should fail create if file already exists', async () => {
258
+ const task: Task = {
259
+ id: 'test-456',
260
+ description: 'Test',
261
+ status: 'in_progress',
262
+ created_at: new Date().toISOString(),
263
+ acceptance_criteria: [],
264
+ steps_completed: 0,
265
+ steps_total: 1,
266
+ files_created: [],
267
+ files_modified: [],
268
+ traces: [],
269
+ };
270
+
271
+ const step = {
272
+ order: 1,
273
+ description: 'Create file',
274
+ target_file: 'src/existing.ts',
275
+ mode: 'create' as const,
276
+ depends_on: [],
277
+ completed: false,
278
+ };
279
+
280
+ vi.mocked(fileUtils.fileExists).mockReturnValue(true);
281
+
282
+ const result = await executeStep(task, step);
283
+
284
+ expect(result.success).toBe(false);
285
+ expect(result.error).toContain('already exists');
286
+ });
287
+
288
+ it('should execute modify mode step', async () => {
289
+ const task: Task = {
290
+ id: 'test-789',
291
+ description: 'Test',
292
+ status: 'in_progress',
293
+ created_at: new Date().toISOString(),
294
+ acceptance_criteria: [],
295
+ steps_completed: 0,
296
+ steps_total: 1,
297
+ files_created: [],
298
+ files_modified: [],
299
+ traces: [],
300
+ };
301
+
302
+ const step = {
303
+ order: 1,
304
+ description: 'Fix errors',
305
+ target_file: 'src/existing.ts',
306
+ mode: 'error_reducer' as const,
307
+ depends_on: [],
308
+ completed: false,
309
+ };
310
+
311
+ vi.mocked(fileUtils.fileExists).mockReturnValue(true);
312
+ vi.mocked(fileUtils.readFile).mockReturnValue('original content');
313
+
314
+ const result = await executeStep(task, step);
315
+
316
+ expect(result.success).toBe(true);
317
+ expect(result.trace_id).toBeDefined();
318
+ });
319
+
320
+ it('should revert changes if CI fails', async () => {
321
+ const task: Task = {
322
+ id: 'test-999',
323
+ description: 'Test',
324
+ status: 'in_progress',
325
+ created_at: new Date().toISOString(),
326
+ acceptance_criteria: [],
327
+ steps_completed: 0,
328
+ steps_total: 1,
329
+ files_created: [],
330
+ files_modified: [],
331
+ traces: [],
332
+ };
333
+
334
+ const step = {
335
+ order: 1,
336
+ description: 'Modify file',
337
+ target_file: 'src/test.ts',
338
+ mode: 'debt_payer' as const,
339
+ depends_on: [],
340
+ completed: false,
341
+ };
342
+
343
+ const originalContent = 'original';
344
+ vi.mocked(fileUtils.fileExists).mockReturnValue(true);
345
+ vi.mocked(fileUtils.readFile).mockReturnValue(originalContent);
346
+ vi.mocked(ciProvider.runCI).mockResolvedValue({
347
+ passed: false,
348
+ output: 'Tests failed',
349
+ });
350
+
351
+ const result = await executeStep(task, step);
352
+
353
+ expect(result.success).toBe(false);
354
+ // Should revert to original content
355
+ expect(fileUtils.writeFile).toHaveBeenCalledWith('src/test.ts', originalContent);
356
+ });
357
+ });
358
+
359
+ describe('trackProgress', () => {
360
+ it('should calculate progress percentage', () => {
361
+ const task: Task = {
362
+ id: 'test-123',
363
+ description: 'Test',
364
+ status: 'in_progress',
365
+ created_at: new Date().toISOString(),
366
+ acceptance_criteria: [],
367
+ steps_completed: 3,
368
+ steps_total: 10,
369
+ files_created: [],
370
+ files_modified: [],
371
+ traces: [],
372
+ };
373
+
374
+ const progress = trackProgress(task);
375
+
376
+ expect(progress.percentage).toBe(30);
377
+ expect(progress.completed).toBe(3);
378
+ expect(progress.total).toBe(10);
379
+ expect(progress.status).toBe('in_progress');
380
+ });
381
+
382
+ it('should handle zero total steps', () => {
383
+ const task: Task = {
384
+ id: 'test-456',
385
+ description: 'Test',
386
+ status: 'pending',
387
+ created_at: new Date().toISOString(),
388
+ acceptance_criteria: [],
389
+ steps_completed: 0,
390
+ steps_total: 0,
391
+ files_created: [],
392
+ files_modified: [],
393
+ traces: [],
394
+ };
395
+
396
+ const progress = trackProgress(task);
397
+
398
+ expect(progress.percentage).toBe(0);
399
+ });
400
+
401
+ it('should show 100% for completed task', () => {
402
+ const task: Task = {
403
+ id: 'test-789',
404
+ description: 'Test',
405
+ status: 'completed',
406
+ created_at: new Date().toISOString(),
407
+ acceptance_criteria: [],
408
+ steps_completed: 5,
409
+ steps_total: 5,
410
+ files_created: [],
411
+ files_modified: [],
412
+ traces: [],
413
+ };
414
+
415
+ const progress = trackProgress(task);
416
+
417
+ expect(progress.percentage).toBe(100);
418
+ expect(progress.status).toBe('completed');
419
+ });
420
+ });
421
+ });