Add stashed prompts - #260
Conversation
|
Warning Review limit reached
Next review available in: 32 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Free Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughAdds prompt stashing for composer text and images, including persistence, restoration, deletion, attachment limits, keyboard shortcuts, picker UI, draft-state preservation, and browser coverage. ChangesPrompt stash
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant ChatComposer
participant PromptStashStore
participant ComposerDraftStore
participant ComposerStashPicker
User->>ChatComposer: Press mod+s
ChatComposer->>PromptStashStore: Stash or retrieve prompt entry
PromptStashStore->>ComposerDraftStore: Persist or clear composer content
ChatComposer->>ComposerStashPicker: Open stash picker
ComposerStashPicker->>ChatComposer: Restore or delete selected entry
Note 🎁 Summarized by CodeRabbit FreeYour organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8ed0b40a23
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| function mergeStashedPrompt(currentPrompt: string, stashedPrompt: string): string { | ||
| if (stashedPrompt.trim().length === 0) return currentPrompt; | ||
| if (stripInlineTerminalContextPlaceholders(currentPrompt).trim().length === 0) { | ||
| return `${currentPrompt}${stashedPrompt}`; |
There was a problem hiding this comment.
Preserve a separator after terminal-context placeholders
When a draft retains terminal contexts, clearPromptAndImages leaves only their inline placeholders, so this branch concatenates the restored text directly onto the last placeholder. At send time that placeholder materializes as a label such as @terminal-1:3-4, producing @terminal-1:3-4Stashed text rather than a separated prompt. Insert whitespace between the preserved placeholders and restored text.
Useful? React with 👍 / 👎.
| const handler = (event: globalThis.KeyboardEvent) => { | ||
| const command = resolveShortcutCommand(event, keybindings, { |
There was a problem hiding this comment.
Ignore stash shortcuts while another dialog is active
When Settings > Keybindings is recording a shortcut, this long-lived capture listener runs before the settings listener registered later, resolves the default mod+s, stops propagation, and stashes the hidden composer instead of recording the key. The same unexpected mutation can occur from other dialog inputs. Apply the existing event.defaultPrevented and shouldIgnoreGlobalNavigationShortcut guards before resolving this global command.
Useful? React with 👍 / 👎.
| return; | ||
| } | ||
|
|
||
| stashSnapshotsRef.current.set(entryId, { key: snapshotKey, images }); |
There was a problem hiding this comment.
Release completed in-memory image snapshots
Every image stash retains the original File objects and blob preview URLs in this map, but successful image finalization never removes them; they remain until restore, delete, eviction, or component unmount. Since a stash may contain eight 10 MiB images and the queue holds 20 entries, routine repeated stashing can retain roughly 1.6 GiB despite the persisted-image budget and can exhaust the browser process. Keep the snapshot only while encoding or while Undo is actionable, then release it and revoke unreferenced blob URLs.
Useful? React with 👍 / 👎.
| if (event.key === "ArrowDown" || event.key === "ArrowUp") { | ||
| if (entries.length === 0) return; | ||
| event.preventDefault(); |
There was a problem hiding this comment.
Stop intercepting arrows after focus leaves the stash picker
If the picker is open and the user clicks back into the composer, the picker remains mounted while this window-level handler still prevents every ArrowUp/ArrowDown event. Cursor navigation in the editor is therefore replaced by changing the hidden picker selection until the picker is explicitly closed. Restrict these keys to focus within the picker, or close the picker when focus moves outside it.
Useful? React with 👍 / 👎.
What Changed
composer.stashcommand (defaultmod+swith!terminalFocus), including browser Save suppression only when the command resolves.Why
This lets users temporarily put aside a prompt and recover it after switching threads, providers, or models without carrying provider/model/mode/context state into the destination composer. The implementation follows the final global-queue design from pingdotgg/t3code#4787 and deliberately excludes image compression.
UI Changes
A compact bookmark badge appears beside the desktop composer when stashes exist. It opens a keyboard-accessible picker with prompt previews, relative times, image/pending states, and visible delete controls. The frozen web phone tier is unchanged, and no flying-prompt animation was added.
Screenshots/video are not included in this draft.
Validation
Passed:
bun install --frozen-lockfilebun fmtbunx oxfmt --checkfor all 19 changed filesbun lint(existing unrelated warnings only)bun typecheckbun run typecheck:effectbun run testbun run buildbun run build --filter=@ryco/webbun run --cwd apps/web test:browser(70 files, 580 passed, 1 expected failure)Known repository baseline:
bun run fmt:checkstill reports four pre-existing generated declaration files (scripts/lib/brand-assets.d.ts,scripts/lib/build-target-arch.d.ts,scripts/lib/resolve-catalog.d.ts, andscripts/lib/update-manifest.d.ts). They were left unchanged because they are unrelated to this feature.Checklist
Summary by CodeRabbit
New Features
mod+sshortcut and configurable keybinding support.Bug Fixes