Skip to content

feat: implement interactive Rewind Viewer component - #15718

Merged
Adib234 merged 2 commits into
adibakm/rewind-confirmation-dialogfrom
adibakm/rewind-viewer
Jan 9, 2026
Merged

feat: implement interactive Rewind Viewer component#15718
Adib234 merged 2 commits into
adibakm/rewind-confirmation-dialogfrom
adibakm/rewind-viewer

Conversation

@Adib234

@Adib234 Adib234 commented Dec 30, 2025

Copy link
Copy Markdown
Contributor

Summary

This PR introduces the RewindViewer component, providing a dedicated, interactive interface for navigating conversation history and selecting rewind points. It features intelligent content filtering to keep the history clean and integrates with the RewindConfirmation flow to safely revert both chat history and code changes.

Details

Interactive History Browsing

  • Navigation: Leverages BaseSelectionList to allow users to scroll through past user prompts using arrow keys.
  • Selective Expansion: Messages are truncated by default to save screen space and automatically expand when selected, allowing for a dense but readable history view.
  • Dynamic Sizing: The viewer automatically adapts to terminal dimensions, calculating the optimal number of items to display based on available vertical space.

Intelligent Content Filtering

  • stripReferenceContent: A new utility that identifies and removes large blocks of "referenced file content" often injected into prompts. This ensures the viewer shows the user's actual intent rather than walls of technical context.
  • Inline Stats: For each entry in the history, the viewer displays a summary of the model's impact (files changed, lines added/removed) associated with that specific turn.

Integrated Rewind Flow

  • Confirmation Bridge: Upon selecting a message, the UI seamlessly transitions to the RewindConfirmation dialog (added in a previous PR).
  • Callback Orchestration: Provides the onRewind handler with the target messageId, the cleaned userText (for prompt re-execution), and the user's chosen RewindOutcome (Conversation, Code, or both).

Related Issues

After this PR gets merged here are the other PRs that will get merged in order
#15720

How to Validate

Pre-Merge Checklist

  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker

@Adib234 Adib234 self-assigned this Dec 30, 2025
@Adib234
Adib234 requested a review from a team as a code owner December 30, 2025 16:34
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @Adib234, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request delivers a new RewindViewer component, enhancing the user experience by providing an interactive way to review and potentially revert to previous states of a conversation. The viewer intelligently presents user prompts, filtering out internal system markers for clarity, and offers a confirmation step before executing a rewind operation, complete with relevant file modification details.

Highlights

  • New Rewind Viewer Component: Introduces RewindViewer.tsx to allow users to browse and select past conversation interactions within the CLI.
  • Interactive Conversation History: Enables navigation through user prompts using up/down keys, displaying truncated messages that expand upon selection for better readability.
  • Intelligent Content Filtering: Implements a stripReferenceContent utility to automatically remove internal markers and expanded file content from user prompts, ensuring a clean and focused display of the original input.
  • Rewind Confirmation Flow: Integrates a confirmation dialog for selected rewind actions, including displaying associated file change statistics (added/removed lines, file count) before proceeding.
  • Comprehensive Testing: Adds RewindViewer.test.tsx with extensive unit tests covering the component's rendering, navigation, selection, and content filtering logic to ensure robustness.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new "RewindViewer" component and its tests. A high-severity potential Command Injection vulnerability has been identified in "packages/cli/src/ui/components/RewindViewer.tsx". This is due to untrusted user input from conversation history being passed to an "onRewind" handler without proper sanitization, which could lead to arbitrary command execution if the handler re-runs the prompt. The "onRewind" handler must implement strict input validation and sanitization. Furthermore, the "RewindViewer" component has a critical bug in message selection due to reliance on non-unique message IDs, potentially causing incorrect rewinding. The tests also exhibit issues, such as using non-unique IDs that mask this bug and an incorrect mock for a core utility function.

