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.
- package/.agent-meta/_inhibitors.ndjson +1287 -0
- package/.agent-meta/_quarantine.json +45 -0
- package/.agent-meta/config.json +9 -0
- package/.claude/memory.db +0 -0
- package/.claude/settings.local.json +4 -1
- package/README.md +81 -235
- package/SECURITY.md +145 -0
- package/dist/agent/worker.d.ts +8 -0
- package/dist/agent/worker.d.ts.map +1 -0
- package/dist/agent/worker.js +97 -0
- package/dist/agent/worker.js.map +1 -0
- package/dist/bin.d.ts +7 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +11 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli/cost.d.ts +10 -0
- package/dist/cli/cost.d.ts.map +1 -0
- package/dist/cli/cost.js +163 -0
- package/dist/cli/cost.js.map +1 -0
- package/dist/cli/gc.d.ts +10 -0
- package/dist/cli/gc.d.ts.map +1 -0
- package/dist/cli/gc.js +108 -0
- package/dist/cli/gc.js.map +1 -0
- package/dist/cli/gradients.d.ts +10 -0
- package/dist/cli/gradients.d.ts.map +1 -0
- package/dist/cli/gradients.js +69 -0
- package/dist/cli/gradients.js.map +1 -0
- package/dist/cli/index.d.ts +17 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +72 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +11 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +97 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/status.d.ts +10 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +191 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/coordination/file-locks.d.ts +42 -0
- package/dist/coordination/file-locks.d.ts.map +1 -0
- package/dist/coordination/file-locks.js +269 -0
- package/dist/coordination/file-locks.js.map +1 -0
- package/dist/coordination/index.d.ts +4 -0
- package/dist/coordination/index.d.ts.map +1 -1
- package/dist/coordination/index.js +4 -0
- package/dist/coordination/index.js.map +1 -1
- package/dist/coordination/inhibitors.d.ts +84 -0
- package/dist/coordination/inhibitors.d.ts.map +1 -0
- package/dist/coordination/inhibitors.js +290 -0
- package/dist/coordination/inhibitors.js.map +1 -0
- package/dist/coordination/process-manager.d.ts +73 -0
- package/dist/coordination/process-manager.d.ts.map +1 -0
- package/dist/coordination/process-manager.js +144 -0
- package/dist/coordination/process-manager.js.map +1 -0
- package/dist/core/agent-executor.d.ts.map +1 -1
- package/dist/core/agent-executor.js +28 -10
- package/dist/core/agent-executor.js.map +1 -1
- package/dist/core/change-applier.d.ts +29 -5
- package/dist/core/change-applier.d.ts.map +1 -1
- package/dist/core/change-applier.js +254 -24
- package/dist/core/change-applier.js.map +1 -1
- package/dist/core/signals/churn.d.ts.map +1 -1
- package/dist/core/signals/churn.js +6 -4
- package/dist/core/signals/churn.js.map +1 -1
- package/dist/core/signals/debt.d.ts.map +1 -1
- package/dist/core/signals/debt.js +4 -3
- package/dist/core/signals/debt.js.map +1 -1
- package/dist/cost/cost-tracker.d.ts.map +1 -1
- package/dist/cost/cost-tracker.js +2 -0
- package/dist/cost/cost-tracker.js.map +1 -1
- package/dist/gc/index.d.ts +17 -0
- package/dist/gc/index.d.ts.map +1 -0
- package/dist/gc/index.js +17 -0
- package/dist/gc/index.js.map +1 -0
- package/dist/gc/runner.d.ts +39 -0
- package/dist/gc/runner.d.ts.map +1 -0
- package/dist/gc/runner.js +277 -0
- package/dist/gc/runner.js.map +1 -0
- package/dist/gc/trace-compactor.d.ts +31 -0
- package/dist/gc/trace-compactor.d.ts.map +1 -0
- package/dist/gc/trace-compactor.js +162 -0
- package/dist/gc/trace-compactor.js.map +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/prompts/index.d.ts +2 -1
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js.map +1 -1
- package/dist/quarantine/explorer.d.ts +65 -0
- package/dist/quarantine/explorer.d.ts.map +1 -0
- package/dist/quarantine/explorer.js +175 -0
- package/dist/quarantine/explorer.js.map +1 -0
- package/dist/quarantine/index.d.ts +7 -0
- package/dist/quarantine/index.d.ts.map +1 -0
- package/dist/quarantine/index.js +7 -0
- package/dist/quarantine/index.js.map +1 -0
- package/dist/quarantine/manager.d.ts +75 -0
- package/dist/quarantine/manager.d.ts.map +1 -0
- package/dist/quarantine/manager.js +275 -0
- package/dist/quarantine/manager.js.map +1 -0
- package/dist/task/acceptance.d.ts +29 -0
- package/dist/task/acceptance.d.ts.map +1 -0
- package/dist/task/acceptance.js +228 -0
- package/dist/task/acceptance.js.map +1 -0
- package/dist/task/executor.d.ts +30 -0
- package/dist/task/executor.d.ts.map +1 -0
- package/dist/task/executor.js +429 -0
- package/dist/task/executor.js.map +1 -0
- package/dist/task/index.d.ts +12 -0
- package/dist/task/index.d.ts.map +1 -0
- package/dist/task/index.js +12 -0
- package/dist/task/index.js.map +1 -0
- package/dist/task/planner.d.ts +21 -0
- package/dist/task/planner.d.ts.map +1 -0
- package/dist/task/planner.js +253 -0
- package/dist/task/planner.js.map +1 -0
- package/dist/task/storage.d.ts +46 -0
- package/dist/task/storage.d.ts.map +1 -0
- package/dist/task/storage.js +266 -0
- package/dist/task/storage.js.map +1 -0
- package/dist/trace/trace-event.d.ts +2 -18
- package/dist/trace/trace-event.d.ts.map +1 -1
- package/dist/trace/trace-event.js +6 -6
- package/dist/trace/trace-event.js.map +1 -1
- package/dist/utils/file-utils.d.ts.map +1 -1
- package/dist/utils/file-utils.js +54 -15
- package/dist/utils/file-utils.js.map +1 -1
- package/docs/PHASE5_IMPLEMENTATION.md +237 -0
- package/docs/PHASES-3-7-COMPLETE.md +177 -0
- package/docs/PHASE_4_COMPLETE.md +135 -0
- package/docs/PHASE_7_DELIVERABLES.md +295 -0
- package/docs/PHASE_7_IMPLEMENTATION.md +306 -0
- package/docs/PHASE_7_SUMMARY.txt +195 -0
- package/docs/RELEASE-NOTES-v2.1.md +213 -0
- package/docs/ROADMAP.md +64 -57
- package/docs/SECURITY-AUDIT.md +387 -0
- package/docs/SNAPSHOT.md +59 -32
- package/docs/implementation/phase3-summary.md +220 -0
- package/package.json +19 -11
- package/src/agent/worker.ts +111 -0
- package/src/bin.ts +13 -0
- package/src/cli/cost.ts +210 -0
- package/src/cli/gc.ts +138 -0
- package/src/cli/gradients.ts +95 -0
- package/src/cli/index.ts +79 -0
- package/src/cli/init.ts +139 -0
- package/src/cli/status.ts +218 -0
- package/src/coordination/file-locks.ts +300 -0
- package/src/coordination/index.ts +4 -0
- package/src/coordination/inhibitors.ts +345 -0
- package/src/coordination/process-manager.ts +199 -0
- package/src/core/agent-executor.ts +20 -4
- package/src/core/signals/churn.ts +8 -5
- package/src/core/signals/debt.ts +4 -3
- package/src/cost/cost-tracker.ts +2 -0
- package/src/gc/index.ts +17 -0
- package/src/gc/runner.ts +314 -0
- package/src/gc/trace-compactor.ts +187 -0
- package/src/index.ts +7 -1
- package/src/prompts/index.ts +2 -1
- package/src/quarantine/explorer.ts +234 -0
- package/src/quarantine/index.ts +7 -0
- package/src/quarantine/manager.ts +336 -0
- package/src/task/acceptance.ts +267 -0
- package/src/task/executor.ts +538 -0
- package/src/task/index.ts +38 -0
- package/src/task/planner.ts +294 -0
- package/src/task/storage.ts +332 -0
- package/src/trace/trace-event.ts +7 -26
- package/src/utils/file-utils.ts +61 -15
- package/tests/cli/gc.test.ts +206 -0
- package/tests/cli/init.test.ts +181 -0
- package/tests/cli/status.test.ts +282 -0
- package/tests/coordination/file-locks.test.ts +196 -0
- package/tests/coordination/inhibitors.test.ts +459 -0
- package/tests/coordination/integration.test.ts +195 -0
- package/tests/coordination/process-manager.test.ts +165 -0
- package/tests/gc/trace-compactor.test.ts +245 -0
- package/tests/integration/phase-7.test.ts +145 -0
- package/tests/quarantine/explorer.test.ts +381 -0
- package/tests/quarantine/manager.test.ts +399 -0
- package/tests/security/command-injection.test.ts +88 -0
- package/tests/security/path-traversal.test.ts +103 -0
- package/tests/task/acceptance.test.ts +411 -0
- package/tests/task/executor.test.ts +421 -0
- package/tests/task/planner.test.ts +359 -0
- package/tsconfig.json +2 -2
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Acceptance Criteria Validation
|
|
3
|
+
* Per ROADMAP §Phase 5 Week 6 Day 5-6: Acceptance Criteria
|
|
4
|
+
*
|
|
5
|
+
* Validates task completion against acceptance criteria including
|
|
6
|
+
* file existence, test execution, lint checks, and custom validation.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Task, AcceptanceCriterion } from '../types/index.js';
|
|
10
|
+
import { fileExists } from '../utils/file-utils.js';
|
|
11
|
+
import { logDebug, logError } from '../utils/logger.js';
|
|
12
|
+
import { exec } from 'child_process';
|
|
13
|
+
import { promisify } from 'util';
|
|
14
|
+
|
|
15
|
+
const execAsync = promisify(exec);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Validate all acceptance criteria for a task
|
|
19
|
+
*/
|
|
20
|
+
export async function validateAcceptance(task: Task): Promise<boolean> {
|
|
21
|
+
logDebug('Validating acceptance criteria', {
|
|
22
|
+
taskId: task.id,
|
|
23
|
+
criteriaCount: task.acceptance_criteria.length,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
let allMet = true;
|
|
27
|
+
|
|
28
|
+
for (const criterion of task.acceptance_criteria) {
|
|
29
|
+
const met = await validateCriterion(criterion);
|
|
30
|
+
criterion.met = met;
|
|
31
|
+
|
|
32
|
+
if (!met) {
|
|
33
|
+
allMet = false;
|
|
34
|
+
logDebug('Acceptance criterion not met', {
|
|
35
|
+
taskId: task.id,
|
|
36
|
+
type: criterion.type,
|
|
37
|
+
description: criterion.description,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
logDebug('Acceptance validation complete', {
|
|
43
|
+
taskId: task.id,
|
|
44
|
+
allMet,
|
|
45
|
+
metCount: task.acceptance_criteria.filter(c => c.met).length,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return allMet;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Validate a single acceptance criterion
|
|
53
|
+
*/
|
|
54
|
+
async function validateCriterion(criterion: AcceptanceCriterion): Promise<boolean> {
|
|
55
|
+
try {
|
|
56
|
+
switch (criterion.type) {
|
|
57
|
+
case 'file_exists':
|
|
58
|
+
return await checkFileExists(criterion.check);
|
|
59
|
+
|
|
60
|
+
case 'test_passes':
|
|
61
|
+
return await runTests(criterion.check);
|
|
62
|
+
|
|
63
|
+
case 'no_lint_errors':
|
|
64
|
+
return await checkLintErrors(criterion.check);
|
|
65
|
+
|
|
66
|
+
case 'custom':
|
|
67
|
+
return await runCustomValidation(criterion.check);
|
|
68
|
+
|
|
69
|
+
default:
|
|
70
|
+
logError('Unknown criterion type', new Error('Invalid type'), {
|
|
71
|
+
type: criterion.type,
|
|
72
|
+
});
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
} catch (error) {
|
|
76
|
+
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
77
|
+
logError('Criterion validation failed', errorObj, {
|
|
78
|
+
type: criterion.type,
|
|
79
|
+
check: criterion.check,
|
|
80
|
+
});
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Check if a file exists
|
|
87
|
+
*/
|
|
88
|
+
export async function checkFileExists(filePath: string): Promise<boolean> {
|
|
89
|
+
const exists = fileExists(filePath);
|
|
90
|
+
logDebug('File existence check', { filePath, exists });
|
|
91
|
+
return exists;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Run specific tests and check if they pass
|
|
96
|
+
*/
|
|
97
|
+
export async function runTests(testPattern: string): Promise<boolean> {
|
|
98
|
+
logDebug('Running tests', { pattern: testPattern });
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
// Run vitest with specific pattern
|
|
102
|
+
const command = `npm test -- --run ${testPattern}`;
|
|
103
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
104
|
+
timeout: 60000, // 60 second timeout
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Check for test failures in output
|
|
108
|
+
const output = stdout + stderr;
|
|
109
|
+
const hasFailed = output.includes('FAILED') ||
|
|
110
|
+
output.includes('failed') ||
|
|
111
|
+
output.includes('Error:');
|
|
112
|
+
|
|
113
|
+
logDebug('Test execution result', {
|
|
114
|
+
pattern: testPattern,
|
|
115
|
+
passed: !hasFailed,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return !hasFailed;
|
|
119
|
+
} catch (error) {
|
|
120
|
+
// exec throws on non-zero exit code
|
|
121
|
+
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
122
|
+
logError('Test execution failed', errorObj, { pattern: testPattern });
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Check if file has lint errors
|
|
129
|
+
*/
|
|
130
|
+
async function checkLintErrors(filePath: string): Promise<boolean> {
|
|
131
|
+
logDebug('Checking lint errors', { filePath });
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
// Run eslint on specific file
|
|
135
|
+
const command = `npx eslint ${filePath} --format json`;
|
|
136
|
+
const { stdout } = await execAsync(command, {
|
|
137
|
+
timeout: 30000, // 30 second timeout
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Parse eslint JSON output
|
|
141
|
+
const results = JSON.parse(stdout);
|
|
142
|
+
|
|
143
|
+
// Check if there are any errors
|
|
144
|
+
const totalErrors = results.reduce(
|
|
145
|
+
(sum: number, result: any) => sum + result.errorCount,
|
|
146
|
+
0
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const noErrors = totalErrors === 0;
|
|
150
|
+
logDebug('Lint check result', {
|
|
151
|
+
filePath,
|
|
152
|
+
errors: totalErrors,
|
|
153
|
+
passed: noErrors,
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
return noErrors;
|
|
157
|
+
} catch (error) {
|
|
158
|
+
// eslint returns non-zero exit code when errors found
|
|
159
|
+
// Try to parse the output to get error count
|
|
160
|
+
if (error instanceof Error && 'stdout' in error) {
|
|
161
|
+
try {
|
|
162
|
+
const results = JSON.parse((error as any).stdout);
|
|
163
|
+
const totalErrors = results.reduce(
|
|
164
|
+
(sum: number, result: any) => sum + result.errorCount,
|
|
165
|
+
0
|
|
166
|
+
);
|
|
167
|
+
return totalErrors === 0;
|
|
168
|
+
} catch {
|
|
169
|
+
// Failed to parse, assume errors
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
175
|
+
logError('Lint check failed', errorObj, { filePath });
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Run custom validation command
|
|
182
|
+
*/
|
|
183
|
+
async function runCustomValidation(command: string): Promise<boolean> {
|
|
184
|
+
logDebug('Running custom validation', { command });
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
await execAsync(command, {
|
|
188
|
+
timeout: 60000, // 60 second timeout
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
logDebug('Custom validation passed', { command });
|
|
192
|
+
return true;
|
|
193
|
+
} catch (error) {
|
|
194
|
+
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
195
|
+
logError('Custom validation failed', errorObj, { command });
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Generate default acceptance criteria for a task
|
|
202
|
+
*/
|
|
203
|
+
export function generateDefaultCriteria(task: Task): AcceptanceCriterion[] {
|
|
204
|
+
const criteria: AcceptanceCriterion[] = [];
|
|
205
|
+
|
|
206
|
+
// If task plan exists, generate criteria based on files
|
|
207
|
+
if (task.plan) {
|
|
208
|
+
// Check that all created files exist
|
|
209
|
+
const createSteps = task.plan.steps.filter(s => s.mode === 'create');
|
|
210
|
+
for (const step of createSteps) {
|
|
211
|
+
criteria.push({
|
|
212
|
+
description: `File ${step.target_file} exists`,
|
|
213
|
+
type: 'file_exists',
|
|
214
|
+
check: step.target_file,
|
|
215
|
+
met: false,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// If it's a test file, add a test_passes criterion
|
|
219
|
+
if (step.target_file.includes('.test.')) {
|
|
220
|
+
criteria.push({
|
|
221
|
+
description: `Tests in ${step.target_file} pass`,
|
|
222
|
+
type: 'test_passes',
|
|
223
|
+
check: step.target_file,
|
|
224
|
+
met: false,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Add lint check for all touched files
|
|
230
|
+
const allFiles = new Set([
|
|
231
|
+
...createSteps.map(s => s.target_file),
|
|
232
|
+
...task.plan.steps.filter(s => s.mode !== 'create').map(s => s.target_file),
|
|
233
|
+
]);
|
|
234
|
+
|
|
235
|
+
for (const file of allFiles) {
|
|
236
|
+
// Only check non-test files for lint
|
|
237
|
+
if (!file.includes('.test.')) {
|
|
238
|
+
criteria.push({
|
|
239
|
+
description: `No lint errors in ${file}`,
|
|
240
|
+
type: 'no_lint_errors',
|
|
241
|
+
check: file,
|
|
242
|
+
met: false,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return criteria;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Check if task can be marked as completed
|
|
253
|
+
*/
|
|
254
|
+
export function canCompleteTask(task: Task): boolean {
|
|
255
|
+
// All steps must be completed
|
|
256
|
+
if (task.steps_completed < task.steps_total) {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// All acceptance criteria must be met
|
|
261
|
+
if (task.acceptance_criteria.length > 0) {
|
|
262
|
+
return task.acceptance_criteria.every(c => c.met);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// If no criteria defined, task is complete when all steps done
|
|
266
|
+
return true;
|
|
267
|
+
}
|