feat: chat persistence fixes, mobile UX, analytics scrubbing, and toolbar polish#44
feat: chat persistence fixes, mobile UX, analytics scrubbing, and toolbar polish#44
Conversation
- Add scrubForAnalytics utility to redact sensitive fields/patterns before PostHog capture (emails, phones, keys, addresses). - Replace silently-swallowed tool-call-log write errors with structured console.warn JSON for debuggability. - Mark /api/payclaw/status as deprecated with HTTP headers and log. Co-authored-by: Cursor <cursoragent@cursor.com>
- Replace markdown rendering in user messages with plain-text whitespace-pre-wrap, removing custom component overrides in both message-user and chat-preview-panel. - Enhance ModelSelectorHeader to read the current chat's persisted model and write model changes back to the chat record. - Add Payclaw architecture hardening plan (#47). - Add ChatGPT nav list widget analysis research. Co-authored-by: Cursor <cursoragent@cursor.com>
Restructure sidebar header for consistent home link placement, close sidebar on chat navigation, swap to hamburger menu icon, add share option to chat actions menu on mobile, and smooth sheet animations. Co-authored-by: Cursor <cursoragent@cursor.com>
…toolbar reveal - Read IndexedDB cache directly in cacheAndAddMessage instead of stale closure state, preventing the second sequential call from dropping the first's write - Defer edited user message persistence to onFinish to avoid provider state mutations during the sendMessage/setMessages React batch - Ensure createdAt on cached messages for correct sort order - Auto-play mask-reveal animation on fresh stream completion; keep hover-trigger for historical messages - Include Convex auth loading in ChatsProvider isLoading - Add dual-message-state and stale-closure-persistence agent skills Co-authored-by: Cursor <cursoragent@cursor.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR fixes a critical stale closure data loss bug in edit persistence, adds PII scrubbing to analytics, improves mobile UX, and polishes the assistant toolbar animation. Key changes:
Confidence Score: 5/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant EditUI as Edit UI
participant ChatCore as use-chat-core
participant Provider as MessagesProvider
participant IDB as IndexedDB
participant Convex
User->>EditUI: Edit message
EditUI->>ChatCore: setPendingEditUserMessage(editedMsg)
Note over ChatCore: Store in pendingEditUserMsgRef
EditUI->>ChatCore: sendMessage()
ChatCore->>Provider: Stream starts
Provider-->>User: Display streaming response
Note over ChatCore: onFinish triggered
ChatCore->>Provider: cacheAndAddMessage(pendingEdit)
Provider->>IDB: Read current cache
IDB-->>Provider: Return existing messages
Provider->>IDB: Write [existing + editedUser]
Provider->>Convex: Persist editedUser
ChatCore->>Provider: cacheAndAddMessage(assistantMsg)
Provider->>IDB: Read current cache (includes editedUser)
IDB-->>Provider: Return messages with editedUser
Provider->>IDB: Write [existing + assistant]
Provider->>Convex: Persist assistant
Last reviewed commit: 6b6aa99 |
There was a problem hiding this comment.
3 issues found across 26 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="app/components/layout/share-publish-drawer.tsx">
<violation number="1" location="app/components/layout/share-publish-drawer.tsx:40">
P2: URL-encode the tweet text before interpolating it into the intent URL; unencoded spaces/punctuation can produce an invalid query string.</violation>
</file>
<file name="app/components/chat/use-chat-core.ts">
<violation number="1" location="app/components/chat/use-chat-core.ts:186">
P2: Pending edited user messages are only persisted on successful stream completion. If the stream aborts/errors, the early return skips this block, so edited user messages can be dropped from persistence. Consider persisting (or at least clearing) pending edits before the early return on error/abort.</violation>
</file>
<file name="app/components/layout/chat-actions-menu.tsx">
<violation number="1" location="app/components/layout/chat-actions-menu.tsx:68">
P1: Share action targets the active session chatId instead of the menu’s chat prop, so sharing from a chat list will publish the wrong chat. Use the `chat.id` prop for mutations and drawer rendering.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| } | ||
|
|
||
| const handleShare = async () => { | ||
| if (!chatId) return |
There was a problem hiding this comment.
P1: Share action targets the active session chatId instead of the menu’s chat prop, so sharing from a chat list will publish the wrong chat. Use the chat.id prop for mutations and drawer rendering.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/components/layout/chat-actions-menu.tsx, line 68:
<comment>Share action targets the active session chatId instead of the menu’s chat prop, so sharing from a chat list will publish the wrong chat. Use the `chat.id` prop for mutations and drawer rendering.</comment>
<file context>
@@ -39,19 +47,36 @@ export function ChatActionsMenu({
}
+ const handleShare = async () => {
+ if (!chatId) return
+ setIsShareLoading(true)
+ try {
</file context>
| const shareOnX = () => { | ||
| onOpenChange(false) | ||
| const text = `Check out this conversation I shared with Not A Wrapper! ${publicLink}` | ||
| window.open(`https://x.com/intent/tweet?text=${text}`, "_blank") |
There was a problem hiding this comment.
P2: URL-encode the tweet text before interpolating it into the intent URL; unencoded spaces/punctuation can produce an invalid query string.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/components/layout/share-publish-drawer.tsx, line 40:
<comment>URL-encode the tweet text before interpolating it into the intent URL; unencoded spaces/punctuation can produce an invalid query string.</comment>
<file context>
@@ -0,0 +1,97 @@
+ const shareOnX = () => {
+ onOpenChange(false)
+ const text = `Check out this conversation I shared with Not A Wrapper! ${publicLink}`
+ window.open(`https://x.com/intent/tweet?text=${text}`, "_blank")
+ }
+
</file context>
| if (effectiveChatId) { | ||
| // Persist the edited user message first (if any) so the user→assistant | ||
| // pair is written in order before ID reconciliation. | ||
| const pendingEdit = pendingEditUserMsgRef.current |
There was a problem hiding this comment.
P2: Pending edited user messages are only persisted on successful stream completion. If the stream aborts/errors, the early return skips this block, so edited user messages can be dropped from persistence. Consider persisting (or at least clearing) pending edits before the early return on error/abort.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/components/chat/use-chat-core.ts, line 186:
<comment>Pending edited user messages are only persisted on successful stream completion. If the stream aborts/errors, the early return skips this block, so edited user messages can be dropped from persistence. Consider persisting (or at least clearing) pending edits before the early return on error/abort.</comment>
<file context>
@@ -166,6 +181,14 @@ export function useChatCore({
if (effectiveChatId) {
+ // Persist the edited user message first (if any) so the user→assistant
+ // pair is written in order before ID reconciliation.
+ const pendingEdit = pendingEditUserMsgRef.current
+ if (pendingEdit) {
+ pendingEditUserMsgRef.current = null
</file context>
Remove outdated archive, plans, and research files from .agents/. Simplify and consolidate .cursor/rules; drop 070-documentation and 090-icon-sizing. Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
cacheAndAddMessagenow reads the current IndexedDB cache directly instead of relying on stale closure-captured React state, preventing sequential calls from silently dropping messages. Edited user messages are deferred toonFinishto avoid mutating provider state mid-batch.mask-revealkeyframe; historical messages keep the hover-triggered reveal.Test plan
Made with Cursor
Summary by cubic
Fixes edit persistence that could drop messages, adds a mobile share flow and sidebar polish, scrubs PII from analytics, smooths the assistant toolbar reveal, and prunes stale agent docs while simplifying Cursor rules. Also persists the selected model per chat and simplifies user message rendering.
New Features
Bug Fixes
Written for commit a8976fe. Summary will update on new commits.