fix(handoff): use env var fallback when town root detection fails
When the repo is in a broken state (wrong branch, detached HEAD, deleted worktree), gt handoff would fail with "cannot detect town root" error. This is exactly when handoff is most needed - to recover and hand off to a fresh session. Changes: - detectTownRootFromCwd() now falls back to GT_TOWN_ROOT and GT_ROOT environment variables when cwd-based detection fails - buildRestartCommand() now propagates GT_ROOT to ensure subsequent handoffs can also use the fallback - Added tests for the fallback behavior Fixes gt-x2q81. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -411,6 +411,10 @@ func buildRestartCommand(sessionName string) (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Propagate GT_ROOT so subsequent handoffs can use it as fallback
|
||||
// when cwd-based detection fails (broken state recovery)
|
||||
exports = append(exports, "GT_ROOT="+townRoot)
|
||||
|
||||
// Preserve GT_AGENT across handoff so agent override persists
|
||||
if currentAgent != "" {
|
||||
exports = append(exports, "GT_AGENT="+currentAgent)
|
||||
@@ -498,14 +502,33 @@ func sessionToGTRole(sessionName string) string {
|
||||
}
|
||||
|
||||
// detectTownRootFromCwd walks up from the current directory to find the town root.
|
||||
// Falls back to GT_TOWN_ROOT or GT_ROOT env vars if cwd detection fails (broken state recovery).
|
||||
func detectTownRootFromCwd() string {
|
||||
// Use workspace.FindFromCwd which handles both primary (mayor/town.json)
|
||||
// and secondary (mayor/ directory) markers
|
||||
townRoot, err := workspace.FindFromCwd()
|
||||
if err != nil {
|
||||
return ""
|
||||
if err == nil && townRoot != "" {
|
||||
return townRoot
|
||||
}
|
||||
return townRoot
|
||||
|
||||
// Fallback: try environment variables for town root
|
||||
// GT_TOWN_ROOT is set by shell integration, GT_ROOT is set by session manager
|
||||
// This enables handoff to work even when cwd detection fails due to
|
||||
// detached HEAD, wrong branch, deleted worktree, etc.
|
||||
for _, envName := range []string{"GT_TOWN_ROOT", "GT_ROOT"} {
|
||||
if envRoot := os.Getenv(envName); envRoot != "" {
|
||||
// Verify it's actually a workspace
|
||||
if _, statErr := os.Stat(filepath.Join(envRoot, workspace.PrimaryMarker)); statErr == nil {
|
||||
return envRoot
|
||||
}
|
||||
// Try secondary marker too
|
||||
if info, statErr := os.Stat(filepath.Join(envRoot, workspace.SecondaryMarker)); statErr == nil && info.IsDir() {
|
||||
return envRoot
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// handoffRemoteSession respawns a different session and optionally switches to it.
|
||||
|
||||
Reference in New Issue
Block a user