Comment thread packages/cli/src/ui/components/RewindViewer.test.tsx Outdated
Comment on lines +120 to +135
onConfirm={(outcome) => {
if (outcome === RewindOutcome.Cancel) {
clearSelection();
} else {
const userPrompt = interactions.find(
(m) => m.id === selectedMessageId,
);
if (userPrompt) {
const originalUserText = userPrompt.content
? partToString(userPrompt.content)
: '';
const cleanedText = stripReferenceContent(originalUserText);
onRewind(selectedMessageId, cleanedText, outcome);
}
}
}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

security-high high

A high-severity Command Injection vulnerability exists in the "onConfirm" handler. User prompts from conversation history are processed, and "stripReferenceContent" is not a security sanitizer. This means malicious payloads (e.g., a shell command) in user prompts could pass through unmodified as "cleanedText" to the "onRewind" callback. If "onRewind" re-executes this prompt, it leads to arbitrary command execution. The "onRewind" handler must treat the "newText" parameter as untrusted user input and apply proper validation and sanitization before any sensitive operations.

Furthermore, the component's logic for handling message selection is flawed as it relies on "message.id", which is not guaranteed to be unique. If multiple messages share the same ID, "find()" will always pick the first message, potentially leading to rewinding to an incorrect point. Consider managing the selected message state locally within "RewindViewer" by storing the entire "MessageRecord" object upon selection to address 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.

I'm not sure why a shell command would appear in the rewind viewer because it doesn't get recorded in ChatRecordingService

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.

Also message selection is done in onSelect and it sets the selectedMessageId as userPrompt.id

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.

/gemini review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the clarification, Adib234. Let me elaborate on the points raised:

Command Injection Vulnerability

Your point about the ChatRecordingService not recording shell commands is well-taken. However, the security concern here operates on a principle of defense-in-depth. While the ChatRecordingService might currently filter out shell commands, this is not a guarantee against future vulnerabilities or unexpected scenarios:

  1. Future Changes: The ChatRecordingService's filtering logic could change, or a bug could allow malicious content to be recorded.
  2. Compromised Client: A compromised client could directly inject malicious content into the conversation history.
  3. stripReferenceContent's Purpose: The stripReferenceContent function is designed for UI display purposes (removing verbose reference content), not for security sanitization. It only removes specific markers and does not neutralize arbitrary malicious payloads (e.g., $(rm -rf /)).
  4. onRewind's Responsibility: The onRewind callback receives cleanedText. If this cleanedText is subsequently used in a context where it could be executed (e.g., passed to a shell, an eval function, or a tool that executes commands), it must be treated as untrusted user input and properly sanitized or validated at that point of use. Relying solely on upstream filtering is a single point of failure.

Therefore, to ensure robust security, the onRewind handler (or the function it calls with newText) should implement proper validation and sanitization of the newText parameter before any sensitive operations, regardless of how the input was initially recorded.

Flawed Message Selection

You are correct that onSelect sets selectedMessageId using userPrompt.id. However, the issue lies with the subsequent use of interactions.find((m) => m.id === selectedMessageId) within the onConfirm handler. As demonstrated in the RewindViewer.test.tsx file (e.g., lines 110-111, 154-157, 189-190, 227-228, 259-260), multiple MessageRecord objects can share the same id (e.g., both user and Gemini messages often have id: '1').

If interactions contains multiple messages with the same id, Array.prototype.find() will always return the first matching element. This means that if you select a message that happens to have the same id as an earlier message in the interactions array, the onConfirm handler might inadvertently retrieve the wrong message, leading to an incorrect rewind point.

To address this, I recommend using a truly unique identifier for selection. The items array already generates unique key values using both msg.id and idx (key: ${msg.id || 'msg'}-${idx}``). You could leverage this idx or store the entire `MessageRecord` object in the `selectedMessageId` state to ensure that the correct message is always retrieved.

For example, you could modify the onSelect and onConfirm logic to use the index from the items array:

// In useRewindLogic or similar state management
const [selectedIndex, setSelectedIndex] = useState<number | null>(null);

// ...

// In onSelect for BaseSelectionList
onSelect={(itemWrapper) => {
  selectMessageByIndex(itemWrapper.index);
}}

// In onConfirm handler
const userPrompt = interactions[selectedIndex];

This would guarantee that the exact message selected by the user is the one processed during confirmation.

Comment thread packages/cli/src/ui/components/RewindViewer.test.tsx
@Adib234
Adib234 force-pushed the adibakm/rewind-viewer branch from 2ddfa74 to 4c4cb62 Compare December 30, 2025 17:50
@gemini-cli gemini-cli Bot added status/need-issue Pull requests that need to have an associated issue. priority/p1 Important and should be addressed in the near term. and removed status/need-issue Pull requests that need to have an associated issue. labels Jan 7, 2026
@Adib234
Adib234 merged commit 861163b into adibakm/rewind-confirmation-dialog Jan 9, 2026
5 checks passed
@Adib234
Adib234 deleted the adibakm/rewind-viewer branch January 9, 2026 20:32
@sripasg sripasg added the size/l A large sized PR label Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority/p1 Important and should be addressed in the near term. size/l A large sized PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants