Extract timing constants to constants package (gt-795e8)
Added 6 timing constants: - ShutdownNotifyDelay (500ms) - ClaudeStartTimeout (15s) - ShellReadyTimeout (5s) - DefaultDebounceMs (100) - DefaultDisplayMs (5000) - PollInterval (100ms) Updated 7 files to use these constants instead of magic numbers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,6 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/steveyegge/gastown/internal/config"
|
"github.com/steveyegge/gastown/internal/config"
|
||||||
@@ -106,7 +105,7 @@ func runCrewAt(cmd *cobra.Command, args []string) error {
|
|||||||
_ = t.ConfigureGasTownSession(sessionID, theme, r.Name, name, "crew")
|
_ = t.ConfigureGasTownSession(sessionID, theme, r.Name, name, "crew")
|
||||||
|
|
||||||
// Wait for shell to be ready after session creation
|
// Wait for shell to be ready after session creation
|
||||||
if err := t.WaitForShellReady(sessionID, 5*time.Second); err != nil {
|
if err := t.WaitForShellReady(sessionID, constants.ShellReadyTimeout); err != nil {
|
||||||
return fmt.Errorf("waiting for shell: %w", err)
|
return fmt.Errorf("waiting for shell: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ func runCrewRefresh(cmd *cobra.Command, args []string) error {
|
|||||||
_ = t.SetEnvironment(sessionID, "GT_CREW", name)
|
_ = t.SetEnvironment(sessionID, "GT_CREW", name)
|
||||||
|
|
||||||
// Wait for shell to be ready
|
// Wait for shell to be ready
|
||||||
if err := t.WaitForShellReady(sessionID, 5*time.Second); err != nil {
|
if err := t.WaitForShellReady(sessionID, constants.ShellReadyTimeout); err != nil {
|
||||||
return fmt.Errorf("waiting for shell: %w", err)
|
return fmt.Errorf("waiting for shell: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +236,7 @@ func runCrewRestart(cmd *cobra.Command, args []string) error {
|
|||||||
_ = t.ConfigureGasTownSession(sessionID, theme, r.Name, name, "crew")
|
_ = t.ConfigureGasTownSession(sessionID, theme, r.Name, name, "crew")
|
||||||
|
|
||||||
// Wait for shell to be ready
|
// Wait for shell to be ready
|
||||||
if err := t.WaitForShellReady(sessionID, 5*time.Second); err != nil {
|
if err := t.WaitForShellReady(sessionID, constants.ShellReadyTimeout); err != nil {
|
||||||
return fmt.Errorf("waiting for shell: %w", err)
|
return fmt.Errorf("waiting for shell: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,11 +250,11 @@ func runCrewRestart(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
// Wait for Claude to start, then prime it
|
// Wait for Claude to start, then prime it
|
||||||
shells := constants.SupportedShells
|
shells := constants.SupportedShells
|
||||||
if err := t.WaitForCommand(sessionID, shells, 15*time.Second); err != nil {
|
if err := t.WaitForCommand(sessionID, shells, constants.ClaudeStartTimeout); err != nil {
|
||||||
style.PrintWarning("Timeout waiting for Claude to start: %v", err)
|
style.PrintWarning("Timeout waiting for Claude to start: %v", err)
|
||||||
}
|
}
|
||||||
// Give Claude time to initialize after process starts
|
// Give Claude time to initialize after process starts
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(constants.ShutdownNotifyDelay)
|
||||||
if err := t.SendKeys(sessionID, "gt prime"); err != nil {
|
if err := t.SendKeys(sessionID, "gt prime"); err != nil {
|
||||||
// Non-fatal: Claude started but priming failed
|
// Non-fatal: Claude started but priming failed
|
||||||
style.PrintWarning("Could not send prime command: %v", err)
|
style.PrintWarning("Could not send prime command: %v", err)
|
||||||
@@ -358,7 +358,7 @@ func runCrewRestartAll() error {
|
|||||||
crewRig = savedRig
|
crewRig = savedRig
|
||||||
|
|
||||||
// Small delay between restarts to avoid overwhelming the system
|
// Small delay between restarts to avoid overwhelming the system
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(constants.ShutdownNotifyDelay)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
@@ -402,7 +402,7 @@ func restartCrewSession(rigName, crewName, clonePath string) error {
|
|||||||
_ = t.ConfigureGasTownSession(sessionID, theme, rigName, crewName, "crew")
|
_ = t.ConfigureGasTownSession(sessionID, theme, rigName, crewName, "crew")
|
||||||
|
|
||||||
// Wait for shell to be ready
|
// Wait for shell to be ready
|
||||||
if err := t.WaitForShellReady(sessionID, 5*time.Second); err != nil {
|
if err := t.WaitForShellReady(sessionID, constants.ShellReadyTimeout); err != nil {
|
||||||
return fmt.Errorf("waiting for shell: %w", err)
|
return fmt.Errorf("waiting for shell: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,10 +415,10 @@ func restartCrewSession(rigName, crewName, clonePath string) error {
|
|||||||
|
|
||||||
// Wait for Claude to start, then prime it
|
// Wait for Claude to start, then prime it
|
||||||
shells := constants.SupportedShells
|
shells := constants.SupportedShells
|
||||||
if err := t.WaitForCommand(sessionID, shells, 15*time.Second); err != nil {
|
if err := t.WaitForCommand(sessionID, shells, constants.ClaudeStartTimeout); err != nil {
|
||||||
// Non-fatal warning
|
// Non-fatal warning
|
||||||
}
|
}
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(constants.ShutdownNotifyDelay)
|
||||||
if err := t.SendKeys(sessionID, "gt prime"); err != nil {
|
if err := t.SendKeys(sessionID, "gt prime"); err != nil {
|
||||||
// Non-fatal
|
// Non-fatal
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -459,7 +459,7 @@ func runGracefulShutdown(t *tmux.Tmux, gtSessions []string, townRoot string) err
|
|||||||
shutdownMsg := "[SHUTDOWN] Gas Town is shutting down. Please save your state and update your handoff bead, then type /exit or wait to be terminated."
|
shutdownMsg := "[SHUTDOWN] Gas Town is shutting down. Please save your state and update your handoff bead, then type /exit or wait to be terminated."
|
||||||
for _, sess := range gtSessions {
|
for _, sess := range gtSessions {
|
||||||
// Small delay then send the message
|
// Small delay then send the message
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(constants.ShutdownNotifyDelay)
|
||||||
_ = t.SendKeys(sess, shutdownMsg) // best-effort notification
|
_ = t.SendKeys(sess, shutdownMsg) // best-effort notification
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -748,10 +748,10 @@ func runStartCrew(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
// Wait for Claude to start, then prime
|
// Wait for Claude to start, then prime
|
||||||
shells := constants.SupportedShells
|
shells := constants.SupportedShells
|
||||||
if err := t.WaitForCommand(sessionID, shells, 15*time.Second); err != nil {
|
if err := t.WaitForCommand(sessionID, shells, constants.ClaudeStartTimeout); err != nil {
|
||||||
style.PrintWarning("Timeout waiting for Claude to start: %v", err)
|
style.PrintWarning("Timeout waiting for Claude to start: %v", err)
|
||||||
}
|
}
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(constants.ShutdownNotifyDelay)
|
||||||
if err := t.SendKeys(sessionID, "gt prime"); err != nil {
|
if err := t.SendKeys(sessionID, "gt prime"); err != nil {
|
||||||
style.PrintWarning("Could not send prime command: %v", err)
|
style.PrintWarning("Could not send prime command: %v", err)
|
||||||
}
|
}
|
||||||
@@ -779,7 +779,7 @@ func runStartCrew(cmd *cobra.Command, args []string) error {
|
|||||||
_ = t.ConfigureGasTownSession(sessionID, theme, rigName, name, "crew")
|
_ = t.ConfigureGasTownSession(sessionID, theme, rigName, name, "crew")
|
||||||
|
|
||||||
// Wait for shell to be ready after session creation
|
// Wait for shell to be ready after session creation
|
||||||
if err := t.WaitForShellReady(sessionID, 5*time.Second); err != nil {
|
if err := t.WaitForShellReady(sessionID, constants.ShellReadyTimeout); err != nil {
|
||||||
return fmt.Errorf("waiting for shell: %w", err)
|
return fmt.Errorf("waiting for shell: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -790,12 +790,12 @@ func runStartCrew(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
// Wait for Claude to start
|
// Wait for Claude to start
|
||||||
shells := constants.SupportedShells
|
shells := constants.SupportedShells
|
||||||
if err := t.WaitForCommand(sessionID, shells, 15*time.Second); err != nil {
|
if err := t.WaitForCommand(sessionID, shells, constants.ClaudeStartTimeout); err != nil {
|
||||||
style.PrintWarning("Timeout waiting for Claude to start: %v", err)
|
style.PrintWarning("Timeout waiting for Claude to start: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give Claude time to initialize after process starts
|
// Give Claude time to initialize after process starts
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(constants.ShutdownNotifyDelay)
|
||||||
|
|
||||||
// Send gt prime to initialize context
|
// Send gt prime to initialize context
|
||||||
if err := t.SendKeys(sessionID, "gt prime"); err != nil {
|
if err := t.SendKeys(sessionID, "gt prime"); err != nil {
|
||||||
@@ -913,7 +913,7 @@ func startCrewMember(rigName, crewName, townRoot string) error {
|
|||||||
_ = t.SetCrewCycleBindings(sessionID)
|
_ = t.SetCrewCycleBindings(sessionID)
|
||||||
|
|
||||||
// Wait for shell to be ready
|
// Wait for shell to be ready
|
||||||
if err := t.WaitForShellReady(sessionID, 5*time.Second); err != nil {
|
if err := t.WaitForShellReady(sessionID, constants.ShellReadyTimeout); err != nil {
|
||||||
return fmt.Errorf("waiting for shell: %w", err)
|
return fmt.Errorf("waiting for shell: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -924,12 +924,12 @@ func startCrewMember(rigName, crewName, townRoot string) error {
|
|||||||
|
|
||||||
// Wait for Claude to start
|
// Wait for Claude to start
|
||||||
shells := constants.SupportedShells
|
shells := constants.SupportedShells
|
||||||
if err := t.WaitForCommand(sessionID, shells, 15*time.Second); err != nil {
|
if err := t.WaitForCommand(sessionID, shells, constants.ClaudeStartTimeout); err != nil {
|
||||||
// Non-fatal: Claude might still be starting
|
// Non-fatal: Claude might still be starting
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give Claude time to initialize
|
// Give Claude time to initialize
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(constants.ShutdownNotifyDelay)
|
||||||
|
|
||||||
// Send gt prime to initialize context (non-fatal: session works without priming)
|
// Send gt prime to initialize context (non-fatal: session works without priming)
|
||||||
_ = t.SendKeys(sessionID, "gt prime")
|
_ = t.SendKeys(sessionID, "gt prime")
|
||||||
|
|||||||
@@ -2,6 +2,29 @@
|
|||||||
// Centralizing these magic strings improves maintainability and consistency.
|
// Centralizing these magic strings improves maintainability and consistency.
|
||||||
package constants
|
package constants
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// Timing constants for session management and tmux operations.
|
||||||
|
const (
|
||||||
|
// ShutdownNotifyDelay is the pause after sending shutdown notification.
|
||||||
|
ShutdownNotifyDelay = 500 * time.Millisecond
|
||||||
|
|
||||||
|
// ClaudeStartTimeout is how long to wait for Claude to start in a session.
|
||||||
|
ClaudeStartTimeout = 15 * time.Second
|
||||||
|
|
||||||
|
// ShellReadyTimeout is how long to wait for shell prompt after command.
|
||||||
|
ShellReadyTimeout = 5 * time.Second
|
||||||
|
|
||||||
|
// DefaultDebounceMs is the default debounce for SendKeys operations.
|
||||||
|
DefaultDebounceMs = 100
|
||||||
|
|
||||||
|
// DefaultDisplayMs is the default duration for tmux display-message.
|
||||||
|
DefaultDisplayMs = 5000
|
||||||
|
|
||||||
|
// PollInterval is the default polling interval for wait loops.
|
||||||
|
PollInterval = 100 * time.Millisecond
|
||||||
|
)
|
||||||
|
|
||||||
// Directory names within a Gas Town workspace.
|
// Directory names within a Gas Town workspace.
|
||||||
const (
|
const (
|
||||||
// DirMayor is the directory containing mayor configuration and state.
|
// DirMayor is the directory containing mayor configuration and state.
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/steveyegge/gastown/internal/constants"
|
||||||
"github.com/steveyegge/gastown/internal/keepalive"
|
"github.com/steveyegge/gastown/internal/keepalive"
|
||||||
"github.com/steveyegge/gastown/internal/polecat"
|
"github.com/steveyegge/gastown/internal/polecat"
|
||||||
"github.com/steveyegge/gastown/internal/tmux"
|
"github.com/steveyegge/gastown/internal/tmux"
|
||||||
@@ -547,7 +548,7 @@ func StopDaemon(townRoot string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait a bit for graceful shutdown
|
// Wait a bit for graceful shutdown
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(constants.ShutdownNotifyDelay)
|
||||||
|
|
||||||
// Check if still running
|
// Check if still running
|
||||||
if err := process.Signal(syscall.Signal(0)); err == nil {
|
if err := process.Signal(syscall.Signal(0)); err == nil {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/steveyegge/gastown/internal/beads"
|
"github.com/steveyegge/gastown/internal/beads"
|
||||||
|
"github.com/steveyegge/gastown/internal/constants"
|
||||||
"github.com/steveyegge/gastown/internal/tmux"
|
"github.com/steveyegge/gastown/internal/tmux"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -195,7 +196,7 @@ func (d *Daemon) executeLifecycleAction(request *LifecycleRequest) error {
|
|||||||
d.logger.Printf("Killed session %s for restart", sessionName)
|
d.logger.Printf("Killed session %s for restart", sessionName)
|
||||||
|
|
||||||
// Wait a moment
|
// Wait a moment
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(constants.ShutdownNotifyDelay)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restart the session
|
// Restart the session
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ func (t *Tmux) ListSessionIDs() (map[string]string, error) {
|
|||||||
// Always sends Enter as a separate command for reliability.
|
// Always sends Enter as a separate command for reliability.
|
||||||
// Uses a debounce delay between paste and Enter to ensure paste completes.
|
// Uses a debounce delay between paste and Enter to ensure paste completes.
|
||||||
func (t *Tmux) SendKeys(session, keys string) error {
|
func (t *Tmux) SendKeys(session, keys string) error {
|
||||||
return t.SendKeysDebounced(session, keys, 100) // 100ms default debounce
|
return t.SendKeysDebounced(session, keys, constants.DefaultDebounceMs) // 100ms default debounce
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendKeysDebounced sends keystrokes with a configurable delay before Enter.
|
// SendKeysDebounced sends keystrokes with a configurable delay before Enter.
|
||||||
@@ -375,7 +375,7 @@ func (t *Tmux) DisplayMessage(session, message string, durationMs int) error {
|
|||||||
|
|
||||||
// DisplayMessageDefault shows a message with default duration (5 seconds).
|
// DisplayMessageDefault shows a message with default duration (5 seconds).
|
||||||
func (t *Tmux) DisplayMessageDefault(session, message string) error {
|
func (t *Tmux) DisplayMessageDefault(session, message string) error {
|
||||||
return t.DisplayMessage(session, message, 5000)
|
return t.DisplayMessage(session, message, constants.DefaultDisplayMs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendNotificationBanner sends a visible notification banner to a tmux session.
|
// SendNotificationBanner sends a visible notification banner to a tmux session.
|
||||||
@@ -413,7 +413,7 @@ func (t *Tmux) WaitForCommand(session string, excludeCommands []string, timeout
|
|||||||
for time.Now().Before(deadline) {
|
for time.Now().Before(deadline) {
|
||||||
cmd, err := t.GetPaneCommand(session)
|
cmd, err := t.GetPaneCommand(session)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(constants.PollInterval)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Check if current command is NOT in the exclude list
|
// Check if current command is NOT in the exclude list
|
||||||
@@ -427,7 +427,7 @@ func (t *Tmux) WaitForCommand(session string, excludeCommands []string, timeout
|
|||||||
if !excluded {
|
if !excluded {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(constants.PollInterval)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("timeout waiting for command (still running excluded command)")
|
return fmt.Errorf("timeout waiting for command (still running excluded command)")
|
||||||
}
|
}
|
||||||
@@ -440,7 +440,7 @@ func (t *Tmux) WaitForShellReady(session string, timeout time.Duration) error {
|
|||||||
for time.Now().Before(deadline) {
|
for time.Now().Before(deadline) {
|
||||||
cmd, err := t.GetPaneCommand(session)
|
cmd, err := t.GetPaneCommand(session)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(constants.PollInterval)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, shell := range shells {
|
for _, shell := range shells {
|
||||||
@@ -448,7 +448,7 @@ func (t *Tmux) WaitForShellReady(session string, timeout time.Duration) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(constants.PollInterval)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("timeout waiting for shell")
|
return fmt.Errorf("timeout waiting for shell")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user