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) }