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 <noreply@anthropic.com>
This commit is contained in:
Snider 2026-03-09 08:26:00 +00:00
parent 54bfd76104
commit 4fc5c3b0e5
2 changed files with 15 additions and 14 deletions

View file

@ -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.

View file

@ -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 {