CLI Alphabetical Organization
Status: ✅ Complete · Priority: Medium · Created: 2025-11-13
Project: lean-spec
Team: Core Development
Overview
The cli.ts file has grown to 702 lines with 20+ commands, making it difficult to maintain and locate commands. Commands are registered in implementation order (not alphabetical), and the help text groupings are incomplete.
Goal: Refactor CLI architecture to be maintainable at scale with clear organization patterns.
Problems
- Size: 702 lines in single file
- Order: Commands not alphabetically sorted (hard to find)
- Inconsistency: Help text missing
analyze,split,compact,tokens - Duplication: Command logic mixed with registration
- Maintainability: Adding commands requires editing massive file
Design
Pattern: Command Definition Files
Move each command's CLI definition to its own command file, following commander.js patterns used by tools like pnpm, turbo, nx:
commands/
archive.ts - export archiveSpec() AND archiveCommand()
backfill.ts - export backfillTimestamps() AND backfillCommand()
create.ts - export createSpec() AND createCommand()
...
Each command file exports TWO things:
- Business logic function (already exists): e.g.,
archiveSpec() - NEW: Command definition function: e.g.,
archiveCommand()that returns CommanderCommandobject
Architecture
Before (current):
// cli.ts (702 lines)
program
.command('archive <spec>')
.description('...')
.action(async (spec) => {
await archiveSpec(spec);
});
// ... 20+ more commands
After (proposed):
// cli.ts (~150 lines)
import { registerCommands } from './commands/registry.js';
const program = new Command();
registerCommands(program);
program.parse();
// commands/registry.ts
export function registerCommands(program: Command) {
// Alphabetically sorted
program.addCommand(analyzeCommand());
program.addCommand(archiveCommand());
program.addCommand(backfillCommand());
// ... etc
}
// commands/archive.ts
export function archiveCommand(): Command {
return new Command('archive')
.description('Move spec to archived/')
.argument('<spec>', 'Spec to archive')
.action(async (spec) => {
await archiveSpec(spec);
});
}
export async function archiveSpec(specPath: string) {
// existing logic
}
Benefits
- Alphabetical by default: Registry enforces order
- Single responsibility: Each file = one command
- Easier to add commands: Create file, export command, add to registry
- Testable: Can test command definitions separately
- Smaller files: ~50 lines per command vs 702-line monolith
- Clear structure: Command definition co-located with logic
Command Groups in Help
Update help text to use functional grouping with complete command list:
Command Groups:
Core Workflow:
init, create, update, archive, migrate
Discovery & Search:
list, view, open, search, files
Project Analytics:
board, stats, timeline, gantt, deps
Quality & Optimization:
analyze, tokens, validate, check
Advanced Editing:
split, compact
Configuration:
templates
Integration:
mcp (MCP server)
Plan
Phase 1: Extract Command Definitions
- Create
commands/registry.tswithregisterCommands()function - Update each command file (e.g.,
archive.ts) to export command definition function - Verify each command still exports business logic for backward compatibility
Phase 2: Refactor cli.ts
- Import and call
registerCommands()incli.ts - Remove individual command registrations (keep only program setup + help text)
- Update help text with complete alphabetical command list
- Reduce
cli.tsfrom 702 to ~150 lines
Phase 3: Validation
- Run
pnpm build- ensure TypeScript compiles - Run
node bin/lean-spec.js --help- verify alphabetical order - Test sample commands:
create,list,view,validate,tokens - Run existing test suite:
pnpm test:run - Check command count matches (currently 20+ commands)
Test
Validation criteria:
- ✅ Commands appear alphabetically in
--helpoutput - ✅ Help text includes ALL commands (analyze, split, compact, tokens)
- ✅
cli.tsreduced to <200 lines - ✅ All existing tests pass
- ✅ No breaking changes to command behavior
Manual testing:
node bin/lean-spec.js --help # alphabetical order
node bin/lean-spec.js create test-spec # works
node bin/lean-spec.js tokens 059 # works
node bin/lean-spec.js validate # works
Notes
Alternatives Considered
- Keep monolithic cli.ts, just alphabetize: Doesn't solve scalability
- Subcommand grouping (e.g.,
lean-spec analytics board): Breaking change - Plugin architecture: Over-engineering for current scale
Migration Safety
- Commands already have separate files in
commands/ - Business logic stays unchanged
- Only CLI registration moves
- Backward compatible (same command syntax)
Future Enhancements
- Auto-generate help text from command metadata
- Command aliases (e.g.,
ls→list) - Plugin system for custom commands