Skip to content

fix: sync shell history with standard history files#9855

Open
mitre88 wants to merge 1 commit intowarpdotdev:masterfrom
mitre88:fix/3422-sync-shell-history
Open

fix: sync shell history with standard history files#9855
mitre88 wants to merge 1 commit intowarpdotdev:masterfrom
mitre88:fix/3422-sync-shell-history

Conversation

@mitre88
Copy link
Copy Markdown

@mitre88 mitre88 commented May 1, 2026

Implements bidirectional sync between Warp command history and standard shell history files. Fixes issue #3422.

This change implements bidirectional sync between Warp's command history
and standard shell history files (~/.bash_history, ~/.zsh_history, etc.).

Changes:
- Add read_shell_history() function to read from standard shell history files
- Add write_command_to_shell_history() function to append commands to shell history
- Add ensure_shell_history_synced() to merge shell history on session init
- Add automatic write of executed commands to shell history

This fixes issue warpdotdev#3422 where history from other terminals/sessions was not
synced to Warp's history and vice versa.

Key features:
- Reads shell history files on startup and merges unique commands
- Writes executed commands to shell history for cross-terminal sharing
- Deduplicates against existing Warp history
- Uses proper error handling (ShellHistorySyncError) instead of bare except
- Uses context managers for file operations
@cla-bot
Copy link
Copy Markdown

cla-bot Bot commented May 1, 2026

Thank you for your pull request and welcome to our community. We could not parse the GitHub identity of the following contributors: Dr. Alex Mitre.
This is most likely caused by a git client misconfiguration; please make sure to:

  1. check if your git client is configured with an email to sign commits git config --list | grep email
  2. If not, set it up using git config --global user.email email@example.com
  3. Make sure that the git commit email is configured in your GitHub account settings, see https://github.com/settings/emails

@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 1, 2026

@mitre88

I'm starting a first review of this pull request.

You can view the conversation on Warp.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

@github-actions github-actions Bot added the external-contributor Indicates that a PR has been opened by someone outside the Warp team. label May 1, 2026
Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

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

Overview

This PR adds shell-history file import/export helpers and hooks command execution to append commands to standard shell history files.

Concerns

  • Shell-history import is not wired into any call path in the diff, so the claimed shell-to-Warp sync does not run.
  • Import parsing reads raw lines instead of the existing per-shell history parsers, which corrupts zsh, fish, and bash timestamped history.
  • Fish export writes plain text lines that fish will not treat as history entries.

Security

  • Command export writes every session's commands to the host user's local history file based only on shell type, which can leak remote, container, WSL, or other non-host session commands into local history.

Verdict

Found: 0 critical, 4 important, 0 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

std::sync::Mutex::new(HashSet::new());
}

pub fn ensure_shell_history_synced(session_id: SessionId, shell_type: ShellType, ctx: &mut AppContext) {
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.

⚠️ [IMPORTANT] ensure_shell_history_synced is never called in this PR, so shell-history → Warp sync never runs; invoke it during session initialization before claiming bidirectional sync.

let reader = BufReader::new(file);
let mut seen: HashSet<String> = HashSet::new();

for line in reader.lines() {
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.

⚠️ [IMPORTANT] This reads raw history lines instead of using ShellType::parse_history, so zsh extended-history, fish YAML, and bash timestamp lines are imported as bogus commands; read the file bytes and parse with the existing per-shell parser before filtering.

ShellType::Zsh => {
format!(": {}:0;{}\n", chrono::Utc::now().timestamp(), command)
}
ShellType::Bash | ShellType::Fish | ShellType::PowerShell => {
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.

⚠️ [IMPORTANT] Fish history is not line-oriented command text; writing command\n makes entries invisible to fish. Emit fish's - cmd: ... format with the same escaping that parse_history expects.

let command = event.command.to_string();
ctx.background_executor()
.spawn(async move {
if let Err(e) = write_command_to_shell_history(shell_type, &command) {
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.

⚠️ [IMPORTANT] [SECURITY] This writes every session's command into the local user's shell history based only on shell type; remote, WSL, and container commands can be copied into host history and expose sensitive remote commands. Gate this to local/native sessions or resolve the history file in the session environment.

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

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

Overview

This PR adds shell-history file import/export helpers and hooks command execution to append commands to standard shell history files.

Concerns

  • Shell-history import is not wired into any call path in the diff, so the claimed shell-to-Warp sync does not run.
  • Import parsing reads raw lines instead of the existing per-shell history parsers, which corrupts zsh, fish, and bash timestamped history.
  • Fish export writes plain text lines that fish will not treat as history entries.

Security

  • Command export writes every session's commands to the host user's local history file based only on shell type, which can leak remote, container, WSL, or other non-host session commands into local history.

Verdict

Found: 0 critical, 4 important, 0 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

std::sync::Mutex::new(HashSet::new());
}

pub fn ensure_shell_history_synced(session_id: SessionId, shell_type: ShellType, ctx: &mut AppContext) {
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.

⚠️ [IMPORTANT] ensure_shell_history_synced is never called in this PR, so shell-history → Warp sync never runs; invoke it during session initialization before claiming bidirectional sync.

let reader = BufReader::new(file);
let mut seen: HashSet<String> = HashSet::new();

for line in reader.lines() {
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.

⚠️ [IMPORTANT] This reads raw history lines instead of using ShellType::parse_history, so zsh extended-history, fish YAML, and bash timestamp lines are imported as bogus commands; read the file bytes and parse with the existing per-shell parser before filtering.

ShellType::Zsh => {
format!(": {}:0;{}\n", chrono::Utc::now().timestamp(), command)
}
ShellType::Bash | ShellType::Fish | ShellType::PowerShell => {
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.

⚠️ [IMPORTANT] Fish history is not line-oriented command text; writing command\n makes entries invisible to fish. Emit fish's - cmd: ... format with the same escaping that parse_history expects.

let command = event.command.to_string();
ctx.background_executor()
.spawn(async move {
if let Err(e) = write_command_to_shell_history(shell_type, &command) {
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.

⚠️ [IMPORTANT] [SECURITY] This writes every session's command into the local user's shell history based only on shell type; remote, WSL, and container commands can be copied into host history and expose sensitive remote commands. Gate this to local/native sessions or resolve the history file in the session environment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external-contributor Indicates that a PR has been opened by someone outside the Warp team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant