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,538 @@
1
+ /**
2
+ * Task Execution Implementation
3
+ * Per second-spec §12.2: Task Step Execution
4
+ *
5
+ * Executes task steps in dependency order, tracking progress
6
+ * and handling create mode appropriately.
7
+ */
8
+
9
+ import { Task, TaskStep, Mode, ChangeSet, CostRecord } from '../types/index.js';
10
+ import { callLLM, calculateCost } from '../llm/anthropic-client.js';
11
+ import { logDebug, logError } from '../utils/logger.js';
12
+ import { fileExists, readFile, writeFile } from '../utils/file-utils.js';
13
+ import { ciProvider } from '../utils/ci-provider.js';
14
+ import { createTraceEvent, recordTraceEvent } from '../trace/index.js';
15
+ import { calculateGradient } from '../core/gradient.js';
16
+
17
+ /**
18
+ * Execute a complete task by running all steps in dependency order
19
+ */
20
+ export async function executeTask(task: Task): Promise<Task> {
21
+ logDebug('Executing task', { taskId: task.id, steps: task.plan?.steps.length });
22
+
23
+ if (!task.plan) {
24
+ throw new Error('Cannot execute task without a plan');
25
+ }
26
+
27
+ const waves = getParallelizableSteps(task.plan.steps);
28
+
29
+ for (let waveIndex = 0; waveIndex < waves.length; waveIndex++) {
30
+ const wave = waves[waveIndex];
31
+ logDebug('Executing wave', { wave: waveIndex + 1, steps: wave.length });
32
+
33
+ // Execute all steps in this wave (they have no dependencies on each other)
34
+ const results = await Promise.all(
35
+ wave.map(step => executeStep(task, step))
36
+ );
37
+
38
+ // Check for failures
39
+ const failed = results.find(r => !r.success);
40
+ if (failed) {
41
+ task.status = 'failed';
42
+ task.error = failed.error;
43
+ logError('Task step failed', new Error(failed.error), { taskId: task.id });
44
+ return task;
45
+ }
46
+
47
+ // Update completed steps
48
+ for (let i = 0; i < wave.length; i++) {
49
+ wave[i].completed = true;
50
+ wave[i].trace_id = results[i].trace_id;
51
+ task.steps_completed++;
52
+ }
53
+
54
+ // Track file changes
55
+ for (let i = 0; i < wave.length; i++) {
56
+ if (wave[i].mode === 'create') {
57
+ task.files_created.push(wave[i].target_file);
58
+ } else {
59
+ if (!task.files_modified.includes(wave[i].target_file)) {
60
+ task.files_modified.push(wave[i].target_file);
61
+ }
62
+ }
63
+ const traceId = results[i].trace_id;
64
+ if (traceId !== undefined) {
65
+ task.traces.push(traceId);
66
+ }
67
+ }
68
+ }
69
+
70
+ task.status = 'completed';
71
+ logDebug('Task execution completed', { taskId: task.id });
72
+ return task;
73
+ }
74
+
75
+ /**
76
+ * Execute a single task step
77
+ */
78
+ export async function executeStep(
79
+ task: Task,
80
+ step: TaskStep
81
+ ): Promise<{ success: boolean; trace_id?: string; error?: string }> {
82
+ logDebug('Executing step', {
83
+ taskId: task.id,
84
+ stepOrder: step.order,
85
+ mode: step.mode,
86
+ file: step.target_file,
87
+ });
88
+
89
+ try {
90
+ if (step.mode === 'create') {
91
+ return await executeCreateStep(task, step);
92
+ } else {
93
+ return await executeModifyStep(task, step);
94
+ }
95
+ } catch (error) {
96
+ const errorMsg = error instanceof Error ? error.message : 'Unknown error';
97
+ const errorObj = error instanceof Error ? error : new Error(String(error));
98
+ logError('Step execution failed', errorObj, {
99
+ taskId: task.id,
100
+ stepOrder: step.order,
101
+ });
102
+ return { success: false, error: errorMsg };
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Track progress of task execution
108
+ */
109
+ export function trackProgress(task: Task): {
110
+ percentage: number;
111
+ completed: number;
112
+ total: number;
113
+ status: string;
114
+ } {
115
+ const percentage = task.steps_total > 0
116
+ ? Math.round((task.steps_completed / task.steps_total) * 100)
117
+ : 0;
118
+
119
+ return {
120
+ percentage,
121
+ completed: task.steps_completed,
122
+ total: task.steps_total,
123
+ status: task.status,
124
+ };
125
+ }
126
+
127
+ /**
128
+ * Execute a create mode step (new file)
129
+ */
130
+ async function executeCreateStep(
131
+ task: Task,
132
+ step: TaskStep
133
+ ): Promise<{ success: boolean; trace_id?: string; error?: string }> {
134
+ // Check if file already exists
135
+ if (fileExists(step.target_file)) {
136
+ return {
137
+ success: false,
138
+ error: `Cannot create file ${step.target_file} - already exists`,
139
+ };
140
+ }
141
+
142
+ // Build prompt for file creation
143
+ const systemPrompt = buildCreateSystemPrompt();
144
+ const userPrompt = buildCreateUserPrompt(task, step);
145
+
146
+ // Call LLM to generate file content
147
+ const response = await callLLM({
148
+ prompt: userPrompt,
149
+ systemPrompt,
150
+ temperature: 0.5,
151
+ maxTokens: 4000,
152
+ });
153
+
154
+ // Extract code from response
155
+ const fileContent = extractCodeFromResponse(response.content);
156
+ if (!fileContent) {
157
+ return {
158
+ success: false,
159
+ error: 'Failed to extract code from LLM response',
160
+ };
161
+ }
162
+
163
+ // Write the file
164
+ writeFile(step.target_file, fileContent);
165
+
166
+ // Run CI to validate
167
+ const ciResult = await ciProvider.run({
168
+ additions: fileContent.split('\n').length,
169
+ deletions: 0,
170
+ files_touched: [step.target_file],
171
+ });
172
+
173
+ if (!ciResult.passed) {
174
+ // Revert - delete the file
175
+ try {
176
+ const fs = await import('fs');
177
+ fs.unlinkSync(step.target_file);
178
+ } catch {}
179
+ return {
180
+ success: false,
181
+ error: `CI failed: ${ciResult.output}`,
182
+ };
183
+ }
184
+
185
+ // Record trace
186
+ const traceId = await recordCreateTrace(
187
+ step.target_file,
188
+ fileContent,
189
+ response.usage,
190
+ response.model,
191
+ task.id
192
+ );
193
+
194
+ logDebug('Create step completed', {
195
+ file: step.target_file,
196
+ lines: fileContent.split('\n').length,
197
+ traceId,
198
+ });
199
+
200
+ return { success: true, trace_id: traceId };
201
+ }
202
+
203
+ /**
204
+ * Execute a modify mode step (existing file)
205
+ */
206
+ async function executeModifyStep(
207
+ task: Task,
208
+ step: TaskStep
209
+ ): Promise<{ success: boolean; trace_id?: string; error?: string }> {
210
+ if (!fileExists(step.target_file)) {
211
+ return {
212
+ success: false,
213
+ error: `Cannot modify file ${step.target_file} - does not exist`,
214
+ };
215
+ }
216
+
217
+ const originalContent = readFile(step.target_file);
218
+ const gradientBefore = await calculateGradient(step.target_file);
219
+
220
+ // Build prompt for modification
221
+ const systemPrompt = buildModifySystemPrompt(step.mode as Mode);
222
+ const userPrompt = buildModifyUserPrompt(task, step, originalContent);
223
+
224
+ // Call LLM to generate changes
225
+ const response = await callLLM({
226
+ prompt: userPrompt,
227
+ systemPrompt,
228
+ temperature: 0.5,
229
+ maxTokens: 4000,
230
+ });
231
+
232
+ // Extract modified content
233
+ const modifiedContent = extractCodeFromResponse(response.content);
234
+ if (!modifiedContent) {
235
+ return {
236
+ success: false,
237
+ error: 'Failed to extract modified code from LLM response',
238
+ };
239
+ }
240
+
241
+ // Apply changes
242
+ writeFile(step.target_file, modifiedContent);
243
+
244
+ // Calculate change stats
245
+ const changeSet = calculateChanges(originalContent, modifiedContent, step.target_file);
246
+
247
+ // Run CI
248
+ const ciResult = await ciProvider.run(changeSet);
249
+ if (!ciResult.passed) {
250
+ // Revert changes
251
+ writeFile(step.target_file, originalContent);
252
+ return {
253
+ success: false,
254
+ error: `CI failed: ${ciResult.output}`,
255
+ };
256
+ }
257
+
258
+ // Calculate metrics after
259
+ const gradientAfter = await calculateGradient(step.target_file);
260
+
261
+ // Record trace
262
+ const traceId = await recordModifyTrace(
263
+ step.target_file,
264
+ step.mode as Mode,
265
+ gradientBefore,
266
+ gradientAfter,
267
+ changeSet,
268
+ response.usage,
269
+ response.model,
270
+ task.id
271
+ );
272
+
273
+ logDebug('Modify step completed', {
274
+ file: step.target_file,
275
+ mode: step.mode,
276
+ gradientDelta: gradientBefore.score - gradientAfter.score,
277
+ traceId,
278
+ });
279
+
280
+ return { success: true, trace_id: traceId };
281
+ }
282
+
283
+ /**
284
+ * Helper to calculate file metrics (not used in current implementation)
285
+ */
286
+ /*
287
+ async function calculateFileMetrics(filePath: string, allFiles: string[]): Promise<FileMetrics> {
288
+ const [complexity, churn, errorRate, debt, centrality] = await Promise.all([
289
+ calculateComplexity(filePath),
290
+ calculateChurn(filePath),
291
+ calculateErrorRate(filePath),
292
+ calculateDebt(filePath),
293
+ calculateCentrality(filePath),
294
+ ]);
295
+
296
+ return {
297
+ path: filePath,
298
+ complexity: complexity.normalized,
299
+ churn: churn.normalized,
300
+ error_rate: errorRate.normalized,
301
+ debt: debt.normalized,
302
+ centrality: centrality.normalized,
303
+ loc: getLineCount(filePath),
304
+ };
305
+ }
306
+ */
307
+
308
+ /**
309
+ * Get steps grouped by waves (parallelizable groups)
310
+ */
311
+ function getParallelizableSteps(steps: TaskStep[]): TaskStep[][] {
312
+ const waves: TaskStep[][] = [];
313
+ const completed = new Set<number>();
314
+
315
+ while (completed.size < steps.length) {
316
+ // Find steps whose dependencies are all completed
317
+ const ready = steps.filter(
318
+ step =>
319
+ !completed.has(step.order) &&
320
+ step.depends_on.every(dep => completed.has(dep))
321
+ );
322
+
323
+ if (ready.length === 0) {
324
+ throw new Error('Circular dependency detected in task steps');
325
+ }
326
+
327
+ waves.push(ready);
328
+ ready.forEach(step => completed.add(step.order));
329
+ }
330
+
331
+ return waves;
332
+ }
333
+
334
+ /**
335
+ * Build system prompt for create mode
336
+ */
337
+ function buildCreateSystemPrompt(): string {
338
+ return `You are creating a new file as part of a larger task.
339
+
340
+ Output the complete file content wrapped in triple backticks with the language identifier.
341
+
342
+ Example:
343
+ \`\`\`typescript
344
+ // File content here
345
+ \`\`\`
346
+
347
+ Requirements:
348
+ - Include all necessary imports
349
+ - Add appropriate error handling
350
+ - Include JSDoc comments for exported functions
351
+ - Follow TypeScript best practices`;
352
+ }
353
+
354
+ /**
355
+ * Build user prompt for create mode
356
+ */
357
+ function buildCreateUserPrompt(task: Task, step: TaskStep): string {
358
+ return `## Overall Task
359
+ ${task.description}
360
+
361
+ ## This Step
362
+ ${step.description}
363
+
364
+ ## File to Create
365
+ ${step.target_file}
366
+
367
+ ## Requirements
368
+ - Create a working implementation
369
+ - Include basic error handling
370
+ - Add type annotations
371
+ - Follow existing project patterns
372
+
373
+ Generate the complete file content.`;
374
+ }
375
+
376
+ /**
377
+ * Build system prompt for modify mode
378
+ */
379
+ function buildModifySystemPrompt(mode: Mode): string {
380
+ const modeInstructions: Record<Mode, string> = {
381
+ error_reducer: 'Focus on fixing bugs and adding error handling. Do not refactor for style.',
382
+ complexity_reducer: 'Focus on simplifying code structure. Extract functions, reduce nesting.',
383
+ debt_payer: 'Focus on fixing lint issues and improving types. Do not change logic.',
384
+ stabilizer: 'Focus on adding tests and documentation. Do not change implementation.',
385
+ explorer: 'You may challenge assumptions and propose larger changes within constraints.',
386
+ };
387
+
388
+ return `You are modifying an existing file in ${mode} mode.
389
+
390
+ ${modeInstructions[mode]}
391
+
392
+ Output the complete modified file content wrapped in triple backticks.`;
393
+ }
394
+
395
+ /**
396
+ * Build user prompt for modify mode
397
+ */
398
+ function buildModifyUserPrompt(task: Task, step: TaskStep, currentContent: string): string {
399
+ return `## Overall Task
400
+ ${task.description}
401
+
402
+ ## This Step
403
+ ${step.description}
404
+
405
+ ## Current File Content
406
+ \`\`\`typescript
407
+ ${currentContent}
408
+ \`\`\`
409
+
410
+ Modify the file according to the step description and mode constraints.
411
+ Output the complete modified file.`;
412
+ }
413
+
414
+ /**
415
+ * Extract code from LLM response (handle markdown code blocks)
416
+ */
417
+ function extractCodeFromResponse(content: string): string | null {
418
+ // Try to find code in triple backticks
419
+ const codeBlockMatch = content.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)\n```/);
420
+ if (codeBlockMatch) {
421
+ return codeBlockMatch[1];
422
+ }
423
+
424
+ // If no code block found, check if entire content looks like code
425
+ if (content.includes('import') || content.includes('export') || content.includes('function')) {
426
+ return content.trim();
427
+ }
428
+
429
+ return null;
430
+ }
431
+
432
+ /**
433
+ * Calculate changes between original and modified content
434
+ */
435
+ function calculateChanges(
436
+ original: string,
437
+ modified: string,
438
+ filePath: string
439
+ ): ChangeSet {
440
+ const originalLines = original.split('\n');
441
+ const modifiedLines = modified.split('\n');
442
+
443
+ // Simple diff: count added and removed lines
444
+ const additions = modifiedLines.length > originalLines.length
445
+ ? modifiedLines.length - originalLines.length
446
+ : 0;
447
+ const deletions = originalLines.length > modifiedLines.length
448
+ ? originalLines.length - modifiedLines.length
449
+ : 0;
450
+
451
+ return {
452
+ additions,
453
+ deletions,
454
+ files_touched: [filePath],
455
+ };
456
+ }
457
+
458
+ /**
459
+ * Record trace for create step
460
+ */
461
+ async function recordCreateTrace(
462
+ filePath: string,
463
+ content: string,
464
+ usage: { inputTokens: number; outputTokens: number },
465
+ model: string,
466
+ taskId: string
467
+ ): Promise<string> {
468
+ const cost: CostRecord = {
469
+ tokens_in: usage.inputTokens,
470
+ tokens_out: usage.outputTokens,
471
+ model,
472
+ estimated_usd: calculateCost(model, usage.inputTokens, usage.outputTokens),
473
+ };
474
+
475
+ // For create mode, gradient goes from 0 to 0 (no improvement measured)
476
+ const trace = createTraceEvent({
477
+ filePath,
478
+ mode: 'debt_payer', // Create is treated as debt_payer for metrics
479
+ gradientBefore: 0,
480
+ gradientAfter: 0,
481
+ metabolicCost: cost.estimated_usd * 100, // Normalize
482
+ efficiency: 0,
483
+ ciPassed: true,
484
+ changes: {
485
+ additions: content.split('\n').length,
486
+ deletions: 0,
487
+ files_touched: [filePath],
488
+ },
489
+ costRecord: cost,
490
+ notes: ['File created as part of task'],
491
+ taskId,
492
+ });
493
+
494
+ await recordTraceEvent(trace);
495
+ return trace.id;
496
+ }
497
+
498
+ /**
499
+ * Record trace for modify step
500
+ */
501
+ async function recordModifyTrace(
502
+ filePath: string,
503
+ mode: Mode,
504
+ gradientBefore: { score: number },
505
+ gradientAfter: { score: number },
506
+ changes: ChangeSet,
507
+ usage: { inputTokens: number; outputTokens: number },
508
+ model: string,
509
+ taskId: string
510
+ ): Promise<string> {
511
+ const cost: CostRecord = {
512
+ tokens_in: usage.inputTokens,
513
+ tokens_out: usage.outputTokens,
514
+ model,
515
+ estimated_usd: calculateCost(model, usage.inputTokens, usage.outputTokens),
516
+ };
517
+
518
+ const gradientDelta = gradientBefore.score - gradientAfter.score;
519
+ const metabolicCost = cost.estimated_usd * 100; // Normalize
520
+ const efficiency = metabolicCost > 0 ? gradientDelta / metabolicCost : 0;
521
+
522
+ const trace = createTraceEvent({
523
+ filePath,
524
+ mode,
525
+ gradientBefore: gradientBefore.score,
526
+ gradientAfter: gradientAfter.score,
527
+ metabolicCost,
528
+ efficiency,
529
+ ciPassed: true,
530
+ changes,
531
+ costRecord: cost,
532
+ notes: ['Modified as part of task'],
533
+ taskId,
534
+ });
535
+
536
+ await recordTraceEvent(trace);
537
+ return trace.id;
538
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Task System Module
3
+ * Phase 5: Task Planning & Execution
4
+ *
5
+ * Exports all task-related functionality for LLM-based task decomposition,
6
+ * execution tracking, and acceptance criteria validation.
7
+ */
8
+
9
+ export {
10
+ planTask,
11
+ analyzeDependencies,
12
+ identifyRisks,
13
+ } from './planner.js';
14
+
15
+ export {
16
+ executeTask,
17
+ executeStep,
18
+ trackProgress,
19
+ } from './executor.js';
20
+
21
+ export {
22
+ validateAcceptance,
23
+ checkFileExists,
24
+ runTests,
25
+ generateDefaultCriteria,
26
+ canCompleteTask,
27
+ } from './acceptance.js';
28
+
29
+ export {
30
+ storeTask,
31
+ loadTask,
32
+ listTasks,
33
+ listActiveTasks,
34
+ deleteTask,
35
+ updateTaskStatus,
36
+ getTaskHistoryForFile,
37
+ getTaskStatistics,
38
+ } from './storage.js';