Skip to content

Multi-Session and Multi-Repository Support with Performance Optimizations#66

Merged
agavra merged 12 commits intoagavra:mainfrom
avifenesh:feat/handle_multipule_sessions
Jan 25, 2026
Merged

Multi-Session and Multi-Repository Support with Performance Optimizations#66
agavra merged 12 commits intoagavra:mainfrom
avifenesh:feat/handle_multipule_sessions

Conversation

@avifenesh
Copy link
Copy Markdown
Contributor

@avifenesh avifenesh commented Jan 12, 2026

Multi-Session and Multi-Repository Support

fixes #5

Overview

This PR updates session persistence to support multiple review contexts (branch + diff source) without deleting existing sessions. It also fixes commit-range session persistence so reopening the same commit selection restores comments, and hardens session filename parsing so branch names with underscores or hex-like segments do not prevent loading.

Key Changes

  • Review sessions now record branch, diff source, and commit range (schema v1.2) with backward-compatible defaults.
  • Session loading is context-aware (repo fingerprint + diff source + branch + commit range) and updates base commit non-destructively.
  • Session filenames include repo fingerprint/branch/diff source; parsing tolerates underscores and hex-like branch segments.
  • Added commit-range persistence tests and filename parsing regression coverage.

Tests

  • cargo test

Copy link
Copy Markdown
Owner

@agavra agavra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome @avifenesh thanks for the detailed design and contribution! 🚀 🔥 🤩

I left some comments inline, but for the most part I'd like to split this PR into multiple so that we're not jamming a bunch of unrelated changes into one thing.

// Mode changes (use _ for shifted characters like : and ?)
(KeyCode::Char(':'), _) => Action::EnterCommandMode,
(KeyCode::Char('?'), _) => Action::ToggleHelp,
(KeyCode::Char('m'), KeyModifiers::NONE) => Action::EnterCommitSelectMode,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's punt this to a separate PR since this is already a big PR, and also consider #48 instead

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done - reverted keybindings.rs to upstream. The m key binding is not part of this PR.

KeyCode::Char(' ') => Action::ToggleCommitSelect,
KeyCode::Enter => Action::ConfirmCommitSelect,
KeyCode::Char('q') | KeyCode::Esc => Action::Quit,
KeyCode::Esc => Action::ExitMode,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's punt this to a separate PR as well

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done - reverted keybindings.rs to upstream. Esc behavior unchanged from main.

Comment on lines +44 to +47
pub enum SessionDiffSource {
WorkingTree,
CommitRange,
}
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should consider how this will work if we allow selecting commits + working tree (e.g. I want to see the diff from the last commit AND the current working tree). also see #43

we shouldn't fix this in this PR, but the design should allow for it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged. The current SessionDiffSource enum design can be extended to support WorkingTreeWithCommits(Vec<String>) or similar in the future without breaking changes, since serde handles enum variants gracefully.

session: ReviewSession,
}

static SESSION_CACHE: OnceLock<Mutex<Option<CachedSession>>> = OnceLock::new();
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's remove caching, 1ms load time is more than good enough and I'd rather keep it simple and avoid needing to think about caching

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done - removed SESSION_CACHE entirely. The code now loads sessions directly without caching.

}

