Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

fix(cli): escape @ symbols on paste to prevent unintended file expansion - #21239

#21239
Merged
scidomino merged 1 commit into
google-gemini:maingoogle-gemini/gemini-cli:mainfrom
krishdef7:fix/paste-at-escape-completekrishdef7/gemini-cli:fix/paste-at-escape-completeCopy head branch name to clipboard
Mar 12, 2026
Merged

fix(cli): escape @ symbols on paste to prevent unintended file expansion#21239
scidomino merged 1 commit into
google-gemini:maingoogle-gemini/gemini-cli:mainfrom
krishdef7:fix/paste-at-escape-completekrishdef7/gemini-cli:fix/paste-at-escape-completeCopy head branch name to clipboard

Conversation

@krishdef7

@krishdef7 krishdef7 commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds an opt-in setting ui.escapePastedAtSymbols (default: false) that escapes @ symbols in pasted text before they enter the input buffer, preventing emails and npm-style paths like @scope/pkg from triggering unintended @path expansion and ReadManyFiles flooding. Disabled by default to preserve existing behavior for users who intentionally paste @file references.

Details

When enabled, escaping is applied at both paste paths (Ctrl/Cmd+V and bracketed paste events). Escaped \@ is shown as-is in the input, and unescaped back to @ before the query is sent to the model. The unescapeLiteralAt() utility correctly handles sequences like \\@ without corrupting surrounding backslashes. Both escapeAtSymbols() and unescapeLiteralAt() live in atCommandProcessor.ts so they can be tested together.

Related Issues

Fixes #13487

How to Validate

  1. Set "ui": { "escapePastedAtSymbols": true } in ~/.gemini/settings.json
  2. Run node packages/cli/dist/index.js
  3. Paste test@domain.com @README.md, verify no file expansion, input shows test\@domain.com, model receives clean text
  4. With setting at default (false), verify pasted @README.md still expands normally

Pre-Merge Checklist

  • Added/updated tests (if needed)
  • Updated settings documentation (npm run docs:settings)
  • Noted breaking changes (none, disabled by default)

@krishdef7
krishdef7 requested a review from a team as a code owner March 5, 2026 09:16
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 significantly enhances the robustness of the CLI by improving how @ symbols are handled during input, particularly when pasting content. It prevents unintended @path command interpretations, ensures a clean user experience by displaying @ symbols correctly, and guarantees that the language model receives accurate, unescaped input. Additionally, it refines the transcript flushing mechanism to ensure that all model responses, including tool-only calls, are properly recorded, providing a more consistent and reliable interaction flow.

Highlights

  • Robust @ Symbol Handling: Implemented a mechanism to automatically escape @ symbols when content is pasted into the CLI, preventing them from being misinterpreted as @path commands. This applies to both clipboard and bracketed paste events.
  • Clean User Interface Display: Ensured that while @ symbols are internally escaped (e.g., to \@) for safe processing, they are displayed to the user in their original, unescaped form (@) to maintain readability and avoid confusing \@ sequences.
  • Accurate Model Input: Normalized escaped @ symbols back to their literal form before sending text to the language model, guaranteeing that the model receives the intended input without accidental @path interpretations or leaked backslashes.
  • Consistent Transcript Flushing: Updated the chat logic to ensure that the transcript is flushed even when a model response consists solely of tool invocations or thoughts, without any accompanying text. This guarantees downstream hooks always observe the latest state.
Changelog
  • packages/cli/src/ui/components/InputPrompt.tsx
    • Escaped @ symbols in text pasted from the clipboard to prevent misinterpretation.
    • Modified bracketed paste handling to escape @ symbols in the input sequence.
    • Updated display logic to unescape \@ back to @ for user-facing text.
  • packages/cli/src/ui/hooks/atCommandProcessor.ts
    • Modified parseAllAtCommands to unescape \@ in text content before processing, ensuring clean input to the model.
    • Ensured remaining text segments also have \@ unescaped before being sent to the model.
  • packages/core/src/core/geminiChat.test.ts
    • Added a new test case to verify that the transcript flushes correctly for model responses containing only tool calls, without text or thoughts.
  • packages/core/src/core/geminiChat.ts
    • Introduced a hasThoughts flag to track if a model response includes thoughts.
    • Updated the logic to set hasThoughts to true when thoughts are recorded from model content.
    • Modified the condition for recording model responses to include cases where there are thoughts or tool calls, even if no explicit response text is present, ensuring timely transcript flushing.
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.

