package main import ( "fmt" "github.com/orchard9/rdev/internal/sdlc" "github.com/spf13/cobra" ) var queryCmd = &cobra.Command{ Use: "query", Short: "Query SDLC state", } var queryBlockedCmd = &cobra.Command{ Use: "blocked", Short: "List all blocked items", RunE: func(_ *cobra.Command, _ []string) error { root := mustResolveRoot() features, err := sdlc.ListFeatures(root) if err != nil { return err } type blockedInfo struct { Slug string `json:"slug"` Phase string `json:"phase"` Blockers []string `json:"blockers"` } var blocked []blockedInfo for _, f := range features { if f.IsBlocked() { blocked = append(blocked, blockedInfo{ Slug: f.Slug, Phase: string(f.Phase), Blockers: f.Blockers, }) } } if jsonOutput { return printJSON(blocked) } if len(blocked) == 0 { fmt.Println("No blocked items.") return nil } fmt.Println("Blocked Items:") for _, b := range blocked { fmt.Printf(" %s [%s]:\n", b.Slug, b.Phase) for _, reason := range b.Blockers { fmt.Printf(" - %s\n", reason) } } return nil }, } var queryReadyCmd = &cobra.Command{ Use: "ready", Short: "List items ready for work", RunE: func(_ *cobra.Command, _ []string) error { root := mustResolveRoot() state, err := sdlc.LoadState(root) if err != nil { return err } cfg, err := sdlc.LoadConfig(root) if err != nil { return err } features, err := sdlc.ListFeatures(root) if err != nil { return err } classifier := sdlc.NewClassifier() type readyInfo struct { Slug string `json:"slug"` Phase string `json:"phase"` Action string `json:"action"` } var ready []readyInfo for _, f := range features { if f.IsBlocked() { continue } cl := classifier.Classify(&sdlc.EvalContext{ State: state, Feature: f, Config: cfg, Root: root, }) if cl.Action != sdlc.ActionIdle && cl.Action != sdlc.ActionBlocked && cl.Action != sdlc.ActionAwaitApproval { ready = append(ready, readyInfo{ Slug: f.Slug, Phase: string(f.Phase), Action: string(cl.Action), }) } } if jsonOutput { return printJSON(ready) } if len(ready) == 0 { fmt.Println("No items ready for work.") return nil } fmt.Println("Ready for Work:") for _, r := range ready { fmt.Printf(" %-20s [%-15s] -> %s\n", r.Slug, r.Phase, r.Action) } return nil }, } var queryNeedsApprovalCmd = &cobra.Command{ Use: "needs-approval", Short: "List items awaiting approval", RunE: func(_ *cobra.Command, _ []string) error { root := mustResolveRoot() state, err := sdlc.LoadState(root) if err != nil { return err } cfg, err := sdlc.LoadConfig(root) if err != nil { return err } features, err := sdlc.ListFeatures(root) if err != nil { return err } classifier := sdlc.NewClassifier() type approvalInfo struct { Slug string `json:"slug"` Phase string `json:"phase"` Message string `json:"message"` } var pending []approvalInfo for _, f := range features { cl := classifier.Classify(&sdlc.EvalContext{ State: state, Feature: f, Config: cfg, Root: root, }) if cl.Action == sdlc.ActionAwaitApproval { pending = append(pending, approvalInfo{ Slug: f.Slug, Phase: string(f.Phase), Message: cl.Message, }) } } if jsonOutput { return printJSON(pending) } if len(pending) == 0 { fmt.Println("No items awaiting approval.") return nil } fmt.Println("Awaiting Approval:") for _, p := range pending { fmt.Printf(" %-20s [%-15s] %s\n", p.Slug, p.Phase, p.Message) } return nil }, } func init() { queryCmd.AddCommand( queryBlockedCmd, queryReadyCmd, queryNeedsApprovalCmd, ) rootCmd.AddCommand(queryCmd) }