Import beads' UX design system into gastown: - Add internal/ui/ package with Ayu theme colors and semantic styling - styles.go: AdaptiveColor definitions for light/dark mode - terminal.go: TTY detection, NO_COLOR/CLICOLOR support - markdown.go: Glamour rendering with agent mode bypass - pager.go: Smart paging with GT_PAGER support - Add colorized help output (internal/cmd/help.go) - Group headers in accent color - Command names styled for scannability - Flag types and defaults muted - Add gt thanks command (internal/cmd/thanks.go) - Contributor display with same logic as bd thanks - Styled with Ayu theme colors - Update gt doctor to match bd doctor UX - Category grouping (Core, Infrastructure, Rig, Patrol, etc.) - Semantic icons (✓ ⚠ ✖) with Ayu colors - Tree connectors for detail lines - Summary line with pass/warn/fail counts - Warnings section at end with numbered issues - Migrate existing styles to use ui package - internal/style/style.go uses ui.ColorPass etc. - internal/tui/feed/styles.go uses ui package colors Co-Authored-By: SageOx <ox@sageox.ai>
142 lines
3.6 KiB
Go
142 lines
3.6 KiB
Go
package doctor
|
|
|
|
// Doctor manages and executes health checks.
|
|
type Doctor struct {
|
|
checks []Check
|
|
}
|
|
|
|
// NewDoctor creates a new Doctor with no registered checks.
|
|
func NewDoctor() *Doctor {
|
|
return &Doctor{
|
|
checks: make([]Check, 0),
|
|
}
|
|
}
|
|
|
|
// Register adds a check to the doctor's check list.
|
|
func (d *Doctor) Register(check Check) {
|
|
d.checks = append(d.checks, check)
|
|
}
|
|
|
|
// RegisterAll adds multiple checks to the doctor's check list.
|
|
func (d *Doctor) RegisterAll(checks ...Check) {
|
|
d.checks = append(d.checks, checks...)
|
|
}
|
|
|
|
// Checks returns the list of registered checks.
|
|
func (d *Doctor) Checks() []Check {
|
|
return d.checks
|
|
}
|
|
|
|
// categoryGetter interface for checks that provide a category
|
|
type categoryGetter interface {
|
|
Category() string
|
|
}
|
|
|
|
// Run executes all registered checks and returns a report.
|
|
func (d *Doctor) Run(ctx *CheckContext) *Report {
|
|
report := NewReport()
|
|
|
|
for _, check := range d.checks {
|
|
result := check.Run(ctx)
|
|
// Ensure check name is populated
|
|
if result.Name == "" {
|
|
result.Name = check.Name()
|
|
}
|
|
// Set category from check if available
|
|
if cg, ok := check.(categoryGetter); ok && result.Category == "" {
|
|
result.Category = cg.Category()
|
|
}
|
|
report.Add(result)
|
|
}
|
|
|
|
return report
|
|
}
|
|
|
|
// Fix runs all checks with auto-fix enabled where possible.
|
|
// It first runs the check, then if it fails and can be fixed, attempts the fix.
|
|
func (d *Doctor) Fix(ctx *CheckContext) *Report {
|
|
report := NewReport()
|
|
|
|
for _, check := range d.checks {
|
|
result := check.Run(ctx)
|
|
if result.Name == "" {
|
|
result.Name = check.Name()
|
|
}
|
|
// Set category from check if available
|
|
if cg, ok := check.(categoryGetter); ok && result.Category == "" {
|
|
result.Category = cg.Category()
|
|
}
|
|
|
|
// Attempt fix if check failed and is fixable
|
|
if result.Status != StatusOK && check.CanFix() {
|
|
err := check.Fix(ctx)
|
|
if err == nil {
|
|
// Re-run check to verify fix worked
|
|
result = check.Run(ctx)
|
|
if result.Name == "" {
|
|
result.Name = check.Name()
|
|
}
|
|
// Set category again after re-run
|
|
if cg, ok := check.(categoryGetter); ok && result.Category == "" {
|
|
result.Category = cg.Category()
|
|
}
|
|
// Update message to indicate fix was applied
|
|
if result.Status == StatusOK {
|
|
result.Message = result.Message + " (fixed)"
|
|
}
|
|
} else {
|
|
// Fix failed, add error to details
|
|
result.Details = append(result.Details, "Fix failed: "+err.Error())
|
|
}
|
|
}
|
|
|
|
report.Add(result)
|
|
}
|
|
|
|
return report
|
|
}
|
|
|
|
// BaseCheck provides a base implementation for checks that don't support auto-fix.
|
|
// Embed this in custom checks to get default CanFix() and Fix() implementations.
|
|
type BaseCheck struct {
|
|
CheckName string
|
|
CheckDescription string
|
|
CheckCategory string // Category for grouping (e.g., CategoryCore)
|
|
}
|
|
|
|
// Category returns the check's category for grouping in output.
|
|
func (b *BaseCheck) Category() string {
|
|
return b.CheckCategory
|
|
}
|
|
|
|
// Name returns the check name.
|
|
func (b *BaseCheck) Name() string {
|
|
return b.CheckName
|
|
}
|
|
|
|
// Description returns the check description.
|
|
func (b *BaseCheck) Description() string {
|
|
return b.CheckDescription
|
|
}
|
|
|
|
// CanFix returns false by default.
|
|
func (b *BaseCheck) CanFix() bool {
|
|
return false
|
|
}
|
|
|
|
// Fix returns an error indicating this check cannot be auto-fixed.
|
|
func (b *BaseCheck) Fix(ctx *CheckContext) error {
|
|
return ErrCannotFix
|
|
}
|
|
|
|
// FixableCheck provides a base implementation for checks that support auto-fix.
|
|
// Embed this and override CanFix() to return true, and implement Fix().
|
|
type FixableCheck struct {
|
|
BaseCheck
|
|
}
|
|
|
|
// CanFix returns true for fixable checks.
|
|
func (f *FixableCheck) CanFix() bool {
|
|
return true
|
|
}
|