@krishdef7

Copy link
Copy Markdown
Contributor Author

Follow-up commits removed an earlier duplicate paste insert and accidental debug files.

Final implementation ensures:

  • pasted @ tokens are escaped internally
  • clean display in the TUI
  • clean text sent to the model
  • correct handling of real @path commands

Manual validation performed with:
node packages/cli/dist/index.js
pasting: test@domain.com @README.md

@krishdef7

Copy link
Copy Markdown
Contributor Author

Fixes #13487

This change prevents pasted @ tokens from being interpreted as @path commands, which was triggering ReadManyFiles when pasting content like emails or npm package names.

@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 robust mechanism for handling @ symbols in pasted text to prevent them from being misinterpreted as @path commands. It correctly escapes them on input and un-escapes them for display and for the model. Additionally, it fixes an issue where transcripts were not flushed for tool-only responses, ensuring better state consistency for downstream hooks. The changes are logical and well-tested. However, I've identified a high-severity bug in the new un-escaping logic that can cause data corruption when escaped backslashes are involved. Please see the detailed comments for a fix.

Comment thread packages/cli/src/ui/components/InputPrompt.tsx Outdated
Comment thread packages/cli/src/ui/hooks/atCommandProcessor.ts Outdated
Comment thread packages/cli/src/ui/hooks/atCommandProcessor.ts Outdated
@gemini-cli gemini-cli Bot added the status/need-issue Pull requests that need to have an associated issue. label Mar 5, 2026
@krishdef7

Copy link
Copy Markdown
Contributor Author

Addressed earlier review feedback regarding escaped backslashes.
Latest commit uses unescapeLiteralAt() to correctly preserve sequences like:

test\@foo → test@foo

@gemini-cli gemini-cli Bot added priority/p2 Important but can be addressed in a future release. area/core Issues related to User Interface, OS Support, Core Functionality help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! and removed status/need-issue Pull requests that need to have an associated issue. labels Mar 5, 2026
@krishdef7
krishdef7 force-pushed the fix/paste-at-escape-complete branch 2 times, most recently from 39d6838 to 7e57513 Compare March 11, 2026 03:51
@krishdef7

krishdef7 commented Mar 11, 2026

Copy link
Copy Markdown
Contributor Author

All review feedback has been addressed. The high-severity backslash bug flagged by the bot is fixed via unescapeLiteralAt() in the new utils/unescapeLiteralAt.ts. The outdated inline comments refer to earlier versions of the code that no longer exist in the diff, conflicts have also been resolved

@scidomino

Copy link
Copy Markdown
Collaborator

This was already fixed last month in #18965

@scidomino scidomino closed this Mar 11, 2026
@scidomino

Copy link
Copy Markdown
Collaborator

Actually, I realize this is slightly different. Reopening

@scidomino scidomino reopened this Mar 11, 2026
@scidomino

Copy link
Copy Markdown
Collaborator

