Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion internal/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,11 @@ func New(config *Config) (*Daemon, error) {
logger.Printf("Warning: failed to initialize town registry: %v", err)
}

// Set GT_TOWN_ROOT in tmux global environment so run-shell subprocesses
// Set GT_TOWN_ROOT in the daemon process env so Go code (e.g.,
// sessionPrefixPattern) can read it without relying on GT_ROOT.
os.Setenv("GT_TOWN_ROOT", config.TownRoot)

// Also set GT_TOWN_ROOT in tmux global environment so run-shell subprocesses
// (e.g., gt cycle next/prev) can find the workspace even when CWD is $HOME.
// Non-fatal: tmux server may not be running yet — daemon creates sessions shortly.
t := tmux.NewTmux()
Expand Down
3 changes: 3 additions & 0 deletions internal/tmux/tmux.go
Original file line number Diff line number Diff line change
Expand Up @@ -1650,7 +1650,7 @@
// to avoid ambiguity. On some tmux versions (e.g., 3.3 on Windows),
// pane IDs are NOT globally unique — every session may have "%1".
// A bare "send-keys -t %1" targets the attached session's pane,
// not necessarily this session's. (gt-ect)

Check failure on line 1653 in internal/tmux/tmux.go

View workflow job for this annotation

GitHub Actions / Lint

`ect` is a misspelling of `etc` (misspell)
target = session + ":" + agentPane
}

Expand Down Expand Up @@ -3426,6 +3426,9 @@
func sessionPrefixPattern() string {
seen := map[string]bool{"hq": true, "gt": true} // always include HQ + gastown fallback
townRoot := os.Getenv("GT_ROOT")
if townRoot == "" {
townRoot = os.Getenv("GT_TOWN_ROOT")
}
if townRoot != "" {
for _, p := range config.AllRigPrefixes(townRoot) {
if safePrefixRe.MatchString(p) {
Expand Down
32 changes: 32 additions & 0 deletions internal/tmux/tmux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2146,6 +2146,38 @@ func TestSessionPrefixPattern_WithTownRoot(t *testing.T) {
}
}

func TestSessionPrefixPattern_FallsBackToGTTownRoot(t *testing.T) {
// When GT_ROOT is empty but GT_TOWN_ROOT is set, sessionPrefixPattern
// should use GT_TOWN_ROOT to discover rig prefixes.
townRoot := os.Getenv("GT_ROOT")
if townRoot == "" {
townRoot = os.Getenv("GT_TOWN_ROOT")
}
if townRoot == "" {
t.Skip("neither GT_ROOT nor GT_TOWN_ROOT set; skipping")
}

// Clear GT_ROOT, set GT_TOWN_ROOT — simulates daemon startup env.
t.Setenv("GT_ROOT", "")
t.Setenv("GT_TOWN_ROOT", townRoot)

pattern := sessionPrefixPattern()
if !strings.Contains(pattern, "gt") {
t.Errorf("pattern %q missing 'gt'", pattern)
}
if !strings.Contains(pattern, "hq") {
t.Errorf("pattern %q missing 'hq'", pattern)
}
// With a real rigs.json via GT_TOWN_ROOT, we expect more than just gt+hq.
// At minimum there should be 3+ prefixes in a multi-rig town.
inner := strings.TrimPrefix(pattern, "^(")
inner = strings.TrimSuffix(inner, ")-")
prefixes := strings.Split(inner, "|")
if len(prefixes) < 3 {
t.Errorf("expected at least 3 prefixes via GT_TOWN_ROOT fallback, got %d: %v", len(prefixes), prefixes)
}
}

func TestZombieStatusString(t *testing.T) {
t.Parallel()
tests := []struct {
Expand Down
Loading