resume picker: address Copilot/Cursor review comments · Entire

resume picker: address Copilot/Cursor review comments

5d9e2a5→main·

Soph·1mo ago·4 files·+80 added/-7 removed

Adds TestCaptureSessionBranch (on-branch capture + detached-HEAD clear).

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

Sessions

cb36c5558f2cView transcript

Changes

4

// resumeSingleSession restores a single session (fallback when multi-session restore fails).
// Always overwrites existing session logs to ensure consistency with checkpoint state.
// If force is false, prompts for confirmation when local log has newer timestamps.
// By default it never overwrites an existing local session log — if one is present it is
// kept and only the resume command is printed; --force overwrites it from the checkpoint.
// A missing local log is always restored from the checkpoint.
func resumeSingleSession(ctx context.Context, w, _ io.Writer, ag agent.Agent, sessionID string, checkpointID id.CheckpointID, repoRoot string, force bool) error {
    sessionLogPath, err := resolveTranscriptPath(ctx, sessionID, ag)
    if err != nil {
        // Handle error scenario
    }
    if !force {
        if _, statErr := os.Stat(sessionLogPath); statErr == nil {
            fmt.Fprintf(w, "Session '%s' already has a local log — keeping it (use --force to overwrite from checkpoint).\n", sessionID)
            fmt.Fprintf(w, "Keeping existing local session log for '%s' (use --force to overwrite from checkpoint).\n", sessionID)
            fmt.Fprintf(w, "\nTo continue this session:\n")
            fmt.Fprintf(w, "  %s\n", ag.FormatResumeCommand(sessionID))
            return nil
        }
    }
}
package strategy

import (
    "testing"
    "github.com/entireio/cli/cmd/entire/cli/testutil"
    "github.com/go-git/go-git/v6"
    "github.com/go-git/go-git/v6/plumbing"
)

// TestCaptureSessionBranch verifies the branch is recorded while on a branch and
// cleared on a detached HEAD (so a stale value can't survive into resume).
func TestCaptureSessionBranch(t *testing.T) {
    t.Parallel()
    dir := t.TempDir()
    testutil.InitRepo(t, dir)
    testutil.WriteFile(t, dir, "f.txt", "x")
    testutil.GitAdd(t, dir, "f.txt")
    testutil.GitCommit(t, dir, "init")

repo, err := git.PlainOpen(dir)
    if err != nil {
        t.Fatalf("open repo: %v", err)
    }
    defer repo.Close()

head, err := repo.Head()
    if err != nil {
        t.Fatalf("head: %v", err)
    }

// On a branch: captures the current branch name (overwriting any prior value).
    state := &SessionState{Branch: "stale"}
    captureSessionBranch(repo, state)
    if want := head.Name().Short(); state.Branch != want {
        t.Errorf("on-branch: Branch = %q, want %q", state.Branch, want)
    }

// Detached HEAD: clears the stale branch so resume derives it instead.
    if err := repo.Storer.SetReference(plumbing.NewHashReference(plumbing.HEAD, head.Hash())); err != nil {
        t.Fatalf("detach HEAD: %v", err)
    }
    state.Branch = "stale-branch"
    captureSessionBranch(repo, state)
    if state.Branch != "" {
        t.Errorf("detached HEAD should clear Branch, got %q", state.Branch)
    }
}