My policy is to not review PRs just because someone tagged me (since that's obviously not scalable if everyone does it). But I will make an exception in this case since I accidentally closed it.

I don't think we want to enable this by default. There are many users who depend on this feature (I have many times in the past). Add a setting to control this that is disabled by default.

@scidomino
scidomino self-requested a review March 11, 2026 04:48
@scidomino

Copy link
Copy Markdown
Collaborator

Also, please clean up and shorten the description to a length that a human can actually read it. Follow the PR format in pull_request_template.md.

@krishdef7 krishdef7 closed this Mar 11, 2026
@krishdef7
krishdef7 force-pushed the fix/paste-at-escape-complete branch from e2771a4 to 88638c1 Compare March 11, 2026 10:31
@krishdef7

krishdef7 commented Mar 11, 2026

Copy link
Copy Markdown
Contributor Author

Addressed reviewer feedback:

  • Added ui.escapePastedAtSymbols setting (default: false) so existing behavior is unchanged for users who paste @file references intentionally
  • Escaping is only applied when the setting is enabled
  • Shortened PR description per template

@krishdef7 krishdef7 reopened this Mar 11, 2026
@krishdef7
krishdef7 requested a review from a team as a code owner March 11, 2026 10:44
@krishdef7 krishdef7 changed the title fix(cli): robust @ paste escaping and model handling fix(cli): escape @ symbols on paste to prevent unintended file expansion Mar 11, 2026

@scidomino scidomino left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Even when it's escaped, we still highlight it as if it were a link. There might not be an elegant way to fix that.

Comment thread docs/cli/settings.md Outdated
| Show Home Directory Warning | `ui.showHomeDirectoryWarning` | Show a warning when running Gemini CLI in the home directory. | `true` |
| Show Compatibility Warnings | `ui.showCompatibilityWarnings` | Show warnings about terminal or OS compatibility issues. | `true` |
| Hide Tips | `ui.hideTips` | Hide helpful tips in the UI | `false` |
| Escape Pasted @ Symbols | `ui.escapePastedAtSymbols` | When enabled, @ symbols in pasted text are escaped to prevent unintended @path expansion. Disable if you intentionally paste @file references. | `false` |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

"Disable if you intentionally paste @file references."

if you intentionally paste @file references, you don't need to do anything at all since this is the default. I'd leave this sentence out.

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.

Removed.

Comment thread docs/reference/configuration.md Outdated

- **`ui.escapePastedAtSymbols`** (boolean):
- **Description:** When enabled, @ symbols in pasted text are escaped to
prevent unintended @path expansion. Disable if you intentionally paste @file

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

ditto

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.

Removed.

requiresRestart: false,
default: false,
description:
'When enabled, @ symbols in pasted text are escaped to prevent unintended @path expansion. Disable if you intentionally paste @file references.',

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

ditto

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.

Removed.

}
// Ensure we never accidentally interpret paste as regular input.
buffer.handleInput(key);
let sequenceToProcess = key.sequence || '';

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This can be simplified a lot:

if (settings.ui?.escapePastedAtSymbols) {
const escapedSequence = (key.sequence || '').replace(/(?<!\)@/g, '\@');
buffer.handleInput({ ...key, sequence: escapedSequence });
} else {
buffer.handleInput(key);
}

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, matches your suggested pattern.

