package health import ( "fmt" "os" "os/exec" "path/filepath" "runtime" "strings" "github.com/OpeItcLoc03/factory/pkg/manifest" ) type Result struct { Name string `json:"name"` Healthy bool `json:"healthy"` Version string `json:"version,omitempty"` Message string `json:"message,omitempty"` } func Check(comp *manifest.Component, vars map[string]string) (*Result, error) { if comp.HealthCheck == nil { return &Result{ Name: comp.Name, Healthy: true, Message: "no health check defined", }, nil } // Substitute variables in path path := comp.HealthCheck.Path for k, v := range vars { path = filepath.Clean(strings.ReplaceAll(path, "{"+k+"}", v)) } switch comp.HealthCheck.Type { case "file_exists": return checkFileExists(comp.Name, path) case "directory_exists": return checkDirExists(comp.Name, path) case "mcp_tool": return checkMCPTool(comp.Name, comp.HealthCheck.Tool) case "command": return checkCommand(comp.Name, comp.HealthCheck.Command) default: return &Result{ Name: comp.Name, Healthy: false, Message: fmt.Sprintf("unknown health check type: %s", comp.HealthCheck.Type), }, nil } } func checkFileExists(name, path string) (*Result, error) { if _, err := os.Stat(path); err == nil { return &Result{Name: name, Healthy: true}, nil } return &Result{ Name: name, Healthy: false, Message: fmt.Sprintf("file not found: %s", path), }, nil } func checkDirExists(name, path string) (*Result, error) { if info, err := os.Stat(path); err == nil && info.IsDir() { return &Result{Name: name, Healthy: true}, nil } return &Result{ Name: name, Healthy: false, Message: fmt.Sprintf("directory not found: %s", path), }, nil } func checkMCPTool(name, tool string) (*Result, error) { // Check if tool is available in ~/.claude.json home, _ := os.UserHomeDir() configPath := filepath.Join(home, ".claude.json") data, err := os.ReadFile(configPath) if err != nil { return &Result{ Name: name, Healthy: false, Message: "claude.json not found", }, nil } // Simple string check (proper parsing would be better) toolKey := `"` + tool + `"` if strings.Contains(string(data), toolKey) { return &Result{Name: name, Healthy: true}, nil } return &Result{ Name: name, Healthy: false, Message: fmt.Sprintf("MCP tool not found: %s", tool), }, nil } func checkCommand(name, cmd string) (*Result, error) { var shell string var args []string switch runtime.GOOS { case "windows": shell = "pwsh" args = []string{"-Command", cmd} default: shell = "bash" args = []string{"-c", cmd} } execCmd := exec.Command(shell, args...) output, err := execCmd.CombinedOutput() if err != nil { return &Result{ Name: name, Healthy: false, Message: fmt.Sprintf("command failed: %s", output), }, nil } return &Result{ Name: name, Healthy: true, Message: strings.TrimSpace(string(output)), }, nil }