From 4fc5c3b0e5f3164e44655e0ff8b92bcd73c7f4e0 Mon Sep 17 00:00:00 2001 From: Snider Date: Mon, 9 Mar 2026 08:26:00 +0000 Subject: [PATCH] fix: correct Signal to use os.Signal, return errors instead of panicking Signal() now properly forwards to cmd.Process.Signal() instead of calling Kill(). SetDefault(nil) returns error instead of panicking. Wait() returns descriptive errors with process context. Co-Authored-By: Claude Opus 4.6 --- process.go | 22 +++++++++++----------- process_global.go | 7 ++++--- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/process.go b/process.go index 45ee0d9..e69c5ee 100644 --- a/process.go +++ b/process.go @@ -2,7 +2,9 @@ package process import ( "context" + "fmt" "io" + "os" "os/exec" "sync" "time" @@ -84,11 +86,14 @@ func (p *Process) Wait() error { <-p.done p.mu.RLock() defer p.mu.RUnlock() - if p.Status == StatusFailed || p.Status == StatusKilled { - return &exec.ExitError{} + if p.Status == StatusFailed { + return fmt.Errorf("process failed to start: %s", p.ID) + } + if p.Status == StatusKilled { + return fmt.Errorf("process was killed: %s", p.ID) } if p.ExitCode != 0 { - return &exec.ExitError{} + return fmt.Errorf("process exited with code %d", p.ExitCode) } return nil } @@ -115,24 +120,19 @@ func (p *Process) Kill() error { } // Signal sends a signal to the process. -func (p *Process) Signal(sig interface{ Signal() }) error { +func (p *Process) Signal(sig os.Signal) error { p.mu.Lock() defer p.mu.Unlock() if p.Status != StatusRunning { - return nil + return ErrProcessNotRunning } if p.cmd == nil || p.cmd.Process == nil { return nil } - // Type assert to os.Signal for Process.Signal - if osSig, ok := sig.(interface{ String() string }); ok { - _ = osSig // Satisfy linter - } - - return p.cmd.Process.Kill() // Simplified - would use Signal in full impl + return p.cmd.Process.Signal(sig) } // SendInput writes to the process stdin. diff --git a/process_global.go b/process_global.go index f59157d..162b8d8 100644 --- a/process_global.go +++ b/process_global.go @@ -23,11 +23,12 @@ func Default() *Service { // SetDefault sets the global process service. // Thread-safe: can be called concurrently with Default(). -func SetDefault(s *Service) { +func SetDefault(s *Service) error { if s == nil { - panic("process: SetDefault called with nil service") + return &ServiceError{msg: "process: SetDefault called with nil service"} } defaultService.Store(s) + return nil } // Init initializes the default global service with a Core instance. @@ -120,7 +121,7 @@ func Running() []*Process { } // ErrServiceNotInitialized is returned when the service is not initialized. -var ErrServiceNotInitialized = &ServiceError{msg: "process: service not initialized"} +var ErrServiceNotInitialized = &ServiceError{msg: "process: service not initialized; call process.Init(core) first"} // ServiceError represents a service-level error. type ServiceError struct {