@lumenflow/cli 2.7.0 → 2.9.0
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 +121 -105
- package/dist/__tests__/agent-spawn-coordination.test.js +451 -0
- package/dist/__tests__/commands/integrate.test.js +165 -0
- package/dist/__tests__/commands.test.js +75 -0
- package/dist/__tests__/doctor.test.js +510 -0
- package/dist/__tests__/gates-config.test.js +0 -1
- package/dist/__tests__/hooks/enforcement.test.js +279 -0
- package/dist/__tests__/init-greenfield.test.js +247 -0
- package/dist/__tests__/init-quick-ref.test.js +0 -1
- package/dist/__tests__/init-template-portability.test.js +0 -1
- package/dist/__tests__/init.test.js +249 -0
- package/dist/__tests__/initiative-e2e.test.js +442 -0
- package/dist/__tests__/initiative-plan-replacement.test.js +0 -1
- package/dist/__tests__/memory-integration.test.js +333 -0
- package/dist/__tests__/release.test.js +1 -1
- package/dist/__tests__/safe-git.test.js +0 -1
- package/dist/__tests__/state-doctor.test.js +54 -0
- package/dist/__tests__/sync-templates.test.js +255 -0
- package/dist/__tests__/wu-create-required-fields.test.js +121 -0
- package/dist/__tests__/wu-done-auto-cleanup.test.js +135 -0
- package/dist/__tests__/wu-lifecycle-integration.test.js +388 -0
- package/dist/backlog-prune.js +0 -1
- package/dist/cli-entry-point.js +0 -1
- package/dist/commands/integrate.js +229 -0
- package/dist/commands.js +171 -0
- package/dist/docs-sync.js +46 -0
- package/dist/doctor.js +479 -10
- package/dist/gates.js +0 -7
- package/dist/hooks/enforcement-checks.js +209 -0
- package/dist/hooks/enforcement-generator.js +365 -0
- package/dist/hooks/enforcement-sync.js +243 -0
- package/dist/hooks/index.js +7 -0
- package/dist/init.js +502 -17
- package/dist/initiative-add-wu.js +0 -2
- package/dist/initiative-create.js +0 -3
- package/dist/initiative-edit.js +0 -5
- package/dist/initiative-plan.js +0 -1
- package/dist/initiative-remove-wu.js +0 -2
- package/dist/lane-health.js +0 -2
- package/dist/lane-suggest.js +0 -1
- package/dist/mem-checkpoint.js +0 -2
- package/dist/mem-cleanup.js +0 -2
- package/dist/mem-context.js +0 -3
- package/dist/mem-create.js +0 -2
- package/dist/mem-delete.js +0 -3
- package/dist/mem-inbox.js +0 -2
- package/dist/mem-index.js +0 -1
- package/dist/mem-init.js +0 -2
- package/dist/mem-profile.js +0 -1
- package/dist/mem-promote.js +0 -1
- package/dist/mem-ready.js +0 -2
- package/dist/mem-signal.js +0 -2
- package/dist/mem-start.js +0 -2
- package/dist/mem-summarize.js +0 -2
- package/dist/metrics-cli.js +1 -1
- package/dist/metrics-snapshot.js +1 -1
- package/dist/onboarding-smoke-test.js +0 -5
- package/dist/orchestrate-init-status.js +0 -1
- package/dist/orchestrate-initiative.js +0 -1
- package/dist/orchestrate-monitor.js +0 -1
- package/dist/plan-create.js +0 -2
- package/dist/plan-edit.js +0 -2
- package/dist/plan-link.js +0 -2
- package/dist/plan-promote.js +0 -2
- package/dist/signal-cleanup.js +0 -4
- package/dist/state-bootstrap.js +0 -1
- package/dist/state-cleanup.js +0 -4
- package/dist/state-doctor-fix.js +5 -8
- package/dist/state-doctor.js +0 -11
- package/dist/sync-templates.js +188 -34
- package/dist/wu-block.js +100 -48
- package/dist/wu-claim.js +1 -22
- package/dist/wu-cleanup.js +0 -1
- package/dist/wu-create.js +0 -2
- package/dist/wu-done-auto-cleanup.js +139 -0
- package/dist/wu-done.js +11 -4
- package/dist/wu-edit.js +0 -12
- package/dist/wu-preflight.js +0 -1
- package/dist/wu-prep.js +0 -1
- package/dist/wu-proto.js +0 -1
- package/dist/wu-spawn.js +0 -3
- package/dist/wu-unblock.js +0 -2
- package/dist/wu-validate.js +0 -1
- package/package.json +9 -7
|
@@ -491,4 +491,253 @@ describe('lumenflow init', () => {
|
|
|
491
491
|
});
|
|
492
492
|
});
|
|
493
493
|
});
|
|
494
|
+
// WU-1382: Improved templates for agent clarity
|
|
495
|
+
describe('WU-1382: improved templates for agent clarity', () => {
|
|
496
|
+
describe('CLAUDE.md template enhancements', () => {
|
|
497
|
+
it('should include CLI commands table inline in CLAUDE.md', async () => {
|
|
498
|
+
const options = {
|
|
499
|
+
force: false,
|
|
500
|
+
full: false,
|
|
501
|
+
client: 'claude',
|
|
502
|
+
};
|
|
503
|
+
await scaffoldProject(tempDir, options);
|
|
504
|
+
const claudeMdPath = path.join(tempDir, 'CLAUDE.md');
|
|
505
|
+
expect(fs.existsSync(claudeMdPath)).toBe(true);
|
|
506
|
+
const content = fs.readFileSync(claudeMdPath, 'utf-8');
|
|
507
|
+
// Should have CLI commands table with common commands
|
|
508
|
+
expect(content).toContain('| Command');
|
|
509
|
+
expect(content).toContain('wu:claim');
|
|
510
|
+
expect(content).toContain('wu:done');
|
|
511
|
+
expect(content).toContain('wu:status');
|
|
512
|
+
expect(content).toContain('gates');
|
|
513
|
+
});
|
|
514
|
+
it('should include warning about manual YAML editing in CLAUDE.md', async () => {
|
|
515
|
+
const options = {
|
|
516
|
+
force: false,
|
|
517
|
+
full: false,
|
|
518
|
+
client: 'claude',
|
|
519
|
+
};
|
|
520
|
+
await scaffoldProject(tempDir, options);
|
|
521
|
+
const claudeMdPath = path.join(tempDir, 'CLAUDE.md');
|
|
522
|
+
const content = fs.readFileSync(claudeMdPath, 'utf-8');
|
|
523
|
+
// Should warn against manual WU YAML edits
|
|
524
|
+
expect(content).toMatch(/do\s+not\s+(manually\s+)?edit|never\s+(manually\s+)?edit/i);
|
|
525
|
+
expect(content).toMatch(/wu.*yaml|yaml.*wu/i);
|
|
526
|
+
});
|
|
527
|
+
});
|
|
528
|
+
describe('config.yaml managed file header', () => {
|
|
529
|
+
it('should include managed file header in .lumenflow.config.yaml', async () => {
|
|
530
|
+
const options = {
|
|
531
|
+
force: false,
|
|
532
|
+
full: false,
|
|
533
|
+
};
|
|
534
|
+
await scaffoldProject(tempDir, options);
|
|
535
|
+
const configPath = path.join(tempDir, '.lumenflow.config.yaml');
|
|
536
|
+
expect(fs.existsSync(configPath)).toBe(true);
|
|
537
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
538
|
+
// Should have managed file header
|
|
539
|
+
expect(content).toMatch(/LUMENFLOW\s+MANAGED\s+FILE/i);
|
|
540
|
+
expect(content).toMatch(/do\s+not\s+(manually\s+)?edit/i);
|
|
541
|
+
});
|
|
542
|
+
});
|
|
543
|
+
describe('lane-inference.yaml managed file header', () => {
|
|
544
|
+
it('should include managed file header in .lumenflow.lane-inference.yaml', async () => {
|
|
545
|
+
const options = {
|
|
546
|
+
force: false,
|
|
547
|
+
full: true,
|
|
548
|
+
};
|
|
549
|
+
await scaffoldProject(tempDir, options);
|
|
550
|
+
const laneInferencePath = path.join(tempDir, '.lumenflow.lane-inference.yaml');
|
|
551
|
+
expect(fs.existsSync(laneInferencePath)).toBe(true);
|
|
552
|
+
const content = fs.readFileSync(laneInferencePath, 'utf-8');
|
|
553
|
+
// Should have managed file header
|
|
554
|
+
expect(content).toMatch(/LUMENFLOW\s+MANAGED\s+FILE/i);
|
|
555
|
+
expect(content).toMatch(/do\s+not\s+(manually\s+)?edit/i);
|
|
556
|
+
});
|
|
557
|
+
});
|
|
558
|
+
});
|
|
559
|
+
// WU-1383: CLI safeguards against manual file editing
|
|
560
|
+
describe('WU-1383: CLI safeguards for Claude client', () => {
|
|
561
|
+
const CONFIG_FILE_NAME = '.lumenflow.config.yaml';
|
|
562
|
+
describe('enforcement hooks enabled by default for --client claude', () => {
|
|
563
|
+
it('should add enforcement hooks config when --client claude is used', async () => {
|
|
564
|
+
const options = {
|
|
565
|
+
force: false,
|
|
566
|
+
full: false,
|
|
567
|
+
client: 'claude',
|
|
568
|
+
};
|
|
569
|
+
await scaffoldProject(tempDir, options);
|
|
570
|
+
const configPath = path.join(tempDir, CONFIG_FILE_NAME);
|
|
571
|
+
expect(fs.existsSync(configPath)).toBe(true);
|
|
572
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
573
|
+
// Should have enforcement hooks enabled for claude-code
|
|
574
|
+
expect(content).toContain('claude-code');
|
|
575
|
+
expect(content).toContain('enforcement');
|
|
576
|
+
expect(content).toContain('hooks: true');
|
|
577
|
+
});
|
|
578
|
+
it('should set block_outside_worktree to true by default for claude client', async () => {
|
|
579
|
+
const options = {
|
|
580
|
+
force: false,
|
|
581
|
+
full: false,
|
|
582
|
+
client: 'claude',
|
|
583
|
+
};
|
|
584
|
+
await scaffoldProject(tempDir, options);
|
|
585
|
+
const configPath = path.join(tempDir, CONFIG_FILE_NAME);
|
|
586
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
587
|
+
expect(content).toContain('block_outside_worktree: true');
|
|
588
|
+
});
|
|
589
|
+
it('should NOT add enforcement hooks for other clients like cursor', async () => {
|
|
590
|
+
const options = {
|
|
591
|
+
force: false,
|
|
592
|
+
full: false,
|
|
593
|
+
client: 'cursor',
|
|
594
|
+
};
|
|
595
|
+
await scaffoldProject(tempDir, options);
|
|
596
|
+
const configPath = path.join(tempDir, CONFIG_FILE_NAME);
|
|
597
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
598
|
+
// Should NOT have claude-code enforcement section (check for the nested enforcement block)
|
|
599
|
+
// Note: The default config has agents.defaultClient: claude-code, but no enforcement section
|
|
600
|
+
expect(content).not.toContain('block_outside_worktree');
|
|
601
|
+
expect(content).not.toMatch(/claude-code:\s*\n\s*enforcement/);
|
|
602
|
+
});
|
|
603
|
+
});
|
|
604
|
+
describe('warning when config already exists', () => {
|
|
605
|
+
it('should add warning to result when config yaml already exists', async () => {
|
|
606
|
+
// Create existing config file
|
|
607
|
+
fs.writeFileSync(path.join(tempDir, CONFIG_FILE_NAME), '# Existing config\ndirectories:\n tasksDir: docs/tasks\n');
|
|
608
|
+
const options = {
|
|
609
|
+
force: false,
|
|
610
|
+
full: false,
|
|
611
|
+
};
|
|
612
|
+
const result = await scaffoldProject(tempDir, options);
|
|
613
|
+
// Should have warning about existing config
|
|
614
|
+
expect(result.warnings).toBeDefined();
|
|
615
|
+
expect(result.warnings?.some((w) => w.includes('already exists'))).toBe(true);
|
|
616
|
+
// Warning should suggest CLI commands
|
|
617
|
+
expect(result.warnings?.some((w) => w.includes('CLI') || w.includes('lumenflow'))).toBe(true);
|
|
618
|
+
});
|
|
619
|
+
it('should skip config file when it already exists (not force)', async () => {
|
|
620
|
+
const existingContent = '# My custom config\n';
|
|
621
|
+
fs.writeFileSync(path.join(tempDir, CONFIG_FILE_NAME), existingContent);
|
|
622
|
+
const options = {
|
|
623
|
+
force: false,
|
|
624
|
+
full: false,
|
|
625
|
+
};
|
|
626
|
+
const result = await scaffoldProject(tempDir, options);
|
|
627
|
+
expect(result.skipped).toContain(CONFIG_FILE_NAME);
|
|
628
|
+
// Content should not be changed
|
|
629
|
+
const content = fs.readFileSync(path.join(tempDir, CONFIG_FILE_NAME), 'utf-8');
|
|
630
|
+
expect(content).toBe(existingContent);
|
|
631
|
+
});
|
|
632
|
+
});
|
|
633
|
+
describe('post-init output shows CLI commands prominently', () => {
|
|
634
|
+
// Note: These test the ScaffoldResult which contains info for the CLI output
|
|
635
|
+
// The main() function uses these to print output
|
|
636
|
+
it('should include CLI usage guidance in warnings when config exists', async () => {
|
|
637
|
+
fs.writeFileSync(path.join(tempDir, CONFIG_FILE_NAME), '# Existing\n');
|
|
638
|
+
const options = {
|
|
639
|
+
force: false,
|
|
640
|
+
full: false,
|
|
641
|
+
};
|
|
642
|
+
const result = await scaffoldProject(tempDir, options);
|
|
643
|
+
// Warning should mention CLI commands for editing config
|
|
644
|
+
expect(result.warnings?.some((w) => /pnpm|lumenflow|CLI/i.test(w))).toBe(true);
|
|
645
|
+
});
|
|
646
|
+
});
|
|
647
|
+
describe('warning message suggests CLI commands not manual editing', () => {
|
|
648
|
+
it('should warn users to use CLI commands instead of manual editing', async () => {
|
|
649
|
+
fs.writeFileSync(path.join(tempDir, CONFIG_FILE_NAME), '# Existing config\n');
|
|
650
|
+
const options = {
|
|
651
|
+
force: false,
|
|
652
|
+
full: false,
|
|
653
|
+
};
|
|
654
|
+
const result = await scaffoldProject(tempDir, options);
|
|
655
|
+
// Should have a warning that mentions not to manually edit
|
|
656
|
+
expect(result.warnings?.some((w) => w.includes('manual') || w.includes('CLI') || w.includes('lumenflow'))).toBe(true);
|
|
657
|
+
});
|
|
658
|
+
});
|
|
659
|
+
});
|
|
660
|
+
// WU-1362: Branch guard tests for init.ts
|
|
661
|
+
describe('WU-1362: branch guard for tracked file writes', () => {
|
|
662
|
+
it('should block scaffold when on main branch and targeting main checkout', async () => {
|
|
663
|
+
// This test verifies that scaffoldProject checks branch before writing
|
|
664
|
+
// Note: This test uses a temp directory (not on main), so it should pass
|
|
665
|
+
// The actual blocking only applies when targeting main checkout on main branch
|
|
666
|
+
const options = {
|
|
667
|
+
force: false,
|
|
668
|
+
full: false,
|
|
669
|
+
};
|
|
670
|
+
// Since we're in a temp dir, not on main branch, this should work
|
|
671
|
+
const result = await scaffoldProject(tempDir, options);
|
|
672
|
+
expect(result.created.length).toBeGreaterThan(0);
|
|
673
|
+
});
|
|
674
|
+
it('should allow scaffold in worktree directory', async () => {
|
|
675
|
+
// Simulate worktree-like path by creating directory structure
|
|
676
|
+
const worktreePath = path.join(tempDir, 'worktrees', 'operations-wu-999');
|
|
677
|
+
fs.mkdirSync(worktreePath, { recursive: true });
|
|
678
|
+
const options = {
|
|
679
|
+
force: false,
|
|
680
|
+
full: false,
|
|
681
|
+
};
|
|
682
|
+
// Should succeed when in worktree-like path
|
|
683
|
+
const result = await scaffoldProject(worktreePath, options);
|
|
684
|
+
expect(result.created.length).toBeGreaterThan(0);
|
|
685
|
+
});
|
|
686
|
+
});
|
|
687
|
+
// WU-1385: Include wu-sizing-guide.md in lumenflow init onboarding docs
|
|
688
|
+
describe('WU-1385: wu-sizing-guide.md scaffolding', () => {
|
|
689
|
+
describe('wu-sizing-guide.md creation with --full', () => {
|
|
690
|
+
it('should scaffold wu-sizing-guide.md in onboarding docs with --full', async () => {
|
|
691
|
+
const options = {
|
|
692
|
+
force: false,
|
|
693
|
+
full: true,
|
|
694
|
+
docsStructure: 'arc42',
|
|
695
|
+
};
|
|
696
|
+
await scaffoldProject(tempDir, options);
|
|
697
|
+
const onboardingDir = path.join(tempDir, ONBOARDING_DOCS_PATH);
|
|
698
|
+
const sizingGuidePath = path.join(onboardingDir, 'wu-sizing-guide.md');
|
|
699
|
+
expect(fs.existsSync(sizingGuidePath)).toBe(true);
|
|
700
|
+
});
|
|
701
|
+
it('should include key sizing guide content', async () => {
|
|
702
|
+
const options = {
|
|
703
|
+
force: false,
|
|
704
|
+
full: true,
|
|
705
|
+
docsStructure: 'arc42',
|
|
706
|
+
};
|
|
707
|
+
await scaffoldProject(tempDir, options);
|
|
708
|
+
const onboardingDir = path.join(tempDir, ONBOARDING_DOCS_PATH);
|
|
709
|
+
const sizingGuidePath = path.join(onboardingDir, 'wu-sizing-guide.md');
|
|
710
|
+
const content = fs.readFileSync(sizingGuidePath, 'utf-8');
|
|
711
|
+
// Should have key content from the sizing guide
|
|
712
|
+
expect(content).toContain('Complexity');
|
|
713
|
+
expect(content).toContain('Tool Calls');
|
|
714
|
+
expect(content).toContain('Context');
|
|
715
|
+
});
|
|
716
|
+
it('should not scaffold wu-sizing-guide.md with --minimal (full=false)', async () => {
|
|
717
|
+
const options = {
|
|
718
|
+
force: false,
|
|
719
|
+
full: false,
|
|
720
|
+
};
|
|
721
|
+
await scaffoldProject(tempDir, options);
|
|
722
|
+
const onboardingDir = path.join(tempDir, ONBOARDING_DOCS_PATH);
|
|
723
|
+
const sizingGuidePath = path.join(onboardingDir, 'wu-sizing-guide.md');
|
|
724
|
+
expect(fs.existsSync(sizingGuidePath)).toBe(false);
|
|
725
|
+
});
|
|
726
|
+
});
|
|
727
|
+
describe('starting-prompt.md references sizing guide', () => {
|
|
728
|
+
it('should reference wu-sizing-guide.md in starting-prompt.md', async () => {
|
|
729
|
+
const options = {
|
|
730
|
+
force: false,
|
|
731
|
+
full: true,
|
|
732
|
+
docsStructure: 'arc42',
|
|
733
|
+
};
|
|
734
|
+
await scaffoldProject(tempDir, options);
|
|
735
|
+
const onboardingDir = path.join(tempDir, ONBOARDING_DOCS_PATH);
|
|
736
|
+
const startingPromptPath = path.join(onboardingDir, 'starting-prompt.md');
|
|
737
|
+
const content = fs.readFileSync(startingPromptPath, 'utf-8');
|
|
738
|
+
// Should reference the sizing guide
|
|
739
|
+
expect(content).toContain('wu-sizing-guide.md');
|
|
740
|
+
});
|
|
741
|
+
});
|
|
742
|
+
});
|
|
494
743
|
});
|