specs

package
v0.3.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 1, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var SpecsCmd = &cobra.Command{
	Use:   "specs [flags]",
	Short: "List all requirement specification directories",
	Long: `Specs lists all requirement specification directories in .canary/specs/.

Shows requirement ID, feature name (extracted from directory name), and paths
to spec.md and plan.md files if they exist.

Examples:
  canary specs
  canary specs --path .canary/specs
  canary specs --json`,
	RunE: func(cmd *cobra.Command, args []string) error {
		specsPath, _ := cmd.Flags().GetString("path")
		jsonOutput, _ := cmd.Flags().GetBool("json")

		if _, err := os.Stat(specsPath); os.IsNotExist(err) {
			return fmt.Errorf("specs directory not found: %s", specsPath)
		}

		entries, err := os.ReadDir(specsPath)
		if err != nil {
			return fmt.Errorf("read specs directory: %w", err)
		}

		// Collect spec information
		type SpecInfo struct {
			ReqID       string `json:"req_id"`
			FeatureName string `json:"feature_name"`
			Directory   string `json:"directory"`
			HasSpec     bool   `json:"has_spec"`
			HasPlan     bool   `json:"has_plan"`
		}

		var specs []SpecInfo

		for _, entry := range entries {
			if !entry.IsDir() {
				continue
			}

			dirName := entry.Name()
			dirPath := filepath.Join(specsPath, dirName)

			parts := strings.SplitN(dirName, "-", 3)
			reqID := dirName
			featureName := ""
			if len(parts) >= 3 {
				reqID = parts[0] + "-" + parts[1]
				featureName = strings.ReplaceAll(parts[2], "-", " ")
				featureName = strings.Title(featureName)
			}

			specPath := filepath.Join(dirPath, "spec.md")
			planPath := filepath.Join(dirPath, "plan.md")

			hasSpec := false
			hasPlan := false

			if _, err := os.Stat(specPath); err == nil {
				hasSpec = true
			}
			if _, err := os.Stat(planPath); err == nil {
				hasPlan = true
			}

			specs = append(specs, SpecInfo{
				ReqID:       reqID,
				FeatureName: featureName,
				Directory:   dirPath,
				HasSpec:     hasSpec,
				HasPlan:     hasPlan,
			})
		}

		sort.Slice(specs, func(i, j int) bool {
			return specs[i].ReqID < specs[j].ReqID
		})

		if jsonOutput {
			if specs == nil {
				specs = []SpecInfo{}
			}
			data, err := json.MarshalIndent(specs, "", "  ")
			if err != nil {
				return fmt.Errorf("marshal specs: %w", err)
			}
			fmt.Println(string(data))
			return nil
		}

		if len(specs) == 0 {
			fmt.Printf("No specification directories found in %s\n", specsPath)
			return nil
		}

		fmt.Printf("Found %d specification directories:\n\n", len(specs))

		for _, spec := range specs {
			fmt.Printf("📁 %s", spec.ReqID)
			if spec.FeatureName != "" {
				fmt.Printf(" - %s", spec.FeatureName)
			}
			fmt.Println()
			fmt.Printf("   %s\n", spec.Directory)

			files := []string{}
			if spec.HasSpec {
				files = append(files, "spec.md")
			}
			if spec.HasPlan {
				files = append(files, "plan.md")
			}
			if len(files) > 0 {
				fmt.Printf("   Files: %s\n", strings.Join(files, ", "))
			} else {
				fmt.Printf("   (no spec or plan files)\n")
			}
			fmt.Println()
		}

		fmt.Printf("Total: %d specifications\n", len(specs))

		return nil
	},
}

CANARY: REQ=ENG-4318; FEATURE="SpecsCmd"; ASPECT=CLI; STATUS=TESTED; TEST=TestCANARY_CBIN_145_CLI_SpecsCmd; UPDATED=2026-08-29

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL