Support full session paths in gt handoff (gt-tocb)

resolveRoleToSession now accepts paths like <rig>/crew/<name>,
<rig>/witness, and <rig>/refinery in addition to role shortcuts.
For example: 'gt handoff gastown/crew/max' now works.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-23 13:25:38 -08:00
parent e804d4d52d
commit 9c85b834cd

View File

@@ -136,9 +136,19 @@ func getCurrentTmuxSession() (string, error) {
return strings.TrimSpace(string(out)), nil
}
// resolveRoleToSession converts a role name to a tmux session name.
// For roles that need context (crew, witness, refinery), it auto-detects from environment.
// resolveRoleToSession converts a role name or path to a tmux session name.
// Accepts:
// - Role shortcuts: "crew", "witness", "refinery", "mayor", "deacon"
// - Full paths: "<rig>/crew/<name>", "<rig>/witness", "<rig>/refinery"
// - Direct session names (passed through)
//
// For role shortcuts that need context (crew, witness, refinery), it auto-detects from environment.
func resolveRoleToSession(role string) (string, error) {
// First, check if it's a path format (contains /)
if strings.Contains(role, "/") {
return resolvePathToSession(role)
}
switch strings.ToLower(role) {
case "mayor", "may":
return "gt-mayor", nil
@@ -178,11 +188,44 @@ func resolveRoleToSession(role string) (string, error) {
return fmt.Sprintf("gt-%s-refinery", rig), nil
default:
// Assume it's a direct session name
// Assume it's a direct session name (e.g., gt-gastown-crew-max)
return role, nil
}
}
// resolvePathToSession converts a path like "<rig>/crew/<name>" to a session name.
// Supported formats:
// - <rig>/crew/<name> -> gt-<rig>-crew-<name>
// - <rig>/witness -> gt-<rig>-witness
// - <rig>/refinery -> gt-<rig>-refinery
func resolvePathToSession(path string) (string, error) {
parts := strings.Split(path, "/")
// Handle <rig>/crew/<name> format
if len(parts) == 3 && parts[1] == "crew" {
rig := parts[0]
name := parts[2]
return fmt.Sprintf("gt-%s-crew-%s", rig, name), nil
}
// Handle <rig>/<role> format (witness, refinery)
if len(parts) == 2 {
rig := parts[0]
role := strings.ToLower(parts[1])
switch role {
case "witness":
return fmt.Sprintf("gt-%s-witness", rig), nil
case "refinery":
return fmt.Sprintf("gt-%s-refinery", rig), nil
case "crew":
// Just "<rig>/crew" without a name - need more info
return "", fmt.Errorf("crew path requires name: %s/crew/<name>", rig)
}
}
return "", fmt.Errorf("cannot parse path '%s' - expected <rig>/crew/<name>, <rig>/witness, or <rig>/refinery", path)
}
// buildRestartCommand creates the command to run when respawning a session's pane.
// This needs to be the actual command to execute (e.g., claude), not a session attach command.
// The command includes a cd to the correct working directory for the role.