package service import ( "log/slog" "io" "codespace/internal/process" "codespace/internal/workspace" ) // ProcessService manages OpenCode processes for workspaces. type ProcessService struct { workspaces workspace.Manager processes process.Manager logger *slog.Logger } // NewProcessService creates a ProcessService. // If lg is nil, slog.Default() is used. func NewProcessService(workspaces workspace.Manager, processes process.Manager, lg *slog.Logger) *ProcessService { if lg == nil { lg = slog.Default() } return &ProcessService{workspaces: workspaces, processes: processes, logger: lg} } // Start starts an OpenCode process for the given workspace. func (s *ProcessService) Start(workspaceID string) error { ws, err := s.workspaces.Get(workspaceID) if err != nil { return err } if err := s.processes.Start(workspaceID, ws.Root); err != nil { s.logger.Error("process start failed", "workspace_id", workspaceID, "error", err) return err } status := s.processes.Status(workspaceID) s.logger.Info("process started", "workspace_id", workspaceID, "pid", status.PID) return nil } // Stop stops the OpenCode process for the given workspace. func (s *ProcessService) Stop(workspaceID string) error { if err := s.processes.Stop(workspaceID); err != nil { s.logger.Error("process stop failed", "workspace_id", workspaceID, "error", err) return err } s.logger.Info("process stopped", "workspace_id", workspaceID) return nil } // Restart restarts the OpenCode process for the given workspace. func (s *ProcessService) Restart(workspaceID string) error { ws, err := s.workspaces.Get(workspaceID) if err != nil { return err } if err := s.processes.Restart(workspaceID, ws.Root); err != nil { s.logger.Error("process restart failed", "workspace_id", workspaceID, "error", err) return err } status := s.processes.Status(workspaceID) s.logger.Info("process restarted", "workspace_id", workspaceID, "pid", status.PID) return nil } // Status returns the process status for the given workspace. func (s *ProcessService) Status(workspaceID string) (process.Status, error) { if _, err := s.workspaces.Get(workspaceID); err != nil { return process.Status{}, err } return s.processes.Status(workspaceID), nil } // Subscribe subscribes to output events for the workspace process. func (s *ProcessService) Subscribe(workspaceID string) (process.Subscription, error) { if _, err := s.workspaces.Get(workspaceID); err != nil { return nil, err } return s.processes.Subscribe(workspaceID) } // Input returns the stdin writer for the workspace process. func (s *ProcessService) Input(workspaceID string) (io.WriteCloser, error) { if _, err := s.workspaces.Get(workspaceID); err != nil { return nil, err } return s.processes.Stdin(workspaceID) } // ExitStatus returns the exit status for the workspace process. func (s *ProcessService) ExitStatus(workspaceID string) (process.ExitInfo, error) { if _, err := s.workspaces.Get(workspaceID); err != nil { return process.ExitInfo{}, err } return s.processes.ExitStatus(workspaceID) }