@@ -0,0 +1,15 @@
/**

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Do not create a new file for a single method. There are many files this could reasonably be added to. Too many, in fact. Review the options and pick one of them.

Also, add some tests 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.

Moved to atCommandProcessor.ts, tests added.

* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It would make sense for the escaping logic to live next to this method so we can test them together.

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, both live in atCommandProcessor.ts.

segments.forEach((seg, segIdx) => {
const segLen = cpLen(seg.text);
let display = seg.text;
let display = unescapeLiteralAt(seg.text);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm worried this will lead to display bugs since the cursor position is calculated using this in cursorVisualColAbsolute()

Honestly, I think we should just show the slash in the input so users aren't confused.

@krishdef7 krishdef7 Mar 11, 2026

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.

Kept \@ visible in input as suggested.

parts.push({
type: 'text',
content: query.substring(lastIndex, matchIndex),
content: unescapeLiteralAt(query.substring(lastIndex, matchIndex)),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Here and elsewhere in this class, we should only unescape if the setting is enabled. Otherwise, we will be taking out only slashes we ourselves did not put in.

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.

Gated behind escapePastedAtSymbols check.

@krishdef7
krishdef7 force-pushed the fix/paste-at-escape-complete branch from 160fe07 to b010834 Compare March 11, 2026 19:49
@krishdef7
krishdef7 force-pushed the fix/paste-at-escape-complete branch from b010834 to 2007ae5 Compare March 11, 2026 20:06

@scidomino scidomino left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please look into fixing the highlighting problem in parseInputForHighlighting(). It might be hard. It might be easy. Either way I need to hear from you that you looked into it.

}
// Ensure we never accidentally interpret paste as regular input.
buffer.handleInput(key);
if (settings.ui?.escapePastedAtSymbols) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Restrict this to paste keys only:

if(key.paste && settings.ui?.escapePastedAtSymbols)

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, guarded with key.paste &&.

// Ensure we never accidentally interpret paste as regular input.
buffer.handleInput(key);
if (settings.ui?.escapePastedAtSymbols) {
const escapedSequence = (key.sequence || '').replace(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

use the escape function you wrote instead of reimplementing 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.

Done, using escapeAtSymbols().

@krishdef7
krishdef7 force-pushed the fix/paste-at-escape-complete branch 2 times, most recently from 2f50eff to 51176a3 Compare March 11, 2026 22:03
@krishdef7

krishdef7 commented Mar 11, 2026

Copy link
Copy Markdown
Contributor Author

Addressed both points. Also looked into parseInputForHighlighting() in highlight.ts, the @ pattern there had no lookbehind, so \@ was still being highlighted as a link. Fixed it by adding (?<!\\)@ to the regex, so escaped \@ tokens are no longer treated as file references. The fix is in the same commit.

@scidomino
scidomino enabled auto-merge March 12, 2026 15:55

@scidomino scidomino left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I misremembered. it's actual key.name == 'paste' or something like that. You would have noticed that had you tested your code after making the change, or even tried to build it. As it is, your PR doesn't build. Please make the change, and test it manually. Let me know when you are ready for review.

Adds an opt-in setting \ui.escapePastedAtSymbols\ (default: false) that
escapes @ symbols in pasted text before they enter the input buffer,
preventing emails and npm-style paths like @scope/pkg from triggering
unintended @path expansion and ReadManyFiles flooding.

When enabled, escaping is applied at both paste paths (Ctrl/Cmd+V and
bracketed paste events). Escaped tokens are unescaped at the display
layer so users see clean @ in the UI, and again before text is sent to
the model via unescapeLiteralAt(). The setting is disabled by default
to preserve existing behavior for users who intentionally paste @file
references.

Fixes google-gemini#13487
auto-merge was automatically disabled March 12, 2026 19:43

Head branch was pushed to by a user without write access

@krishdef7
krishdef7 force-pushed the fix/paste-at-escape-complete branch from 51176a3 to 008eb83 Compare March 12, 2026 19:43
@krishdef7

Copy link
Copy Markdown
Contributor Author

Build is fixed, removed key.paste && since we're already inside if (key.name === 'paste') and key.paste doesn't exist on the Key type. Build passes clean.
Sorry for pushing without verifying the build first, still getting used to open source contribution workflow. Won't happen again.

@scidomino
scidomino added this pull request to the merge queue Mar 12, 2026
@scidomino

Copy link
Copy Markdown
Collaborator

Awesome! Thanks for the contribution!

Merged via the queue into google-gemini:main with commit 19e0b1f Mar 12, 2026
26 of 27 checks passed
SUNDRAM07 pushed a commit to SUNDRAM07/gemini-cli that referenced this pull request Mar 30, 2026
warrenzhu25 pushed a commit to warrenzhu25/gemini-cli that referenced this pull request Apr 9, 2026
@sripasg sripasg added the size/m A medium sized PR label Jun 2, 2026
software-0ficial pushed a commit to software-0ficial/gemini-cli that referenced this pull request Jul 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core Issues related to User Interface, OS Support, Core Functionality help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! priority/p2 Important but can be addressed in a future release. size/m A medium sized PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ReadManyFiles triggered erroneously on pasted input, flooding context window

3 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.