resume picker: resume the selected session, not the branch's latest · Entire

resume picker: resume the selected session, not the branch's latest

5866380→main· Soph·1mo ago·3 files·+243 added/-45 removed

The picker is session-oriented but the action only passed the branch to runResume, which re-derived the latest checkpoint on that branch and ignored the selected session. So two sessions on the same branch both resumed the latest, and an idle session with a stored branch but no committed checkpoint was selectable yet resumed unrelated work (or failed with "No Entire checkpoint found").

Fix:

Tests:

Sessions

f0b960dc6333View transcript

Changes

3

88 unmodified lines
func switchToBranchForResume(ctx context.Context, w, errW io.Writer, branchName string, force bool) (bool, error) {
    // Check if we're already on this branch
    currentBranch, err := GetCurrentBranch(ctx)
    if err == nil && currentBranch == branchName {
        // Already on the branch, skip checkout
        return resumeFromCurrentBranch(ctx, w, errW, branchName, force)
    }

// Check if branch exists locally
    exists, err := BranchExistsLocally(ctx, branchName)
    if err != nil {
        return fmt.Errorf("failed to check branch: %w", err)
    }

if !exists {
        // Branch doesn't exist locally, check if it exists on remote
        remoteExists, err := BranchExistsOnRemote(ctx, branchName)
        if err != nil {
            return fmt.Errorf("failed to check remote branch: %w", err)
        }

if !remoteExists {
            return fmt.Errorf("branch '%s' not found locally or on origin", branchName)
        }

// Ask user if they want to fetch from remote (--force skips the prompt)
        if !force {
            shouldFetch, err := promptFetchFromRemote(branchName)
            if err != nil {
                return err
            }
            if !shouldFetch {
                return nil
            }
        }
    }

// Checkout the branch
    if err := CheckoutBranch(ctx, branchName); err != nil {
        fmt.Fprintf(errW, "Error: failed to checkout branch: %v\n", err)
        return NewSilentError(errors.New("failed to checkout branch"))
    }
    fmt.Fprintf(w, "✓ Switched to branch %s\n", branchName)
    return true, nil
}
func resumeSessionOnBranch(ctx context.Context, cmd *cobra.Command, branchName string, checkpointID id.CheckpointID, force bool) error {
    // Check if session can be resumed
    return resumeFromCurrentBranch(ctx, w, errW, branchName, force)
}

resumableSession struct

type resumableSession struct {
    state        *strategy.SessionState
    branch       string
    checkpointID id.CheckpointID
}

func (r resumableSession) isResumable() bool {
    return r.branch != "" && !r.checkpointID.IsEmpty()
}

func (r resumableSession) unresumableReason() string {
    if r.branch == "" {
        return "no branch"
    }
    return "no committed checkpoint"
}
func buildResumeOptions(items []resumableSession) (string, bool) {
    options := []huh.Option{}
    hasSelectable := false
    for i, item := range items {
        options = append(options, huh.NewOption(resumeOptionLabel(item), strconv.Itoa(i)))
        if item.branch != "" {
            if item.isResumable() {
                hasSelectable = true
            }
        }
    }
    return options, hasSelectable
}

Summary

The session picker allows dynamic resumption of multiple checkpoints, facilitating effective session management across branches with robust validation to prevent process overlap.