package api import ( "bytes" "context" "net/http" "os/exec" "path/filepath" "time" ) const scriptTimeout = 30 * time.Second func (s *Server) startNextTaskScriptPath() string { if s.startNextTaskScript != "" { return s.startNextTaskScript } return filepath.Join(s.workDir, "scripts", "start-next-task") } func (s *Server) deployScriptPath() string { if s.deployScript != "" { return s.deployScript } return filepath.Join(s.workDir, "scripts", "deploy") } func (s *Server) handleStartNextTask(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(r.Context(), scriptTimeout) defer cancel() scriptPath := s.startNextTaskScriptPath() cmd := exec.CommandContext(ctx, scriptPath) var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr err := cmd.Run() exitCode := 0 if err != nil { if exitErr, ok := err.(*exec.ExitError); ok { exitCode = exitErr.ExitCode() } else { s.logger.Error("start-next-task: script execution failed", "error", err, "path", scriptPath) writeJSON(w, http.StatusInternalServerError, map[string]string{ "error": "script execution failed: " + err.Error(), }) return } } writeJSON(w, http.StatusOK, map[string]interface{}{ "output": stdout.String(), "exit_code": exitCode, }) } func (s *Server) handleDeploy(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(r.Context(), scriptTimeout) defer cancel() scriptPath := s.deployScriptPath() cmd := exec.CommandContext(ctx, scriptPath) var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr err := cmd.Run() exitCode := 0 if err != nil { if exitErr, ok := err.(*exec.ExitError); ok { exitCode = exitErr.ExitCode() } else { s.logger.Error("deploy: script execution failed", "error", err, "path", scriptPath) writeJSON(w, http.StatusInternalServerError, map[string]string{ "error": "script execution failed: " + err.Error(), }) return } } writeJSON(w, http.StatusOK, map[string]interface{}{ "output": stdout.String() + stderr.String(), "exit_code": exitCode, }) }