Files
factory/pkg/health/health.go
vitya 561a7fd66f feat: L0b bootstrap scripts + L1 Go CLI structure
L0b (factory bootstrap):
- bootstrap.ps1 (Windows): pre-checks, interactive config, clone .factory, home.toml
- bootstrap.sh (Linux/Mac): same functionality for bash
- Idempotent re-run with home.toml verification

L1 (Go CLI):
- factory.yaml: manifest schema with components, deps, health-checks
- cmd/factory: Cobra CLI (install/update/status/diagnose)
- pkg/config: home.toml reader
- pkg/manifest: factory.yaml parser + topological sort
- pkg/health: health-check logic (file/dir/mcp_tool/command)

Scripts:
- build.sh: cross-compile for linux/win/darwin × amd64/arm64
- build.ps1: PowerShell cross-compile

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 23:59:09 +03:00

132 lines
2.9 KiB
Go

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
}