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>
119 lines
3.4 KiB
Go
119 lines
3.4 KiB
Go
package doctor
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
"strings"
|
|
)
|
|
|
|
// TownRootBranchCheck verifies that the town root directory is on the main branch.
|
|
// The town root should always stay on main to avoid confusion and broken gt commands.
|
|
// Accidental branch switches can happen when git commands run in the wrong directory.
|
|
type TownRootBranchCheck struct {
|
|
FixableCheck
|
|
currentBranch string // Cached during Run for use in Fix
|
|
}
|
|
|
|
// NewTownRootBranchCheck creates a new town root branch check.
|
|
func NewTownRootBranchCheck() *TownRootBranchCheck {
|
|
return &TownRootBranchCheck{
|
|
FixableCheck: FixableCheck{
|
|
BaseCheck: BaseCheck{
|
|
CheckName: "town-root-branch",
|
|
CheckDescription: "Verify town root is on main branch",
|
|
CheckCategory: CategoryCore,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// Run checks if the town root is on the main branch.
|
|
func (c *TownRootBranchCheck) Run(ctx *CheckContext) *CheckResult {
|
|
// Get current branch
|
|
cmd := exec.Command("git", "branch", "--show-current")
|
|
cmd.Dir = ctx.TownRoot
|
|
out, err := cmd.Output()
|
|
if err != nil {
|
|
// Not a git repo - skip this check (handled by town-git check)
|
|
return &CheckResult{
|
|
Name: c.Name(),
|
|
Status: StatusOK,
|
|
Message: "Town root is not a git repository (skipped)",
|
|
}
|
|
}
|
|
|
|
branch := strings.TrimSpace(string(out))
|
|
c.currentBranch = branch
|
|
|
|
// Empty branch means detached HEAD
|
|
if branch == "" {
|
|
return &CheckResult{
|
|
Name: c.Name(),
|
|
Status: StatusWarning,
|
|
Message: "Town root is in detached HEAD state",
|
|
Details: []string{
|
|
"The town root should be on the main branch",
|
|
"Detached HEAD can cause gt commands to fail",
|
|
},
|
|
FixHint: "Run 'gt doctor --fix' or manually: cd ~/gt && git checkout main",
|
|
}
|
|
}
|
|
|
|
// Accept main or master
|
|
if branch == "main" || branch == "master" {
|
|
return &CheckResult{
|
|
Name: c.Name(),
|
|
Status: StatusOK,
|
|
Message: fmt.Sprintf("Town root is on %s branch", branch),
|
|
}
|
|
}
|
|
|
|
// On wrong branch - this is the problem we're trying to prevent
|
|
return &CheckResult{
|
|
Name: c.Name(),
|
|
Status: StatusError,
|
|
Message: fmt.Sprintf("Town root is on wrong branch: %s", branch),
|
|
Details: []string{
|
|
"The town root (~/gt) must stay on main branch",
|
|
fmt.Sprintf("Currently on: %s", branch),
|
|
"This can cause gt commands to fail (missing rigs.json, etc.)",
|
|
"The branch switch was likely accidental (git command in wrong dir)",
|
|
},
|
|
FixHint: "Run 'gt doctor --fix' or manually: cd ~/gt && git checkout main",
|
|
}
|
|
}
|
|
|
|
// Fix switches the town root back to main branch.
|
|
func (c *TownRootBranchCheck) Fix(ctx *CheckContext) error {
|
|
// Only fix if we're not already on main
|
|
if c.currentBranch == "main" || c.currentBranch == "master" {
|
|
return nil
|
|
}
|
|
|
|
// Check for uncommitted changes that would block checkout
|
|
cmd := exec.Command("git", "status", "--porcelain")
|
|
cmd.Dir = ctx.TownRoot
|
|
out, err := cmd.Output()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to check git status: %w", err)
|
|
}
|
|
|
|
if strings.TrimSpace(string(out)) != "" {
|
|
return fmt.Errorf("cannot switch to main: uncommitted changes in town root (stash or commit first)")
|
|
}
|
|
|
|
// Switch to main
|
|
cmd = exec.Command("git", "checkout", "main")
|
|
cmd.Dir = ctx.TownRoot
|
|
if err := cmd.Run(); err != nil {
|
|
// Try master if main doesn't exist
|
|
cmd = exec.Command("git", "checkout", "master")
|
|
cmd.Dir = ctx.TownRoot
|
|
if err := cmd.Run(); err != nil {
|
|
return fmt.Errorf("failed to checkout main: %w", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|