Commit 386fa8c
Eric Bower
·
2026-05-07 10:07:59 -0400 EDT
parent e2e0d12
style(runner): update session status
1 files changed,
+40,
-13
M
main.go
M
main.go
+40,
-13
1@@ -14,6 +14,7 @@ import (
2 "os/exec"
3 "os/signal"
4 "path/filepath"
5+ "strconv"
6 "strings"
7 "syscall"
8 "time"
9@@ -500,16 +501,17 @@ func waitAndReport(cfg *Cfg, log *slog.Logger, name, jobID string) error {
10 fmt.Fprintln(os.Stdout)
11 fmt.Fprint(os.Stdout, "⏳ waiting for completion...\n")
12
13- // Track what we've already printed to avoid duplicates
14+ // Track state for each session
15 type sessionState struct {
16 status string // "running", "success", "failed"
17 exitCode string
18 duration string
19- printed bool
20+ printed bool // true once final state (success/failed) is printed
21 }
22 known := make(map[string]*sessionState)
23 var jobSessions []SessionInfo
24 var sessionOrder []string // track insertion order for deterministic output
25+ var liveLines []string // last set of status lines printed (for overwrite)
26
27 for {
28 select {
29@@ -552,6 +554,8 @@ func waitAndReport(cfg *Cfg, log *slog.Logger, name, jobID string) error {
30
31 if s.Ended == "" {
32 state.status = "running"
33+ created, _ := strconv.ParseInt(s.Created, 10, 64)
34+ state.duration = fmtDurationTs(created, time.Now().Unix())
35 } else {
36 if s.ExitCode == "0" {
37 state.status = "success"
38@@ -560,22 +564,45 @@ func waitAndReport(cfg *Cfg, log *slog.Logger, name, jobID string) error {
39 state.exitCode = s.ExitCode
40 }
41 state.duration = fmtDuration(s.Created, s.Ended)
42+ state.printed = true // lock final state
43 }
44+ }
45
46- // Print when state changes
47- if !state.printed {
48- icon := map[string]string{"running": "🚀", "success": "✅", "failed": "❌"}[state.status]
49- detail := ""
50- if state.status == "failed" && state.exitCode != "" {
51- detail = fmt.Sprintf(", exit %s", state.exitCode)
52- }
53- if state.duration != "" && state.duration != "—" {
54- detail += fmt.Sprintf(" (%s)", state.duration)
55+ // Build current status lines
56+ lines := make([]string, 0, len(sessionOrder))
57+ for _, short := range sessionOrder {
58+ state := known[short]
59+ icon := map[string]string{"running": "🚀", "success": "✅", "failed": "❌"}[state.status]
60+ detail := ""
61+ if state.status == "failed" && state.exitCode != "" {
62+ detail = fmt.Sprintf(", exit %s", state.exitCode)
63+ }
64+ if state.duration != "" && state.duration != "—" {
65+ detail += fmt.Sprintf(" (%s)", state.duration)
66+ }
67+ lines = append(lines, fmt.Sprintf(" %-12s %s %s%s", short, icon, state.status, detail))
68+ }
69+
70+ // Overwrite previous lines with cursor-up, or print fresh
71+ if len(liveLines) > 0 {
72+ // Move cursor up to overwrite previous lines
73+ for range len(liveLines) {
74+ fmt.Fprint(os.Stdout, "\033[A")
75+ }
76+ // Clear each line
77+ for i, line := range lines {
78+ if i > 0 {
79+ fmt.Fprint(os.Stdout, "\n")
80 }
81- fmt.Fprintf(os.Stdout, " %-12s %s %s%s\n", s.Short, icon, state.status, detail)
82- state.printed = true
83+ fmt.Fprint(os.Stdout, line+"\033[K")
84+ }
85+ fmt.Fprint(os.Stdout, "\n")
86+ } else {
87+ for _, line := range lines {
88+ fmt.Fprintln(os.Stdout, line)
89 }
90 }
91+ liveLines = lines
92
93 // Check if all sessions are done
94 if allCompleted(jobSessions) {