Skip to content

feat(tui): add Alt+S input stash/recall hotkey (#1438)#1572

Merged
esengine merged 1 commit into
esengine:mainfrom
dacec354:stash-input
May 23, 2026
Merged

feat(tui): add Alt+S input stash/recall hotkey (#1438)#1572
esengine merged 1 commit into
esengine:mainfrom
dacec354:stash-input

Conversation

@dacec354

Copy link
Copy Markdown

What

Adds Alt+S hotkey to stash and recall the composer input buffer. Press once to save the current
input, press again on an empty line to recall it. If there's already stashed text, the current input
is replaced by the stash.

Why

Quick temp register — save a half-written message or thought for later without losing it. Closes
#1438.

How to verify

  1. npm run dev (or npm run build && node dist/cli/index.js)
  2. Type something → Alt+S → input clears, "Stashed" hint appears
  3. Alt+S again → input fills with the stashed text, "Recalled"
  4. Alt+S twice on empty input → "Nothing to stash"
  5. Type something, Alt+S to stash, type something else, Alt+S again → stash replaces current text
  6. Ctrl+P → shortcuts modal shows Alt+S under Input group

Checklist

  • npm run verify passes locally (lint + typecheck + tests — 3 pre-existing web-tools failures,
    same as main)
  • No Co-Authored-By: Claude trailer in commits
  • Comments follow CONTRIBUTING.md (no module-essay headers, no incident history)
  • No edits to CHANGELOG.md — release notes are maintainer-written at release time

@dacec354 dacec354 changed the title feat: Alt+S stash/recall input buffer (#1438) feat(tui): add Alt+S input stash/recall hotkey (#1438) May 22, 2026
@esengine

Copy link
Copy Markdown
Owner

Thanks for picking this up — the shape is right and the diff is small. Three things I'd want fixed before merging, plus a couple of small notes.

1. Doesn't match the issue spec — current input silently disappears (blocker)

#1438 says: "if message has been stashed, exchange stash and input". The PR doesn't exchange — when the input is non-empty and the stash already has content, the current input is dropped and replaced by the stash:

} else {  // input.length > 0
  if (stashRef.current) {
    setInput(stashRef.current);   // current input is lost
    stashRef.current = "";
    ...

This is the deviation noted in your PR description ("current input is replaced by the stash"). It means an accidental Alt+S in the middle of a half-typed message destroys the message without any recovery path. The point of a stash register is that one extra Alt+S brings it back. Please make it a true swap:

const recalled = stashRef.current;
stashRef.current = input;
setInput(recalled);

2. No gating — fires under modals and while busy

The handler is placed above if (busy) return; and above the whole !pendingShell && !pendingPath && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !walkthroughActive && !pendingChoice && !pendingReviseEditor && !pendingEditReview && !stagedInput && !pendingRevision guard set that every other composer-targeting shortcut in this file uses. Consequences:

  • Pressing Alt+S during a running turn mutates composer state the user can't see, and pushes a "Stashed" / "Recalled" row into the log out of nowhere.
  • Same thing under shell/path confirms, session picker, walkthrough, edit-review, etc.

Copy the same guard block that Ctrl+O and the Space-toggle-undo blocks above it use.

3. composer.hintStash is a dead i18n key

hintStash: "stash" / "暂存" is declared in EN, zh-CN, and types.ts, but never rendered anywhere — no composer hint bar references it. Either wire it into the bottom hint strip alongside hintClear / hintHistory / hintAbort, or drop the key. As-is it'll confuse the next person grepping for unused strings.

Smaller notes

Leaving this open — push a fixup and I'll take another look.

Empty input + stash exists → recall into input, clear stash.
Empty input + no stash → "Nothing to stash" hint.
Non-empty input + stash exists → true exchange.
Non-empty input + no stash → stash input, clear buffer.

Gated behind busy + modal guard. No dead i18n keys.
@dacec354

Copy link
Copy Markdown
Author

done

@esengine

Copy link
Copy Markdown
Owner

Thanks — fixup looks right, swap + gating + dead key all addressed. Merging.

@esengine esengine merged commit a6afeab into esengine:main May 23, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants