diff --git a/.golangci.yml b/.golangci.yml index e216e9f..b96ead8 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -9,15 +9,13 @@ run: modules-download-mode: readonly linters: - disable-all: true enable: # Default linters - govet - staticcheck + - errcheck - ineffassign - unused - # Additional useful linters - - errcheck linters-settings: govet: diff --git a/README.md b/README.md index 547a308..a174545 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ mo purge --paths # Configure project scan directories - **Safety**: Built with strict protections. See [Security Audit](SECURITY_AUDIT.md). Preview changes with `mo clean --dry-run`. - **Debug Mode**: Use `--debug` for detailed logs (e.g., `mo clean --debug`). Combine with `--dry-run` for comprehensive preview including risk levels and file details. - **Navigation**: Supports arrow keys and Vim bindings (`h/j/k/l`). +- **Status Shortcuts**: In `mo status`, press `k` to toggle cat visibility and save preference, `q` to quit. - **Configuration**: Run `mo touchid` for Touch ID sudo, `mo completion` for shell tab completion, `mo clean --whitelist` to manage protected paths. ## Features in Detail @@ -185,7 +186,7 @@ Up ▮▯▯▯▯ 0.8 MB/s Chrome ▮▮▮▯▯ 2 Proxy HTTP · 192.168.1.100 Terminal ▮▯▯▯▯ 12.5% ``` -Health score based on CPU, memory, disk, temperature, and I/O load. Color-coded by range. Press `k` to hide/show cat, `q` to quit. +Health score based on CPU, memory, disk, temperature, and I/O load. Color-coded by range. ### Project Artifact Purge diff --git a/cmd/status/main.go b/cmd/status/main.go index cc5ba0e..b8f7aeb 100644 --- a/cmd/status/main.go +++ b/cmd/status/main.go @@ -1,8 +1,11 @@ +// Package main provides the mo status command for real-time system monitoring. package main import ( "fmt" "os" + "path/filepath" + "strings" "time" tea "github.com/charmbracelet/bubbletea" @@ -37,10 +40,50 @@ type model struct { catHidden bool // true = hidden, false = visible } +// getConfigPath returns the path to the status preferences file. +func getConfigPath() string { + home, err := os.UserHomeDir() + if err != nil { + return "" + } + return filepath.Join(home, ".config", "mole", "status_prefs") +} + +// loadCatHidden loads the cat hidden preference from config file. +func loadCatHidden() bool { + path := getConfigPath() + if path == "" { + return false + } + data, err := os.ReadFile(path) + if err != nil { + return false + } + return strings.TrimSpace(string(data)) == "cat_hidden=true" +} + +// saveCatHidden saves the cat hidden preference to config file. +func saveCatHidden(hidden bool) { + path := getConfigPath() + if path == "" { + return + } + // Ensure directory exists + dir := filepath.Dir(path) + if err := os.MkdirAll(dir, 0755); err != nil { + return + } + value := "cat_hidden=false" + if hidden { + value = "cat_hidden=true" + } + _ = os.WriteFile(path, []byte(value+"\n"), 0644) +} + func newModel() model { return model{ collector: NewCollector(), - catHidden: false, + catHidden: loadCatHidden(), } } @@ -55,8 +98,9 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "q", "esc", "ctrl+c": return m, tea.Quit case "k": - // Toggle cat visibility + // Toggle cat visibility and persist preference m.catHidden = !m.catHidden + saveCatHidden(m.catHidden) return m, nil } case tea.WindowSizeMsg: diff --git a/cmd/status/metrics.go b/cmd/status/metrics.go index 73e20a1..2b24bba 100644 --- a/cmd/status/metrics.go +++ b/cmd/status/metrics.go @@ -286,9 +286,8 @@ func commandExists(name string) bool { return false } defer func() { - if r := recover(); r != nil { //nolint:staticcheck - // Treat LookPath panics as "missing". - } + // Treat LookPath panics as "missing". + _ = recover() }() _, err := exec.LookPath(name) return err == nil diff --git a/cmd/status/metrics_cpu.go b/cmd/status/metrics_cpu.go index 737ebce..29c7690 100644 --- a/cmd/status/metrics_cpu.go +++ b/cmd/status/metrics_cpu.go @@ -32,7 +32,7 @@ func collectCPU() (CPUStatus, error) { } // Two-call pattern for more reliable CPU usage. - warmUpCpu() + warmUpCPU() time.Sleep(cpuSampleInterval) percents, err := cpu.Percent(0, true) var totalPercent float64 @@ -256,6 +256,6 @@ func fallbackCPUUtilization(logical int) (float64, []float64, error) { return avg, perCore, nil } -func warmUpCpu() { +func warmUpCPU() { cpu.Percent(0, true) //nolint:errcheck } diff --git a/cmd/status/metrics_health.go b/cmd/status/metrics_health.go index 4b92693..0e34828 100644 --- a/cmd/status/metrics_health.go +++ b/cmd/status/metrics_health.go @@ -134,15 +134,16 @@ func calculateHealthScore(cpu CPUStatus, mem MemoryStatus, disks []DiskStatus, d // Build message. var msg string - if score >= 90 { + switch { + case score >= 90: msg = "Excellent" - } else if score >= 75 { + case score >= 75: msg = "Good" - } else if score >= 60 { + case score >= 60: msg = "Fair" - } else if score >= 40 { + case score >= 40: msg = "Poor" - } else { + default: msg = "Critical" } diff --git a/cmd/status/view.go b/cmd/status/view.go index 0a3f540..7ef56cd 100644 --- a/cmd/status/view.go +++ b/cmd/status/view.go @@ -187,15 +187,16 @@ func renderHeader(m MetricsSnapshot, errMsg string, animFrame int, termWidth int } func getScoreStyle(score int) lipgloss.Style { - if score >= 90 { + switch { + case score >= 90: return lipgloss.NewStyle().Foreground(lipgloss.Color("#87FF87")).Bold(true) - } else if score >= 75 { + case score >= 75: return lipgloss.NewStyle().Foreground(lipgloss.Color("#87D787")).Bold(true) - } else if score >= 60 { + case score >= 60: return lipgloss.NewStyle().Foreground(lipgloss.Color("#FFD75F")).Bold(true) - } else if score >= 40 { + case score >= 40: return lipgloss.NewStyle().Foreground(lipgloss.Color("#FFAF5F")).Bold(true) - } else { + default: return lipgloss.NewStyle().Foreground(lipgloss.Color("#FF6B6B")).Bold(true) } } @@ -707,11 +708,11 @@ func humanBytesCompact(v uint64) string { } } -func shorten(s string, max int) string { - if len(s) <= max { +func shorten(s string, maxLen int) string { + if len(s) <= maxLen { return s } - return s[:max-1] + "…" + return s[:maxLen-1] + "…" } func renderTwoColumns(cards []cardData, width int) string {