diff --git a/.cursor/rules/general.mdc b/.cursor/rules/general.mdc index 8bfc170..48cf9bd 100644 --- a/.cursor/rules/general.mdc +++ b/.cursor/rules/general.mdc @@ -4,20 +4,49 @@ alwaysApply: true When working with this project, follow these rules: +## Core Behavior - NEVER do anything i didn't ask you for! -- Use double quotes ("") for strings. -- Do NOT "test the implementation" when you are done. The only exception is when you - need to typecheck or build the app, in that case: +- Don't talk like a robot. Behave more like a human. +- Be concise and direct in responses. +- If you're unsure about something, ask for clarification instead of guessing. - - To typecheck, run `npm run frontend:typecheck`. - - To build, run `npm run frontend:build`. - - Do NOT execute other commands like "cd". -- Do NOT "cd" to the project directory. -- If possible, try to update files in a single edit. -- When you need a delay, use `await delay(millis);` in an async function. If the current function is not async, - make it async. The import is `/frontend/src/utils/utils`. -- When you complete your task, remove unused imports if there are any. +## Code Quality & Principles - Follow DRY, SOLID, YAGNI and KISS principles. - Do NOT use old, outdated or deprecated APIs and functions. -- Don't talk like a robot. Behave more like a human. \ No newline at end of file +- Use double quotes ("") for strings consistently. +- Prefer functional components over class components in React. +- Use TypeScript strictly - avoid `any` types unless absolutely necessary. + +## File Operations +- If possible, try to update files in a single edit when making multiple changes. +- Do NOT "cd" to the project directory.å + +## Testing & Validation +- Do NOT "test the implementation" when you are done. The only exception is when you + need to typecheck or build the app, in that case: + - To typecheck, run `npm run frontend:typecheck`. + - To build, run `npm run frontend:build`. +- Do NOT execute other commands like "cd". +- If the typecheck passed, there's no need for checking the linter errors. + +## Async Operations +- When you need a delay, use `await delay(millis);` in an async function. If the current function is not async, + make it async. + +## Database +- NEVER create database migrations, they are auto-generated. + +## Project Structure Awareness +- This is a React/TypeScript frontend with Python FastAPI backend +- Uses MDUI components for UI +- Has Electron support for desktop app +- Uses Zustand for state management +- Uses use-immer for immutable state updates +- Uses React Router for navigation +- Has WebSocket support for real-time features +- Uses encryption (tweetnacl) for security + +## Performance & Efficiency +- Batch tool calls when possible to reduce latency +- Use semantic search before grep when looking for concepts +- Use TODOs for complex multi-step tasks to track progress diff --git a/backend/models.py b/backend/models.py index 8681b51..8fcd58d 100644 --- a/backend/models.py +++ b/backend/models.py @@ -120,7 +120,7 @@ class RegisterRequest(BaseModel): class SendMessageRequest(BaseModel): content: str - reply_to_id: int | None + reply_to_id: int | None = None class EditMessageRequest(BaseModel): diff --git a/frontend/src/pages/app/ui/components/chat/ChatMessages.tsx b/frontend/src/pages/app/ui/components/chat/ChatMessages.tsx index 9dcb11e..a275492 100644 --- a/frontend/src/pages/app/ui/components/chat/ChatMessages.tsx +++ b/frontend/src/pages/app/ui/components/chat/ChatMessages.tsx @@ -90,20 +90,6 @@ export function ChatMessages({ messages = [], children, isDm = false, onReplySel if (!toBeDeleted || !user.authToken) return; try { onDelete?.(toBeDeleted.id); - // if (toBeDeleted.isDm) { - // // For DM, send dmDelete - // await request({ - // type: "dmDelete", - // data: { id: toBeDeleted.id }, - // credentials: { scheme: "Bearer", credentials: user.authToken } - // }); - // } else { - // await request({ - // type: "deleteMessage", - // data: { message_id: toBeDeleted.id }, - // credentials: { scheme: "Bearer", credentials: user.authToken } - // }); - // } } catch (error) { console.error("Failed to delete message:", error); } diff --git a/frontend/src/pages/app/ui/components/core/RichTextArea.tsx b/frontend/src/pages/app/ui/components/core/RichTextArea.tsx index 3543438..8fb44e0 100644 --- a/frontend/src/pages/app/ui/components/core/RichTextArea.tsx +++ b/frontend/src/pages/app/ui/components/core/RichTextArea.tsx @@ -26,12 +26,12 @@ export function RichTextArea({ const hiddenTextareaRef = useRef(null); const heightRef = useRef(null); - const getStyleValue = (computedStyle: CSSStyleDeclaration, prop: keyof CSSStyleDeclaration): number => { - const raw = (computedStyle as any)[prop] as string | number | undefined; + function getStyleValue(computedStyle: CSSStyleDeclaration, prop: keyof CSSStyleDeclaration): number { + const raw = computedStyle[prop] as string | number | undefined; if (raw == null) return 0; const str = String(raw); return str.endsWith("px") ? parseFloat(str) : parseFloat(str) || 0; - }; + } const calculateTextareaStyles = useCallback(() => { const textarea = textareaRef.current; @@ -116,9 +116,7 @@ export function RichTextArea({ textarea.style.overflowY = overflowing ? "hidden" : ""; }, [calculateTextareaStyles]); - const useEnhancedEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect; - - useEnhancedEffect(() => { + useLayoutEffect(() => { syncHeight(); }, [syncHeight, text]); @@ -142,13 +140,13 @@ export function RichTextArea({ }; }, [syncHeight]); - const handleChange = (e: React.ChangeEvent) => { + function handleChange(e: React.ChangeEvent) { // Keep height responsive during rapid uncontrolled input bursts syncHeight(); onTextChange(e.target.value); - }; + } - const handleKeyDown = (e: React.KeyboardEvent) => { + function handleKeyDown(e: React.KeyboardEvent) { const isCtrlEnter = e.key === "Enter" && (e.ctrlKey || e.metaKey); const isPlainEnter = e.key === "Enter" && !e.ctrlKey && !e.metaKey && !e.shiftKey && !e.altKey; @@ -175,7 +173,7 @@ export function RichTextArea({ return; } } - }; + } return ( <>