项目文件夹

文件
wehub-resource-sync 26f897c1ec
release / release-please (push) Failing after 1m49s
docs / build (push) Failing after 6m34s
release / build-and-upload (arm64, linux) (push) Has been cancelled
release / build-and-upload (arm64, windows) (push) Has been cancelled
release / build-darwin (amd64, darwin) (push) Has been cancelled
release / checksums (push) Has been cancelled
release / finalize (push) Has been cancelled
release / build-darwin (arm64, darwin) (push) Has been cancelled
release / build-and-upload (amd64, linux) (push) Has been cancelled
release / build-and-upload (amd64, windows) (push) Has been cancelled
docs / deploy (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:34:16 +08:00

154 行
4.1 KiB
Go

package cli
import (
"fmt"
"os"
"os/exec"
"strings"
"github.com/kunchenguid/no-mistakes/internal/config"
"github.com/kunchenguid/no-mistakes/internal/daemon"
"github.com/kunchenguid/no-mistakes/internal/db"
"github.com/kunchenguid/no-mistakes/internal/paths"
"github.com/kunchenguid/no-mistakes/internal/winproc"
"github.com/spf13/cobra"
)
func newDoctorCmd() *cobra.Command {
return &cobra.Command{
Use: "doctor",
Short: "Check system health and dependencies",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return trackCommandStatus("doctor", func() (string, error) {
w := cmd.OutOrStdout()
allOK := true
ok := func(label, detail string) {
fmt.Fprintf(w, " %s %s %s\n", sGreen.Render("✓"), sDim.Render(label), detail)
}
warn := func(label, detail string) {
fmt.Fprintf(w, " %s %s %s\n", sYellow.Render("–"), sDim.Render(label), detail)
}
fail := func(label, detail string) {
fmt.Fprintf(w, " %s %s %s\n", sRed.Render("✗"), sDim.Render(label), detail)
}
fmt.Fprintf(w, " %s\n", sCyan.Render("System"))
if _, err := exec.LookPath("git"); err != nil {
fail("git ", "not found")
allOK = false
} else {
gitCmd := exec.Command("git", "--version")
winproc.Harden(gitCmd)
out, err := gitCmd.Output()
if err != nil {
fail("git ", fmt.Sprintf("error (%v)", err))
allOK = false
} else {
ok("git ", strings.TrimSpace(string(out)))
}
}
if _, err := exec.LookPath("gh"); err != nil {
warn("gh ", "not found "+sDim.Render("(optional, needed for PR/CI)"))
} else {
ok("gh ", "ok")
}
if _, err := exec.LookPath("az"); err != nil {
warn("az ", "not found "+sDim.Render("(optional, needed for Azure DevOps PR/CI)"))
} else {
ok("az ", "ok")
}
p, err := paths.New()
if err != nil {
fail("data directory", fmt.Sprintf("error resolving paths (%v)", err))
allOK = false
} else if _, err := os.Stat(p.Root()); os.IsNotExist(err) {
fail("data directory", fmt.Sprintf("not found (%s)", p.Root()))
allOK = false
} else {
ok("data directory", p.Root())
}
if p != nil {
if _, err := os.Stat(p.DB()); os.IsNotExist(err) {
warn("database ", "not found "+sDim.Render("(will be created on first use)"))
} else {
d, err := db.Open(p.DB())
if err != nil {
fail("database ", fmt.Sprintf("error (%v)", err))
allOK = false
} else {
d.Close()
ok("database ", "ok")
}
}
}
if p != nil {
alive, _ := daemon.IsRunning(p)
if alive {
ok("daemon ", "running")
} else {
warn("daemon ", "stopped")
}
}
agents := []struct {
name string
binary string
}{
{"claude", "claude"},
{"codex", "codex"},
{"rovodev", "acli"},
{"opencode", "opencode"},
{"pi", "pi"},
{"copilot", "copilot"},
{"acpx", "acpx"},
}
fmt.Fprintln(w)
fmt.Fprintf(w, " %s\n", sCyan.Render("Agents"))
for _, a := range agents {
label := fmt.Sprintf("%-14s", a.name)
if path, err := exec.LookPath(a.binary); err != nil {
warn(label, "not found")
} else {
ok(label, path)
}
}
if p == nil {
fail("gate validation", "unavailable: data directory could not be resolved")
allOK = false
} else {
globalCfg, err := config.LoadGlobal(p.ConfigFile())
if err != nil {
fail("gate validation", fmt.Sprintf("unavailable: load config (%v)", err))
allOK = false
} else {
cfg := config.Merge(globalCfg, &config.RepoConfig{})
if err := cfg.ResolveAgent(cmd.Context(), exec.LookPath); err != nil {
fail("gate validation", err.Error())
allOK = false
} else {
ok("gate validation", fmt.Sprintf("%s is runnable", cfg.Agent))
}
}
}
if !allOK {
fmt.Fprintln(w)
fmt.Fprintf(w, " %s\n", sRed.Render("some checks failed"))
return "error", nil
}
return "success", nil
})
},
}
}