Files
Devour/cmd/status.go
T
Tomas Dvorak 898a3c303f update
2026-02-24 10:33:59 +01:00

131 lines
3.2 KiB
Go

package cmd
import (
"context"
"fmt"
"time"
"github.com/spf13/cobra"
"github.com/yourorg/devour/internal/projectstate"
"github.com/yourorg/devour/internal/search"
"github.com/yourorg/devour/internal/ui"
)
var statusCmd = &cobra.Command{
Use: "status",
Short: "Show index status and statistics",
Long: `Display the current status of the Devour index.
Shows:
- Index health
- Document count
- Last update time
- Source status
- Storage usage`,
RunE: runStatus,
}
func runStatus(cmd *cobra.Command, args []string) error {
cfg, err := loadAppConfig()
if err != nil {
return err
}
// Print the small character mascot
ui.PrintCharacterSmall()
fmt.Println()
ui.PrintHeader("Devour Status")
docsStats, err := projectstate.CollectDocsStats(cfg.Storage.DocsDir)
if err != nil {
return err
}
engine := search.NewEngine(cfg)
indexStats, indexErr := engine.EnsureIndexed(context.Background())
indexHealth := "✓ Healthy"
if indexErr != nil {
if docsStats.DocumentCount == 0 {
indexHealth = "⚠️ No docs indexed yet"
} else {
indexHealth = "✗ Index error"
}
}
lastUpdated := "Never"
if !docsStats.LastUpdated.IsZero() {
lastUpdated = docsStats.LastUpdated.Format(time.RFC3339)
}
chunks := 0
if indexStats != nil {
chunks = indexStats.Documents
}
ui.PrintKeyValue("Index Health", indexHealth)
ui.PrintKeyValue("Documents", fmt.Sprintf("%d indexed", docsStats.DocumentCount))
ui.PrintKeyValue("Chunks", fmt.Sprintf("%d total", chunks))
ui.PrintKeyValue("Vector Dimension", fmt.Sprintf("%d", cfg.Embeddings.Dimensions))
ui.PrintKeyValue("Last Updated", lastUpdated)
ui.PrintKeyValue("Storage Used", humanSize(docsStats.StorageBytes))
fmt.Println()
ui.PrintSection("Sources")
state, stateErr := projectstate.LoadSourceState(cfg.Storage.MetadataDir)
if stateErr != nil || len(state.Sources) == 0 {
ui.PrintInfo(" None tracked yet")
} else {
keys := make([]string, 0, len(state.Sources))
for k := range state.Sources {
keys = append(keys, k)
}
sortStrings(keys)
for _, k := range keys {
s := state.Sources[k]
last := "never"
if !s.LastSync.IsZero() {
last = s.LastSync.Format("2006-01-02 15:04:05")
}
fmt.Printf(" • %s (%s): %d docs, last sync %s\n", s.Name, s.Type, s.DocCount, last)
}
}
fmt.Println()
ui.PrintSection("Next Steps")
if docsStats.DocumentCount == 0 {
fmt.Println(" 1. Run 'devour scrape <source>' to index documentation")
fmt.Println(" 2. Run 'devour query \"<topic>\"' to search indexed docs")
} else {
fmt.Println(" 1. Run 'devour query \"<topic>\"' for local docs search")
fmt.Println(" 2. Run 'devour ask --lang <lang> \"<question>\"' for structured answers")
}
if indexErr != nil {
fmt.Printf(" ⚠️ Index note: %v\n", indexErr)
}
// Show when check happened
fmt.Printf("\nStatus as of: %s\n", time.Now().Format(time.RFC3339))
return nil
}
func humanSize(b int64) string {
const mb = 1024 * 1024
if b < mb {
return fmt.Sprintf("%d KB", b/1024)
}
return fmt.Sprintf("%.2f MB", float64(b)/float64(mb))
}
func sortStrings(values []string) {
if len(values) < 2 {
return
}
for i := 1; i < len(values); i++ {
for j := i; j > 0 && values[j] < values[j-1]; j-- {
values[j], values[j-1] = values[j-1], values[j]
}
}
}