fn get_reviews_dir() -> Result<PathBuf> {
if let Some(dir) = std::env::var_os("TUICR_REVIEWS_DIR") {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice! I like this change, but let's have it in a separate PR as well 🙏 thanks! making these separate PRs also makes the version changelog easier to review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The \ env var is now guarded by \ so it only compiles in test builds for test isolation. Not exposed in production. Let me know if you'd still prefer it removed entirely.

Comment on lines +211 to +223
Line::from(Span::styled(
"Review Modes",
Style::default().add_modifier(Modifier::BOLD | Modifier::UNDERLINED),
)),
Line::from(""),
Line::from(vec![
Span::styled(
" m ",
Style::default().add_modifier(Modifier::BOLD),
),
Span::raw("Switch to commit selection mode"),
]),
Line::from(""),
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's save this for another PR, I'm not sure we want it at all if we have #48

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done - help_popup.rs is unchanged from upstream. The m key help text is not part of this PR.


pub fn find_session_for_repo(repo_path: &Path) -> Result<Option<PathBuf>> {
let reviews_dir = get_reviews_dir()?;
pub fn load_latest_session_for_context(
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while we're iterating the files here I think we should clean up reviews that are older than 7 days. it's a good enough default and if people have need to keep reviews around that are older than that we can revisit it and maybe make it a config but I don't want these files taking up space on the user's disk without them knowing (I think many won't realize this)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done - implemented 7-day session cleanup. Sessions older than 7 days are automatically deleted during the directory iteration in load_latest_session_for_context().

@avifenesh avifenesh force-pushed the feat/handle_multipule_sessions branch from 5d6d286 to 79415c6 Compare January 15, 2026 08:47
avifenesh added a commit to avifenesh/tuicr that referenced this pull request Jan 15, 2026
Changes based on review comments from PR agavra#66:

1. **Remove session caching** - Simplified storage.rs by removing
   the session cache. 1ms load time is sufficient.

2. **Add automatic session cleanup** - Sessions older than 7 days
   are now automatically deleted during file iteration to prevent
   disk space accumulation.

3. **Remove manual commit selection mode** - Removed the 'm'
   keybinding and related handlers for manually entering commit
   selection mode. This will be addressed in a separate PR
   considering issue agavra#48. Automatic commit selection when no
   working tree changes exist is preserved.

4. **Remove TUICR_REVIEWS_DIR override** - Removed the environment
   variable override feature. Test infrastructure still uses it
   for isolation.

5. **Revert help text updates** - Removed the "Review Modes"
   section from help popup that documented the manual commit
   selection feature.

6. **Revert commit select mode navigation** - Changed Esc behavior
   in commit select mode back to Quit (original behavior).
avifenesh added a commit to avifenesh/tuicr that referenced this pull request Jan 15, 2026
Add the ability to manually enter commit selection mode using the 'm'
keybinding. This allows users to review commits even when there are
working tree changes.

Features:
- Press 'm' in normal mode to enter commit selection mode
- Browse and select commits to review
- Press Esc to exit back to normal mode (returns to working tree if applicable)
- Updated status bar hints to show 'm:commits' in normal mode
- Updated help text with new "Review Modes" section

This addresses the deferred feature from PR agavra#66 review feedback.

Related: agavra#48
avifenesh added a commit to avifenesh/tuicr that referenced this pull request Jan 15, 2026
Add the ability to manually enter commit selection mode using the 'm'
keybinding. This allows users to review commits even when there are
working tree changes.

Features:
- Press 'm' in normal mode to enter commit selection mode
- Browse and select commits to review
- Press Esc to exit back to normal mode (returns to working tree if applicable)
- Updated status bar hints to show 'm:commits' in normal mode
- Updated help text with new "Review Modes" section

This addresses the deferred feature from PR agavra#66 review feedback.

Related: agavra#48
avifenesh added a commit to avifenesh/tuicr that referenced this pull request Jan 15, 2026
Updates ReviewSession structure to match PR agavra#66's multi-session support:
- Add SessionDiffSource enum (WorkingTree, CommitRange)
- Add branch_name field to ReviewSession
- Add diff_source field to ReviewSession
- Update ReviewSession::new() to take 4 parameters
- Fix all session creation calls throughout the codebase
- Update test code to use new session structure

This fixes the bug where comments weren't being saved/restored when
reviewing commit ranges. Sessions now properly track whether they're
for working tree changes or commit ranges, enabling proper session
matching and persistence.

Fixes the issue where selecting commits, adding comments, saving with
:w, quitting, and reopening would lose all comments.
avifenesh added a commit to avifenesh/tuicr that referenced this pull request Jan 15, 2026
Updates ReviewSession structure to match PR agavra#66's multi-session support:
- Add SessionDiffSource enum (WorkingTree, CommitRange)
- Add branch_name field to ReviewSession
- Add diff_source field to ReviewSession
- Update ReviewSession::new() to take 4 parameters
- Fix all session creation calls throughout the codebase
- Update test code to use new session structure

This fixes the bug where comments weren't being saved/restored when
reviewing commit ranges. Sessions now properly track whether they're
for working tree changes or commit ranges, enabling proper session
matching and persistence.

Fixes the issue where selecting commits, adding comments, saving with
:w, quitting, and reopening would lose all comments.
avifenesh added a commit to avifenesh/tuicr that referenced this pull request Jan 19, 2026
Add the ability to manually enter commit selection mode using the 'm'
keybinding. This allows users to review commits even when there are
working tree changes.

Features:
- Press 'm' in normal mode to enter commit selection mode
- Browse and select commits to review
- Press Esc to exit back to normal mode (returns to working tree if applicable)
- Updated status bar hints to show 'm:commits' in normal mode
- Updated help text with new "Review Modes" section

This addresses the deferred feature from PR agavra#66 review feedback.

Related: agavra#48
avifenesh added a commit to avifenesh/tuicr that referenced this pull request Jan 19, 2026
Updates ReviewSession structure to match PR agavra#66's multi-session support:
- Add SessionDiffSource enum (WorkingTree, CommitRange)
- Add branch_name field to ReviewSession
- Add diff_source field to ReviewSession
- Update ReviewSession::new() to take 4 parameters
- Fix all session creation calls throughout the codebase
- Update test code to use new session structure

This fixes the bug where comments weren't being saved/restored when
reviewing commit ranges. Sessions now properly track whether they're
for working tree changes or commit ranges, enabling proper session
matching and persistence.

Fixes the issue where selecting commits, adding comments, saving with
:w, quitting, and reopening would lose all comments.
avifenesh added a commit to avifenesh/tuicr that referenced this pull request Jan 19, 2026
Apply review feedback from @agavra:
- Replace m keybinding with :commits command for entering commit select mode
- Update help popup to show :commits in Commands section
- Keep Esc to exit commit select mode back to working tree

Remove unrelated multi-session changes (belong in PR agavra#66):
- Remove SessionDiffSource enum
- Remove branch_name and diff_source fields from ReviewSession
- Remove find_session_for_commit function
- Revert ReviewSession to 2-parameter constructor
@avifenesh
Copy link
Copy Markdown
Contributor Author

@agavra What are our intentions with this one?

@agavra
Copy link
Copy Markdown
Owner

agavra commented Jan 20, 2026

@avifenesh I would like to continue with this one, I haven't had time to give it another round of review after you split out the other stuff. Because it's a pretty substantial PR I'll need to do a heavy round of testing and review. Did you update this PR after splitting out the other stuff?

@avifenesh
Copy link
Copy Markdown
Contributor Author

Will do, wanted to know that it is still relevant 👍🏽 @agavra

@avifenesh avifenesh force-pushed the feat/handle_multipule_sessions branch from acac103 to a7e51f6 Compare January 24, 2026 13:00
avifenesh added a commit to avifenesh/tuicr that referenced this pull request Jan 24, 2026
Changes based on review comments from PR agavra#66:

1. **Remove session caching** - Simplified storage.rs by removing
   the session cache. 1ms load time is sufficient.

2. **Add automatic session cleanup** - Sessions older than 7 days
   are now automatically deleted during file iteration to prevent
   disk space accumulation.

3. **Remove manual commit selection mode** - Removed the 'm'
   keybinding and related handlers for manually entering commit
   selection mode. This will be addressed in a separate PR
   considering issue agavra#48. Automatic commit selection when no
   working tree changes exist is preserved.

4. **Remove TUICR_REVIEWS_DIR override** - Removed the environment
   variable override feature. Test infrastructure still uses it
   for isolation.

5. **Revert help text updates** - Removed the "Review Modes"
   section from help popup that documented the manual commit
   selection feature.

6. **Revert commit select mode navigation** - Changed Esc behavior
   in commit select mode back to Quit (original behavior).
@avifenesh
Copy link
Copy Markdown
Contributor Author

@agavra PR updated - rebased on latest main and addressed all review feedback:

Changes Made

  • Removed out-of-scope changes: Reverted keybindings.rs and status_bar.rs to upstream (no m key binding, no Esc behavior change)
  • Removed SESSION_CACHE: Direct session loading without caching
  • Implemented 7-day cleanup: Old sessions auto-deleted during iteration
  • TUICR_REVIEWS_DIR: Now test-only (#[cfg(test)]) for test isolation

Files in this PR (7 total)

.gitignore                 |   2 +
src/app.rs                 |  76 ++++--
src/model/mod.rs           |   2 +-
src/model/review.rs        |  24 +-
src/output/markdown.rs     |  52 +++-
src/persistence/mod.rs     |   2 +-
src/persistence/storage.rs | 634 ++++++++++++++++++++++++++++++++++++++++++--

All 120 tests pass.


Note: This comment and the review responses were written by Claude Opus, by the request and approval of Avi.

@agavra
Copy link
Copy Markdown
Owner

agavra commented Jan 24, 2026

Thanks @avifenesh I'll take a look at this tonight 🫡

@agavra
Copy link
Copy Markdown
Owner

agavra commented Jan 24, 2026

@avifenesh I tested this locally and it doesn't seem to work for me, were you able to get it to work? I created a review on a few local commits, wrote it (confirmed I have the file on disk, see below), but when I load it up with the same commit range the comments don't show:

{
  "id": "0f56d862-140f-4e43-9368-af7052f6937b",
  "version": "1.1",
  "repo_path": "/Users/agavra/dev/tuicr/",
  "branch_name": "avifenesh-feat/handle_multipule_sessions",
  "base_commit": "8231e6e53d6d5fa6bd0d42e14c6a058c85fd6221",
  "diff_source": "commit_range",
  "created_at": "2026-01-24T17:47:50.894983Z",
  "updated_at": "2026-01-24T17:47:50.894983Z",
  "files": {
    ".gitignore": {
      "path": ".gitignore",
      "reviewed": false,
      "status": "modified",
      "file_comments": [],
      "line_comments": {
        "5": [
          {
            "id": "4cf86433-77d1-49d6-af1b-ff78dcc7c91c",
            "content": "test",
            "comment_type": "note",
            "created_at": "2026-01-24T17:47:53.286118Z",
            "line_context": null,
            "side": "new",
            "line_range": null
          }
        ]
      }
    },
    "src/app.rs": {
      "path": "src/app.rs",
      "reviewed": false,
      "status": "modified",
      "file_comments": [],
      "line_comments": {}
    },
    "src/output/markdown.rs": {
      "path": "src/output/markdown.rs",
      "reviewed": false,
      "status": "modified",
      "file_comments": [],
      "line_comments": {}
    },
    "src/ui/status_bar.rs": {
      "path": "src/ui/status_bar.rs",
      "reviewed": false,
      "status": "modified",
      "file_comments": [],
      "line_comments": {}
    },
    "src/input/keybindings.rs": {
      "path": "src/input/keybindings.rs",
      "reviewed": false,
      "status": "modified",
      "file_comments": [],
      "line_comments": {}
    }
  },
  "session_notes": null
}%

I can spend some time debugging this if it works for you to see why it isn't for me.

@avifenesh
Copy link
Copy Markdown
Contributor Author

avifenesh commented Jan 24, 2026

@avifenesh I tested this locally and it doesn't seem to work for me, were you able to get it to work? I created a review on a few local commits, wrote it (confirmed I have the file on disk, see below), but when I load it up with the same commit range the comments don't show:

{
  "id": "0f56d862-140f-4e43-9368-af7052f6937b",
  "version": "1.1",
  "repo_path": "/Users/agavra/dev/tuicr/",
  "branch_name": "avifenesh-feat/handle_multipule_sessions",
  "base_commit": "8231e6e53d6d5fa6bd0d42e14c6a058c85fd6221",
  "diff_source": "commit_range",
  "created_at": "2026-01-24T17:47:50.894983Z",
  "updated_at": "2026-01-24T17:47:50.894983Z",
  "files": {
    ".gitignore": {
      "path": ".gitignore",
      "reviewed": false,
      "status": "modified",
      "file_comments": [],
      "line_comments": {
        "5": [
          {
            "id": "4cf86433-77d1-49d6-af1b-ff78dcc7c91c",
            "content": "test",
            "comment_type": "note",
            "created_at": "2026-01-24T17:47:53.286118Z",
            "line_context": null,
            "side": "new",
            "line_range": null
          }
        ]
      }
    },
    "src/app.rs": {
      "path": "src/app.rs",
      "reviewed": false,
      "status": "modified",
      "file_comments": [],
      "line_comments": {}
    },
    "src/output/markdown.rs": {
      "path": "src/output/markdown.rs",
      "reviewed": false,
      "status": "modified",
      "file_comments": [],
      "line_comments": {}
    },
    "src/ui/status_bar.rs": {
      "path": "src/ui/status_bar.rs",
      "reviewed": false,
      "status": "modified",
      "file_comments": [],
      "line_comments": {}
    },
    "src/input/keybindings.rs": {
      "path": "src/input/keybindings.rs",
      "reviewed": false,
      "status": "modified",
      "file_comments": [],
      "line_comments": {}
    }
  },
  "session_notes": null
}%

I can spend some time debugging this if it works for you to see why it isn't for me.

@agavra
So two issues found, 1. I didn't add commit range base sessions. 2. Parser gets a break on - or . in the naming of the object it's generating the session signature from. Fixed. Added tests to cover it and cover edges.

…izations

- Add branch and diff_source tracking to sessions
- Generate unique filenames with repo fingerprint to prevent collisions
- Implement context-aware session loading
- Add session cache for instant repeated loads
- Add filename-based pre-filtering to reduce JSON parsing
- Support TUICR_REVIEWS_DIR environment variable
- Non-destructive session updates when branches move forward
- Legacy session migration support
Fix Windows input handling:
- Filter KeyEventKind::Press to prevent processing both press and release events
- Resolves up/down jumping 2 lines per keypress
- Resolves space toggle requiring multiple presses

Add manual commit selection mode:
- Press 'm' in normal mode to enter commit selector (shows last 20 commits)
- Press 'Esc' in commit select mode to return to working tree review
- Update status bar hints to show mode switching keys
- Add 'Review Modes' section to help popup
Changes based on review comments from PR agavra#66:

1. **Remove session caching** - Simplified storage.rs by removing
   the session cache. 1ms load time is sufficient.

2. **Add automatic session cleanup** - Sessions older than 7 days
   are now automatically deleted during file iteration to prevent
   disk space accumulation.

3. **Remove manual commit selection mode** - Removed the 'm'
   keybinding and related handlers for manually entering commit
   selection mode. This will be addressed in a separate PR
   considering issue agavra#48. Automatic commit selection when no
   working tree changes exist is preserved.

4. **Remove TUICR_REVIEWS_DIR override** - Removed the environment
   variable override feature. Test infrastructure still uses it
   for isolation.

5. **Revert help text updates** - Removed the "Review Modes"
   section from help popup that documented the manual commit
   selection feature.

6. **Revert commit select mode navigation** - Changed Esc behavior
   in commit select mode back to Quit (original behavior).
Tests were setting TUICR_REVIEWS_DIR but get_reviews_dir() wasn't
checking it, causing tests to write to the real user data directory.

This fix adds a cfg(test) check to honor the environment variable
during test runs, ensuring test isolation and preventing pollution
of user data.

Also removed unused SystemTime import from test module.
Store commit ranges and harden session filename parsing so saved reviews load correctly.
Update markdown tests and tighten filename parsing to satisfy clippy.
@avifenesh avifenesh force-pushed the feat/handle_multipule_sessions branch from c240b14 to af18e97 Compare January 24, 2026 20:23
Copy link
Copy Markdown
Owner

@agavra agavra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 thanks @avifenesh this is a huge improvement to tuicr! LGTM

@agavra agavra merged commit 7714398 into agavra:main Jan 25, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

handle multiple sessions / multiple repositories

2 participants