Skip to content

Commit 4948673

Browse files
Refactor: Centralize CLI command registration
Co-authored-by: benji <benji@codepros.org>
1 parent 5ce6853 commit 4948673

File tree

3 files changed

+368
-60
lines changed

3 files changed

+368
-60
lines changed

CLI_COMMANDS_REFACTOR.md

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
# CLI Commands() Refactor Summary
2+
3+
## Overview
4+
Refactored the command registration system to use a centralized `cli.Commands()` function that can be called with `rootCmd.AddCommand(cli.Commands()...)`.
5+
6+
## Changes Made
7+
8+
### 1. Created `cli/cmds.go`
9+
New file that exports all top-level commands from a single function:
10+
11+
```go
12+
package cli
13+
14+
func Commands() []*cobra.Command {
15+
return []*cobra.Command{
16+
// All commands listed here
17+
}
18+
}
19+
```
20+
21+
**Key Features:**
22+
- Single source of truth for all commands
23+
- Subcommands automatically registered via `init()` functions
24+
- Well-documented with comments explaining command hierarchy
25+
- Organized into logical groups (workflow, database, query, etc.)
26+
27+
### 2. Simplified `cmd/canary/main.go`
28+
29+
#### Before:
30+
```go
31+
import (
32+
// 30+ individual command imports
33+
"go.devnw.com/canary/cli/bug"
34+
"go.devnw.com/canary/cli/create"
35+
// ... etc
36+
)
37+
38+
func init() {
39+
rootCmd.AddCommand(scan.ScanCmd)
40+
rootCmd.AddCommand(canaryinit.InitCmd)
41+
rootCmd.AddCommand(create.CreateCmd)
42+
// ... 30+ more AddCommand calls
43+
}
44+
```
45+
46+
#### After:
47+
```go
48+
import (
49+
"go.devnw.com/canary/cli"
50+
"go.devnw.com/canary/cli/db"
51+
canaryinit "go.devnw.com/canary/cli/init"
52+
"go.devnw.com/canary/cli/legacy"
53+
"go.devnw.com/canary/cli/next"
54+
// Only 5 imports needed for flag configuration
55+
)
56+
57+
func init() {
58+
// Add all commands with subcommands automatically included
59+
rootCmd.AddCommand(cli.Commands()...)
60+
61+
// Configure flags for specific commands that need it
62+
canaryinit.InitCmd.Flags().Bool("local", false, "...")
63+
// ... etc
64+
}
65+
```
66+
67+
**Benefits:**
68+
- Reduced imports from 30+ to 5
69+
- Reduced code from 40+ lines to 1 line for command registration
70+
- Cleaner, more maintainable structure
71+
- Easy to add new commands (just add to `cli/cmds.go`)
72+
73+
### 3. Command Hierarchy
74+
75+
The system now properly handles command hierarchies:
76+
77+
#### Parent Commands with Subcommands:
78+
- **bug** ? list, create, update, show
79+
- **gap** ? mark, query, report, helpful, unhelpful, config, categories
80+
- **deps** ? (dynamically created subcommands)
81+
- **project** ? DbCmd, ProjectCmd
82+
- **db** ? MigrateCmd, RollbackCmd
83+
- **doc** ? (document management subcommands)
84+
- **legacy** ? DetectCmd, MigrateFromCmd
85+
- **migrate** ? OrphanCmd
86+
87+
All subcommands are registered in their respective package `init()` functions, so they're automatically available when the parent command is added.
88+
89+
## File Structure
90+
91+
```
92+
cli/
93+
??? cmds.go # NEW: Central command registry
94+
??? bug/
95+
? ??? bug.go # Parent + helpers
96+
? ??? list.go # Subcommand
97+
? ??? create.go # Subcommand
98+
? ??? update.go # Subcommand
99+
? ??? show.go # Subcommand
100+
??? gap/
101+
? ??? gap.go # Parent + all subcommands
102+
??? create/
103+
? ??? create.go # Standalone command
104+
??? list/
105+
? ??? list.go # Standalone command
106+
??? ... (other commands)
107+
108+
cmd/canary/
109+
??? main.go # SIMPLIFIED: Uses cli.Commands()
110+
```
111+
112+
## Usage Pattern
113+
114+
### For Adding New Commands:
115+
116+
1. **Create command in its package:**
117+
```go
118+
// cli/mycommand/mycommand.go
119+
package mycommand
120+
121+
var MyCmd = &cobra.Command{
122+
Use: "mycommand",
123+
// ...
124+
}
125+
126+
func init() {
127+
MyCmd.Flags().String("prompt", "", "...")
128+
// ... other flags
129+
}
130+
```
131+
132+
2. **Add to `cli/cmds.go`:**
133+
```go
134+
import "go.devnw.com/canary/cli/mycommand"
135+
136+
func Commands() []*cobra.Command {
137+
return []*cobra.Command{
138+
// ... existing commands
139+
mycommand.MyCmd,
140+
}
141+
}
142+
```
143+
144+
3. **Done!** No need to modify `cmd/canary/main.go`
145+
146+
### For Adding Subcommands:
147+
148+
1. **Create subcommand file:**
149+
```go
150+
// cli/parent/subcommand.go
151+
package parent
152+
153+
var subCmd = &cobra.Command{
154+
Use: "sub",
155+
// ...
156+
}
157+
158+
func init() {
159+
ParentCmd.AddCommand(subCmd)
160+
subCmd.Flags().String("prompt", "", "...")
161+
}
162+
```
163+
164+
2. **Already works!** Subcommand is automatically included when parent is added
165+
166+
## Testing
167+
168+
All functionality verified:
169+
- ? All commands available: `canary --help`
170+
- ? Bug subcommands work: `canary bug --help`
171+
- ? Gap subcommands work: `canary gap --help`
172+
- ? All --prompt flags present
173+
- ? Binary builds successfully
174+
- ? No duplicate command registrations
175+
176+
## Benefits
177+
178+
1. **Maintainability**
179+
- Single place to see all commands
180+
- Easy to add/remove commands
181+
- Clear command hierarchy
182+
183+
2. **Cleaner Code**
184+
- Reduced imports in main.go (30+ ? 5)
185+
- Reduced code lines (40+ ? 1 for registration)
186+
- Better separation of concerns
187+
188+
3. **Flexibility**
189+
- Easy to reorganize commands
190+
- Easy to add command groups
191+
- Subcommands automatically included
192+
193+
4. **Documentation**
194+
- Self-documenting structure in `cli/cmds.go`
195+
- Comments explain command relationships
196+
- Easy to understand command hierarchy
197+
198+
## Migration Notes
199+
200+
### What Changed:
201+
- `cmd/canary/main.go`: Uses `cli.Commands()` instead of individual `AddCommand` calls
202+
- `cli/cmds.go`: NEW file with centralized command registry
203+
- Imports: Reduced to only what's needed for flag configuration
204+
205+
### What Stayed the Same:
206+
- All command functionality
207+
- All flag definitions
208+
- All subcommand relationships
209+
- All tests and behavior
210+
211+
### Backward Compatibility:
212+
- ? 100% backward compatible
213+
- No breaking changes
214+
- All commands work identically
215+
- All flags preserved
216+
217+
## Future Enhancements
218+
219+
With this structure, it's easy to add:
220+
- Command groups/categories
221+
- Dynamic command loading
222+
- Plugin system for external commands
223+
- Command aliases
224+
- Command deprecation warnings
225+
226+
## Example: Adding a New Command
227+
228+
```go
229+
// 1. Create cli/export/export.go
230+
package export
231+
232+
import "github.com/spf13/cobra"
233+
234+
var ExportCmd = &cobra.Command{
235+
Use: "export",
236+
Short: "Export CANARY tokens",
237+
RunE: func(cmd *cobra.Command, args []string) error {
238+
// Implementation
239+
return nil
240+
},
241+
}
242+
243+
func init() {
244+
ExportCmd.Flags().String("prompt", "", "Custom prompt (future use)")
245+
ExportCmd.Flags().String("format", "json", "Export format")
246+
}
247+
248+
// 2. Update cli/cmds.go
249+
import "go.devnw.com/canary/cli/export"
250+
251+
func Commands() []*cobra.Command {
252+
return []*cobra.Command{
253+
// ... existing commands
254+
export.ExportCmd, // Add new command here
255+
}
256+
}
257+
258+
// 3. Done! Command is now available
259+
```
260+
261+
## Conclusion
262+
263+
The refactored command system provides a clean, maintainable structure that:
264+
- Centralizes command registration
265+
- Simplifies the main entry point
266+
- Properly handles command hierarchies
267+
- Makes it easy to add new commands
268+
- Maintains full backward compatibility

