package handlers import ( "context" "fmt" "time" "github.com/orchard9/rdev/internal/domain" "github.com/orchard9/rdev/internal/logging" "github.com/orchard9/rdev/internal/service" ) // startWebUI launches claude-code-ui as a background process in the session pod. // This is fire-and-forget — UI startup failure does not block session creation. func (h *SessionsHandler) startWebUI(ctx context.Context, session *domain.Session) { log := logging.FromContext(ctx).WithService("SessionsHandler") bgCtx := context.WithoutCancel(ctx) go func() { startCtx, cancel := context.WithTimeout(bgCtx, TimeoutStandard) defer cancel() cmd := &domain.Command{ ID: domain.CommandID(fmt.Sprintf("webui-%s", session.ID)), ProjectID: session.ProjectID, Type: domain.CommandTypeShell, Args: []string{fmt.Sprintf("nohup claude-code-ui --port %d > /tmp/claude-code-ui.log 2>&1 &", service.WebUIPort)}, StartedAt: time.Now(), } if _, err := h.executor.Execute(startCtx, cmd, session.PodName, func(_ domain.OutputLine) {}); err != nil { log.Error("failed to start claude-code-ui", logging.FieldError, err, "session_id", session.ID, logging.FieldProjectID, session.ProjectID, ) } else { log.Info("claude-code-ui started", "session_id", session.ID, "port", service.WebUIPort, ) } }() } // stopWebUI kills the claude-code-ui process in the session pod. // Best-effort — failure is logged but does not block session teardown. func (h *SessionsHandler) stopWebUI(ctx context.Context, session *domain.Session) { log := logging.FromContext(ctx).WithService("SessionsHandler") killCtx, cancel := context.WithTimeout(ctx, TimeoutFastLookup) defer cancel() cmd := &domain.Command{ ID: domain.CommandID(fmt.Sprintf("webui-stop-%s", session.ID)), ProjectID: session.ProjectID, Type: domain.CommandTypeShell, Args: []string{"pkill -f claude-code-ui || true"}, StartedAt: time.Now(), } if _, err := h.executor.Execute(killCtx, cmd, session.PodName, func(_ domain.OutputLine) {}); err != nil { log.Warn("failed to stop claude-code-ui", logging.FieldError, err, "session_id", session.ID, logging.FieldProjectID, session.ProjectID, ) } }