feat: add rebuild and restart functionality for agents, including build process and status reporting
This commit is contained in:
@@ -379,6 +379,15 @@ func (m *Manager) PidPath(id string) string { return m.pidPath(id) }
|
||||
// LogPath returns the path to the log file for an agent.
|
||||
func (m *Manager) LogPath(id string) string { return m.logPath(id) }
|
||||
|
||||
// Build compiles all project binaries by running build.sh.
|
||||
// Returns the combined output and any error.
|
||||
func (m *Manager) Build() (string, error) {
|
||||
cmd := exec.Command("bash", "build.sh")
|
||||
cmd.Env = m.buildEnv()
|
||||
out, err := cmd.CombinedOutput()
|
||||
return string(out), err
|
||||
}
|
||||
|
||||
// ── internal helpers ─────────────────────────────────────────────────────
|
||||
|
||||
func (m *Manager) pidPath(id string) string { return filepath.Join(m.runDir, id+".pid") }
|
||||
|
||||
@@ -4,6 +4,7 @@ package tui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
@@ -56,6 +57,9 @@ func (a *Adapter) RunIntent(intent puretui.Intent) tea.Cmd {
|
||||
case puretui.IntentKillAll:
|
||||
return a.killAll()
|
||||
|
||||
case puretui.IntentRebuildRestart:
|
||||
return a.rebuildRestart()
|
||||
|
||||
case puretui.IntentTick:
|
||||
return a.tick()
|
||||
|
||||
@@ -267,6 +271,86 @@ func (a *Adapter) killAll() tea.Cmd {
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Adapter) rebuildRestart() tea.Cmd {
|
||||
return func() tea.Msg {
|
||||
// 1. Remember which agents are currently running
|
||||
statuses, err := a.mgr.StatusAll()
|
||||
if err != nil {
|
||||
return puretui.MsgRebuildDone{Errors: []string{err.Error()}}
|
||||
}
|
||||
var wasRunning []string
|
||||
for _, s := range statuses {
|
||||
if s.Running {
|
||||
wasRunning = append(wasRunning, s.ID)
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Stop all running agents
|
||||
for _, id := range wasRunning {
|
||||
_ = a.mgr.Stop(id)
|
||||
}
|
||||
if len(wasRunning) > 0 {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
||||
// 3. Build
|
||||
buildOut, buildErr := a.mgr.Build()
|
||||
if buildErr != nil {
|
||||
// Build failed — try to restart what was running before
|
||||
for _, id := range wasRunning {
|
||||
agents, _ := a.mgr.Scan()
|
||||
for _, ag := range agents {
|
||||
if ag.ID == id {
|
||||
_ = a.mgr.Start(ag)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return last lines of build output
|
||||
lines := strings.Split(strings.TrimSpace(buildOut), "\n")
|
||||
tail := buildOut
|
||||
if len(lines) > 5 {
|
||||
tail = strings.Join(lines[len(lines)-5:], "\n")
|
||||
}
|
||||
return puretui.MsgRebuildDone{BuildLog: tail}
|
||||
}
|
||||
|
||||
// 4. Restart only the agents that were running before
|
||||
agents, _ := a.mgr.Scan()
|
||||
agentMap := make(map[string]process.AgentInfo)
|
||||
for _, ag := range agents {
|
||||
agentMap[ag.ID] = ag
|
||||
}
|
||||
|
||||
var restarted, failed int
|
||||
var errs []string
|
||||
for _, id := range wasRunning {
|
||||
ag, ok := agentMap[id]
|
||||
if !ok {
|
||||
failed++
|
||||
errs = append(errs, fmt.Sprintf("%s: not found after build", id))
|
||||
continue
|
||||
}
|
||||
if err := a.mgr.Start(ag); err != nil {
|
||||
failed++
|
||||
errs = append(errs, fmt.Sprintf("%s: %v", id, err))
|
||||
} else {
|
||||
restarted++
|
||||
}
|
||||
}
|
||||
if restarted > 0 {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
||||
return puretui.MsgRebuildDone{
|
||||
BuildOK: true,
|
||||
Restarted: restarted,
|
||||
Failed: failed,
|
||||
Errors: errs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Adapter) loadLogs(id string) tea.Cmd {
|
||||
return func() tea.Msg {
|
||||
lines, err := a.mgr.LogTail(id, 100)
|
||||
|
||||
Reference in New Issue
Block a user