feat(enable): show progress while importing existing sessions - #1848
Open
ecgang wants to merge 3 commits into
Open
feat(enable): show progress while importing existing sessions#1848ecgang wants to merge 3 commits into
ecgang wants to merge 3 commits into
Conversation
Run previously gave callers no visibility into a potentially long import (sessions x turns with a documented O(turns^2) recompute), so first-run 'entire enable' sat silent for its whole duration. Add an optional, UI-agnostic Progress struct on Options: SessionStart fires per session after turn splitting, TurnWritten after each turn actually written (never for skips or dry runs). Nil stays byte-identical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Entire-Checkpoint: 01KY93365A3ZBK69V2948N4V4W
First-run 'entire enable' could sit silent for the whole session import (an hour on a large corpus) between the setup summary and the final Imported line. Wire the agentimport Progress reporter into user-visible output via one shared helper: - interactive terminals get the standard spinner, extended with an updatable message (startUpdatableSpinner; startSpinner now delegates to it) tracking 'session i/N - turn j/M' live - non-TTY and ACCESSIBLE runs get one plain ANSI-free line per session, keeping output complete for agents and screen readers - the standalone 'entire import <agent>' command gets the same wiring The final summary line is unchanged, and the spinner stops before any error path prints. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Entire-Checkpoint: 01KY93WZV7TJ0P4CSY40NYGZ1Q
The progress counter only advanced on TurnWritten, so a fully idempotent re-import or a --dry-run pass sat at 'turn 0/M' and then rendered that stale count into the completion line. Add Progress.TurnSkipped, fired for every turn Run processes without writing (already imported, or DryRun), and drive the UI counter from both callbacks: exactly one of TurnWritten/TurnSkipped now fires per turn, so the counter always sweeps to M/M truthfully. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Entire-Checkpoint: 01KY95QCD5YDCST7YNYKW063FA
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1847.
First-run
entire enableimports existing agent sessions with zero output between the setup summary and the finalImported N turn(s)line — on a large corpus that's an hour of bare cursor with no way to tell working from hung. This wires live progress into that import, following the CLI's existingstartSpinnerconventions.Honesty note on the demo: both gifs use a synthetic fixture (6 sessions × 60 turns, ~15s import) so the behavior is visible in a short recording; the real-world case that motivated this was ~1h of silence.
What changed
agentimport: optional, UI-agnosticProgressreporter onOptions—SessionStartfires per session after turn-splitting; exactly one ofTurnWritten/TurnSkippedfires per turn (skips cover already-imported turns and--dry-run), so callbacks always sum toturnCount. Nil reporter is byte-identical to before. No printing or logging inside the package.startUpdatableSpinner— the smallest variant of the existing spinner whose message can change while it runs;startSpinnernow delegates to it. Same glyphs, tick rate, 250 ms initial-draw delay, and TTY gating. One deliberate change: animated frames draw\r\033[Kinstead of bare\r, so a shrinking message can't leave stale trailing characters (final stop lines are byte-identical).newImportProgressReporter) used by both import surfaces — theentire enablefirst-run import and the standaloneentire import <agent>:Importing Claude Code sessions... (session i/N · turn j/M)updating liveACCESSIBLE=1: one plain ANSI-free line per session (Importing Claude Code session i/N (M turns)...), keeping output complete for agents and screen readers per the repo's agent-safe CLI fallback guidanceImported N turn(s) from M session(s)summary line is unchanged, and the spinner is stopped before any error path prints.Tests
agentimport: callback contract (counts, ordering, exact tuples), nil-reporter equivalence, skipped-turn and dry-run invariants (written + skipped == turnCount).cli: non-TTY progress lines (one per session, zero ESC bytes, unchanged summary line), spinner-variant behavior (fallback line, update-before-first-draw, stop semantics).mise run check(fmt, lint, unit + integration + Vogon canary) green; also manually verified against a real built binary: piped output,ACCESSIBLE=1under a PTY, and live-TTY spinner animation.Happy to adjust the message format or UX approach if maintainers prefer something different.
🤖 Generated with Claude Code