@lumenflow/cli 2.20.1 → 2.21.1
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/README.md +8 -4
- package/dist/hooks/enforcement-checks.js +120 -0
- package/dist/hooks/enforcement-checks.js.map +1 -1
- package/dist/init-lane-validation.js +141 -0
- package/dist/init-lane-validation.js.map +1 -0
- package/dist/init-templates.js +36 -8
- package/dist/init-templates.js.map +1 -1
- package/dist/init.js +27 -58
- package/dist/init.js.map +1 -1
- package/dist/initiative-create.js +35 -4
- package/dist/initiative-create.js.map +1 -1
- package/dist/lane-lifecycle-process.js +364 -0
- package/dist/lane-lifecycle-process.js.map +1 -0
- package/dist/lane-lock.js +41 -0
- package/dist/lane-lock.js.map +1 -0
- package/dist/lane-setup.js +55 -0
- package/dist/lane-setup.js.map +1 -0
- package/dist/lane-status.js +38 -0
- package/dist/lane-status.js.map +1 -0
- package/dist/lane-validate.js +43 -0
- package/dist/lane-validate.js.map +1 -0
- package/dist/onboarding-smoke-test.js +17 -0
- package/dist/onboarding-smoke-test.js.map +1 -1
- package/dist/public-manifest.js +28 -0
- package/dist/public-manifest.js.map +1 -1
- package/dist/wu-claim-cloud.js +16 -0
- package/dist/wu-claim-cloud.js.map +1 -1
- package/dist/wu-claim.js +12 -2
- package/dist/wu-claim.js.map +1 -1
- package/dist/wu-create-content.js +8 -2
- package/dist/wu-create-content.js.map +1 -1
- package/dist/wu-create-validation.js +5 -3
- package/dist/wu-create-validation.js.map +1 -1
- package/dist/wu-create.js +21 -1
- package/dist/wu-create.js.map +1 -1
- package/dist/wu-done.js +57 -8
- package/dist/wu-done.js.map +1 -1
- package/dist/wu-prep.js +22 -0
- package/dist/wu-prep.js.map +1 -1
- package/package.json +15 -11
- package/dist/__tests__/agent-log-issue.test.js +0 -56
- package/dist/__tests__/agent-spawn-coordination.test.js +0 -451
- package/dist/__tests__/backlog-prune.test.js +0 -478
- package/dist/__tests__/cli-entry-point.test.js +0 -160
- package/dist/__tests__/cli-subprocess.test.js +0 -89
- package/dist/__tests__/commands/integrate.test.js +0 -165
- package/dist/__tests__/commands.test.js +0 -271
- package/dist/__tests__/deps-operations.test.js +0 -206
- package/dist/__tests__/doctor.test.js +0 -510
- package/dist/__tests__/file-operations.test.js +0 -906
- package/dist/__tests__/flow-report.test.js +0 -24
- package/dist/__tests__/gates-config.test.js +0 -303
- package/dist/__tests__/gates-integration-tests.test.js +0 -112
- package/dist/__tests__/git-operations.test.js +0 -668
- package/dist/__tests__/guard-main-branch.test.js +0 -79
- package/dist/__tests__/guards-validation.test.js +0 -416
- package/dist/__tests__/hooks/enforcement.test.js +0 -279
- package/dist/__tests__/init-config-lanes.test.js +0 -131
- package/dist/__tests__/init-docs-structure.test.js +0 -152
- package/dist/__tests__/init-greenfield.test.js +0 -247
- package/dist/__tests__/init-lane-inference.test.js +0 -125
- package/dist/__tests__/init-onboarding-docs.test.js +0 -132
- package/dist/__tests__/init-quick-ref.test.js +0 -144
- package/dist/__tests__/init-scripts.test.js +0 -207
- package/dist/__tests__/init-template-portability.test.js +0 -96
- package/dist/__tests__/init.test.js +0 -968
- package/dist/__tests__/initiative-add-wu.test.js +0 -490
- package/dist/__tests__/initiative-e2e.test.js +0 -442
- package/dist/__tests__/initiative-plan-replacement.test.js +0 -161
- package/dist/__tests__/initiative-plan.test.js +0 -340
- package/dist/__tests__/initiative-remove-wu.test.js +0 -458
- package/dist/__tests__/lumenflow-upgrade.test.js +0 -260
- package/dist/__tests__/mem-cleanup-execution.test.js +0 -19
- package/dist/__tests__/memory-integration.test.js +0 -333
- package/dist/__tests__/merge-block.test.js +0 -220
- package/dist/__tests__/metrics-cli.test.js +0 -619
- package/dist/__tests__/metrics-snapshot.test.js +0 -24
- package/dist/__tests__/no-beacon-references-docs.test.js +0 -30
- package/dist/__tests__/no-beacon-references.test.js +0 -39
- package/dist/__tests__/onboarding-smoke-test.test.js +0 -211
- package/dist/__tests__/path-centralization-cli.test.js +0 -234
- package/dist/__tests__/plan-create.test.js +0 -126
- package/dist/__tests__/plan-edit.test.js +0 -157
- package/dist/__tests__/plan-link.test.js +0 -239
- package/dist/__tests__/plan-promote.test.js +0 -181
- package/dist/__tests__/release.test.js +0 -372
- package/dist/__tests__/rotate-progress.test.js +0 -127
- package/dist/__tests__/safe-git.test.js +0 -190
- package/dist/__tests__/session-coordinator.test.js +0 -109
- package/dist/__tests__/state-bootstrap.test.js +0 -432
- package/dist/__tests__/state-doctor.test.js +0 -328
- package/dist/__tests__/sync-templates.test.js +0 -255
- package/dist/__tests__/templates-sync.test.js +0 -219
- package/dist/__tests__/trace-gen.test.js +0 -115
- package/dist/__tests__/wu-create-required-fields.test.js +0 -143
- package/dist/__tests__/wu-create-strict.test.js +0 -118
- package/dist/__tests__/wu-create.test.js +0 -121
- package/dist/__tests__/wu-done-auto-cleanup.test.js +0 -135
- package/dist/__tests__/wu-done-docs-only-policy.test.js +0 -20
- package/dist/__tests__/wu-done-staging-whitelist.test.js +0 -35
- package/dist/__tests__/wu-done.test.js +0 -36
- package/dist/__tests__/wu-edit-strict.test.js +0 -109
- package/dist/__tests__/wu-edit.test.js +0 -119
- package/dist/__tests__/wu-lifecycle-integration.test.js +0 -388
- package/dist/__tests__/wu-prep-default-exec.test.js +0 -35
- package/dist/__tests__/wu-prep.test.js +0 -140
- package/dist/__tests__/wu-proto.test.js +0 -97
- package/dist/__tests__/wu-validate-strict.test.js +0 -113
- package/dist/__tests__/wu-validate.test.js +0 -36
- package/dist/spawn-list.js +0 -143
- package/dist/spawn-list.js.map +0 -1
|
@@ -1,432 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* @file state-bootstrap.test.ts
|
|
4
|
-
* @description Tests for state-bootstrap CLI command (WU-1107)
|
|
5
|
-
*
|
|
6
|
-
* state-bootstrap is a one-time migration utility that:
|
|
7
|
-
* - Reads all WU YAML files
|
|
8
|
-
* - Generates corresponding events in the state store
|
|
9
|
-
* - Allows migration from YAML-only repos to event-sourced state
|
|
10
|
-
*
|
|
11
|
-
* TDD: RED phase - these tests define expected behavior before implementation
|
|
12
|
-
*/
|
|
13
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
14
|
-
import { existsSync, mkdirSync, writeFileSync, rmSync, readFileSync } from 'node:fs';
|
|
15
|
-
import { join } from 'node:path';
|
|
16
|
-
import { tmpdir } from 'node:os';
|
|
17
|
-
import { fileURLToPath } from 'node:url';
|
|
18
|
-
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
19
|
-
// These imports will fail until we implement the module (RED phase)
|
|
20
|
-
// We define the expected exports here
|
|
21
|
-
import { parseStateBootstrapArgs, inferEventsFromWu, generateBootstrapEvents, runStateBootstrap, STATE_BOOTSTRAP_DEFAULTS, } from '../state-bootstrap.js';
|
|
22
|
-
describe('state-bootstrap CLI', () => {
|
|
23
|
-
describe('source file existence', () => {
|
|
24
|
-
it('should have the CLI source file', () => {
|
|
25
|
-
const srcPath = join(__dirname, '../state-bootstrap.ts');
|
|
26
|
-
expect(existsSync(srcPath)).toBe(true);
|
|
27
|
-
});
|
|
28
|
-
it('should be buildable (dist file exists after build)', () => {
|
|
29
|
-
// This test verifies that tsc compiled the file successfully
|
|
30
|
-
const distPath = join(__dirname, '../../dist/state-bootstrap.js');
|
|
31
|
-
expect(existsSync(distPath)).toBe(true);
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
describe('STATE_BOOTSTRAP_DEFAULTS', () => {
|
|
35
|
-
it('should have default WU directory path', () => {
|
|
36
|
-
expect(STATE_BOOTSTRAP_DEFAULTS.wuDir).toBeTypeOf('string');
|
|
37
|
-
});
|
|
38
|
-
it('should have default state directory path', () => {
|
|
39
|
-
expect(STATE_BOOTSTRAP_DEFAULTS.stateDir).toBeTypeOf('string');
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
describe('parseStateBootstrapArgs', () => {
|
|
43
|
-
it('should parse --dry-run flag (default)', () => {
|
|
44
|
-
const args = parseStateBootstrapArgs(['node', 'state-bootstrap']);
|
|
45
|
-
expect(args.dryRun).toBe(true);
|
|
46
|
-
});
|
|
47
|
-
it('should parse --execute flag', () => {
|
|
48
|
-
const args = parseStateBootstrapArgs(['node', 'state-bootstrap', '--execute']);
|
|
49
|
-
expect(args.dryRun).toBe(false);
|
|
50
|
-
});
|
|
51
|
-
it('should parse --wu-dir option', () => {
|
|
52
|
-
const args = parseStateBootstrapArgs([
|
|
53
|
-
'node',
|
|
54
|
-
'state-bootstrap',
|
|
55
|
-
'--wu-dir',
|
|
56
|
-
'/custom/wu/path',
|
|
57
|
-
]);
|
|
58
|
-
expect(args.wuDir).toBe('/custom/wu/path');
|
|
59
|
-
});
|
|
60
|
-
it('should parse --state-dir option', () => {
|
|
61
|
-
const args = parseStateBootstrapArgs([
|
|
62
|
-
'node',
|
|
63
|
-
'state-bootstrap',
|
|
64
|
-
'--state-dir',
|
|
65
|
-
'/custom/state/path',
|
|
66
|
-
]);
|
|
67
|
-
expect(args.stateDir).toBe('/custom/state/path');
|
|
68
|
-
});
|
|
69
|
-
it('should parse --help flag', () => {
|
|
70
|
-
const args = parseStateBootstrapArgs(['node', 'state-bootstrap', '--help']);
|
|
71
|
-
expect(args.help).toBe(true);
|
|
72
|
-
});
|
|
73
|
-
it('should parse -h flag as help', () => {
|
|
74
|
-
const args = parseStateBootstrapArgs(['node', 'state-bootstrap', '-h']);
|
|
75
|
-
expect(args.help).toBe(true);
|
|
76
|
-
});
|
|
77
|
-
it('should parse --force flag to overwrite existing state', () => {
|
|
78
|
-
const args = parseStateBootstrapArgs(['node', 'state-bootstrap', '--force']);
|
|
79
|
-
expect(args.force).toBe(true);
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
describe('inferEventsFromWu', () => {
|
|
83
|
-
it('should generate claim event for in_progress WU', () => {
|
|
84
|
-
const wu = {
|
|
85
|
-
id: 'WU-100',
|
|
86
|
-
status: 'in_progress',
|
|
87
|
-
lane: 'Framework: CLI',
|
|
88
|
-
title: 'Test WU',
|
|
89
|
-
created: '2026-01-20',
|
|
90
|
-
claimed_at: '2026-01-20T10:00:00Z',
|
|
91
|
-
};
|
|
92
|
-
const events = inferEventsFromWu(wu);
|
|
93
|
-
expect(events).toHaveLength(1);
|
|
94
|
-
expect(events[0].type).toBe('claim');
|
|
95
|
-
expect(events[0].wuId).toBe('WU-100');
|
|
96
|
-
expect(events[0].lane).toBe('Framework: CLI');
|
|
97
|
-
expect(events[0].title).toBe('Test WU');
|
|
98
|
-
});
|
|
99
|
-
it('should generate claim and complete events for done WU', () => {
|
|
100
|
-
const wu = {
|
|
101
|
-
id: 'WU-100',
|
|
102
|
-
status: 'done',
|
|
103
|
-
lane: 'Framework: CLI',
|
|
104
|
-
title: 'Test WU',
|
|
105
|
-
created: '2026-01-15',
|
|
106
|
-
claimed_at: '2026-01-15T10:00:00Z',
|
|
107
|
-
completed_at: '2026-01-20T15:00:00Z',
|
|
108
|
-
};
|
|
109
|
-
const events = inferEventsFromWu(wu);
|
|
110
|
-
expect(events).toHaveLength(2);
|
|
111
|
-
expect(events[0].type).toBe('claim');
|
|
112
|
-
expect(events[1].type).toBe('complete');
|
|
113
|
-
expect(events[1].wuId).toBe('WU-100');
|
|
114
|
-
});
|
|
115
|
-
it('should generate claim and block events for blocked WU', () => {
|
|
116
|
-
const wu = {
|
|
117
|
-
id: 'WU-100',
|
|
118
|
-
status: 'blocked',
|
|
119
|
-
lane: 'Framework: CLI',
|
|
120
|
-
title: 'Test WU',
|
|
121
|
-
created: '2026-01-15',
|
|
122
|
-
claimed_at: '2026-01-15T10:00:00Z',
|
|
123
|
-
};
|
|
124
|
-
const events = inferEventsFromWu(wu);
|
|
125
|
-
expect(events).toHaveLength(2);
|
|
126
|
-
expect(events[0].type).toBe('claim');
|
|
127
|
-
expect(events[1].type).toBe('block');
|
|
128
|
-
});
|
|
129
|
-
it('should return empty array for ready WU (not yet claimed)', () => {
|
|
130
|
-
const wu = {
|
|
131
|
-
id: 'WU-100',
|
|
132
|
-
status: 'ready',
|
|
133
|
-
lane: 'Framework: CLI',
|
|
134
|
-
title: 'Test WU',
|
|
135
|
-
created: '2026-01-20',
|
|
136
|
-
};
|
|
137
|
-
const events = inferEventsFromWu(wu);
|
|
138
|
-
expect(events).toHaveLength(0);
|
|
139
|
-
});
|
|
140
|
-
it('should use created date as fallback for claim timestamp', () => {
|
|
141
|
-
const wu = {
|
|
142
|
-
id: 'WU-100',
|
|
143
|
-
status: 'in_progress',
|
|
144
|
-
lane: 'Framework: CLI',
|
|
145
|
-
title: 'Test WU',
|
|
146
|
-
created: '2026-01-20',
|
|
147
|
-
// No claimed_at
|
|
148
|
-
};
|
|
149
|
-
const events = inferEventsFromWu(wu);
|
|
150
|
-
expect(events).toHaveLength(1);
|
|
151
|
-
expect(events[0].timestamp).toContain('2026-01-20');
|
|
152
|
-
});
|
|
153
|
-
it('should handle legacy completed status same as done', () => {
|
|
154
|
-
const wu = {
|
|
155
|
-
id: 'WU-100',
|
|
156
|
-
status: 'completed',
|
|
157
|
-
lane: 'Framework: CLI',
|
|
158
|
-
title: 'Test WU',
|
|
159
|
-
created: '2026-01-15',
|
|
160
|
-
claimed_at: '2026-01-15T10:00:00Z',
|
|
161
|
-
completed_at: '2026-01-20T15:00:00Z',
|
|
162
|
-
};
|
|
163
|
-
const events = inferEventsFromWu(wu);
|
|
164
|
-
expect(events).toHaveLength(2);
|
|
165
|
-
expect(events[0].type).toBe('claim');
|
|
166
|
-
expect(events[1].type).toBe('complete');
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
describe('generateBootstrapEvents', () => {
|
|
170
|
-
it('should generate events for multiple WUs', () => {
|
|
171
|
-
const wus = [
|
|
172
|
-
{
|
|
173
|
-
id: 'WU-100',
|
|
174
|
-
status: 'in_progress',
|
|
175
|
-
lane: 'Framework: CLI',
|
|
176
|
-
title: 'WU 100',
|
|
177
|
-
created: '2026-01-20',
|
|
178
|
-
},
|
|
179
|
-
{
|
|
180
|
-
id: 'WU-101',
|
|
181
|
-
status: 'done',
|
|
182
|
-
lane: 'Framework: Core',
|
|
183
|
-
title: 'WU 101',
|
|
184
|
-
created: '2026-01-15',
|
|
185
|
-
completed_at: '2026-01-18T10:00:00Z',
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
id: 'WU-102',
|
|
189
|
-
status: 'ready',
|
|
190
|
-
lane: 'Framework: CLI',
|
|
191
|
-
title: 'WU 102',
|
|
192
|
-
created: '2026-01-22',
|
|
193
|
-
},
|
|
194
|
-
];
|
|
195
|
-
const events = generateBootstrapEvents(wus);
|
|
196
|
-
// WU-100: 1 claim, WU-101: 1 claim + 1 complete, WU-102: 0 (ready)
|
|
197
|
-
expect(events).toHaveLength(3);
|
|
198
|
-
});
|
|
199
|
-
it('should order events chronologically', () => {
|
|
200
|
-
const wus = [
|
|
201
|
-
{
|
|
202
|
-
id: 'WU-102',
|
|
203
|
-
status: 'done',
|
|
204
|
-
lane: 'Framework: CLI',
|
|
205
|
-
title: 'WU 102',
|
|
206
|
-
created: '2026-01-20',
|
|
207
|
-
claimed_at: '2026-01-20T10:00:00Z',
|
|
208
|
-
completed_at: '2026-01-22T10:00:00Z',
|
|
209
|
-
},
|
|
210
|
-
{
|
|
211
|
-
id: 'WU-100',
|
|
212
|
-
status: 'done',
|
|
213
|
-
lane: 'Framework: Core',
|
|
214
|
-
title: 'WU 100',
|
|
215
|
-
created: '2026-01-15',
|
|
216
|
-
claimed_at: '2026-01-15T08:00:00Z',
|
|
217
|
-
completed_at: '2026-01-16T10:00:00Z',
|
|
218
|
-
},
|
|
219
|
-
];
|
|
220
|
-
const events = generateBootstrapEvents(wus);
|
|
221
|
-
// Events should be ordered: WU-100 claim, WU-100 complete, WU-102 claim, WU-102 complete
|
|
222
|
-
expect(events[0].wuId).toBe('WU-100');
|
|
223
|
-
expect(events[0].type).toBe('claim');
|
|
224
|
-
expect(events[1].wuId).toBe('WU-100');
|
|
225
|
-
expect(events[1].type).toBe('complete');
|
|
226
|
-
expect(events[2].wuId).toBe('WU-102');
|
|
227
|
-
expect(events[2].type).toBe('claim');
|
|
228
|
-
});
|
|
229
|
-
it('should return empty array for empty WU list', () => {
|
|
230
|
-
const events = generateBootstrapEvents([]);
|
|
231
|
-
expect(events).toHaveLength(0);
|
|
232
|
-
});
|
|
233
|
-
});
|
|
234
|
-
describe('runStateBootstrap', () => {
|
|
235
|
-
let tempDir;
|
|
236
|
-
beforeEach(() => {
|
|
237
|
-
// Create a temporary directory for test fixtures
|
|
238
|
-
tempDir = join(tmpdir(), `state-bootstrap-test-${Date.now()}`);
|
|
239
|
-
mkdirSync(join(tempDir, 'wu'), { recursive: true });
|
|
240
|
-
mkdirSync(join(tempDir, 'state'), { recursive: true });
|
|
241
|
-
});
|
|
242
|
-
afterEach(() => {
|
|
243
|
-
// Cleanup temp directory
|
|
244
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
245
|
-
});
|
|
246
|
-
it('should not write events in dry-run mode', async () => {
|
|
247
|
-
// Create a test WU YAML (lane value must be quoted due to colon)
|
|
248
|
-
const wuYaml = `id: WU-100
|
|
249
|
-
title: Test WU
|
|
250
|
-
lane: "Framework: CLI"
|
|
251
|
-
status: in_progress
|
|
252
|
-
created: 2026-01-20
|
|
253
|
-
`;
|
|
254
|
-
writeFileSync(join(tempDir, 'wu', 'WU-100.yaml'), wuYaml);
|
|
255
|
-
const result = await runStateBootstrap({
|
|
256
|
-
dryRun: true,
|
|
257
|
-
wuDir: join(tempDir, 'wu'),
|
|
258
|
-
stateDir: join(tempDir, 'state'),
|
|
259
|
-
force: false,
|
|
260
|
-
help: false,
|
|
261
|
-
});
|
|
262
|
-
expect(result.success).toBe(true);
|
|
263
|
-
expect(result.eventsGenerated).toBe(1);
|
|
264
|
-
expect(result.eventsWritten).toBe(0);
|
|
265
|
-
expect(existsSync(join(tempDir, 'state', 'wu-events.jsonl'))).toBe(false);
|
|
266
|
-
});
|
|
267
|
-
it('should write events in execute mode', async () => {
|
|
268
|
-
// Create a test WU YAML (lane value must be quoted due to colon)
|
|
269
|
-
const wuYaml = `id: WU-100
|
|
270
|
-
title: Test WU
|
|
271
|
-
lane: "Framework: CLI"
|
|
272
|
-
status: in_progress
|
|
273
|
-
created: 2026-01-20
|
|
274
|
-
`;
|
|
275
|
-
writeFileSync(join(tempDir, 'wu', 'WU-100.yaml'), wuYaml);
|
|
276
|
-
const result = await runStateBootstrap({
|
|
277
|
-
dryRun: false,
|
|
278
|
-
wuDir: join(tempDir, 'wu'),
|
|
279
|
-
stateDir: join(tempDir, 'state'),
|
|
280
|
-
force: false,
|
|
281
|
-
help: false,
|
|
282
|
-
});
|
|
283
|
-
expect(result.success).toBe(true);
|
|
284
|
-
expect(result.eventsGenerated).toBe(1);
|
|
285
|
-
expect(result.eventsWritten).toBe(1);
|
|
286
|
-
expect(existsSync(join(tempDir, 'state', 'wu-events.jsonl'))).toBe(true);
|
|
287
|
-
});
|
|
288
|
-
it('should fail if state file already exists without --force', async () => {
|
|
289
|
-
// Create existing state file
|
|
290
|
-
writeFileSync(join(tempDir, 'state', 'wu-events.jsonl'), '{"existing":"data"}\n');
|
|
291
|
-
// Create a test WU YAML (lane value must be quoted due to colon)
|
|
292
|
-
const wuYaml = `id: WU-100
|
|
293
|
-
title: Test WU
|
|
294
|
-
lane: "Framework: CLI"
|
|
295
|
-
status: in_progress
|
|
296
|
-
created: 2026-01-20
|
|
297
|
-
`;
|
|
298
|
-
writeFileSync(join(tempDir, 'wu', 'WU-100.yaml'), wuYaml);
|
|
299
|
-
const result = await runStateBootstrap({
|
|
300
|
-
dryRun: false,
|
|
301
|
-
wuDir: join(tempDir, 'wu'),
|
|
302
|
-
stateDir: join(tempDir, 'state'),
|
|
303
|
-
force: false,
|
|
304
|
-
help: false,
|
|
305
|
-
});
|
|
306
|
-
expect(result.success).toBe(false);
|
|
307
|
-
expect(result.error).toContain('exists');
|
|
308
|
-
});
|
|
309
|
-
it('should overwrite state file with --force', async () => {
|
|
310
|
-
// Create existing state file
|
|
311
|
-
writeFileSync(join(tempDir, 'state', 'wu-events.jsonl'), '{"existing":"data"}\n');
|
|
312
|
-
// Create a test WU YAML (lane value must be quoted due to colon)
|
|
313
|
-
const wuYaml = `id: WU-100
|
|
314
|
-
title: Test WU
|
|
315
|
-
lane: "Framework: CLI"
|
|
316
|
-
status: in_progress
|
|
317
|
-
created: 2026-01-20
|
|
318
|
-
`;
|
|
319
|
-
writeFileSync(join(tempDir, 'wu', 'WU-100.yaml'), wuYaml);
|
|
320
|
-
const result = await runStateBootstrap({
|
|
321
|
-
dryRun: false,
|
|
322
|
-
wuDir: join(tempDir, 'wu'),
|
|
323
|
-
stateDir: join(tempDir, 'state'),
|
|
324
|
-
force: true,
|
|
325
|
-
help: false,
|
|
326
|
-
});
|
|
327
|
-
expect(result.success).toBe(true);
|
|
328
|
-
expect(result.eventsWritten).toBe(1);
|
|
329
|
-
});
|
|
330
|
-
it('should handle missing WU directory gracefully', async () => {
|
|
331
|
-
const result = await runStateBootstrap({
|
|
332
|
-
dryRun: true,
|
|
333
|
-
wuDir: join(tempDir, 'nonexistent'),
|
|
334
|
-
stateDir: join(tempDir, 'state'),
|
|
335
|
-
force: false,
|
|
336
|
-
help: false,
|
|
337
|
-
});
|
|
338
|
-
expect(result.success).toBe(true);
|
|
339
|
-
expect(result.eventsGenerated).toBe(0);
|
|
340
|
-
expect(result.warnings).toContain('WU directory not found');
|
|
341
|
-
});
|
|
342
|
-
it('should skip invalid YAML files', async () => {
|
|
343
|
-
// Create valid WU YAML (lane value must be quoted due to colon)
|
|
344
|
-
const validWuYaml = `id: WU-100
|
|
345
|
-
title: Valid WU
|
|
346
|
-
lane: "Framework: CLI"
|
|
347
|
-
status: in_progress
|
|
348
|
-
created: 2026-01-20
|
|
349
|
-
`;
|
|
350
|
-
writeFileSync(join(tempDir, 'wu', 'WU-100.yaml'), validWuYaml);
|
|
351
|
-
// Create invalid YAML file
|
|
352
|
-
writeFileSync(join(tempDir, 'wu', 'WU-101.yaml'), 'invalid: yaml: content:');
|
|
353
|
-
const result = await runStateBootstrap({
|
|
354
|
-
dryRun: false,
|
|
355
|
-
wuDir: join(tempDir, 'wu'),
|
|
356
|
-
stateDir: join(tempDir, 'state'),
|
|
357
|
-
force: false,
|
|
358
|
-
help: false,
|
|
359
|
-
});
|
|
360
|
-
expect(result.success).toBe(true);
|
|
361
|
-
expect(result.eventsGenerated).toBe(1);
|
|
362
|
-
expect(result.skipped).toBe(1);
|
|
363
|
-
});
|
|
364
|
-
it('should process multiple valid WU files', async () => {
|
|
365
|
-
// Create multiple valid WU YAMLs (lane value must be quoted due to colon)
|
|
366
|
-
for (let i = 100; i <= 105; i++) {
|
|
367
|
-
const wuYaml = `id: WU-${i}
|
|
368
|
-
title: Test WU ${i}
|
|
369
|
-
lane: "Framework: CLI"
|
|
370
|
-
status: ${i <= 102 ? 'done' : 'in_progress'}
|
|
371
|
-
created: 2026-01-${10 + i - 100}
|
|
372
|
-
${i <= 102 ? `completed_at: 2026-01-${15 + i - 100}T10:00:00Z` : ''}
|
|
373
|
-
`;
|
|
374
|
-
writeFileSync(join(tempDir, 'wu', `WU-${i}.yaml`), wuYaml);
|
|
375
|
-
}
|
|
376
|
-
const result = await runStateBootstrap({
|
|
377
|
-
dryRun: false,
|
|
378
|
-
wuDir: join(tempDir, 'wu'),
|
|
379
|
-
stateDir: join(tempDir, 'state'),
|
|
380
|
-
force: false,
|
|
381
|
-
help: false,
|
|
382
|
-
});
|
|
383
|
-
expect(result.success).toBe(true);
|
|
384
|
-
// 3 done WUs = 3 claim + 3 complete = 6 events
|
|
385
|
-
// 3 in_progress WUs = 3 claim = 3 events
|
|
386
|
-
// Total = 9 events
|
|
387
|
-
expect(result.eventsGenerated).toBe(9);
|
|
388
|
-
expect(result.eventsWritten).toBe(9);
|
|
389
|
-
});
|
|
390
|
-
});
|
|
391
|
-
describe('integration: written events are valid', () => {
|
|
392
|
-
let tempDir;
|
|
393
|
-
beforeEach(() => {
|
|
394
|
-
tempDir = join(tmpdir(), `state-bootstrap-integration-${Date.now()}`);
|
|
395
|
-
mkdirSync(join(tempDir, 'wu'), { recursive: true });
|
|
396
|
-
mkdirSync(join(tempDir, 'state'), { recursive: true });
|
|
397
|
-
});
|
|
398
|
-
afterEach(() => {
|
|
399
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
400
|
-
});
|
|
401
|
-
it('should write events that can be loaded by WUStateStore', async () => {
|
|
402
|
-
// lane value must be quoted due to colon
|
|
403
|
-
const wuYaml = `id: WU-100
|
|
404
|
-
title: Test WU
|
|
405
|
-
lane: "Framework: CLI"
|
|
406
|
-
status: done
|
|
407
|
-
created: 2026-01-15
|
|
408
|
-
claimed_at: 2026-01-15T10:00:00Z
|
|
409
|
-
completed_at: 2026-01-20T15:00:00Z
|
|
410
|
-
`;
|
|
411
|
-
writeFileSync(join(tempDir, 'wu', 'WU-100.yaml'), wuYaml);
|
|
412
|
-
await runStateBootstrap({
|
|
413
|
-
dryRun: false,
|
|
414
|
-
wuDir: join(tempDir, 'wu'),
|
|
415
|
-
stateDir: join(tempDir, 'state'),
|
|
416
|
-
force: false,
|
|
417
|
-
help: false,
|
|
418
|
-
});
|
|
419
|
-
// Read the generated file
|
|
420
|
-
const content = readFileSync(join(tempDir, 'state', 'wu-events.jsonl'), 'utf-8');
|
|
421
|
-
const lines = content.trim().split('\n');
|
|
422
|
-
expect(lines.length).toBe(2); // claim + complete
|
|
423
|
-
// Verify each line is valid JSON with required fields
|
|
424
|
-
for (const line of lines) {
|
|
425
|
-
const event = JSON.parse(line);
|
|
426
|
-
expect(event).toHaveProperty('type');
|
|
427
|
-
expect(event).toHaveProperty('wuId');
|
|
428
|
-
expect(event).toHaveProperty('timestamp');
|
|
429
|
-
}
|
|
430
|
-
});
|
|
431
|
-
});
|
|
432
|
-
});
|