From 612e50808a68a9e4c6f81298bd0c9929303b98d6 Mon Sep 17 00:00:00 2001 From: Shantur Rathore Date: Wed, 11 Feb 2026 13:52:02 +0000 Subject: [PATCH] fix(ui): preserve draft across prompt history Stop resetting history navigation on input so editing recalled entries doesn't wipe the bottom draft. Allow ArrowDown navigation while in history and persist the session draft only for fresh prompts. --- packages/ui/src/components/prompt-input.tsx | 2 -- .../src/components/prompt-input/usePromptPicker.ts | 2 -- .../src/components/prompt-input/usePromptState.ts | 14 ++++++++++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/ui/src/components/prompt-input.tsx b/packages/ui/src/components/prompt-input.tsx index 8229b877..77ce1aeb 100644 --- a/packages/ui/src/components/prompt-input.tsx +++ b/packages/ui/src/components/prompt-input.tsx @@ -135,7 +135,6 @@ export default function PromptInput(props: PromptInputProps) { instanceFolder: () => props.instanceFolder, prompt, setPrompt, - resetHistoryNavigation, getTextarea: () => textareaRef ?? null, instanceAgents, commands: () => getCommands(props.instanceId), @@ -303,7 +302,6 @@ export default function PromptInput(props: PromptInputProps) { const nextValue = before + insertion + after setPrompt(nextValue) - resetHistoryNavigation() setShowPicker(false) setAtPosition(null) diff --git a/packages/ui/src/components/prompt-input/usePromptPicker.ts b/packages/ui/src/components/prompt-input/usePromptPicker.ts index 958f4a4c..ada32cc9 100644 --- a/packages/ui/src/components/prompt-input/usePromptPicker.ts +++ b/packages/ui/src/components/prompt-input/usePromptPicker.ts @@ -17,7 +17,6 @@ type PromptPickerOptions = { prompt: Accessor setPrompt: (value: string) => void - resetHistoryNavigation?: () => void getTextarea: () => HTMLTextAreaElement | null instanceAgents: Accessor @@ -53,7 +52,6 @@ export function usePromptPicker(options: PromptPickerOptions): PromptPickerContr const target = e.target as HTMLTextAreaElement const value = target.value options.setPrompt(value) - options.resetHistoryNavigation?.() const cursorPos = target.selectionStart diff --git a/packages/ui/src/components/prompt-input/usePromptState.ts b/packages/ui/src/components/prompt-input/usePromptState.ts index 3ca38612..3b326f2c 100644 --- a/packages/ui/src/components/prompt-input/usePromptState.ts +++ b/packages/ui/src/components/prompt-input/usePromptState.ts @@ -50,7 +50,11 @@ export function usePromptState(options: PromptStateOptions): PromptState { const setPrompt = (value: string) => { setPromptInternal(value) - setSessionDraftPrompt(options.instanceId(), options.sessionId(), value) + // Persist drafts only when the user is at the "fresh" position (not browsing history). + // This keeps the bottom-of-history draft stable even if the user edits recalled history entries. + if (historyIndex() === -1) { + setSessionDraftPrompt(options.instanceId(), options.sessionId(), value) + } } const clearPrompt = () => { @@ -121,6 +125,12 @@ export function usePromptState(options: PromptStateOptions): PromptState { const textarea = selectOptions.getTextarea() if (!textarea) return false + + // Only require the cursor to be at the buffer start when *entering* history navigation. + // Once we're already navigating history (historyIndex >= 0), allow ArrowUp/ArrowDown + // regardless of cursor position (we focus the end of the entry). + if (historyIndex() !== -1) return true + return textarea.selectionStart === 0 && textarea.selectionEnd === 0 } @@ -164,7 +174,7 @@ export function usePromptState(options: PromptStateOptions): PromptState { setPrompt(entries[newIndex]) } else { setHistoryIndex(-1) - const draft = historyDraft() + const draft = historyDraft() ?? getSessionDraftPrompt(options.instanceId(), options.sessionId()) setPrompt(draft ?? "") setHistoryDraft(null) }