resume picker: resume the selected session, not the branch's latest · Entire
resume picker: resume the selected session, not the branch's latest
32bed47·
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:
- Carry each session's checkpoint ID through the picker. A row is selectable only when it has BOTH a branch and a committed checkpoint; otherwise it's shown disabled with the reason (no branch / no committed checkpoint).
- On selection, resume that specific checkpoint via a new resumeSessionOnBranch/resumeByCheckpointID path that switches to the branch and restores the chosen session, instead of searching branch history. Checkout logic is shared with runResume via switchToBranchForResume (no duplication).
Tests: two sessions on one branch each carry their own checkpoint; resuming a specific checkpoint restores that session and not the newer one; a branch-only session with no checkpoint is not selectable.
Sessions
f0b960dc6333View transcript
Changes
3
cmd/entire/cli
Mresume.go+92/-23
Mresume_picker.go+38/-16
Mresume_picker_test.go+113/-6
88 unmodified lines
Example Code Logic
// switchToBranchForResume ensures the working tree is on branchName, checking it
// out (or fetching it from origin) as needed. It returns proceed=false with a nil
// error when the user declined to fetch a remote-only branch, so callers should
// stop without treating that as a failure.
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 false, 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 false, fmt.Errorf("failed to check remote branch: %w", err)
}
if !remoteExists {
return false, 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 false, err
}
if !shouldFetch {
return false, nil
}
}
}
}
Test Cases
// TestResumableSession_RequiresCheckpoint covers a session with a stored branch but no committed checkpoint—must not be selectable.
func TestResumableSession_RequiresCheckpoint(t *testing.T) {
t.Parallel()
withCheckpoint := resumableSession{branch: "b", checkpointID: id.MustCheckpointID("abc123abc123")}
if !withCheckpoint.isResumable() {
t.Error("branch + checkpoint should be resumable")
}
branchOnly := resumableSession{branch: "b"} // empty checkpoint ID
if branchOnly.isResumable() {
t.Error("a branch with no committed checkpoint must not be resumable")
}
}