@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,219 +0,0 @@
1
- /**
2
- * @file templates-sync.test.ts
3
- * Tests for templates synchronization and drift detection (WU-1353)
4
- */
5
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
6
- import * as fs from 'node:fs';
7
- import * as path from 'node:path';
8
- import * as os from 'node:os';
9
- import { syncTemplates, syncOnboardingDocs, syncCoreDocs, convertToTemplate, checkTemplateDrift, } from '../sync-templates.js';
10
- // Constants for frequently used path segments (sonarjs/no-duplicate-string)
11
- const PACKAGES_DIR = 'packages';
12
- const LUMENFLOW_SCOPE = '@lumenflow';
13
- const CLI_DIR = 'cli';
14
- const TEMPLATES_DIR = 'templates';
15
- const CORE_DIR = 'core';
16
- const LUMENFLOW_DOT_DIR = '.lumenflow';
17
- const CONSTRAINTS_FILE = 'constraints.md';
18
- const CONSTRAINTS_TEMPLATE = 'constraints.md.template';
19
- describe('templates-sync', () => {
20
- let tempDir;
21
- beforeEach(() => {
22
- tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'templates-sync-test-'));
23
- });
24
- afterEach(() => {
25
- if (tempDir && fs.existsSync(tempDir)) {
26
- fs.rmSync(tempDir, { recursive: true, force: true });
27
- }
28
- });
29
- describe('convertToTemplate', () => {
30
- it('should replace dates with {{DATE}} placeholder', () => {
31
- const content = 'Updated: 2026-02-02\nCreated: 2025-01-15';
32
- const result = convertToTemplate(content, '/home/test/project');
33
- expect(result).toBe('Updated: {{DATE}}\nCreated: {{DATE}}');
34
- });
35
- it('should preserve content without dates', () => {
36
- const content = '# Title\n\nSome content without dates.';
37
- const result = convertToTemplate(content, '/home/test/project');
38
- expect(result).toBe(content);
39
- });
40
- });
41
- describe('syncCoreDocs', () => {
42
- beforeEach(() => {
43
- // Set up directory structure
44
- const templatesDir = path.join(tempDir, PACKAGES_DIR, LUMENFLOW_SCOPE, CLI_DIR, TEMPLATES_DIR, CORE_DIR, LUMENFLOW_DOT_DIR);
45
- fs.mkdirSync(templatesDir, { recursive: true });
46
- // Create source constraints.md with v1.1 content
47
- const lumenflowDir = path.join(tempDir, LUMENFLOW_DOT_DIR);
48
- fs.mkdirSync(lumenflowDir, { recursive: true });
49
- fs.writeFileSync(path.join(lumenflowDir, CONSTRAINTS_FILE), `# LumenFlow Constraints Capsule
50
-
51
- **Version:** 1.1
52
- **Last updated:** 2026-02-02
53
-
54
- This document contains the 7 non-negotiable constraints.
55
-
56
- ### 1. Worktree Discipline and Git Safety
57
-
58
- **MANDATORY PRE-WRITE CHECK**
59
-
60
- **NEVER "QUICK FIX" ON MAIN**
61
- `);
62
- // Create LUMENFLOW.md
63
- fs.writeFileSync(path.join(tempDir, 'LUMENFLOW.md'), `# LumenFlow Workflow Guide
64
-
65
- **Last updated:** 2026-02-02
66
-
67
- ## Critical Rule: Use wu:prep Then wu:done
68
- `);
69
- });
70
- it('should sync constraints.md to template', async () => {
71
- const result = await syncCoreDocs(tempDir, false);
72
- expect(result.errors).toHaveLength(0);
73
- expect(result.synced).toContain(`${PACKAGES_DIR}/${LUMENFLOW_SCOPE}/${CLI_DIR}/${TEMPLATES_DIR}/${CORE_DIR}/${LUMENFLOW_DOT_DIR}/${CONSTRAINTS_TEMPLATE}`);
74
- // Verify template content
75
- const templatePath = path.join(tempDir, PACKAGES_DIR, LUMENFLOW_SCOPE, CLI_DIR, TEMPLATES_DIR, CORE_DIR, LUMENFLOW_DOT_DIR, CONSTRAINTS_TEMPLATE);
76
- const templateContent = fs.readFileSync(templatePath, 'utf-8');
77
- // Should have {{DATE}} placeholder
78
- expect(templateContent).toContain('{{DATE}}');
79
- expect(templateContent).not.toContain('2026-02-02');
80
- // Should have v1.1 content markers
81
- expect(templateContent).toContain('Version:** 1.1');
82
- expect(templateContent).toContain('7 non-negotiable constraints');
83
- expect(templateContent).toContain('MANDATORY PRE-WRITE CHECK');
84
- expect(templateContent).toContain('NEVER "QUICK FIX" ON MAIN');
85
- });
86
- it('should use dry-run mode without writing files', async () => {
87
- // First, ensure no template exists
88
- const templatePath = path.join(tempDir, PACKAGES_DIR, LUMENFLOW_SCOPE, CLI_DIR, TEMPLATES_DIR, CORE_DIR, LUMENFLOW_DOT_DIR, CONSTRAINTS_TEMPLATE);
89
- // Remove if it exists from beforeEach
90
- if (fs.existsSync(templatePath)) {
91
- fs.unlinkSync(templatePath);
92
- }
93
- const result = await syncCoreDocs(tempDir, true);
94
- expect(result.errors).toHaveLength(0);
95
- expect(result.synced.length).toBeGreaterThan(0);
96
- expect(fs.existsSync(templatePath)).toBe(false);
97
- });
98
- });
99
- describe('syncOnboardingDocs', () => {
100
- const ONBOARDING_SUBPATH = [
101
- 'docs',
102
- '04-operations',
103
- '_frameworks',
104
- 'lumenflow',
105
- 'agent',
106
- 'onboarding',
107
- ];
108
- const FIRST_WU_MISTAKES_FILE = 'first-wu-mistakes.md';
109
- beforeEach(() => {
110
- // Set up onboarding source directory
111
- const onboardingDir = path.join(tempDir, ...ONBOARDING_SUBPATH);
112
- fs.mkdirSync(onboardingDir, { recursive: true });
113
- // Create first-wu-mistakes.md with v1.1 content (11 mistakes)
114
- fs.writeFileSync(path.join(onboardingDir, FIRST_WU_MISTAKES_FILE), `# First WU Mistakes
115
-
116
- **Last updated:** 2026-02-02
117
-
118
- ## Mistake 1: Not Using Worktrees
119
-
120
- pnpm wu:prep --id WU-123
121
-
122
- ## Mistake 11: "Quick Fixing" on Main
123
-
124
- ## Quick Checklist
125
-
126
- - [ ] Check spec_refs for plans
127
- `);
128
- // Set up target directory
129
- const templatesDir = path.join(tempDir, PACKAGES_DIR, LUMENFLOW_SCOPE, CLI_DIR, TEMPLATES_DIR, CORE_DIR, 'ai', 'onboarding');
130
- fs.mkdirSync(templatesDir, { recursive: true });
131
- });
132
- it('should sync first-wu-mistakes.md to template', async () => {
133
- const result = await syncOnboardingDocs(tempDir, false);
134
- expect(result.errors).toHaveLength(0);
135
- expect(result.synced).toContain(`${PACKAGES_DIR}/${LUMENFLOW_SCOPE}/${CLI_DIR}/${TEMPLATES_DIR}/${CORE_DIR}/ai/onboarding/${FIRST_WU_MISTAKES_FILE}.template`);
136
- // Verify template content
137
- const templatePath = path.join(tempDir, PACKAGES_DIR, LUMENFLOW_SCOPE, CLI_DIR, TEMPLATES_DIR, CORE_DIR, 'ai', 'onboarding', `${FIRST_WU_MISTAKES_FILE}.template`);
138
- const templateContent = fs.readFileSync(templatePath, 'utf-8');
139
- // Should have {{DATE}} placeholder
140
- expect(templateContent).toContain('{{DATE}}');
141
- expect(templateContent).not.toContain('2026-02-02');
142
- // Should have v1.1 content markers
143
- expect(templateContent).toContain('Mistake 11:');
144
- expect(templateContent).toContain('Quick Fixing" on Main');
145
- expect(templateContent).toContain('wu:prep');
146
- expect(templateContent).toContain('spec_refs');
147
- });
148
- });
149
- describe('checkTemplateDrift', () => {
150
- beforeEach(() => {
151
- // Set up source files
152
- const lumenflowDir = path.join(tempDir, LUMENFLOW_DOT_DIR);
153
- fs.mkdirSync(lumenflowDir, { recursive: true });
154
- fs.writeFileSync(path.join(lumenflowDir, CONSTRAINTS_FILE), `# Constraints
155
- **Version:** 1.1
156
- **Last updated:** 2026-02-02
157
- 7 constraints`);
158
- // Set up template directory
159
- const templatesDir = path.join(tempDir, PACKAGES_DIR, LUMENFLOW_SCOPE, CLI_DIR, TEMPLATES_DIR, CORE_DIR, LUMENFLOW_DOT_DIR);
160
- fs.mkdirSync(templatesDir, { recursive: true });
161
- });
162
- it('should detect drift when template is outdated', async () => {
163
- // Create outdated template (v1.0, 6 constraints)
164
- const templatePath = path.join(tempDir, PACKAGES_DIR, LUMENFLOW_SCOPE, CLI_DIR, TEMPLATES_DIR, CORE_DIR, LUMENFLOW_DOT_DIR, CONSTRAINTS_TEMPLATE);
165
- fs.writeFileSync(templatePath, `# Constraints
166
- **Version:** 1.0
167
- **Last updated:** {{DATE}}
168
- 6 constraints`);
169
- const drift = await checkTemplateDrift(tempDir);
170
- expect(drift.hasDrift).toBe(true);
171
- expect(drift.driftingFiles.length).toBeGreaterThan(0);
172
- expect(drift.driftingFiles.some((f) => f.includes(CONSTRAINTS_FILE))).toBe(true);
173
- });
174
- it('should report no drift when templates are in sync', async () => {
175
- // First sync templates
176
- await syncCoreDocs(tempDir, false);
177
- // Then check for drift
178
- const drift = await checkTemplateDrift(tempDir);
179
- // After sync, constraints should not be drifting
180
- expect(drift.driftingFiles.filter((f) => f.includes(CONSTRAINTS_FILE))).toHaveLength(0);
181
- });
182
- it('should return detailed drift report', async () => {
183
- // Create outdated template
184
- const templatePath = path.join(tempDir, PACKAGES_DIR, LUMENFLOW_SCOPE, CLI_DIR, TEMPLATES_DIR, CORE_DIR, LUMENFLOW_DOT_DIR, CONSTRAINTS_TEMPLATE);
185
- fs.writeFileSync(templatePath, 'outdated content');
186
- const drift = await checkTemplateDrift(tempDir);
187
- expect(drift.hasDrift).toBe(true);
188
- expect(drift.driftingFiles).toBeDefined();
189
- expect(Array.isArray(drift.driftingFiles)).toBe(true);
190
- });
191
- });
192
- describe('syncTemplates (full sync)', () => {
193
- beforeEach(() => {
194
- // Set up minimal directory structure
195
- const lumenflowDir = path.join(tempDir, LUMENFLOW_DOT_DIR);
196
- fs.mkdirSync(lumenflowDir, { recursive: true });
197
- fs.writeFileSync(path.join(lumenflowDir, CONSTRAINTS_FILE), 'content');
198
- fs.writeFileSync(path.join(tempDir, 'LUMENFLOW.md'), 'content');
199
- const onboardingDir = path.join(tempDir, 'docs', '04-operations', '_frameworks', 'lumenflow', 'agent', 'onboarding');
200
- fs.mkdirSync(onboardingDir, { recursive: true });
201
- fs.writeFileSync(path.join(onboardingDir, 'first-wu-mistakes.md'), 'content');
202
- const skillsDir = path.join(tempDir, '.claude', 'skills', 'test-skill');
203
- fs.mkdirSync(skillsDir, { recursive: true });
204
- fs.writeFileSync(path.join(skillsDir, 'SKILL.md'), 'skill content');
205
- });
206
- it('should sync all template categories', async () => {
207
- const result = await syncTemplates(tempDir, false);
208
- expect(result.core.errors).toHaveLength(0);
209
- expect(result.onboarding.errors).toHaveLength(0);
210
- expect(result.skills.errors).toHaveLength(0);
211
- // Should sync at least constraints and LUMENFLOW
212
- expect(result.core.synced.length).toBeGreaterThanOrEqual(2);
213
- // Should sync onboarding docs
214
- expect(result.onboarding.synced.length).toBeGreaterThanOrEqual(1);
215
- // Should sync skills
216
- expect(result.skills.synced.length).toBeGreaterThanOrEqual(1);
217
- });
218
- });
219
- });
@@ -1,115 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Tests for trace-gen CLI command
4
- *
5
- * WU-1112: INIT-003 Phase 6 - Migrate remaining Tier 1 tools
6
- *
7
- * Trace generator creates traceability reports linking WUs to code changes,
8
- * useful for audit trails and compliance documentation.
9
- */
10
- import { describe, it, expect, vi, beforeEach } from 'vitest';
11
- // Import functions under test
12
- import { parseTraceArgs, TraceFormat, buildTraceEntry, } from '../trace-gen.js';
13
- describe('trace-gen', () => {
14
- beforeEach(() => {
15
- vi.clearAllMocks();
16
- });
17
- describe('parseTraceArgs', () => {
18
- it('should parse --wu flag', () => {
19
- const args = parseTraceArgs(['node', 'trace-gen.js', '--wu', 'WU-1112']);
20
- expect(args.wuId).toBe('WU-1112');
21
- });
22
- it('should parse --format json', () => {
23
- const args = parseTraceArgs(['node', 'trace-gen.js', '--format', 'json']);
24
- expect(args.format).toBe('json');
25
- });
26
- it('should parse --format markdown', () => {
27
- const args = parseTraceArgs(['node', 'trace-gen.js', '--format', 'markdown']);
28
- expect(args.format).toBe('markdown');
29
- });
30
- it('should parse --output flag', () => {
31
- const args = parseTraceArgs(['node', 'trace-gen.js', '--output', 'trace.json']);
32
- expect(args.output).toBe('trace.json');
33
- });
34
- it('should parse --since flag', () => {
35
- const args = parseTraceArgs(['node', 'trace-gen.js', '--since', '2024-01-01']);
36
- expect(args.since).toBe('2024-01-01');
37
- });
38
- it('should parse --help flag', () => {
39
- const args = parseTraceArgs(['node', 'trace-gen.js', '--help']);
40
- expect(args.help).toBe(true);
41
- });
42
- it('should default format to json', () => {
43
- const args = parseTraceArgs(['node', 'trace-gen.js']);
44
- expect(args.format).toBeUndefined();
45
- });
46
- });
47
- describe('TraceFormat enum', () => {
48
- it('should have JSON format', () => {
49
- expect(TraceFormat.JSON).toBe('json');
50
- });
51
- it('should have markdown format', () => {
52
- expect(TraceFormat.MARKDOWN).toBe('markdown');
53
- });
54
- it('should have CSV format', () => {
55
- expect(TraceFormat.CSV).toBe('csv');
56
- });
57
- });
58
- describe('buildTraceEntry', () => {
59
- it('should build trace entry from WU and commit data', () => {
60
- const entry = buildTraceEntry({
61
- wuId: 'WU-1112',
62
- title: 'Migrate tools',
63
- status: 'done',
64
- commits: [{ sha: 'abc1234', message: 'feat: add deps-add', date: '2024-01-15T10:00:00Z' }],
65
- files: ['src/deps-add.ts'],
66
- });
67
- expect(entry.wuId).toBe('WU-1112');
68
- expect(entry.title).toBe('Migrate tools');
69
- expect(entry.status).toBe('done');
70
- expect(entry.commitCount).toBe(1);
71
- expect(entry.fileCount).toBe(1);
72
- });
73
- it('should calculate commit count correctly', () => {
74
- const entry = buildTraceEntry({
75
- wuId: 'WU-1112',
76
- title: 'Test',
77
- status: 'done',
78
- commits: [
79
- { sha: 'abc1234', message: 'feat: first', date: '2024-01-15T10:00:00Z' },
80
- { sha: 'def5678', message: 'feat: second', date: '2024-01-16T10:00:00Z' },
81
- { sha: 'ghi9012', message: 'fix: third', date: '2024-01-17T10:00:00Z' },
82
- ],
83
- files: ['a.ts', 'b.ts'],
84
- });
85
- expect(entry.commitCount).toBe(3);
86
- expect(entry.fileCount).toBe(2);
87
- });
88
- it('should include first and last commit dates', () => {
89
- const entry = buildTraceEntry({
90
- wuId: 'WU-1112',
91
- title: 'Test',
92
- status: 'done',
93
- commits: [
94
- { sha: 'abc1234', message: 'feat: first', date: '2024-01-15T10:00:00Z' },
95
- { sha: 'def5678', message: 'feat: last', date: '2024-01-20T10:00:00Z' },
96
- ],
97
- files: [],
98
- });
99
- expect(entry.firstCommit).toBe('2024-01-15T10:00:00Z');
100
- expect(entry.lastCommit).toBe('2024-01-20T10:00:00Z');
101
- });
102
- it('should handle empty commits array', () => {
103
- const entry = buildTraceEntry({
104
- wuId: 'WU-1112',
105
- title: 'Test',
106
- status: 'done',
107
- commits: [],
108
- files: [],
109
- });
110
- expect(entry.commitCount).toBe(0);
111
- expect(entry.firstCommit).toBeUndefined();
112
- expect(entry.lastCommit).toBeUndefined();
113
- });
114
- });
115
- });
@@ -1,143 +0,0 @@
1
- /**
2
- * @file wu-create-required-fields.test.ts
3
- * Test suite for wu:create required field aggregation (WU-1366)
4
- *
5
- * WU-1366: Missing required fields in wu:create should be reported together
6
- * in a single error block.
7
- *
8
- * Tests:
9
- * - Multiple missing required fields are collected and reported together
10
- * - Error block formatting includes all missing fields
11
- * - Single missing field still reports correctly
12
- */
13
- import { describe, it, expect } from 'vitest';
14
- import { validateCreateSpec } from '../wu-create.js';
15
- /** Default lane for test cases */
16
- const TEST_LANE = 'Framework: CLI';
17
- /** Default test WU ID */
18
- const TEST_WU_ID = 'WU-9999';
19
- /** Minimum valid description with required sections */
20
- const VALID_DESCRIPTION = 'Context: test context.\nProblem: test problem.\nSolution: test solution that exceeds minimum.';
21
- /** Default acceptance criteria for tests */
22
- const TEST_ACCEPTANCE = ['Acceptance criterion'];
23
- describe('wu:create required field aggregation (WU-1366)', () => {
24
- describe('validateCreateSpec error aggregation', () => {
25
- it('should aggregate multiple missing required fields into a single error block', () => {
26
- // Missing: description, acceptance, exposure, code-paths, test-paths
27
- const result = validateCreateSpec({
28
- id: TEST_WU_ID,
29
- lane: TEST_LANE,
30
- title: 'Test WU',
31
- priority: 'P2',
32
- type: 'feature',
33
- opts: {
34
- // All required fields missing
35
- strict: false, // Skip path existence checks
36
- },
37
- });
38
- expect(result.valid).toBe(false);
39
- // Should have multiple errors collected
40
- expect(result.errors.length).toBeGreaterThan(1);
41
- // Verify specific missing fields are included
42
- expect(result.errors.some((e) => e.includes('--description'))).toBe(true);
43
- expect(result.errors.some((e) => e.includes('--acceptance'))).toBe(true);
44
- expect(result.errors.some((e) => e.includes('--exposure'))).toBe(true);
45
- });
46
- it('should report code-paths and test-paths as missing for non-documentation WUs', () => {
47
- const result = validateCreateSpec({
48
- id: TEST_WU_ID,
49
- lane: TEST_LANE,
50
- title: 'Test WU',
51
- priority: 'P2',
52
- type: 'feature',
53
- opts: {
54
- description: VALID_DESCRIPTION,
55
- acceptance: TEST_ACCEPTANCE,
56
- exposure: 'backend-only',
57
- // Missing: codePaths, testPaths, specRefs
58
- strict: false,
59
- },
60
- });
61
- expect(result.valid).toBe(false);
62
- expect(result.errors.some((e) => e.includes('--code-paths'))).toBe(true);
63
- expect(result.errors.some((e) => e.includes('test path'))).toBe(true);
64
- });
65
- it('should report spec-refs as missing for feature WUs', () => {
66
- const result = validateCreateSpec({
67
- id: TEST_WU_ID,
68
- lane: TEST_LANE,
69
- title: 'Test WU',
70
- priority: 'P2',
71
- type: 'feature',
72
- opts: {
73
- description: VALID_DESCRIPTION,
74
- acceptance: TEST_ACCEPTANCE,
75
- exposure: 'backend-only',
76
- codePaths: ['packages/@lumenflow/cli/src/wu-create.ts'],
77
- testPathsUnit: ['packages/@lumenflow/cli/src/__tests__/wu-create.test.ts'],
78
- // Missing: specRefs (required for feature type)
79
- strict: false,
80
- },
81
- });
82
- expect(result.valid).toBe(false);
83
- expect(result.errors.some((e) => e.includes('--spec-refs'))).toBe(true);
84
- });
85
- it('should treat empty spec-refs array as missing for feature WUs', () => {
86
- const result = validateCreateSpec({
87
- id: TEST_WU_ID,
88
- lane: TEST_LANE,
89
- title: 'Test WU',
90
- priority: 'P2',
91
- type: 'feature',
92
- opts: {
93
- description: VALID_DESCRIPTION,
94
- acceptance: TEST_ACCEPTANCE,
95
- exposure: 'backend-only',
96
- codePaths: ['packages/@lumenflow/cli/src/wu-create.ts'],
97
- testPathsUnit: [
98
- 'packages/@lumenflow/cli/src/__tests__/wu-create-required-fields.test.ts',
99
- ],
100
- specRefs: [],
101
- strict: false,
102
- },
103
- });
104
- expect(result.valid).toBe(false);
105
- expect(result.errors.some((e) => e.includes('--spec-refs'))).toBe(true);
106
- });
107
- it('should return all errors at once, not fail on first error', () => {
108
- const result = validateCreateSpec({
109
- id: TEST_WU_ID,
110
- lane: TEST_LANE,
111
- title: 'Test WU',
112
- priority: 'P2',
113
- type: 'feature',
114
- opts: {
115
- // All required fields missing to ensure multiple errors
116
- strict: false,
117
- },
118
- });
119
- expect(result.valid).toBe(false);
120
- // Verify multiple errors are present (at least 3: description, acceptance, exposure)
121
- expect(result.errors.length).toBeGreaterThanOrEqual(3);
122
- });
123
- it('should validate documentation WUs without requiring code-paths', () => {
124
- const result = validateCreateSpec({
125
- id: TEST_WU_ID,
126
- lane: 'Content: Documentation',
127
- title: 'Test Docs WU',
128
- priority: 'P2',
129
- type: 'documentation',
130
- opts: {
131
- description: VALID_DESCRIPTION,
132
- acceptance: TEST_ACCEPTANCE,
133
- exposure: 'documentation',
134
- testPathsManual: ['Verify docs render correctly'],
135
- strict: false,
136
- },
137
- });
138
- // Documentation WUs should not require code-paths
139
- const hasCodePathsError = result.errors.some((e) => e.includes('--code-paths'));
140
- expect(hasCodePathsError).toBe(false);
141
- });
142
- });
143
- });
@@ -1,118 +0,0 @@
1
- /**
2
- * @file wu-create-strict.test.ts
3
- * Test suite for wu:create strict validation behavior (WU-1329)
4
- *
5
- * WU-1329: Make wu:create run strict validation by default
6
- *
7
- * Tests:
8
- * - Strict validation runs by default (validates code_paths/test_paths exist)
9
- * - --no-strict flag bypasses strict validation
10
- * - --no-strict usage is logged
11
- */
12
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
13
- // Import test utilities (WU-1329)
14
- import { validateCreateSpec } from '../wu-create.js';
15
- // WU-1329: Constants for test file paths
16
- const NON_EXISTENT_CODE_PATH = 'non-existent/file.ts';
17
- const NON_EXISTENT_TEST_PATH = 'non-existent/test.test.ts';
18
- describe('wu:create strict validation (WU-1329)', () => {
19
- describe('validateCreateSpec strict mode', () => {
20
- const baseOpts = {
21
- id: 'WU-9999',
22
- lane: 'Framework: CLI',
23
- title: 'Test WU',
24
- priority: 'P2',
25
- type: 'feature',
26
- opts: {
27
- description: 'Context: test context.\nProblem: test problem.\nSolution: test solution that exceeds minimum length requirement.',
28
- acceptance: ['Acceptance criterion 1'],
29
- codePaths: ['packages/@lumenflow/cli/src/wu-create.ts'],
30
- testPathsUnit: ['packages/@lumenflow/cli/src/__tests__/wu-create-strict.test.ts'],
31
- exposure: 'backend-only',
32
- specRefs: ['lumenflow://plans/WU-9999-plan.md'],
33
- },
34
- };
35
- it('should pass validation with valid spec in non-strict mode', () => {
36
- const result = validateCreateSpec({
37
- ...baseOpts,
38
- opts: {
39
- ...baseOpts.opts,
40
- strict: false,
41
- },
42
- });
43
- expect(result.valid).toBe(true);
44
- expect(result.errors).toHaveLength(0);
45
- });
46
- // WU-1329: This test verifies that strict validation is the default
47
- it('should validate code_paths existence by default (strict=true)', () => {
48
- const result = validateCreateSpec({
49
- ...baseOpts,
50
- opts: {
51
- ...baseOpts.opts,
52
- codePaths: [NON_EXISTENT_CODE_PATH],
53
- // strict is not explicitly set - should default to true
54
- },
55
- });
56
- // In strict mode, non-existent paths should be caught
57
- expect(result.valid).toBe(false);
58
- expect(result.errors.some((e) => e.includes('code_paths') || e.includes('not found'))).toBe(true);
59
- });
60
- // WU-1329: This test verifies --no-strict bypasses path validation
61
- it('should skip code_paths existence check when strict=false', () => {
62
- const result = validateCreateSpec({
63
- ...baseOpts,
64
- opts: {
65
- ...baseOpts.opts,
66
- codePaths: [NON_EXISTENT_CODE_PATH],
67
- strict: false,
68
- },
69
- });
70
- // In non-strict mode, non-existent paths should not fail validation
71
- // (other schema validation may still fail)
72
- expect(result.errors.every((e) => !e.includes('not found') && !e.includes('does not exist'))).toBe(true);
73
- });
74
- // WU-1329: This test verifies test_paths validation in strict mode
75
- it('should validate test_paths existence by default (strict=true)', () => {
76
- const result = validateCreateSpec({
77
- ...baseOpts,
78
- opts: {
79
- ...baseOpts.opts,
80
- testPathsUnit: [NON_EXISTENT_TEST_PATH],
81
- },
82
- });
83
- // In strict mode, non-existent test paths should be caught
84
- expect(result.valid).toBe(false);
85
- expect(result.errors.some((e) => e.includes('test') || e.includes('not found'))).toBe(true);
86
- });
87
- });
88
- describe('--no-strict logging', () => {
89
- let consoleSpy;
90
- beforeEach(() => {
91
- consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
92
- });
93
- afterEach(() => {
94
- consoleSpy.mockRestore();
95
- });
96
- // WU-1329: This test verifies --no-strict usage is logged
97
- it('should log warning when --no-strict is used', () => {
98
- validateCreateSpec({
99
- id: 'WU-9999',
100
- lane: 'Framework: CLI',
101
- title: 'Test WU',
102
- priority: 'P2',
103
- type: 'feature',
104
- opts: {
105
- description: 'Context: test context.\nProblem: test problem.\nSolution: test solution that exceeds minimum.',
106
- acceptance: ['Acceptance criterion'],
107
- codePaths: [NON_EXISTENT_CODE_PATH],
108
- testPathsUnit: [NON_EXISTENT_TEST_PATH],
109
- exposure: 'backend-only',
110
- specRefs: ['lumenflow://plans/WU-9999-plan.md'],
111
- strict: false,
112
- },
113
- });
114
- // Should log that strict validation was bypassed
115
- expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('strict validation bypassed'));
116
- });
117
- });
118
- });