Files
pcli/cmd/status.go
T
Steve Cliff 22d5848e1a feat: Add openspec-sync-specs and openspec-verify-change skills
- Introduced `openspec-sync-specs` skill to sync delta specs to main specs, allowing intelligent merging of requirements.
- Added `openspec-verify-change` skill to verify implementation against change artifacts, ensuring completeness, correctness, and coherence before archiving.

docs: Create CLAUDE.md for project guidance

- Added CLAUDE.md to provide an overview of the PCLI project, including build, test commands, architecture, and resource addition guidelines.

chore: Add new change and design documents for project filter in status command

- Created `.openspec.yaml`, `design.md`, `proposal.md`, and `tasks.md` for the `add-project-filter-to-status` change.
- Updated specs for CLI commands and status command to include project filtering functionality.

feat: Expand board included parsing in API client

- Added parsing for `labels`, `cardLabels`, and `cardMemberships` in the `GetBoard` response.
- Updated `ListCardsByBoard` to enrich card output with label names, enhancing usability in kanban sync workflows.
2026-02-18 21:27:02 +00:00

126 lines
3.4 KiB
Go

package cmd
import (
"fmt"
"os"
"git.franklin.lab/steve.cliff/pcli/model"
"git.franklin.lab/steve.cliff/pcli/output"
"github.com/spf13/cobra"
)
var statusCmd = &cobra.Command{
Use: "status",
Short: "Show status summary of boards and their lists",
Long: "Displays a summary of boards, their lists, and the number of cards in each list.\nUse --project to filter by project name.",
RunE: func(cmd *cobra.Command, args []string) error {
projectName, _ := cmd.Flags().GetString("project")
// Get all boards
boards, err := getClient().ListBoards(getContext())
if err != nil {
return fmt.Errorf("failed to list boards: %w", err)
}
// Filter boards by project if --project flag is provided
if projectName != "" {
projectID, err := resolveProjectNameToID(projectName)
if err != nil {
return err
}
filtered := boards[:0]
for _, board := range boards {
if board.ProjectID == projectID {
filtered = append(filtered, board)
}
}
boards = filtered
}
// Build status summary with error collection
summary := model.StatusSummary{
TotalBoards: len(boards),
Boards: make([]model.BoardSummary, 0, len(boards)),
}
var boardErrors []string
successfulBoards := 0
// For each board, get details and aggregate card counts
for _, board := range boards {
boardDetail, err := getClient().GetBoard(getContext(), board.ID)
if err != nil {
boardErrors = append(boardErrors, fmt.Sprintf("Board %s (%s): %v", board.Name, board.ID, err))
continue
}
// Initialize list summaries with zero counts
listCounts := make(map[string]*model.ListSummary)
listOrder := make([]string, 0, len(boardDetail.Lists))
for _, list := range boardDetail.Lists {
listName := ""
if list.Name != nil {
listName = *list.Name
}
listCounts[list.ID] = &model.ListSummary{
ID: list.ID,
Name: listName,
OpenCards: 0,
ClosedCards: 0,
}
listOrder = append(listOrder, list.ID)
}
// Count cards per list
for _, card := range boardDetail.Cards {
if listSummary, exists := listCounts[card.ListID]; exists {
if card.IsClosed {
listSummary.ClosedCards++
} else {
listSummary.OpenCards++
}
}
}
// Build list summaries in original order
listSummaries := make([]model.ListSummary, 0, len(listOrder))
for _, id := range listOrder {
listSummaries = append(listSummaries, *listCounts[id])
}
// Add board summary
boardSummary := model.BoardSummary{
ID: board.ID,
Name: board.Name,
Lists: listSummaries,
}
summary.Boards = append(summary.Boards, boardSummary)
successfulBoards++
}
// Update total boards to reflect successful loads
summary.TotalBoards = successfulBoards
// If we have errors but some successful boards, add error info to output
if len(boardErrors) > 0 && successfulBoards > 0 {
fmt.Fprintf(os.Stderr, "Warning: %d board(s) failed to load:\n", len(boardErrors))
for _, errMsg := range boardErrors {
fmt.Fprintf(os.Stderr, " - %s\n", errMsg)
}
fmt.Fprintf(os.Stderr, "\nShowing %d successful board(s):\n\n", successfulBoards)
} else if len(boardErrors) > 0 && successfulBoards == 0 {
return fmt.Errorf("failed to load any boards: %s", boardErrors[0])
}
// Output the summary
return output.Print(summary, getFormat(), os.Stdout)
},
}
func init() {
rootCmd.AddCommand(statusCmd)
statusCmd.Flags().String("project", "", "Filter status by project name")
}