@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,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
|
-
});
|