mindforge-cc 1.0.0 → 1.0.2
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/CHANGELOG.md +14 -0
- package/bin/installer-core.js +3 -3
- package/bin/wizard/setup-wizard.js +1 -1
- package/package.json +20 -4
- package/.forge/org/CONVENTIONS.md +0 -0
- package/.forge/org/ORG.md +0 -0
- package/.forge/org/SECURITY.md +0 -0
- package/.forge/org/TOOLS.md +0 -0
- package/.forge/personas/analyst.md +0 -0
- package/.forge/personas/architect.md +0 -0
- package/.forge/personas/debug-specialist.md +0 -0
- package/.forge/personas/developer.md +0 -26
- package/.forge/personas/qa-engineer.md +0 -0
- package/.forge/personas/release-manager.md +0 -0
- package/.forge/personas/security-reviewer.md +0 -33
- package/.forge/personas/tech-writer.md +0 -0
- package/.forge/skills/api-design/SKILL.md +0 -0
- package/.forge/skills/code-quality/SKILL.md +0 -0
- package/.forge/skills/documentation/SKILL.md +0 -0
- package/.forge/skills/security-review/SKILL.md +0 -23
- package/.forge/skills/testing-standards/SKILL.md +0 -27
- package/.github/workflows/mindforge-ci.yml +0 -224
- package/.gitlab-ci-mindforge.yml +0 -18
- package/eslint.config.mjs +0 -31
- package/implementation-roadmap/day-1-imp/DAY1-HARDEN.md +0 -823
- package/implementation-roadmap/day-1-imp/DAY1-IMPLEMENT.md +0 -2459
- package/implementation-roadmap/day-1-imp/DAY1-REVIEW.md +0 -288
- package/implementation-roadmap/day-2-imp/DAY2-HARDEN.md +0 -954
- package/implementation-roadmap/day-2-imp/DAY2-IMPLEMENT.md +0 -2347
- package/implementation-roadmap/day-2-imp/DAY2-REVIEW.md +0 -422
- package/implementation-roadmap/day-3-imp/DAY3-HARDEN.md +0 -870
- package/implementation-roadmap/day-3-imp/DAY3-IMPLEMENT.md +0 -2798
- package/implementation-roadmap/day-3-imp/DAY3-REVIEW.md +0 -484
- package/implementation-roadmap/day-4-imp/DAY4-HARDEN.md +0 -1087
- package/implementation-roadmap/day-4-imp/DAY4-IMPLEMENT.md +0 -2874
- package/implementation-roadmap/day-4-imp/DAY4-REVIEW.md +0 -386
- package/implementation-roadmap/day-5-imp/DAY5-HARDEN.md +0 -1078
- package/implementation-roadmap/day-5-imp/DAY5-IMPLEMENT.md +0 -3151
- package/implementation-roadmap/day-5-imp/DAY5-REVIEW.md +0 -345
- package/implementation-roadmap/day-6-imp/DAY6-COMPLETE.md +0 -3919
- package/implementation-roadmap/day-7-imp-prod/DAY7-PRODUCTION-FINAL.md +0 -4513
- package/sdk/README.md +0 -69
- package/sdk/eslint.config.mjs +0 -34
- package/sdk/package-lock.json +0 -1507
- package/sdk/package.json +0 -30
- package/sdk/src/client.ts +0 -133
- package/sdk/src/commands.ts +0 -63
- package/sdk/src/events.ts +0 -166
- package/sdk/src/index.ts +0 -22
- package/sdk/src/types.ts +0 -87
- package/sdk/tsconfig.json +0 -13
- package/tests/audit.test.js +0 -206
- package/tests/ci-mode.test.js +0 -162
- package/tests/compaction.test.js +0 -161
- package/tests/distribution.test.js +0 -205
- package/tests/e2e.test.js +0 -618
- package/tests/governance.test.js +0 -130
- package/tests/install.test.js +0 -209
- package/tests/integrations.test.js +0 -128
- package/tests/intelligence.test.js +0 -117
- package/tests/metrics.test.js +0 -96
- package/tests/migration.test.js +0 -309
- package/tests/production.test.js +0 -416
- package/tests/sdk.test.js +0 -200
- package/tests/skills-platform.test.js +0 -403
- package/tests/wave-engine.test.js +0 -338
|
@@ -1,338 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MindForge Wave Engine Tests
|
|
3
|
-
* Tests: dependency parsing, wave grouping, and execution planning
|
|
4
|
-
* Run: node tests/wave-engine.test.js
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
const assert = require('assert');
|
|
10
|
-
|
|
11
|
-
let passed = 0;
|
|
12
|
-
let failed = 0;
|
|
13
|
-
|
|
14
|
-
function test(name, fn) {
|
|
15
|
-
try {
|
|
16
|
-
fn();
|
|
17
|
-
console.log(` ✅ ${name}`);
|
|
18
|
-
passed++;
|
|
19
|
-
} catch (err) {
|
|
20
|
-
console.error(` ❌ ${name}`);
|
|
21
|
-
console.error(` ${err.message}`);
|
|
22
|
-
failed++;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// ── Simulate the dependency parser and wave grouper ───────────────────────────
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Simulates parsing a PLAN file's dependency field
|
|
30
|
-
* In real execution, this reads from the actual XML PLAN files
|
|
31
|
-
*/
|
|
32
|
-
function parseDependencies(depString) {
|
|
33
|
-
if (!depString || depString.trim().toLowerCase() === 'none') return [];
|
|
34
|
-
return depString.split(',').map(d => d.trim()).filter(Boolean);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Simulates the wave grouping algorithm (Kahn's topological sort)
|
|
39
|
-
* Input: { "01": { dependsOn: [] }, "02": { dependsOn: ["01"] }, ... }
|
|
40
|
-
* Output: [["01"], ["02"], ...]
|
|
41
|
-
*/
|
|
42
|
-
function groupIntoWaves(graph) {
|
|
43
|
-
const remaining = new Set(Object.keys(graph));
|
|
44
|
-
const completed = new Set();
|
|
45
|
-
const waves = [];
|
|
46
|
-
|
|
47
|
-
while (remaining.size > 0) {
|
|
48
|
-
const wave = [];
|
|
49
|
-
for (const id of remaining) {
|
|
50
|
-
const deps = graph[id].dependsOn;
|
|
51
|
-
if (deps.every(d => completed.has(d))) {
|
|
52
|
-
wave.push(id);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (wave.length === 0 && remaining.size > 0) {
|
|
57
|
-
throw new Error(`Circular dependency detected among: ${[...remaining].join(', ')}`);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
waves.push(wave.sort());
|
|
61
|
-
wave.forEach(id => { completed.add(id); remaining.delete(id); });
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return waves;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Detects circular dependencies
|
|
69
|
-
*/
|
|
70
|
-
function hasCircularDependency(graph) {
|
|
71
|
-
try {
|
|
72
|
-
groupIntoWaves(graph);
|
|
73
|
-
return false;
|
|
74
|
-
} catch {
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Detects file conflicts between plans
|
|
81
|
-
*/
|
|
82
|
-
function findFileConflicts(plans) {
|
|
83
|
-
const fileMap = {};
|
|
84
|
-
const conflicts = [];
|
|
85
|
-
|
|
86
|
-
plans.forEach(({ id, files }) => {
|
|
87
|
-
files.forEach(file => {
|
|
88
|
-
if (fileMap[file]) {
|
|
89
|
-
conflicts.push({ file, plans: [fileMap[file], id] });
|
|
90
|
-
} else {
|
|
91
|
-
fileMap[file] = id;
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
return conflicts;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// ── Tests ─────────────────────────────────────────────────────────────────────
|
|
100
|
-
|
|
101
|
-
console.log('\nMindForge Day 2 — Wave Engine Tests\n');
|
|
102
|
-
|
|
103
|
-
console.log('Dependency parsing:');
|
|
104
|
-
|
|
105
|
-
test('parses "none" as empty dependencies', () => {
|
|
106
|
-
assert.deepStrictEqual(parseDependencies('none'), []);
|
|
107
|
-
assert.deepStrictEqual(parseDependencies('None'), []);
|
|
108
|
-
assert.deepStrictEqual(parseDependencies('NONE'), []);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
test('parses single dependency', () => {
|
|
112
|
-
assert.deepStrictEqual(parseDependencies('01'), ['01']);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test('parses multiple dependencies', () => {
|
|
116
|
-
assert.deepStrictEqual(parseDependencies('01, 02, 03'), ['01', '02', '03']);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
test('handles whitespace in dependency list', () => {
|
|
120
|
-
assert.deepStrictEqual(parseDependencies('01,02, 03'), ['01', '02', '03']);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
test('parses empty string as no dependencies', () => {
|
|
124
|
-
assert.deepStrictEqual(parseDependencies(''), []);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
console.log('\nWave grouping algorithm:');
|
|
128
|
-
|
|
129
|
-
test('single task with no dependencies → 1 wave', () => {
|
|
130
|
-
const graph = { '01': { dependsOn: [] } };
|
|
131
|
-
const waves = groupIntoWaves(graph);
|
|
132
|
-
assert.deepStrictEqual(waves, [['01']]);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
test('two independent tasks → 1 wave with both', () => {
|
|
136
|
-
const graph = {
|
|
137
|
-
'01': { dependsOn: [] },
|
|
138
|
-
'02': { dependsOn: [] },
|
|
139
|
-
};
|
|
140
|
-
const waves = groupIntoWaves(graph);
|
|
141
|
-
assert.strictEqual(waves.length, 1);
|
|
142
|
-
assert.deepStrictEqual(waves[0].sort(), ['01', '02']);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
test('sequential dependency chain → 3 waves, 1 task each', () => {
|
|
146
|
-
const graph = {
|
|
147
|
-
'01': { dependsOn: [] },
|
|
148
|
-
'02': { dependsOn: ['01'] },
|
|
149
|
-
'03': { dependsOn: ['02'] },
|
|
150
|
-
};
|
|
151
|
-
const waves = groupIntoWaves(graph);
|
|
152
|
-
assert.strictEqual(waves.length, 3);
|
|
153
|
-
assert.deepStrictEqual(waves[0], ['01']);
|
|
154
|
-
assert.deepStrictEqual(waves[1], ['02']);
|
|
155
|
-
assert.deepStrictEqual(waves[2], ['03']);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
test('diamond dependency (fan-out then fan-in)', () => {
|
|
159
|
-
const graph = {
|
|
160
|
-
'01': { dependsOn: [] },
|
|
161
|
-
'02': { dependsOn: ['01'] },
|
|
162
|
-
'03': { dependsOn: ['01'] },
|
|
163
|
-
'04': { dependsOn: ['02', '03'] },
|
|
164
|
-
};
|
|
165
|
-
const waves = groupIntoWaves(graph);
|
|
166
|
-
assert.strictEqual(waves.length, 3);
|
|
167
|
-
assert.deepStrictEqual(waves[0], ['01']);
|
|
168
|
-
assert.deepStrictEqual(waves[1].sort(), ['02', '03']);
|
|
169
|
-
assert.deepStrictEqual(waves[2], ['04']);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
test('5-plan realistic example (user model → api → checkout)', () => {
|
|
173
|
-
const graph = {
|
|
174
|
-
'01': { dependsOn: [] },
|
|
175
|
-
'02': { dependsOn: [] },
|
|
176
|
-
'03': { dependsOn: ['01'] },
|
|
177
|
-
'04': { dependsOn: ['02'] },
|
|
178
|
-
'05': { dependsOn: ['03', '04'] },
|
|
179
|
-
};
|
|
180
|
-
const waves = groupIntoWaves(graph);
|
|
181
|
-
assert.strictEqual(waves.length, 3);
|
|
182
|
-
assert.deepStrictEqual(waves[0].sort(), ['01', '02']);
|
|
183
|
-
assert.deepStrictEqual(waves[1].sort(), ['03', '04']);
|
|
184
|
-
assert.deepStrictEqual(waves[2], ['05']);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
console.log('\nCircular dependency detection:');
|
|
188
|
-
|
|
189
|
-
test('detects direct circular dependency (A → B → A)', () => {
|
|
190
|
-
const graph = {
|
|
191
|
-
'01': { dependsOn: ['02'] },
|
|
192
|
-
'02': { dependsOn: ['01'] },
|
|
193
|
-
};
|
|
194
|
-
assert.strictEqual(hasCircularDependency(graph), true);
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
test('detects indirect circular dependency (A → B → C → A)', () => {
|
|
198
|
-
const graph = {
|
|
199
|
-
'01': { dependsOn: ['03'] },
|
|
200
|
-
'02': { dependsOn: ['01'] },
|
|
201
|
-
'03': { dependsOn: ['02'] },
|
|
202
|
-
};
|
|
203
|
-
assert.strictEqual(hasCircularDependency(graph), true);
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
test('does not false-positive on valid DAG', () => {
|
|
207
|
-
const graph = {
|
|
208
|
-
'01': { dependsOn: [] },
|
|
209
|
-
'02': { dependsOn: ['01'] },
|
|
210
|
-
'03': { dependsOn: ['01'] },
|
|
211
|
-
'04': { dependsOn: ['02', '03'] },
|
|
212
|
-
};
|
|
213
|
-
assert.strictEqual(hasCircularDependency(graph), false);
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
console.log('\nFile conflict detection:');
|
|
217
|
-
|
|
218
|
-
test('detects conflict when two plans modify the same file', () => {
|
|
219
|
-
const plans = [
|
|
220
|
-
{ id: '01', files: ['src/models/user.ts', 'src/models/user.test.ts'] },
|
|
221
|
-
{ id: '02', files: ['src/models/product.ts'] },
|
|
222
|
-
{ id: '03', files: ['src/models/user.ts'] },
|
|
223
|
-
];
|
|
224
|
-
const conflicts = findFileConflicts(plans);
|
|
225
|
-
assert.strictEqual(conflicts.length, 1);
|
|
226
|
-
assert.strictEqual(conflicts[0].file, 'src/models/user.ts');
|
|
227
|
-
assert.deepStrictEqual(conflicts[0].plans.sort(), ['01', '03']);
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
test('no conflicts when all plans touch different files', () => {
|
|
231
|
-
const plans = [
|
|
232
|
-
{ id: '01', files: ['src/models/user.ts'] },
|
|
233
|
-
{ id: '02', files: ['src/models/product.ts'] },
|
|
234
|
-
{ id: '03', files: ['src/api/orders.ts'] },
|
|
235
|
-
];
|
|
236
|
-
const conflicts = findFileConflicts(plans);
|
|
237
|
-
assert.strictEqual(conflicts.length, 0);
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
console.log('\nAdditional edge cases:');
|
|
241
|
-
|
|
242
|
-
test('handles empty graph (zero plans)', () => {
|
|
243
|
-
const waves = groupIntoWaves({});
|
|
244
|
-
assert.deepStrictEqual(waves, []);
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
test('detects self-referencing dependency (plan depends on itself)', () => {
|
|
248
|
-
const graph = { '01': { dependsOn: ['01'] } };
|
|
249
|
-
assert.strictEqual(hasCircularDependency(graph), true);
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
test('three plans all touching the same file — all conflict', () => {
|
|
253
|
-
const plans = [
|
|
254
|
-
{ id: '01', files: ['src/shared.ts'] },
|
|
255
|
-
{ id: '02', files: ['src/shared.ts'] },
|
|
256
|
-
{ id: '03', files: ['src/shared.ts'] },
|
|
257
|
-
];
|
|
258
|
-
const conflicts = findFileConflicts(plans);
|
|
259
|
-
assert.ok(conflicts.length >= 2, `Expected >= 2 conflicts, got ${conflicts.length}`);
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
test('6-plan complex graph groups correctly', () => {
|
|
263
|
-
const graph = {
|
|
264
|
-
'01': { dependsOn: [] },
|
|
265
|
-
'02': { dependsOn: [] },
|
|
266
|
-
'03': { dependsOn: [] },
|
|
267
|
-
'04': { dependsOn: ['01', '02'] },
|
|
268
|
-
'05': { dependsOn: ['02', '03'] },
|
|
269
|
-
'06': { dependsOn: ['04', '05'] },
|
|
270
|
-
};
|
|
271
|
-
const waves = groupIntoWaves(graph);
|
|
272
|
-
assert.strictEqual(waves.length, 3);
|
|
273
|
-
assert.deepStrictEqual(waves[0].sort(), ['01', '02', '03']);
|
|
274
|
-
assert.deepStrictEqual(waves[1].sort(), ['04', '05']);
|
|
275
|
-
assert.deepStrictEqual(waves[2], ['06']);
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
test('single linear chain of 4 plans → 4 waves', () => {
|
|
279
|
-
const graph = {
|
|
280
|
-
'01': { dependsOn: [] },
|
|
281
|
-
'02': { dependsOn: ['01'] },
|
|
282
|
-
'03': { dependsOn: ['02'] },
|
|
283
|
-
'04': { dependsOn: ['03'] },
|
|
284
|
-
};
|
|
285
|
-
const waves = groupIntoWaves(graph);
|
|
286
|
-
assert.strictEqual(waves.length, 4);
|
|
287
|
-
waves.forEach((wave, i) => {
|
|
288
|
-
const expectedId = String(i + 1).padStart(2, '0');
|
|
289
|
-
assert.deepStrictEqual(wave, [expectedId]);
|
|
290
|
-
});
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
test('wave executor stops on first failure — does not cascade', () => {
|
|
294
|
-
// Simulates: Wave 1 has 3 tasks. Task 02 fails.
|
|
295
|
-
// Expected: tasks 01 and 03 may run, but Wave 2 must NOT start.
|
|
296
|
-
const executionLog = [];
|
|
297
|
-
|
|
298
|
-
function simulateWaveExecution(graph, failingPlan) {
|
|
299
|
-
const waves = groupIntoWaves(graph);
|
|
300
|
-
let phaseFailed = false;
|
|
301
|
-
|
|
302
|
-
for (const wave of waves) {
|
|
303
|
-
if (phaseFailed) break;
|
|
304
|
-
for (const planId of wave) {
|
|
305
|
-
if (planId === failingPlan) {
|
|
306
|
-
executionLog.push({ plan: planId, status: 'failed' });
|
|
307
|
-
phaseFailed = true;
|
|
308
|
-
} else if (!phaseFailed) {
|
|
309
|
-
executionLog.push({ plan: planId, status: 'completed' });
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
return { phaseFailed, executionLog };
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
const graph = {
|
|
317
|
-
'01': { dependsOn: [] },
|
|
318
|
-
'02': { dependsOn: [] },
|
|
319
|
-
'03': { dependsOn: [] },
|
|
320
|
-
'04': { dependsOn: ['01', '03'] },
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
const result = simulateWaveExecution(graph, '02');
|
|
324
|
-
assert.strictEqual(result.phaseFailed, true);
|
|
325
|
-
const plan04Executed = result.executionLog.some(e => e.plan === '04');
|
|
326
|
-
assert.strictEqual(plan04Executed, false, 'Plan 04 should not execute after wave failure');
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
// ── Results ───────────────────────────────────────────────────────────────────
|
|
330
|
-
console.log(`\n${'─'.repeat(50)}`);
|
|
331
|
-
console.log(`Results: ${passed} passed, ${failed} failed`);
|
|
332
|
-
|
|
333
|
-
if (failed > 0) {
|
|
334
|
-
console.error(`\n❌ ${failed} test(s) failed.\n`);
|
|
335
|
-
process.exit(1);
|
|
336
|
-
} else {
|
|
337
|
-
console.log(`\n✅ All wave engine tests passed.\n`);
|
|
338
|
-
}
|