Merge remote-tracking branch 'origin/polecat/Angharad'
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
|||||||
|
|
||||||
"github.com/steveyegge/gastown/internal/mail"
|
"github.com/steveyegge/gastown/internal/mail"
|
||||||
"github.com/steveyegge/gastown/internal/rig"
|
"github.com/steveyegge/gastown/internal/rig"
|
||||||
|
"github.com/steveyegge/gastown/internal/tmux"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Common errors
|
// Common errors
|
||||||
@@ -42,6 +43,11 @@ func (m *Manager) stateFile() string {
|
|||||||
return filepath.Join(m.rig.Path, ".gastown", "refinery.json")
|
return filepath.Join(m.rig.Path, ".gastown", "refinery.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sessionName returns the tmux session name for this refinery.
|
||||||
|
func (m *Manager) sessionName() string {
|
||||||
|
return fmt.Sprintf("gt-%s-refinery", m.rig.Name)
|
||||||
|
}
|
||||||
|
|
||||||
// loadState loads refinery state from disk.
|
// loadState loads refinery state from disk.
|
||||||
func (m *Manager) loadState() (*Refinery, error) {
|
func (m *Manager) loadState() (*Refinery, error) {
|
||||||
data, err := os.ReadFile(m.stateFile())
|
data, err := os.ReadFile(m.stateFile())
|
||||||
@@ -85,13 +91,35 @@ func (m *Manager) Status() (*Refinery, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If running, verify process is still alive
|
// Check if tmux session exists
|
||||||
if ref.State == StateRunning && ref.PID > 0 {
|
t := tmux.NewTmux()
|
||||||
if !processExists(ref.PID) {
|
sessionID := m.sessionName()
|
||||||
ref.State = StateStopped
|
sessionRunning, _ := t.HasSession(sessionID)
|
||||||
ref.PID = 0
|
|
||||||
|
// If tmux session is running, refinery is running
|
||||||
|
if sessionRunning {
|
||||||
|
if ref.State != StateRunning {
|
||||||
|
// Update state to match reality
|
||||||
|
now := time.Now()
|
||||||
|
ref.State = StateRunning
|
||||||
|
if ref.StartedAt == nil {
|
||||||
|
ref.StartedAt = &now
|
||||||
|
}
|
||||||
m.saveState(ref)
|
m.saveState(ref)
|
||||||
}
|
}
|
||||||
|
return ref, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If state says running but tmux session doesn't exist, check PID
|
||||||
|
if ref.State == StateRunning {
|
||||||
|
if ref.PID > 0 && processExists(ref.PID) {
|
||||||
|
// Process is still running (foreground mode without tmux)
|
||||||
|
return ref, nil
|
||||||
|
}
|
||||||
|
// Neither session nor process exists - mark as stopped
|
||||||
|
ref.State = StateStopped
|
||||||
|
ref.PID = 0
|
||||||
|
m.saveState(ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ref, nil
|
return ref, nil
|
||||||
@@ -99,33 +127,59 @@ func (m *Manager) Status() (*Refinery, error) {
|
|||||||
|
|
||||||
// Start starts the refinery.
|
// Start starts the refinery.
|
||||||
// If foreground is true, runs in the current process (blocking).
|
// If foreground is true, runs in the current process (blocking).
|
||||||
// Otherwise, spawns a background process.
|
// Otherwise, spawns a tmux session running the refinery in foreground mode.
|
||||||
func (m *Manager) Start(foreground bool) error {
|
func (m *Manager) Start(foreground bool) error {
|
||||||
ref, err := m.loadState()
|
ref, err := m.loadState()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if already running via tmux session
|
||||||
|
t := tmux.NewTmux()
|
||||||
|
sessionID := m.sessionName()
|
||||||
|
running, _ := t.HasSession(sessionID)
|
||||||
|
if running {
|
||||||
|
return ErrAlreadyRunning
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also check via PID for backwards compatibility
|
||||||
if ref.State == StateRunning && ref.PID > 0 && processExists(ref.PID) {
|
if ref.State == StateRunning && ref.PID > 0 && processExists(ref.PID) {
|
||||||
return ErrAlreadyRunning
|
return ErrAlreadyRunning
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
ref.State = StateRunning
|
|
||||||
ref.StartedAt = &now
|
|
||||||
ref.PID = os.Getpid() // For foreground mode; background would set actual PID
|
|
||||||
|
|
||||||
if err := m.saveState(ref); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if foreground {
|
if foreground {
|
||||||
|
// Running in foreground - update state and run
|
||||||
|
now := time.Now()
|
||||||
|
ref.State = StateRunning
|
||||||
|
ref.StartedAt = &now
|
||||||
|
ref.PID = os.Getpid()
|
||||||
|
|
||||||
|
if err := m.saveState(ref); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Run the processing loop (blocking)
|
// Run the processing loop (blocking)
|
||||||
return m.run(ref)
|
return m.run(ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Background mode: spawn a new process
|
// Background mode: spawn a tmux session running the refinery
|
||||||
// For MVP, we just mark as running - actual daemon implementation in gt-ov2
|
if err := t.NewSession(sessionID, m.workDir); err != nil {
|
||||||
|
return fmt.Errorf("creating tmux session: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set environment variables
|
||||||
|
t.SetEnvironment(sessionID, "GT_RIG", m.rig.Name)
|
||||||
|
t.SetEnvironment(sessionID, "GT_REFINERY", "1")
|
||||||
|
|
||||||
|
// Send the command to start refinery in foreground mode
|
||||||
|
// The foreground mode handles state updates and the processing loop
|
||||||
|
command := fmt.Sprintf("gt refinery start %s --foreground", m.rig.Name)
|
||||||
|
if err := t.SendKeys(sessionID, command); err != nil {
|
||||||
|
// Clean up the session on failure
|
||||||
|
t.KillSession(sessionID)
|
||||||
|
return fmt.Errorf("starting refinery: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,12 +190,23 @@ func (m *Manager) Stop() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if ref.State != StateRunning {
|
// Check if tmux session exists
|
||||||
|
t := tmux.NewTmux()
|
||||||
|
sessionID := m.sessionName()
|
||||||
|
sessionRunning, _ := t.HasSession(sessionID)
|
||||||
|
|
||||||
|
// If neither state nor session indicates running, it's not running
|
||||||
|
if ref.State != StateRunning && !sessionRunning {
|
||||||
return ErrNotRunning
|
return ErrNotRunning
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have a PID, try to stop it gracefully
|
// Kill tmux session if it exists
|
||||||
if ref.PID > 0 && ref.PID != os.Getpid() {
|
if sessionRunning {
|
||||||
|
t.KillSession(sessionID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a PID and it's a different process, try to stop it gracefully
|
||||||
|
if ref.PID > 0 && ref.PID != os.Getpid() && processExists(ref.PID) {
|
||||||
// Send SIGTERM
|
// Send SIGTERM
|
||||||
if proc, err := os.FindProcess(ref.PID); err == nil {
|
if proc, err := os.FindProcess(ref.PID); err == nil {
|
||||||
proc.Signal(os.Interrupt)
|
proc.Signal(os.Interrupt)
|
||||||
|
|||||||
Reference in New Issue
Block a user