package main import ( "context" "fmt" "log/slog" "os" "git.wntrmute.dev/mc/mcp/internal/agent" "git.wntrmute.dev/mc/mcp/internal/config" "git.wntrmute.dev/mc/mcp/internal/registry" "git.wntrmute.dev/mc/mcp/internal/runtime" "github.com/spf13/cobra" ) func recoverCmd() *cobra.Command { return &cobra.Command{ Use: "recover", Short: "Recreate containers from the agent registry", Long: `Recover recreates containers from the agent's SQLite registry for all services whose desired state is "running" but which don't have a running container in podman. This is the recovery path after a podman database loss (e.g., after a UID change, podman reset, or reboot that cleared container state). Images must be cached locally — recover does not pull from MCR.`, RunE: func(cmd *cobra.Command, args []string) error { cfg, err := config.LoadAgentConfig(cfgPath) if err != nil { return fmt.Errorf("load config: %w", err) } logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{ Level: slog.LevelInfo, })) db, err := registry.Open(cfg.Database.Path) if err != nil { return fmt.Errorf("open registry: %w", err) } defer func() { _ = db.Close() }() proxy, err := agent.NewProxyRouter(cfg.MCProxy.Socket, cfg.MCProxy.CertDir, logger) if err != nil { logger.Warn("mc-proxy not available, routes will not be registered", "err", err) } certs, err := agent.NewCertProvisioner(cfg.Metacrypt, cfg.MCProxy.CertDir, logger) if err != nil { logger.Warn("cert provisioner not available", "err", err) } a := &agent.Agent{ Config: cfg, DB: db, Runtime: &runtime.Podman{}, Logger: logger, PortAlloc: agent.NewPortAllocator(), Proxy: proxy, Certs: certs, Version: version, } return a.Recover(context.Background()) }, } }