feat: complete Command Timeline Phase 3 checkpoint - #29
Merged
Conversation
Adds load, copy, and jump actions to the pane-owned Command Timeline overlay introduced in Phase 2, without adding persistence, an output cache, or any path that can execute a command. - Add a pure C++ CommandTimelineActionModel that decides load, copy, and jump eligibility from the stable selected CommandId, tracks the loaded command, and advances an execution generation so a completion from a retired command is detectable and discarded. - Load the selected command onto the focused pane input with Enter or a single click. The payload is filtered for control codes only, CarriageReturnNewline is deliberately not applied, no carriage return is appended, and SendInput targets this pane connection, so the load never executes, never reads the Windows clipboard, and is never forwarded by input broadcast. - Refuse a multi-line load when the shell has not enabled bracketed paste, and require a confirming Enter above 1024 characters. Escape cancels a pending confirmation before it closes the overlay. - Add Space to jump the viewport to the selected command native mark and a per-entry context menu with copy command, copy output, and jump to output. Ctrl+C copies the selected command while the Timeline owns the keyboard. - Resolve output on demand through Terminal::ResolveCommandTimelineOutput for an explicit copy action only. Output is never cached, indexed, or retained. - Release loaded-input state when the loaded command is evicted, and keep every action bound to the stable CommandId rather than the XAML row. - Advance engineering version surfaces to 1.2.3/1.2.3.0 for checkpoint tag v1.2.3, and extend test-command-timeline.ps1 with guards that fail if the load path gains a submission character or a clipboard read. Public Latest remains v1.2.0. Search, filtering, and public commandTimeline settings remain Phase 4 scope.
HelloThisWorld
marked this pull request as ready for review
August 3, 2026 15:56
12 tasks
HelloThisWorld
added a commit
that referenced
this pull request
Aug 3, 2026
* Complete Command Timeline Phase 3 entry actions Adds load, copy, and jump actions to the pane-owned Command Timeline overlay introduced in Phase 2, without adding persistence, an output cache, or any path that can execute a command. - Add a pure C++ CommandTimelineActionModel that decides load, copy, and jump eligibility from the stable selected CommandId, tracks the loaded command, and advances an execution generation so a completion from a retired command is detectable and discarded. - Load the selected command onto the focused pane input with Enter or a single click. The payload is filtered for control codes only, CarriageReturnNewline is deliberately not applied, no carriage return is appended, and SendInput targets this pane connection, so the load never executes, never reads the Windows clipboard, and is never forwarded by input broadcast. - Refuse a multi-line load when the shell has not enabled bracketed paste, and require a confirming Enter above 1024 characters. Escape cancels a pending confirmation before it closes the overlay. - Add Space to jump the viewport to the selected command native mark and a per-entry context menu with copy command, copy output, and jump to output. Ctrl+C copies the selected command while the Timeline owns the keyboard. - Resolve output on demand through Terminal::ResolveCommandTimelineOutput for an explicit copy action only. Output is never cached, indexed, or retained. - Release loaded-input state when the loaded command is evicted, and keep every action bound to the stable CommandId rather than the XAML row. - Advance engineering version surfaces to 1.2.3/1.2.3.0 for checkpoint tag v1.2.3, and extend test-command-timeline.ps1 with guards that fail if the load path gains a submission character or a clipboard read. Public Latest remains v1.2.0. Search, filtering, and public commandTimeline settings remain Phase 4 scope. * Complete Command Timeline Phase 4 stabilization Completes the in-memory Command Timeline feature surface: pane-local search, the two public settings, trustworthy shell degradation, and bounded history. No persistence, no output cache, and no telemetry are introduced. - Add pane-local search over each pane's bounded in-memory command text. The match is a literal case-insensitive substring search built on std::search and towlower; there is no regex, no fuzzy matching, no output search, and no terminal-buffer rescan. - Cap queries at 256 UTF-16 code units and truncate without leaving a lone surrogate, enforced in NormalizeCommandTimelineQuery and mirrored by MaxLength on the filter box. A query is never persisted. - Rework the navigation model to walk a filtered projection of indices while keeping stable CommandId identity. A still-matching command stays selected, a command that stops matching hands selection to the nearest surviving match, and a new command only takes the selection when it matches and the view was already following the latest command. - Route slash and Tab to the filter box and consume them before the PTY. Filter text never reaches the shell, Left/Right keep normal caret editing, and IME/TSF composition is left to the text box. Escape now clears a non-empty query before it closes the overlay. - Add the commandTimeline.enabled and commandTimeline.historyLimit global settings with defaults true and 500, a clamped 50-5000 range, JSON schema entries, and a Settings UI section under Appearance. An absent setting is not serialized back, so existing settings files need no migration. - Add bounded per-pane history with oldest-first eviction that applies to panes that already exist and to new panes. Raising the limit never resurrects an evicted command and sequence IDs are never reused. - Add four distinct empty states so an unsupported shell is never reported as simply having run no commands. - Report list item position and set size against the filtered result count, and keep localized accessible names, non-color status, High Contrast theme resources, and the Reduced Motion-safe no-animation path. - Advance engineering version surfaces to 1.2.4/1.2.4.0 for checkpoint tag v1.2.4, and extend test-command-timeline.ps1 with guards for search literalness, query bounds, settings defaults/range/schema, and the filter reading only cached command text. Public Latest remains v1.2.0. This builds on the Phase 3 branch and does not begin v1.3.0-alpha. * docs: record Phase 3 merge to main in Phase 4 checkpoint notes Phase 3 was squash-merged to main as 5fd2172 through pull request #29 while Phase 4 was in progress, so the Phase 4 base branch is main rather than the Phase 3 feature branch.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Command Timeline Phase 3 — entry actions. The Phase 2 overlay was read-only;
this makes it actionable. You can load an earlier command back onto the input
line, copy a command or its output, and jump to a command's output.
Engineering checkpoint
1.2.3/1.2.3.0, intended tagv1.2.3. Not a publicrelease — GitHub Latest and README downloads stay on v1.2.0.
Related issues
No tracking issue.
Detailed changes
Load semantics — a load can never execute
ControlCore::LoadCommandTimelineCommandis the only load path:FilterStringForPaste(text, ControlCodes).CarriageReturnNewlineis deliberately not applied — converting a newlineto a carriage return would submit the command instead of loading it.
SendInputtargets this pane's connection only, so the Windows clipboardis never read and input broadcast cannot forward the load to another pane.
test-command-timeline.ps1now fails the build if that function ever gainsCarriageReturnNewline, a carriage-return append, or a clipboard read.Multi-line and large loads
CommandTextUnavailableMultilineUnsafe— refusedConfirmationRequired— Enter again to confirmRefusing multi-line without bracketed paste is stricter than clipboard paste,
which only warns. Same reasoning as the upstream GH#13014 note: unbracketed line
breaks are indistinguishable from the user pressing Enter.
Stable identity
Every action resolves through
viewState.selectedCommandId— a stablepane-scoped
CommandId— never a XAML row index.ActionCopyResolvesStableCommandIdNotRowIndexcovers an eviction shifting every row index by one between two preparations.
Execution generation / late-completion race
CommandTimelineViewStategainsloadedCommandIdalongside the existingloadedIntoInputandexecutionGeneration.NotifyLoadedrecords and bumps;NotifyExecutionStartedfires on OSC 133CommandStart, clears loaded state andbumps again;
IsCurrentGenerationthen reports a retired generation as stale.ResolveCommandTimelineOutputchecks the generation before reading the buffer.Output stays uncached
Output is read from the buffer only for an explicit copy-output action, via
Terminal::ResolveCommandTimelineOutput. Nothing is stored — there is still nooutput field anywhere in the model, and the script guard enforces that.
Keys
Hover still only moves the selection.
Ctrl+Tabtoggle and user-defined keybindings keep precedence (
_TryHandleKeyBindingruns first).Validation performed
Environment: Windows 11 Pro 26100, MSVC 14.44.35207, Windows SDK 10.0.26100.0.
Native build — ran, passed
0 Error(s), 7 warnings (all pre-existingPRI263resource warnings unrelatedto this change). Elapsed 9m04s. Built
TerminalCore,TerminalControlLib, andUnitTests_Control.Unit tests — ran, passed
Total=31, Passed=31, Failed=0— including the 10 newAction*tests:load preparation, missing command text, multi-line refusal, large-load
confirmation, generation tracking, late-completion detection, eviction release,
stable-identity resolution, and output availability.
Repository scripts — ran, passed
test-command-timeline.ps1verify-version.ps1verify-branding.ps1 -ExpectedPublisher 'CN=helloThisWorld'test-release-workflow.ps1test-ci-classification.ps1test-visual-progress.ps1Total=52, Passed=52, Failed=0test-privacy.ps1test.ps1 -Suite Smoke -Configuration Release -Platform x64Static gates — ran, passed
clang-formatover only the changed line ranges (repo.clang-format):identical modulo line endings for every touched C++ file.
git diff --check: clean.TermControl.xaml,Resources.resw,Package-winTerm.appxmanifest: clean.version.json(both): clean.Not run, with reason
test-shell-integration.ps1 -Shell All— blocked by local antivirus/AMSI,not by this change. It fails parsing
shell/powershell/winTerm.Shell/Public/Compatibility.ps1with "This script contains malicious content and has been blocked by your
antivirus software." That file is byte-identical to
mainand is untouchedhere;
git diff main --quieton it reports no change. Needs to run in CI or ona host without the AMSI block.
full upstream test suite — deliberately out of scope for a checkpoint.
No screenshot was needed or created.
Checklist
CHANGELOG.md.Development-Changes.mdledger has been pushed with the final source SHA, link, summary, and checkpoint/release.winterm-siteasset, or no screenshot was added.winterm.exe, and Microsoft Terminal coexistence remain isolated.Source ↔ Wiki mapping
08afcea323473dBoundary
No persistence, no output cache, no search or filtering, no telemetry, no
automatic execution, no ConPTY/VT/TextBuffer/renderer changes, no workspace or
shell protocol schema change, no installer, no Portable packaging, no GitHub
Release, no Latest update, no
winterm-sitechange, no screenshot.Phase 4 (search, filtering,
commandTimeline.enabled/commandTimeline.historyLimit,Settings UI) builds on this and is not included here.