@lumenflow/cli 2.8.0 → 2.10.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 +4 -3
- package/dist/__tests__/commands.test.js +75 -0
- package/dist/__tests__/doctor.test.js +510 -0
- package/dist/__tests__/init.test.js +222 -0
- package/dist/commands.js +171 -0
- package/dist/doctor.js +479 -8
- package/dist/hooks/enforcement-generator.js +256 -5
- package/dist/hooks/enforcement-sync.js +52 -6
- package/dist/init.js +299 -8
- package/dist/mem-recover.js +221 -0
- package/package.json +7 -6
- package/templates/core/LUMENFLOW.md.template +24 -0
- package/templates/core/ai/onboarding/first-wu-mistakes.md.template +47 -0
- package/templates/core/ai/onboarding/lumenflow-force-usage.md.template +183 -0
- package/templates/core/ai/onboarding/quick-ref-commands.md.template +68 -55
- package/templates/core/ai/onboarding/release-process.md.template +58 -4
- package/templates/core/ai/onboarding/starting-prompt.md.template +67 -3
- package/templates/vendors/claude/.claude/hooks/pre-compact-checkpoint.sh +102 -0
- package/templates/vendors/claude/.claude/hooks/session-start-recovery.sh +74 -0
- package/templates/vendors/claude/.claude/settings.json.template +42 -0
- package/templates/vendors/claude/.claude/skills/context-management/SKILL.md.template +23 -6
|
@@ -491,6 +491,172 @@ 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
|
+
});
|
|
494
660
|
// WU-1362: Branch guard tests for init.ts
|
|
495
661
|
describe('WU-1362: branch guard for tracked file writes', () => {
|
|
496
662
|
it('should block scaffold when on main branch and targeting main checkout', async () => {
|
|
@@ -518,4 +684,60 @@ describe('lumenflow init', () => {
|
|
|
518
684
|
expect(result.created.length).toBeGreaterThan(0);
|
|
519
685
|
});
|
|
520
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
|
+
});
|
|
521
743
|
});
|
package/dist/commands.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file commands.ts
|
|
3
|
+
* LumenFlow CLI commands discovery feature (WU-1378)
|
|
4
|
+
*
|
|
5
|
+
* Provides a way to discover all available CLI commands grouped by category.
|
|
6
|
+
* This helps agents and users find CLI workflows without reading docs.
|
|
7
|
+
*/
|
|
8
|
+
import { createWUParser } from '@lumenflow/core';
|
|
9
|
+
import { runCLI } from './cli-entry-point.js';
|
|
10
|
+
/**
|
|
11
|
+
* Command categories organized by function
|
|
12
|
+
* Based on quick-ref-commands.md structure
|
|
13
|
+
*/
|
|
14
|
+
const COMMAND_CATEGORIES = [
|
|
15
|
+
{
|
|
16
|
+
name: 'WU Lifecycle',
|
|
17
|
+
commands: [
|
|
18
|
+
{ name: 'wu:create', description: 'Create new WU spec' },
|
|
19
|
+
{ name: 'wu:claim', description: 'Claim WU and create worktree' },
|
|
20
|
+
{ name: 'wu:prep', description: 'Run gates in worktree, prep for wu:done' },
|
|
21
|
+
{ name: 'wu:done', description: 'Complete WU (merge, stamp, cleanup) from main' },
|
|
22
|
+
{ name: 'wu:edit', description: 'Edit WU spec fields' },
|
|
23
|
+
{ name: 'wu:block', description: 'Block WU with reason' },
|
|
24
|
+
{ name: 'wu:unblock', description: 'Unblock WU' },
|
|
25
|
+
{ name: 'wu:release', description: 'Release orphaned WU (in_progress to ready)' },
|
|
26
|
+
{ name: 'wu:status', description: 'Show WU status, location, valid commands' },
|
|
27
|
+
{ name: 'wu:spawn', description: 'Generate sub-agent spawn prompt' },
|
|
28
|
+
{ name: 'wu:validate', description: 'Validate WU spec' },
|
|
29
|
+
{ name: 'wu:recover', description: 'Analyze and fix WU state inconsistencies' },
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'Gates & Quality',
|
|
34
|
+
commands: [
|
|
35
|
+
{ name: 'gates', description: 'Run all quality gates' },
|
|
36
|
+
{ name: 'format', description: 'Format all files (Prettier)' },
|
|
37
|
+
{ name: 'lint', description: 'Run ESLint' },
|
|
38
|
+
{ name: 'typecheck', description: 'Run TypeScript type checking' },
|
|
39
|
+
{ name: 'test', description: 'Run all tests (Vitest)' },
|
|
40
|
+
{ name: 'lane:health', description: 'Check lane config health' },
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'Memory & Sessions',
|
|
45
|
+
commands: [
|
|
46
|
+
{ name: 'mem:init', description: 'Initialize memory for WU' },
|
|
47
|
+
{ name: 'mem:checkpoint', description: 'Save progress checkpoint' },
|
|
48
|
+
{ name: 'mem:signal', description: 'Broadcast coordination signal' },
|
|
49
|
+
{ name: 'mem:inbox', description: 'Check coordination signals' },
|
|
50
|
+
{ name: 'mem:create', description: 'Create memory node (bug discovery)' },
|
|
51
|
+
{ name: 'mem:context', description: 'Get context for current lane/WU' },
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'Initiatives',
|
|
56
|
+
commands: [
|
|
57
|
+
{ name: 'initiative:create', description: 'Create new initiative' },
|
|
58
|
+
{ name: 'initiative:edit', description: 'Edit initiative fields' },
|
|
59
|
+
{ name: 'initiative:list', description: 'List all initiatives' },
|
|
60
|
+
{ name: 'initiative:status', description: 'Show initiative status' },
|
|
61
|
+
{ name: 'initiative:add-wu', description: 'Add WU to initiative' },
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'Orchestration',
|
|
66
|
+
commands: [
|
|
67
|
+
{ name: 'orchestrate:initiative', description: 'Orchestrate initiative execution' },
|
|
68
|
+
{ name: 'orchestrate:init-status', description: 'Compact initiative progress view' },
|
|
69
|
+
{ name: 'orchestrate:monitor', description: 'Monitor spawn/agent activity' },
|
|
70
|
+
{ name: 'spawn:list', description: 'List active spawned agents' },
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'Setup & Development',
|
|
75
|
+
commands: [
|
|
76
|
+
{ name: 'setup', description: 'Install deps and build CLI (first time)' },
|
|
77
|
+
{ name: 'lumenflow', description: 'Initialize LumenFlow in a project' },
|
|
78
|
+
{ name: 'lumenflow:doctor', description: 'Diagnose LumenFlow configuration' },
|
|
79
|
+
{ name: 'lumenflow:upgrade', description: 'Upgrade LumenFlow packages' },
|
|
80
|
+
{ name: 'docs:sync', description: 'Sync agent docs (for upgrades)' },
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: 'Metrics & Flow',
|
|
85
|
+
commands: [
|
|
86
|
+
{ name: 'flow:report', description: 'Generate flow metrics report' },
|
|
87
|
+
{ name: 'flow:bottlenecks', description: 'Identify flow bottlenecks' },
|
|
88
|
+
{ name: 'metrics:snapshot', description: 'Capture metrics snapshot' },
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: 'State Management',
|
|
93
|
+
commands: [
|
|
94
|
+
{ name: 'state:doctor', description: 'Diagnose state store issues' },
|
|
95
|
+
{ name: 'state:cleanup', description: 'Clean up stale state data' },
|
|
96
|
+
{ name: 'state:bootstrap', description: 'Bootstrap state store' },
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
];
|
|
100
|
+
/**
|
|
101
|
+
* Get the complete commands registry
|
|
102
|
+
* @returns Array of command categories with their commands
|
|
103
|
+
*/
|
|
104
|
+
export function getCommandsRegistry() {
|
|
105
|
+
return COMMAND_CATEGORIES;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Format commands output for terminal display
|
|
109
|
+
* @returns Formatted string with all commands grouped by category
|
|
110
|
+
*/
|
|
111
|
+
export function formatCommandsOutput() {
|
|
112
|
+
const lines = [];
|
|
113
|
+
lines.push('LumenFlow CLI Commands');
|
|
114
|
+
lines.push('======================');
|
|
115
|
+
lines.push('');
|
|
116
|
+
for (const category of COMMAND_CATEGORIES) {
|
|
117
|
+
lines.push(`## ${category.name}`);
|
|
118
|
+
lines.push('');
|
|
119
|
+
// Find the longest command name for alignment
|
|
120
|
+
const maxNameLength = Math.max(...category.commands.map((cmd) => cmd.name.length));
|
|
121
|
+
for (const cmd of category.commands) {
|
|
122
|
+
const padding = ' '.repeat(maxNameLength - cmd.name.length + 2);
|
|
123
|
+
lines.push(` ${cmd.name}${padding}${cmd.description}`);
|
|
124
|
+
}
|
|
125
|
+
lines.push('');
|
|
126
|
+
}
|
|
127
|
+
lines.push('---');
|
|
128
|
+
lines.push('Tip: Run `pnpm <command> --help` for detailed options.');
|
|
129
|
+
lines.push('');
|
|
130
|
+
return lines.join('\n');
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* CLI option definitions for commands command
|
|
134
|
+
*/
|
|
135
|
+
const COMMANDS_OPTIONS = {
|
|
136
|
+
json: {
|
|
137
|
+
name: 'json',
|
|
138
|
+
flags: '--json',
|
|
139
|
+
description: 'Output commands as JSON',
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Parse commands command options using createWUParser
|
|
144
|
+
*/
|
|
145
|
+
export function parseCommandsOptions() {
|
|
146
|
+
const opts = createWUParser({
|
|
147
|
+
name: 'lumenflow-commands',
|
|
148
|
+
description: 'List all available LumenFlow CLI commands',
|
|
149
|
+
options: Object.values(COMMANDS_OPTIONS),
|
|
150
|
+
});
|
|
151
|
+
return {
|
|
152
|
+
json: opts.json ?? false,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Main function for the commands CLI
|
|
157
|
+
*/
|
|
158
|
+
export async function main() {
|
|
159
|
+
const opts = parseCommandsOptions();
|
|
160
|
+
if (opts.json) {
|
|
161
|
+
console.log(JSON.stringify(getCommandsRegistry(), null, 2));
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
console.log(formatCommandsOutput());
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// CLI entry point
|
|
168
|
+
// WU-1071: Use import.meta.main for proper CLI detection with pnpm symlinks
|
|
169
|
+
if (import.meta.main) {
|
|
170
|
+
runCLI(main);
|
|
171
|
+
}
|