cli: dedupe tmp-state cleanup and rewind preview warnings · Entire

cli: dedupe tmp-state cleanup and rewind preview warnings

c839042·

Soph·2w ago·2 files·+24 added/-37 removed

CleanupPrePromptState/CleanupPreTaskState repeated the open-root/remove
dance — extract cleanupTmpStateFile. The interactive and non-interactive
rewind flows repeated the files-to-delete preview warning — extract
printRewindPreviewWarnings. Covered by the existing state and rewind
tests.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

Sessions

7c22eaba7124View transcript

Changes

2

224 unmodified lines

225
226
227
228
229
230
231
232
233
234
235
236
237
238
228
229
230
231
255 unmodified lines

487
488
489
500
501
502
503
504
505
506
507
508
509
510
490
491
492
493
221 unmodified lines

715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736

224 unmodified lines

return handleLogsOnlyRewindInteractive(ctx, w, errW, start, *selectedPoint, shortID)
}

// Preview rewind to show warnings about files that will be deleted
preview, previewErr := start.PreviewRewind(ctx, *selectedPoint)
if previewErr != nil {
    fmt.Fprintf(errW, "Warning: could not preview rewind effects: %v\n", previewErr)
} else if preview != nil && len(preview.FilesToDelete) > 0 {
    fmt.Fprintf(errW, "\nWarning: The following untracked files will be DELETED:\n")
    for _, f := range preview.FilesToDelete {
        fmt.Fprintf(errW, "  - %s\n", f)
    }
    fmt.Fprintf(errW, "\n")
}
printRewindPreviewWarnings(ctx, errW, start, *selectedPoint)

// Confirm rewind
var confirm bool
255 unmodified lines

return handleLogsOnlyRewindNonInteractive(ctx, w, errW, start, *selectedPoint)
}

// Resolve agent once for use throughout
agent, err := getAgent(selectedPoint.Agent)
221 unmodified lines

return filepath.Join(cleaned, paths.TranscriptFileNameLegacy)

// printRewindPreviewWarnings previews the rewind and warns about untracked
// files it would delete. Preview failures are non-fatal — the rewind itself
// still runs, so the warning degrades to a notice.
func printRewindPreviewWarnings(ctx context.Context, errW io.Writer, start *strategy.ManualCommitStrategy, point strategy.RewindPoint) {
preview, previewErr := start.PreviewRewind(ctx, point)
if previewErr != nil {
    fmt.Fprintf(errW, "Warning: could not preview rewind effects: %v\n", previewErr)
} else if preview != nil && len(preview.FilesToDelete) > 0 {
    fmt.Fprintf(errW, "\nWarning: The following untracked files will be DELETED:\n")
    for _, f := range preview.FilesToDelete {
        fmt.Fprintf(errW, "  - %s\n", f)
    }
    fmt.Fprintf(errW, "\n")
}
}

func restoreSessionTranscript(ctx context.Context, w io.Writer, transcriptFile, sessionID string, agent agentpkg.Agent) error {
sessionFile, err := resolveTranscriptPath(ctx, sessionID, agent)
if err != nil {

Mcmd/entire/cli/rewind.go+18/-22

201 unmodified lines

202
203
204
205
206
207
208
209
210
211
212
213
5 unmodified lines

219
220
221
217
222
223
224
349 unmodified lines

574
575
576
573
574
575
576
577
578
579
580
581
582
583
584
585
586
577
578
579
580

201 unmodified lines

if err := validation.ValidateSessionID(sessionID); err != nil {
        return fmt.Errorf("invalid session ID for pre-prompt state cleanup: %w", err)
    }
    return cleanupTmpStateFile(ctx, fmt.Sprintf("pre-prompt-%s.json", sessionID))
}

// cleanupTmpStateFile removes one state file from .entire/tmp, treating a
// missing directory as already clean.
func cleanupTmpStateFile(ctx context.Context, fileName string) error {
tmpDirAbs := resolveTmpDir(ctx)

root, err := os.OpenRoot(tmpDirAbs)
5 unmodified lines

}
defer root.Close()

fileName := fmt.Sprintf("pre-prompt-%s.json", sessionID)
return osroot.Remove(root, fileName) //nolint:wrapcheck // best-effort cleanup, caller adds context via wrapping function name
}

349 unmodified lines

if err := validation.ValidateToolUseID(toolUseID); err != nil {
        return fmt.Errorf("invalid tool use ID for pre-task state cleanup: %w", err)
    }

tmpDirAbs := resolveTmpDir(ctx)

root, err := os.OpenRoot(tmpDirAbs)
    if err != nil {
        if os.IsNotExist(err) {
            return nil // Directory doesn't exist, nothing to clean up
        }
        return fmt.Errorf("failed to open tmp directory root: %w", err)
    }
    defer root.Close()

fileName := fmt.Sprintf("pre-task-%s.json", toolUseID)
    return osroot.Remove(root, fileName) //nolint:wrapcheck // best-effort cleanup, caller adds context via wrapping function name
    return cleanupTmpStateFile(ctx, fmt.Sprintf("pre-task-%s.json", toolUseID))
// preTaskFilePrefix is the prefix for pre-task state files