You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Shell history was lost when more than one shell process used the same config directory, for example two terminals, or a -c script while an interactive shell or MCP server is running. Each process loaded cmd_history once at startup. SaveHistory then rewrote the whole file from that process's in-memory list (FileMode.Create), guarded only by an in-process lock. A save from one process therefore discarded every entry another process had saved since the first one started.
A related issue: --clear-history deleted the file but left the already-loaded entries in memory, so the next save wrote the old history back.
Changes
Each interpreter tracks the newest 60 pending entries recorded since its last successful save.
Saves and clears coordinate through a separate cmd_history.lock file (FileShare.None, short bounded retry). Saving reads the current entries, applies pending entries with the existing remove-and-append de-duplication, keeps the newest MAXHISTORYITEMS, and writes the complete encoded result to a private temporary file. The temporary file is flushed before atomically replacing cmd_history.
The in-memory history of each process stays per-process; only persistence merges.
--clear-history atomically replaces the history file under the same lock and clears in-memory and pending entries only after replacement succeeds. Failed clears report an error.
Owner-only permissions on Linux/macOS, encoded multi-line entries, and best-effort ordinary history saving are preserved. Failed writes leave the saved history intact.
README.md and docs/navigation.md describe concurrent merging and atomic history persistence.
Tests
SerializedExecutionTests cover synchronized independent processes, partial-write failures, shared-lock failures, bounded pending entries, and two interpreters on the same config directory: merging entries from both, de-duplication across processes, trimming to the newest entries, clear-history not resurrecting saved entries, and multi-line entries surviving a merge.
Merge pending per-process history entries with the on-disk file under an exclusive file lock so concurrent shell instances do not overwrite each other. Keep clear-history best-effort and add focused coverage for merge, de-duplication, trimming, clear, and multi-line entries.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This suppresses a failed clear after already clearing only the in-memory list, so Program.cs unconditionally prints “History deleted.” and exits successfully even when the persisted file remains (for example, on permission failure or lock timeout). Unlike ordinary history saving, --clear-history has no useful outcome if truncation fails; propagate/return the failure so the caller reports it instead of claiming success.
Reviewed and addressed the remaining history issues in 381001f, cbc415c, and af4ba85: startup now retries the exclusive history lock, and --clear-history reports persistence failures without clearing in-memory state prematurely. Focused tests and builds pass.
This helper now requires write access even when the constructor only needs to read history. A history file that remains readable but is temporarily unwritable (for example, an owner-read-only file or read-only config mount) previously loaded via File.ReadAllLines; now the open fails, the constructor swallows the exception, and the session starts with empty history. On Unix, save also cannot repair missing write bits because RestrictHistoryFileToOwner runs only after this read/write open succeeds. Please use a read-only, exclusive open for constructor loading and reserve the read/write OpenOrCreate path for save/clear, applying any existing-file mode repair before requesting write access.
Review found that startup opened history read/write, so a readable but non-writable history file could not be loaded. Startup now uses the exclusive lock in read-only mode, with Unix permission coverage. I also synchronized the process regression so both processes load before writes. Fixed in 2a9d454.
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
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.
Problem
Shell history was lost when more than one shell process used the same config directory, for example two terminals, or a
-cscript while an interactive shell or MCP server is running. Each process loadedcmd_historyonce at startup.SaveHistorythen rewrote the whole file from that process's in-memory list (FileMode.Create), guarded only by an in-process lock. A save from one process therefore discarded every entry another process had saved since the first one started.A related issue:
--clear-historydeleted the file but left the already-loaded entries in memory, so the next save wrote the old history back.Changes
cmd_history.lockfile (FileShare.None, short bounded retry). Saving reads the current entries, applies pending entries with the existing remove-and-append de-duplication, keeps the newestMAXHISTORYITEMS, and writes the complete encoded result to a private temporary file. The temporary file is flushed before atomically replacingcmd_history.--clear-historyatomically replaces the history file under the same lock and clears in-memory and pending entries only after replacement succeeds. Failed clears report an error.README.mdanddocs/navigation.mddescribe concurrent merging and atomic history persistence.Tests
SerializedExecutionTestscover synchronized independent processes, partial-write failures, shared-lock failures, bounded pending entries, and two interpreters on the same config directory: merging entries from both, de-duplication across processes, trimming to the newest entries, clear-history not resurrecting saved entries, and multi-line entries surviving a merge.