feat(session): surface imported sessions as read-only in list/info · Entire

feat(session): surface imported sessions as read-only in list/info

ffbe263→main·

computermode·1w ago·4 files·+126 added/-1 removed

Imported sessions are read-only (not resumable/rewindable). Label them so users don't mistake unsupported writes for breakage: - session list card shows "imported (read-only)" - session info text adds a read-only note; --json/list --json expose kind + read_only - resume picker explains when the only sessions present are imports

Rewind already refuses imported checkpoints (refuseIfImportedCheckpoint).

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

Sessions

01KX4B7QPKJ5NFBCE8C0XMW0QMView transcript

[?
Fix Imported Sessions Handling in CLIClaude Code·Opus 4.8·4 steps](/content/gh/entireio/cli/session/91fa7c44-6634-48ab-ae5f-d394502f50d5#timeline-01KX4B7QPKJ5NFBCE8C0XMW0QM/index.html)

Changes

4

79 unmodified lines

...

return resumable
}

// countImportedSessions counts read-only imported sessions in the set. Used to
// explain an empty resume picker when the only sessions present are imports
// (which are deliberately filtered out of the resumable list).
func countImportedSessions(states []*strategy.SessionState) int {
    n := 0
    for _, s := range states {
        if s != nil && s.Kind == session.KindImported {
            n++
        }
    }
    return n
}

// pluralizeImportedSessions renders the count for the picker hint.
func pluralizeImportedSessions(n int) string {
    if n == 1 {
        return "1 imported session is"
    }
    return fmt.Sprintf("%d imported sessions are", n)
}

// sessionLastActiveTime returns the best timestamp to represent when a session
// was last touched: its end time, else last interaction, else start time.
func sessionLastActiveTime(s *strategy.SessionState) time.Time {

Mcmd/entire/cli/resume_picker.go+24

39 unmodified lines

...
}

func TestCountImportedSessions(t *testing.T) {

t.Parallel()

states := []*strategy.SessionState{
    {SessionID: "a", Kind: session.KindImported},
    {SessionID: "b"},
    nil,
    {SessionID: "c", Kind: session.KindImported},
}
if got := countImportedSessions(states); got != 2 {
    t.Fatalf("countImportedSessions = %d, want 2", got)
}
if got := pluralizeImportedSessions(1); got != "1 imported session is" {
    t.Errorf("singular = %q", got)
}
if got := pluralizeImportedSessions(3); got != "3 imported sessions are" {
    t.Errorf("plural = %q", got)
}
}

func TestFilterResumableSessions(t *testing.T) {

t.Parallel()

Mcmd/entire/cli/resume_picker_test.go+19

436 unmodified lines

...

Mcmd/entire/cli/sessions.go+12/-1

973 unmodified lines

...

Mcmd/entire/cli/sessions_test.go+71

{...}