feat: add mouse support + install pnpm, uv, docker, gh
All checks were successful
CI / build (push) Successful in 24s
Release / release (push) Successful in 1m34s

- Added tea.WithMouseCellMotion() for mouse interaction in TUI
- Added installers for pnpm (npm), uv (astral), docker (pacman/apt/dnf/brew),
  gh/github-cli (pacman/apt/dnf/brew)

💘 Generated with Crush

Assisted-by: GLM-5.1 via Crush <crush@charm.land>
This commit is contained in:
Augustin
2026-04-19 23:05:15 +02:00
parent 8e3f8b8770
commit e58e00da13
2 changed files with 85 additions and 1 deletions

View File

@@ -102,7 +102,7 @@ func runTUI() {
result := scanner.ScanSystem()
model := tui.NewModel(cfg, result)
p := tea.NewProgram(model, tea.WithAltScreen())
p := tea.NewProgram(model, tea.WithAltScreen(), tea.WithMouseCellMotion())
if _, err := p.Run(); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)

View File

@@ -47,6 +47,14 @@ func (i *Installer) InstallTool(name string) InstallResult {
return i.installPython()
case "git":
return i.installGit()
case "pnpm":
return i.installPnpm()
case "uv":
return i.installUv()
case "docker":
return i.installDocker()
case "gh":
return i.installGh()
default:
return InstallResult{Tool: name, Success: false, Message: "unknown tool"}
}
@@ -317,3 +325,79 @@ func appendLine(file, line string) {
defer f.Close()
f.WriteString("\n" + line + "\n")
}
func (i *Installer) installPnpm() InstallResult {
if _, err := exec.LookPath("pnpm"); err == nil {
return InstallResult{Tool: "pnpm", Success: true, Message: "already installed"}
}
cmd := exec.Command("npm", "install", "-g", "pnpm")
if output, err := cmd.CombinedOutput(); err != nil {
return InstallResult{Tool: "pnpm", Success: false, Message: fmt.Sprintf("install failed: %s: %s", err, string(output))}
}
return InstallResult{Tool: "pnpm", Success: true, Message: "installed"}
}
func (i *Installer) installUv() InstallResult {
if _, err := exec.LookPath("uv"); err == nil {
return InstallResult{Tool: "uv", Success: true, Message: "already installed"}
}
var cmd *exec.Cmd
switch i.system.OS {
case platform.Linux, platform.MacOS:
cmd = exec.Command("bash", "-c", "curl -LsSf https://astral.sh/uv/install.sh | sh")
case platform.Windows:
cmd = exec.Command("powershell", "-Command", "irm https://astral.sh/uv/install.ps1 | iex")
default:
return InstallResult{Tool: "uv", Success: false, Message: "unsupported OS"}
}
if output, err := cmd.CombinedOutput(); err != nil {
return InstallResult{Tool: "uv", Success: false, Message: fmt.Sprintf("install failed: %s: %s", err, string(output))}
}
return InstallResult{Tool: "uv", Success: true, Message: "installed"}
}
func (i *Installer) installDocker() InstallResult {
if _, err := exec.LookPath("docker"); err == nil {
return InstallResult{Tool: "docker", Success: true, Message: "already installed"}
}
var cmd *exec.Cmd
switch i.system.PackageManager {
case "apt":
cmd = exec.Command("bash", "-c", "apt-get update && apt-get install -y docker.io && systemctl start docker && systemctl enable docker")
case "pacman":
cmd = exec.Command("bash", "-c", "pacman -S --noconfirm docker && systemctl start docker && systemctl enable docker")
case "dnf":
cmd = exec.Command("bash", "-c", "dnf install -y docker && systemctl start docker && systemctl enable docker")
case "brew":
cmd = exec.Command("bash", "-c", "brew install docker")
default:
return InstallResult{Tool: "docker", Success: false, Message: fmt.Sprintf("install via '%s' not supported, install manually", i.system.PackageManager)}
}
if output, err := cmd.CombinedOutput(); err != nil {
return InstallResult{Tool: "docker", Success: false, Message: fmt.Sprintf("install failed: %s: %s", err, string(output))}
}
return InstallResult{Tool: "docker", Success: true, Message: "installed"}
}
func (i *Installer) installGh() InstallResult {
if _, err := exec.LookPath("gh"); err == nil {
return InstallResult{Tool: "gh", Success: true, Message: "already installed"}
}
var cmd *exec.Cmd
switch i.system.PackageManager {
case "apt":
cmd = exec.Command("bash", "-c", "curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && echo 'deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main' | tee /etc/apt/sources.list.d/github-cli.list > /dev/null && apt update && apt install gh -y")
case "pacman":
cmd = exec.Command("pacman", "-S", "--noconfirm", "github-cli")
case "dnf":
cmd = exec.Command("dnf", "install", "-y", "gh")
case "brew":
cmd = exec.Command("brew", "install", "gh")
default:
return InstallResult{Tool: "gh", Success: false, Message: fmt.Sprintf("install via '%s' not supported, install manually", i.system.PackageManager)}
}
if output, err := cmd.CombinedOutput(); err != nil {
return InstallResult{Tool: "gh", Success: false, Message: fmt.Sprintf("install failed: %s: %s", err, string(output))}
}
return InstallResult{Tool: "gh", Success: true, Message: "installed"}
}