cli/cmds.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright (c) 2025 by Developer Network.
2+
//
3+
// For more details, see the LICENSE file in the root directory of this
4+
// source code repository or contact Developer Network at info@devnw.com.
5+
6+
package cli
7+
8+
import (
9+
"github.com/spf13/cobra"
10+
"go.devnw.com/canary/cli/bug"
11+
"go.devnw.com/canary/cli/checkpoint"
12+
"go.devnw.com/canary/cli/constitution"
13+
"go.devnw.com/canary/cli/create"
14+
"go.devnw.com/canary/cli/db"
15+
"go.devnw.com/canary/cli/deps"
16+
"go.devnw.com/canary/cli/doc"
17+
"go.devnw.com/canary/cli/files"
18+
"go.devnw.com/canary/cli/gap"
19+
"go.devnw.com/canary/cli/grep"
20+
"go.devnw.com/canary/cli/implement"
21+
"go.devnw.com/canary/cli/index"
22+
canaryinit "go.devnw.com/canary/cli/init"
23+
"go.devnw.com/canary/cli/legacy"
24+
"go.devnw.com/canary/cli/list"
25+
"go.devnw.com/canary/cli/migrate"
26+
"go.devnw.com/canary/cli/next"
27+
"go.devnw.com/canary/cli/plan"
28+
"go.devnw.com/canary/cli/prioritize"
29+
"go.devnw.com/canary/cli/project"
30+
"go.devnw.com/canary/cli/scan"
31+
"go.devnw.com/canary/cli/search"
32+
"go.devnw.com/canary/cli/show"
33+
"go.devnw.com/canary/cli/specify"
34+
"go.devnw.com/canary/cli/specs"
35+
"go.devnw.com/canary/cli/status"
36+
)
37+
38+
// Commands returns all top-level commands for the canary CLI.
39+
// Subcommands are already registered with their parent commands via init() functions.
40+
//
41+
// Usage:
42+
// rootCmd.AddCommand(cli.Commands()...)
43+
//
44+
// Note: Commands with subcommands (bug, gap, deps, project, db, doc, legacy, migrate)
45+
// have their subcommands registered in their respective package init() functions.
46+
func Commands() []*cobra.Command {
47+
return []*cobra.Command{
48+
// Core workflow commands
49+
scan.ScanCmd,
50+
canaryinit.InitCmd,
51+
create.CreateCmd,
52+
constitution.ConstitutionCmd,
53+
specify.SpecifyCmd,
54+
plan.PlanCmd,
55+
implement.ImplementCmd,
56+
next.NextCmd,
57+
58+
// Database and indexing
59+
index.IndexCmd,
60+
61+
// Query and display commands
62+
list.ListCmd,
63+
search.SearchCmd,
64+
show.ShowCmd,
65+
files.FilesCmd,
66+
status.StatusCmd,
67+
grep.GrepCmd,
68+
69+
// Management commands
70+
prioritize.PrioritizeCmd,
71+
checkpoint.CheckpointCmd,
72+
73+
// Database migration commands
74+
db.MigrateCmd,
75+
db.RollbackCmd,
76+
77+
// Legacy migration commands
78+
legacy.DetectCmd,
79+
legacy.MigrateFromCmd,
80+
migrate.OrphanCmd,
81+
82+
// Documentation and dependencies
83+
doc.DocCmd,
84+
deps.CreateDepsCommand(),
85+
86+
// Advanced features with subcommands
87+
gap.GapCmd, // Subcommands: mark, query, report, helpful, unhelpful, config, categories
88+
specs.SpecsCmd,
89+
bug.BugCmd, // Subcommands: list, create, update, show
90+
91+
// Project management
92+
project.DbCmd,
93+
project.ProjectCmd,
94+
}
95+
}

0 commit comments

Comments
 (0)