@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.
Files changed (111) hide show
  1. package/README.md +8 -4
  2. package/dist/hooks/enforcement-checks.js +120 -0
  3. package/dist/hooks/enforcement-checks.js.map +1 -1
  4. package/dist/init-lane-validation.js +141 -0
  5. package/dist/init-lane-validation.js.map +1 -0
  6. package/dist/init-templates.js +36 -8
  7. package/dist/init-templates.js.map +1 -1
  8. package/dist/init.js +27 -58
  9. package/dist/init.js.map +1 -1
  10. package/dist/initiative-create.js +35 -4
  11. package/dist/initiative-create.js.map +1 -1
  12. package/dist/lane-lifecycle-process.js +364 -0
  13. package/dist/lane-lifecycle-process.js.map +1 -0
  14. package/dist/lane-lock.js +41 -0
  15. package/dist/lane-lock.js.map +1 -0
  16. package/dist/lane-setup.js +55 -0
  17. package/dist/lane-setup.js.map +1 -0
  18. package/dist/lane-status.js +38 -0
  19. package/dist/lane-status.js.map +1 -0
  20. package/dist/lane-validate.js +43 -0
  21. package/dist/lane-validate.js.map +1 -0
  22. package/dist/onboarding-smoke-test.js +17 -0
  23. package/dist/onboarding-smoke-test.js.map +1 -1
  24. package/dist/public-manifest.js +28 -0
  25. package/dist/public-manifest.js.map +1 -1
  26. package/dist/wu-claim-cloud.js +16 -0
  27. package/dist/wu-claim-cloud.js.map +1 -1
  28. package/dist/wu-claim.js +12 -2
  29. package/dist/wu-claim.js.map +1 -1
  30. package/dist/wu-create-content.js +8 -2
  31. package/dist/wu-create-content.js.map +1 -1
  32. package/dist/wu-create-validation.js +5 -3
  33. package/dist/wu-create-validation.js.map +1 -1
  34. package/dist/wu-create.js +21 -1
  35. package/dist/wu-create.js.map +1 -1
  36. package/dist/wu-done.js +57 -8
  37. package/dist/wu-done.js.map +1 -1
  38. package/dist/wu-prep.js +22 -0
  39. package/dist/wu-prep.js.map +1 -1
  40. package/package.json +15 -11
  41. package/dist/__tests__/agent-log-issue.test.js +0 -56
  42. package/dist/__tests__/agent-spawn-coordination.test.js +0 -451
  43. package/dist/__tests__/backlog-prune.test.js +0 -478
  44. package/dist/__tests__/cli-entry-point.test.js +0 -160
  45. package/dist/__tests__/cli-subprocess.test.js +0 -89
  46. package/dist/__tests__/commands/integrate.test.js +0 -165
  47. package/dist/__tests__/commands.test.js +0 -271
  48. package/dist/__tests__/deps-operations.test.js +0 -206
  49. package/dist/__tests__/doctor.test.js +0 -510
  50. package/dist/__tests__/file-operations.test.js +0 -906
  51. package/dist/__tests__/flow-report.test.js +0 -24
  52. package/dist/__tests__/gates-config.test.js +0 -303
  53. package/dist/__tests__/gates-integration-tests.test.js +0 -112
  54. package/dist/__tests__/git-operations.test.js +0 -668
  55. package/dist/__tests__/guard-main-branch.test.js +0 -79
  56. package/dist/__tests__/guards-validation.test.js +0 -416
  57. package/dist/__tests__/hooks/enforcement.test.js +0 -279
  58. package/dist/__tests__/init-config-lanes.test.js +0 -131
  59. package/dist/__tests__/init-docs-structure.test.js +0 -152
  60. package/dist/__tests__/init-greenfield.test.js +0 -247
  61. package/dist/__tests__/init-lane-inference.test.js +0 -125
  62. package/dist/__tests__/init-onboarding-docs.test.js +0 -132
  63. package/dist/__tests__/init-quick-ref.test.js +0 -144
  64. package/dist/__tests__/init-scripts.test.js +0 -207
  65. package/dist/__tests__/init-template-portability.test.js +0 -96
  66. package/dist/__tests__/init.test.js +0 -968
  67. package/dist/__tests__/initiative-add-wu.test.js +0 -490
  68. package/dist/__tests__/initiative-e2e.test.js +0 -442
  69. package/dist/__tests__/initiative-plan-replacement.test.js +0 -161
  70. package/dist/__tests__/initiative-plan.test.js +0 -340
  71. package/dist/__tests__/initiative-remove-wu.test.js +0 -458
  72. package/dist/__tests__/lumenflow-upgrade.test.js +0 -260
  73. package/dist/__tests__/mem-cleanup-execution.test.js +0 -19
  74. package/dist/__tests__/memory-integration.test.js +0 -333
  75. package/dist/__tests__/merge-block.test.js +0 -220
  76. package/dist/__tests__/metrics-cli.test.js +0 -619
  77. package/dist/__tests__/metrics-snapshot.test.js +0 -24
  78. package/dist/__tests__/no-beacon-references-docs.test.js +0 -30
  79. package/dist/__tests__/no-beacon-references.test.js +0 -39
  80. package/dist/__tests__/onboarding-smoke-test.test.js +0 -211
  81. package/dist/__tests__/path-centralization-cli.test.js +0 -234
  82. package/dist/__tests__/plan-create.test.js +0 -126
  83. package/dist/__tests__/plan-edit.test.js +0 -157
  84. package/dist/__tests__/plan-link.test.js +0 -239
  85. package/dist/__tests__/plan-promote.test.js +0 -181
  86. package/dist/__tests__/release.test.js +0 -372
  87. package/dist/__tests__/rotate-progress.test.js +0 -127
  88. package/dist/__tests__/safe-git.test.js +0 -190
  89. package/dist/__tests__/session-coordinator.test.js +0 -109
  90. package/dist/__tests__/state-bootstrap.test.js +0 -432
  91. package/dist/__tests__/state-doctor.test.js +0 -328
  92. package/dist/__tests__/sync-templates.test.js +0 -255
  93. package/dist/__tests__/templates-sync.test.js +0 -219
  94. package/dist/__tests__/trace-gen.test.js +0 -115
  95. package/dist/__tests__/wu-create-required-fields.test.js +0 -143
  96. package/dist/__tests__/wu-create-strict.test.js +0 -118
  97. package/dist/__tests__/wu-create.test.js +0 -121
  98. package/dist/__tests__/wu-done-auto-cleanup.test.js +0 -135
  99. package/dist/__tests__/wu-done-docs-only-policy.test.js +0 -20
  100. package/dist/__tests__/wu-done-staging-whitelist.test.js +0 -35
  101. package/dist/__tests__/wu-done.test.js +0 -36
  102. package/dist/__tests__/wu-edit-strict.test.js +0 -109
  103. package/dist/__tests__/wu-edit.test.js +0 -119
  104. package/dist/__tests__/wu-lifecycle-integration.test.js +0 -388
  105. package/dist/__tests__/wu-prep-default-exec.test.js +0 -35
  106. package/dist/__tests__/wu-prep.test.js +0 -140
  107. package/dist/__tests__/wu-proto.test.js +0 -97
  108. package/dist/__tests__/wu-validate-strict.test.js +0 -113
  109. package/dist/__tests__/wu-validate.test.js +0 -36
  110. package/dist/spawn-list.js +0 -143
  111. 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
- });