diff --git a/add_backspace_pill_removal.py b/add_backspace_pill_removal.py
deleted file mode 100644
index b5580b7e9e..0000000000
--- a/add_backspace_pill_removal.py
+++ /dev/null
@@ -1,62 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Adding backspace removal for both action and mention pills...")
-
-# Find the current backspace handling and enhance it
-old_backspace_handling = ''' // Handle backspace on action pills
- if (e.key === 'Backspace') {
- const cursorPos = e.currentTarget.selectionStart;
- const beforeCursor = value.slice(0, cursorPos);
-
- // Check if cursor is right after an action pill
- const actionMatch = beforeCursor.match(/\[([^\]]+)\]$/);
- if (actionMatch) {
- e.preventDefault();
- handleRemoveAction(actionMatch[1]);
- return;
- }
- }'''
-
-new_backspace_handling = ''' // Handle backspace on action and mention pills
- if (e.key === 'Backspace') {
- const cursorPos = e.currentTarget.selectionStart;
- const beforeCursor = value.slice(0, cursorPos);
-
- console.log('๐ Backspace pressed, cursor at:', cursorPos);
- console.log('๐ Text before cursor:', beforeCursor);
-
- // Check if cursor is right after an action pill [Action]
- const actionMatch = beforeCursor.match(/\[([^\]]+)\]$/);
- if (actionMatch) {
- console.log('๐ Found action pill to remove:', actionMatch[1]);
- e.preventDefault();
- handleRemoveAction(actionMatch[1]);
- return;
- }
-
- // Check if cursor is right after a mention pill @filename
- const mentionMatch = beforeCursor.match(/@([^\s]+)$/);
- if (mentionMatch) {
- console.log('๐ Found mention pill to remove:', mentionMatch[1]);
- e.preventDefault();
- handleRemoveMention(mentionMatch[1]);
- return;
- }
- }'''
-
-content = content.replace(old_backspace_handling, new_backspace_handling)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Added backspace removal for pills:")
-print(" - Enhanced existing action pill removal")
-print(" - Added mention pill removal (@filename)")
-print(" - Added debugging logs for backspace events")
-print(" - Now supports removing both types of pills with backspace")
-print(" - Pills will be removed as complete units")
diff --git a/add_cursor_blink_animation.py b/add_cursor_blink_animation.py
deleted file mode 100644
index f4df823a2e..0000000000
--- a/add_cursor_blink_animation.py
+++ /dev/null
@@ -1,48 +0,0 @@
-import re
-
-# Read the main.css file
-with open('ui/desktop/src/styles/main.css', 'r') as f:
- content = f.read()
-
-print("Adding cursor blink animation to main.css...")
-
-# Find the animations section and add the blink animation
-animations_section = '''/* animations */
-@keyframes appear {
- from {
- opacity: 0;
- }
- to {
- opacity: 1;
- }
-}'''
-
-new_animations_section = '''/* animations */
-@keyframes appear {
- from {
- opacity: 0;
- }
- to {
- opacity: 1;
- }
-}
-
-@keyframes blink {
- 0%, 50% {
- opacity: 1;
- }
- 51%, 100% {
- opacity: 0;
- }
-}'''
-
-content = content.replace(animations_section, new_animations_section)
-
-# Write the modified content back
-with open('ui/desktop/src/styles/main.css', 'w') as f:
- f.write(content)
-
-print("โ Added cursor blink animation to main.css")
-print(" - @keyframes blink: 0-50% visible, 51-100% hidden")
-print(" - Creates a regular text cursor blinking effect")
-print(" - Can be used with 'animate-blink' class")
diff --git a/add_mention_debugging.py b/add_mention_debugging.py
deleted file mode 100644
index dc33f14b8a..0000000000
--- a/add_mention_debugging.py
+++ /dev/null
@@ -1,84 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Adding comprehensive debugging for mention detection...")
-
-# Find the mention regex section and add more debugging
-old_mention_detection = ''' // Find all mention matches
- let mentionMatch;
- mentionRegex.lastIndex = 0; // Reset regex
- while ((mentionMatch = mentionRegex.exec(value)) !== null) {
- allMatches.push({
- type: 'mention',
- match: mentionMatch,
- index: mentionMatch.index,
- length: mentionMatch[0].length,
- content: mentionMatch[1] // filename without @
- });
- }'''
-
-new_mention_detection = ''' // Find all mention matches
- let mentionMatch;
- mentionRegex.lastIndex = 0; // Reset regex
- console.log('๐ Searching for mentions in value:', value);
- console.log('๐ Using mention regex:', mentionRegex);
- while ((mentionMatch = mentionRegex.exec(value)) !== null) {
- console.log('๐ Found mention match:', mentionMatch);
- allMatches.push({
- type: 'mention',
- match: mentionMatch,
- index: mentionMatch.index,
- length: mentionMatch[0].length,
- content: mentionMatch[1] // filename without @
- });
- }'''
-
-content = content.replace(old_mention_detection, new_mention_detection)
-
-# Also add debugging after sorting matches
-old_sort_section = ''' // Sort matches by position
- allMatches.sort((a, b) => a.index - b.index);
-
- console.log('๐ Found matches:', allMatches);'''
-
-new_sort_section = ''' // Sort matches by position
- allMatches.sort((a, b) => a.index - b.index);
-
- console.log('๐ All matches found:', allMatches);
- console.log('๐ Match breakdown:', {
- actions: allMatches.filter(m => m.type === 'action').length,
- mentions: allMatches.filter(m => m.type === 'mention').length,
- total: allMatches.length
- });'''
-
-content = content.replace(old_sort_section, new_sort_section)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Added comprehensive debugging:")
-print(" - Debug logs for mention regex search")
-print(" - Debug logs for found mention matches")
-print(" - Match breakdown statistics")
-print(" - Should help identify if mentions are being detected")
-
-# Also let's test the regex pattern directly
-import re
-
-test_strings = [
- "@filename.txt",
- "Hello @test.py world",
- "@folder/file.js",
- "Multiple @file1.txt and @file2.py mentions"
-]
-
-mention_regex = re.compile(r'@([^\s]+)')
-
-print("\n๐งช Testing mention regex pattern:")
-for test in test_strings:
- matches = mention_regex.findall(test)
- print(f" '{test}' โ {matches}")
diff --git a/add_tailwind_blink_class.py b/add_tailwind_blink_class.py
deleted file mode 100644
index 2b6c095d70..0000000000
--- a/add_tailwind_blink_class.py
+++ /dev/null
@@ -1,27 +0,0 @@
-import re
-
-# Read the main.css file
-with open('ui/desktop/src/styles/main.css', 'r') as f:
- content = f.read()
-
-print("Adding Tailwind animate-blink utility class...")
-
-# Find the @theme inline section and add the animation
-theme_inline_section = '''@theme inline {
- --ease-g2: cubic-bezier(0.55, 0, 1, 0.45);'''
-
-new_theme_inline_section = '''@theme inline {
- --ease-g2: cubic-bezier(0.55, 0, 1, 0.45);
-
- --animate-blink: blink 1s step-end infinite;'''
-
-content = content.replace(theme_inline_section, new_theme_inline_section)
-
-# Write the modified content back
-with open('ui/desktop/src/styles/main.css', 'w') as f:
- f.write(content)
-
-print("โ Added animate-blink utility class to Tailwind theme")
-print(" - Uses the blink keyframe with 1s duration")
-print(" - step-end timing for sharp on/off transitions")
-print(" - infinite loop for continuous blinking")
diff --git a/add_visible_text_selection.py b/add_visible_text_selection.py
deleted file mode 100644
index 446150357b..0000000000
--- a/add_visible_text_selection.py
+++ /dev/null
@@ -1,105 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Adding visible blue text selection highlight...")
-
-# Add selection styling to the hidden textarea
-old_hidden_textarea_style = ''' style={{
- position: 'absolute',
- left: 0,
- top: 0,
- width: '100%',
- height: '100%',
- opacity: 0.01, // Nearly invisible but still selectable
- zIndex: 2, // Higher z-index to capture mouse events
- background: 'transparent',
- border: 'none',
- outline: 'none',
- resize: 'none',
- color: 'transparent', // Hide text but keep selection
- caretColor: 'transparent', // Hide caret (we show our own)
- pointerEvents: 'auto', // Ensure it can receive mouse events
- }}'''
-
-new_hidden_textarea_style = ''' style={{
- position: 'absolute',
- left: 0,
- top: 0,
- width: '100%',
- height: '100%',
- opacity: 0.01, // Nearly invisible but still selectable
- zIndex: 2, // Higher z-index to capture mouse events
- background: 'transparent',
- border: 'none',
- outline: 'none',
- resize: 'none',
- color: 'transparent', // Hide text but keep selection
- caretColor: 'transparent', // Hide caret (we show our own)
- pointerEvents: 'auto', // Ensure it can receive mouse events
- }}
- className="absolute inset-0 w-full h-full resize-none selection:bg-blue-500 selection:text-white"'''
-
-content = content.replace(old_hidden_textarea_style, new_hidden_textarea_style)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-# Also add CSS to the main.css file for better selection styling
-with open('ui/desktop/src/styles/main.css', 'r') as f:
- css_content = f.read()
-
-# Add selection styling at the end of the file
-selection_css = '''
-/* Text selection styling for RichChatInput */
-.rich-text-input textarea::selection {
- background-color: #3b82f6; /* Blue-500 */
- color: white;
-}
-
-.rich-text-input textarea::-moz-selection {
- background-color: #3b82f6; /* Blue-500 */
- color: white;
-}
-
-/* Global selection styling for better visibility */
-::selection {
- background-color: #3b82f6; /* Blue-500 */
- color: white;
-}
-
-::-moz-selection {
- background-color: #3b82f6; /* Blue-500 */
- color: white;
-}
-'''
-
-if '/* Text selection styling for RichChatInput */' not in css_content:
- css_content += selection_css
-
- with open('ui/desktop/src/styles/main.css', 'w') as f:
- f.write(css_content)
-
- print("โ Added selection CSS to main.css")
-
-# Also add a wrapper class to the RichChatInput component
-old_wrapper = ''' return (
-
'''
-
-new_wrapper = ''' return (
-
'''
-
-content = content.replace(old_wrapper, new_wrapper)
-
-# Write the final content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Added visible text selection highlighting:")
-print(" - Added selection:bg-blue-500 selection:text-white to textarea")
-print(" - Added CSS rules for ::selection styling")
-print(" - Added rich-text-input wrapper class")
-print(" - Selection should now be clearly visible with blue highlight")
diff --git a/complete_mention_pill_rendering.py b/complete_mention_pill_rendering.py
deleted file mode 100644
index 310d0df1f2..0000000000
--- a/complete_mention_pill_rendering.py
+++ /dev/null
@@ -1,181 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Completing mention pill rendering in RichChatInput...")
-
-# Find the section after we set up the matches and complete the processing logic
-# We need to replace the old action-only processing with the new combined processing
-
-# First, let's find where the old processing logic ends and replace it
-# Look for the section that processes beforeAction
-old_processing_section = ''' console.log('โ Found action match:', match);
- const beforeAction = value.slice(lastIndex, match.index);
- const actionLabel = match[1];
- console.log('๐ Processing action:', { beforeAction, actionLabel, matchIndex: match.index });
-
- // Add text before action with potential cursor
- if (beforeAction) {
- // Split text by cursor position to insert cursor at the right spot
- let textWithCursor = [];
- for (let i = 0; i < beforeAction.length; i++) {
- if (isFocused && cursorPosition === currentPos) {
- textWithCursor.push(
-
- );
- }
- textWithCursor.push(beforeAction[i]);
- currentPos++;
- }
-
- parts.push(
-
- {textWithCursor}
-
- );
- }
-
- // Find matching action
- const actionEntry = Object.entries(ACTION_MAP).find(
- ([_, config]) => config.label === actionLabel
- );
-
- if (actionEntry) {
- const [actionId, config] = actionEntry;
- parts.push(
- handleRemoveAction(actionLabel)}
- />
- );
- } else {
- // If no matching action, render as text
- parts.push(
-
- {match[0]}
-
- );
- }
-
- currentPos += match[0].length;
- lastIndex = match.index + match[0].length;
- }'''
-
-new_processing_section = ''' console.log('โ Found match:', matchData);
-
- // Add text before this match with potential cursor
- const beforeMatch = value.slice(lastIndex, index);
- if (beforeMatch) {
- let textWithCursor = [];
- for (let i = 0; i < beforeMatch.length; i++) {
- if (isFocused && cursorPosition === currentPos) {
- textWithCursor.push(
-
- );
- }
- textWithCursor.push(beforeMatch[i]);
- currentPos++;
- }
-
- parts.push(
-
- {textWithCursor}
-
- );
- }
-
- // Add cursor before match if needed
- if (isFocused && cursorPosition === currentPos) {
- parts.push(
-
- );
- }
-
- if (type === 'action') {
- // Handle action pills
- const actionLabel = content;
- const actionEntry = Object.entries(ACTION_MAP).find(
- ([_, config]) => config.label === actionLabel
- );
-
- if (actionEntry) {
- const [actionId, config] = actionEntry;
- parts.push(
- handleRemoveAction(actionLabel)}
- />
- );
- } else {
- // If no matching action, render as text
- parts.push(
-
- {match[0]}
-
- );
- }
- } else if (type === 'mention') {
- // Handle mention pills
- const fileName = content; // filename without @
- const filePath = `@${fileName}`; // full mention text
-
- parts.push(
- handleRemoveMention(fileName)}
- />
- );
- }
-
- currentPos += length;
- lastIndex = index + length;
- }'''
-
-content = content.replace(old_processing_section, new_processing_section)
-
-# Add the handleRemoveMention function
-old_handle_remove = ''' const handleRemoveAction = useCallback((actionLabel: string) => {
- const actionText = `[${actionLabel}]`;
- const newValue = value.replace(actionText, '');
- onChange(newValue);
- }, [value, onChange]);'''
-
-new_handle_remove = ''' const handleRemoveAction = useCallback((actionLabel: string) => {
- const actionText = `[${actionLabel}]`;
- const newValue = value.replace(actionText, '');
- onChange(newValue);
- }, [value, onChange]);
-
- const handleRemoveMention = useCallback((fileName: string) => {
- const mentionText = `@${fileName}`;
- const newValue = value.replace(mentionText, '');
- onChange(newValue);
- }, [value, onChange]);'''
-
-content = content.replace(old_handle_remove, new_handle_remove)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Completed mention pill rendering:")
-print(" - Updated processing logic to handle both actions and mentions")
-print(" - Added MentionPill rendering for @filename patterns")
-print(" - Added handleRemoveMention function for pill removal")
-print(" - Mentions will now appear as green pills with file icon")
diff --git a/comprehensive_action_fix.py b/comprehensive_action_fix.py
deleted file mode 100644
index 88b84ec9a5..0000000000
--- a/comprehensive_action_fix.py
+++ /dev/null
@@ -1,98 +0,0 @@
-import re
-
-# Read the ChatInput file
-with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Creating comprehensive fix for action pill population...")
-
-# 1. Clean up the RichChatInput onChange handler
-# Find the current messy onChange and replace with clean version
-old_onchange_pattern = r'onChange=\{\(newValue, cursorPos\) => \{[^}]*\}\}'
-new_onchange = '''onChange={(newValue, cursorPos) => {
- setDisplayValue(newValue);
- updateValue(newValue);
- debouncedSaveDraft(newValue);
- setHasUserTyped(true);
-
- // Check for @ mention and / action triggers
- if (cursorPos !== undefined) {
- const syntheticTarget = {
- getBoundingClientRect: () => textAreaRef.current?.getBoundingClientRect?.() || new DOMRect(),
- selectionStart: cursorPos,
- selectionEnd: cursorPos,
- value: newValue,
- };
- checkForMention(newValue, cursorPos, syntheticTarget as HTMLTextAreaElement);
- }
- }}'''
-
-# Use a more targeted replacement
-lines = content.split('\n')
-start_idx = -1
-end_idx = -1
-brace_count = 0
-in_onchange = False
-
-for i, line in enumerate(lines):
- if 'onChange={(newValue, cursorPos) => {' in line:
- start_idx = i
- in_onchange = True
- brace_count = line.count('{') - line.count('}')
- elif in_onchange:
- brace_count += line.count('{') - line.count('}')
- if '}}' in line and brace_count <= 0:
- end_idx = i
- break
-
-if start_idx != -1 and end_idx != -1:
- # Replace the onChange handler
- new_lines = lines[:start_idx] + [' ' + new_onchange] + lines[end_idx + 1:]
- content = '\n'.join(new_lines)
- print(f"Fixed onChange handler (lines {start_idx}-{end_idx})")
-
-# 2. Ensure the actionPopover state has cursorPosition
-if 'cursorPosition?: number;' not in content:
- content = content.replace(
- 'selectedIndex: number;\n }>({',
- 'selectedIndex: number;\n cursorPosition?: number;\n }>({'
- )
- content = content.replace(
- 'selectedIndex: 0,\n });',
- 'selectedIndex: 0,\n cursorPosition: 0,\n });'
- )
- print("Added cursorPosition to actionPopover state")
-
-# 3. Make sure checkForMention sets cursorPosition when opening action popover
-content = content.replace(
- ''' setActionPopover({
- isOpen: true,
- position: {
- x: textAreaRect.left,
- y: textAreaRect.top,
- },
- selectedIndex: 0,
- });''',
- ''' setActionPopover({
- isOpen: true,
- position: {
- x: textAreaRect.left,
- y: textAreaRect.top,
- },
- selectedIndex: 0,
- cursorPosition: cursorPosition,
- });'''
-)
-
-print("Updated checkForMention to set cursorPosition")
-
-# Write the modified content back
-with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("Comprehensive fix applied successfully!")
-print("\nKey changes made:")
-print("1. Cleaned up RichChatInput onChange handler")
-print("2. Ensured actionPopover state includes cursorPosition")
-print("3. Updated checkForMention to pass cursorPosition to actionPopover")
-print("4. handleActionSelect should now work correctly with proper cursor position")
diff --git a/create_mention_pill_component.py b/create_mention_pill_component.py
deleted file mode 100644
index e076fdf9e0..0000000000
--- a/create_mention_pill_component.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# Create MentionPill component similar to ActionPill
-mention_pill_content = '''import React from 'react';
-import { X, File } from 'lucide-react';
-
-interface MentionPillProps {
- fileName: string;
- filePath: string;
- onRemove?: () => void; // Optional for read-only pills in messages
- variant?: 'default' | 'message'; // Different styles for input vs message display
- size?: 'sm' | 'md';
-}
-
-export const MentionPill: React.FC = ({
- fileName,
- filePath,
- onRemove,
- variant = 'default',
- size = 'sm'
-}) => {
- const baseClasses = "inline-flex items-center gap-1.5 font-medium border rounded-full";
-
- const variantClasses = {
- default: "bg-green-100 text-green-800 border-green-200 dark:bg-green-900 dark:text-green-200 dark:border-green-700",
- message: "bg-green-100 text-green-800 border-green-200 dark:bg-green-900 dark:text-green-200 dark:border-green-700"
- };
-
- const sizeClasses = {
- sm: "px-2 py-1 text-xs",
- md: "px-3 py-1.5 text-sm"
- };
-
- return (
-
-
-
- {fileName}
-
- {onRemove && (
-
- )}
-
- );
-};
-
-export default MentionPill;
-'''
-
-# Write the MentionPill component
-with open('ui/desktop/src/components/MentionPill.tsx', 'w') as f:
- f.write(mention_pill_content)
-
-print("โ Created MentionPill component:")
-print(" - Similar structure to ActionPill")
-print(" - Uses green colors to differentiate from actions (blue)")
-print(" - Shows File icon and filename")
-print(" - Tooltip shows full file path")
-print(" - Supports removal and different variants")
diff --git a/debug_action_flow.py b/debug_action_flow.py
deleted file mode 100644
index df330d8a4e..0000000000
--- a/debug_action_flow.py
+++ /dev/null
@@ -1,75 +0,0 @@
-import re
-
-# Read the ChatInput file
-with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f:
- content = f.read()
-
-# Add debugging to handleActionSelect function
-old_function_pattern = r' const handleActionSelect = \(actionId: string\) => \{[^}]*console\.log\([^)]*\);\s*setActionPopover[^}]*\};'
-
-new_function = ''' const handleActionSelect = (actionId: string) => {
- console.log('๐ฏ handleActionSelect called with:', actionId);
- const actionInfo = getActionInfo(actionId);
- console.log('๐ Action info:', actionInfo);
-
- // Get current cursor position from the actionPopover state
- const currentValue = displayValue;
- const cursorPosition = actionPopover.cursorPosition || 0;
- console.log('๐ Current state:', { currentValue, cursorPosition, displayValue });
-
- const beforeCursor = currentValue.slice(0, cursorPosition);
- const afterCursor = currentValue.slice(cursorPosition);
- const lastSlashIndex = beforeCursor.lastIndexOf('/');
-
- console.log('๐ Cursor analysis:', { beforeCursor, afterCursor, lastSlashIndex });
-
- if (lastSlashIndex !== -1) {
- const afterSlash = beforeCursor.slice(lastSlashIndex + 1);
- console.log('โก After slash:', afterSlash);
-
- if (!afterSlash.includes(' ') && !afterSlash.includes('\\n')) {
- // Replace the /query with [Action] text
- const beforeSlash = currentValue.slice(0, lastSlashIndex);
- const actionText = `[${actionInfo.label}]`;
- const newValue = beforeSlash + actionText + " " + afterCursor;
-
- console.log('๐ Text replacement:', {
- beforeSlash,
- actionText,
- afterCursor,
- newValue,
- oldValue: currentValue
- });
-
- setDisplayValue(newValue);
- setValue(newValue);
-
- console.log('โ Values set, new text should be:', newValue);
-
- // Set cursor position after the action text and space
- const newCursorPosition = lastSlashIndex + actionText.length + 1;
- setTimeout(() => {
- if (textAreaRef.current) {
- textAreaRef.current.setSelectionRange(newCursorPosition, newCursorPosition);
- textAreaRef.current.focus();
- }
- }, 0);
- } else {
- console.log('โ After slash contains space/newline, not replacing');
- }
- } else {
- console.log('โ No slash found in text before cursor');
- }
-
- console.log('๐ฏ Action selected:', actionId, 'at position:', cursorPosition);
- setActionPopover(prev => ({ ...prev, isOpen: false }));
- };'''
-
-# Find and replace the function using regex
-content = re.sub(old_function_pattern, new_function, content, flags=re.DOTALL)
-
-# Write the modified content back
-with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("Added comprehensive debugging to handleActionSelect")
diff --git a/debug_action_popover.py b/debug_action_popover.py
deleted file mode 100644
index fbf613116c..0000000000
--- a/debug_action_popover.py
+++ /dev/null
@@ -1,61 +0,0 @@
-import re
-
-# Read the ActionPopover file
-with open('ui/desktop/src/components/ActionPopover.tsx', 'r') as f:
- content = f.read()
-
-# Add debugging to handleItemClick
-old_handleItemClick = ''' const handleItemClick = (index: number) => {
- onSelectedIndexChange(index);
- onSelect(actions[index].id);
- actions[index].action();
- onClose();
- };'''
-
-new_handleItemClick = ''' const handleItemClick = (index: number) => {
- console.log('๐ฏ ActionPopover: handleItemClick called', { index, actionId: actions[index].id });
- console.log('๐ ActionPopover: onSelect function:', onSelect);
- console.log('๐ ActionPopover: About to call onSelect with:', actions[index].id);
-
- onSelectedIndexChange(index);
-
- // Call onSelect first - this should trigger handleActionSelect in ChatInput
- onSelect(actions[index].id);
-
- console.log('โ ActionPopover: onSelect called successfully');
-
- // Call the local action (just for logging)
- actions[index].action();
-
- console.log('๐ช ActionPopover: Closing popover');
- onClose();
- };'''
-
-content = content.replace(old_handleItemClick, new_handleItemClick)
-
-# Also add debugging to the selectAction method in useImperativeHandle
-old_selectAction = ''' selectAction: (index: number) => {
- if (actions[index]) {
- onSelect(actions[index].id);
- actions[index].action();
- onClose();
- }
- },'''
-
-new_selectAction = ''' selectAction: (index: number) => {
- console.log('โจ๏ธ ActionPopover: selectAction called via keyboard', { index, actionId: actions[index]?.id });
- if (actions[index]) {
- console.log('๐ ActionPopover: Calling onSelect from selectAction:', actions[index].id);
- onSelect(actions[index].id);
- actions[index].action();
- onClose();
- }
- },'''
-
-content = content.replace(old_selectAction, new_selectAction)
-
-# Write the modified content back
-with open('ui/desktop/src/components/ActionPopover.tsx', 'w') as f:
- f.write(content)
-
-print("Added comprehensive debugging to ActionPopover")
diff --git a/debug_richtextinput.py b/debug_richtextinput.py
deleted file mode 100644
index d682b2d5b7..0000000000
--- a/debug_richtextinput.py
+++ /dev/null
@@ -1,97 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-# Add debugging to the renderContent function
-# Find the while loop that processes actions
-old_while_section = ''' while ((match = actionRegex.exec(value)) !== null) {
- const beforeAction = value.slice(lastIndex, match.index);
- const actionLabel = match[1];
-
- // Add text before action with potential cursor
- if (beforeAction) {'''
-
-new_while_section = ''' console.log('๐จ RichChatInput renderContent called with value:', value);
- console.log('๐ Looking for action patterns with regex:', actionRegex);
-
- while ((match = actionRegex.exec(value)) !== null) {
- console.log('โ Found action match:', match);
- const beforeAction = value.slice(lastIndex, match.index);
- const actionLabel = match[1];
- console.log('๐ Processing action:', { beforeAction, actionLabel, matchIndex: match.index });
-
- // Add text before action with potential cursor
- if (beforeAction) {'''
-
-content = content.replace(old_while_section, new_while_section)
-
-# Add debugging to the action pill creation
-old_pill_creation = ''' // Add the action pill
- addCursorIfNeeded(currentPos);
- const actionInfo = ACTION_MAP[actionLabel.toLowerCase().replace(/\\s+/g, '-') as keyof typeof ACTION_MAP] ||
- { label: actionLabel, icon: };
-
- parts.push(
- handleRemoveAction(actionLabel)}
- />
- );'''
-
-new_pill_creation = ''' // Add the action pill
- addCursorIfNeeded(currentPos);
- const actionInfo = ACTION_MAP[actionLabel.toLowerCase().replace(/\\s+/g, '-') as keyof typeof ACTION_MAP] ||
- { label: actionLabel, icon: };
-
- console.log('๐ท๏ธ Creating action pill:', { actionLabel, actionInfo });
-
- parts.push(
- handleRemoveAction(actionLabel)}
- />
- );
-
- console.log('โ Action pill added to parts array');'''
-
-content = content.replace(old_pill_creation, new_pill_creation)
-
-# Add debugging to the onChange handler
-old_onchange = ''' const handleTextareaChange = useCallback((e: React.ChangeEvent) => {
- const newValue = e.target.value;
- const newCursorPos = e.target.selectionStart;
-
- console.log('RichChatInput: onChange', { newValue, newCursorPos });
- onChange(newValue, newCursorPos);
- setCursorPosition(newCursorPos);
- }, [onChange]);'''
-
-new_onchange = ''' const handleTextareaChange = useCallback((e: React.ChangeEvent) => {
- const newValue = e.target.value;
- const newCursorPos = e.target.selectionStart;
-
- console.log('๐ RichChatInput: onChange', { newValue, newCursorPos });
- console.log('๐จ Will trigger re-render with new value:', newValue);
- onChange(newValue, newCursorPos);
- setCursorPosition(newCursorPos);
- }, [onChange]);'''
-
-content = content.replace(old_onchange, new_onchange)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("Added comprehensive debugging to RichChatInput")
diff --git a/fix_action_popover_order.py b/fix_action_popover_order.py
deleted file mode 100644
index 8c92ebb662..0000000000
--- a/fix_action_popover_order.py
+++ /dev/null
@@ -1,80 +0,0 @@
-import re
-
-# Read the ActionPopover file
-with open('ui/desktop/src/components/ActionPopover.tsx', 'r') as f:
- content = f.read()
-
-# Fix the order of operations in handleItemClick - onSelect should happen BEFORE onClose
-old_handleItemClick = ''' const handleItemClick = (index: number) => {
- console.log('๐ฏ ActionPopover: handleItemClick called', { index, actionId: actions[index].id });
- console.log('๐ ActionPopover: onSelect function:', onSelect);
- console.log('๐ ActionPopover: About to call onSelect with:', actions[index].id);
-
- onSelectedIndexChange(index);
-
- // Call onSelect first - this should trigger handleActionSelect in ChatInput
- onSelect(actions[index].id);
-
- console.log('โ ActionPopover: onSelect called successfully');
-
- // Call the local action (just for logging)
- actions[index].action();
-
- console.log('๐ช ActionPopover: Closing popover');
- onClose();
- };'''
-
-new_handleItemClick = ''' const handleItemClick = (index: number) => {
- console.log('๐ฏ ActionPopover: handleItemClick called', { index, actionId: actions[index].id });
- console.log('๐ ActionPopover: onSelect function:', onSelect);
- console.log('๐ ActionPopover: About to call onSelect with:', actions[index].id);
-
- onSelectedIndexChange(index);
-
- // Call onSelect first - this should trigger handleActionSelect in ChatInput
- onSelect(actions[index].id);
-
- console.log('โ ActionPopover: onSelect called successfully');
-
- // Call the local action (just for logging)
- actions[index].action();
-
- // Close popover after a small delay to allow text replacement to complete
- console.log('๐ช ActionPopover: Closing popover after delay');
- setTimeout(() => {
- onClose();
- }, 10);
- };'''
-
-content = content.replace(old_handleItemClick, new_handleItemClick)
-
-# Also fix the selectAction method
-old_selectAction = ''' selectAction: (index: number) => {
- console.log('โจ๏ธ ActionPopover: selectAction called via keyboard', { index, actionId: actions[index]?.id });
- if (actions[index]) {
- console.log('๐ ActionPopover: Calling onSelect from selectAction:', actions[index].id);
- onSelect(actions[index].id);
- actions[index].action();
- onClose();
- }
- },'''
-
-new_selectAction = ''' selectAction: (index: number) => {
- console.log('โจ๏ธ ActionPopover: selectAction called via keyboard', { index, actionId: actions[index]?.id });
- if (actions[index]) {
- console.log('๐ ActionPopover: Calling onSelect from selectAction:', actions[index].id);
- onSelect(actions[index].id);
- actions[index].action();
- setTimeout(() => {
- onClose();
- }, 10);
- }
- },'''
-
-content = content.replace(old_selectAction, new_selectAction)
-
-# Write the modified content back
-with open('ui/desktop/src/components/ActionPopover.tsx', 'w') as f:
- f.write(content)
-
-print("Fixed ActionPopover to delay onClose() call")
diff --git a/fix_action_popover_state.py b/fix_action_popover_state.py
deleted file mode 100644
index 8fc01c7a0e..0000000000
--- a/fix_action_popover_state.py
+++ /dev/null
@@ -1,81 +0,0 @@
-import re
-
-# Read the ChatInput file
-with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f:
- content = f.read()
-
-# Fix 1: Update actionPopover state to include cursorPosition
-old_state = ''' const [actionPopover, setActionPopover] = useState<{
- isOpen: boolean;
- position: { x: number; y: number };
- selectedIndex: number;
- }>({
- isOpen: false,
- position: { x: 0, y: 0 },
- selectedIndex: 0,
- });'''
-
-new_state = ''' const [actionPopover, setActionPopover] = useState<{
- isOpen: boolean;
- position: { x: number; y: number };
- selectedIndex: number;
- cursorPosition?: number;
- }>({
- isOpen: false,
- position: { x: 0, y: 0 },
- selectedIndex: 0,
- cursorPosition: 0,
- });'''
-
-content = content.replace(old_state, new_state)
-
-# Fix 2: Update the checkForMention function to set cursorPosition when opening action popover
-# Find the section where action popover is opened
-old_action_open = ''' setActionPopover({
- isOpen: true,
- position: {
- x: textAreaRect.left,
- y: textAreaRect.top,
- },
- selectedIndex: 0,
- });'''
-
-new_action_open = ''' setActionPopover({
- isOpen: true,
- position: {
- x: textAreaRect.left,
- y: textAreaRect.top,
- },
- selectedIndex: 0,
- cursorPosition: cursorPosition,
- });'''
-
-content = content.replace(old_action_open, new_action_open)
-
-# Fix 3: Update handleActionButtonClick to include cursorPosition
-old_button_click = ''' setActionPopover({
- isOpen: true,
- position: {
- x: buttonRect.left,
- y: buttonRect.top,
- },
- selectedIndex: 0,
- });'''
-
-new_button_click = ''' setActionPopover({
- isOpen: true,
- position: {
- x: buttonRect.left,
- y: buttonRect.top,
- },
- selectedIndex: 0,
- cursorPosition: textAreaRef.current?.getBoundingClientRect ? 0 : 0, // Will be set by RichChatInput
- });'''
-
-content = content.replace(old_button_click, new_button_click)
-
-# Write the modified content back
-with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("Fixed actionPopover state to include cursorPosition")
diff --git a/fix_action_selection.py b/fix_action_selection.py
deleted file mode 100644
index d3ca5cfcd4..0000000000
--- a/fix_action_selection.py
+++ /dev/null
@@ -1,90 +0,0 @@
-import re
-
-# Read the ChatInput file
-with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f:
- content = f.read()
-
-# Find and replace the handleActionSelect function
-old_function = ''' const handleActionSelect = (actionId: string) => {
- const actionInfo = getActionInfo(actionId);
-
- // Replace / with [Action] text inline
- const currentValue = displayValue;
- const cursorPosition = 0; // RichChatInput handles cursor position internally
- const beforeCursor = currentValue.slice(0, cursorPosition);
- const lastSlashIndex = beforeCursor.lastIndexOf('/');
-
- if (lastSlashIndex !== -1) {
- const afterSlash = beforeCursor.slice(lastSlashIndex + 1);
- if (!afterSlash.includes(' ') && !afterSlash.includes('\\n')) {
- // Replace / with [Action] text
- const beforeSlash = currentValue.slice(0, lastSlashIndex);
- // Simplified approach for RichChatInput
- const actionText = `[${actionInfo.label}]`;
- const newValue = beforeSlash + actionText + " ";
-
- setDisplayValue(newValue);
- setValue(newValue);
-
- // Track selected action for pill display
-
-
- // Set cursor position after the action text
- setTimeout(() => {
- if (textAreaRef.current) {
- // Cursor positioning handled by RichChatInput
- // Focus handled by RichChatInput
- }
- }, 0);
- }
- }
-
- console.log('Action selected:', actionId);
- setActionPopover(prev => ({ ...prev, isOpen: false }));
- };'''
-
-new_function = ''' const handleActionSelect = (actionId: string) => {
- const actionInfo = getActionInfo(actionId);
-
- // Get current cursor position from the RichChatInput
- const currentValue = displayValue;
- const cursorPosition = actionPopover.cursorPosition || 0;
- const beforeCursor = currentValue.slice(0, cursorPosition);
- const afterCursor = currentValue.slice(cursorPosition);
- const lastSlashIndex = beforeCursor.lastIndexOf('/');
-
- if (lastSlashIndex !== -1) {
- const afterSlash = beforeCursor.slice(lastSlashIndex + 1);
- // Check if we're still in the same "word" after the slash
- if (!afterSlash.includes(' ') && !afterSlash.includes('\\n')) {
- // Replace the /query with [Action] text
- const beforeSlash = currentValue.slice(0, lastSlashIndex);
- const actionText = `[${actionInfo.label}]`;
- const newValue = beforeSlash + actionText + " " + afterCursor;
-
- setDisplayValue(newValue);
- setValue(newValue);
-
- // Set cursor position after the action text and space
- const newCursorPosition = lastSlashIndex + actionText.length + 1;
- setTimeout(() => {
- if (textAreaRef.current) {
- textAreaRef.current.setSelectionRange(newCursorPosition, newCursorPosition);
- textAreaRef.current.focus();
- }
- }, 0);
- }
- }
-
- console.log('Action selected:', actionId, 'at position:', cursorPosition);
- setActionPopover(prev => ({ ...prev, isOpen: false }));
- };'''
-
-# Replace the function
-content = content.replace(old_function, new_function)
-
-# Write the modified content back
-with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("Fixed handleActionSelect function to properly handle cursor position and create action pills")
diff --git a/fix_chatinput.py b/fix_chatinput.py
deleted file mode 100644
index b726a75984..0000000000
--- a/fix_chatinput.py
+++ /dev/null
@@ -1,106 +0,0 @@
-import re
-
-# Read the ChatInput file
-with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f:
- content = f.read()
-
-# 1. Add RichTextInput import after ActionPill import
-content = re.sub(
- r'(import ActionPill from \'\.\/ActionPill\';)',
- r'\1\nimport RichTextInput, { ActionData } from \'./RichTextInput\';',
- content
-)
-
-# 2. Replace selectedActions state with actions state - find the exact pattern
-selectedactions_pattern = r' // Action pills for visual display\s*const \[selectedActions, setSelectedActions\] = useState>.*?\[\]\);'
-content = re.sub(
- selectedactions_pattern,
- ' // Action pills for visual display\n const [actions, setActions] = useState([]);',
- content,
- flags=re.DOTALL
-)
-
-# 3. Remove the Selected Actions Pills section completely
-selected_pills_pattern = r'\s*\{\/\* Selected Actions Pills \*\/\}\s*\{selectedActions\.length > 0 && \(\s*
\s*Selected:<\/span>\s*\{selectedActions\.map\(\(action\) => \(\s* handleRemoveAction\(action\.id\)\}\s*\/>\s*\)\)\}\s*<\/div>\s*\)\}'
-content = re.sub(selected_pills_pattern, '', content, flags=re.DOTALL)
-
-# 4. Replace all selectedActions with actions and setSelectedActions with setActions
-content = content.replace('selectedActions', 'actions')
-content = content.replace('setActions([]);', 'setActions([]);') # Fix double replacement
-
-# 5. Update handleActionSelect - find and replace the entire function
-handle_action_select_old = r' const handleActionSelect = \(actionId: string\) => \{[^}]*\};'
-handle_action_select_new = ''' const handleActionSelect = (actionId: string) => {
- const actionInfo = getActionInfo(actionId);
-
- // Replace / with [Action] text inline
- const currentValue = displayValue;
- const cursorPosition = textAreaRef.current?.selectionStart || 0;
- const beforeCursor = currentValue.slice(0, cursorPosition);
- const lastSlashIndex = beforeCursor.lastIndexOf('/');
-
- if (lastSlashIndex !== -1) {
- const afterSlash = beforeCursor.slice(lastSlashIndex + 1);
- if (!afterSlash.includes(' ') && !afterSlash.includes('\\n')) {
- // Replace / with [Action] text
- const beforeSlash = currentValue.slice(0, lastSlashIndex);
- const afterCursor = currentValue.slice(cursorPosition);
- const actionText = `[${actionInfo.label}]`;
- const newValue = beforeSlash + actionText + afterCursor;
-
- setDisplayValue(newValue);
- setValue(newValue);
-
- // Track action for pill display
- const newAction: ActionData = {
- id: Date.now().toString() + Math.random().toString(36).substr(2, 9),
- actionId,
- label: actionInfo.label,
- icon: actionInfo.icon,
- position: lastSlashIndex,
- };
-
- setActions(prev => [...prev, newAction]);
-
- // Set cursor position after the action text
- setTimeout(() => {
- if (textAreaRef.current) {
- const newCursorPosition = lastSlashIndex + actionText.length;
- textAreaRef.current.setSelectionRange(newCursorPosition, newCursorPosition);
- }
- }, 0);
- }
- }
-
- console.log('Action selected:', actionId);
- setActionPopover(prev => ({ ...prev, isOpen: false }));
- };'''
-
-# Find the function more carefully
-lines = content.split('\n')
-start_idx = -1
-end_idx = -1
-brace_count = 0
-in_function = False
-
-for i, line in enumerate(lines):
- if 'const handleActionSelect = (actionId: string) => {' in line:
- start_idx = i
- in_function = True
- brace_count = line.count('{') - line.count('}')
- elif in_function:
- brace_count += line.count('{') - line.count('}')
- if brace_count == 0:
- end_idx = i
- break
-
-if start_idx != -1 and end_idx != -1:
- # Replace the function
- new_lines = lines[:start_idx] + handle_action_select_new.split('\n') + lines[end_idx + 1:]
- content = '\n'.join(new_lines)
-
-print("ChatInput.tsx updated successfully")
-
-# Write the modified content back
-with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f:
- f.write(content)
diff --git a/fix_correct_tailwind_classes.py b/fix_correct_tailwind_classes.py
deleted file mode 100644
index dec0cc8ef4..0000000000
--- a/fix_correct_tailwind_classes.py
+++ /dev/null
@@ -1,34 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing Tailwind class names to match the CSS variables...")
-
-# Looking at the CSS, the correct classes should be:
-# - text-text-default (maps to --color-text-default)
-# - text-text-muted (maps to --color-text-muted)
-# - border-text-default (maps to --color-text-default)
-
-# Fix 1: Change placeholder text class
-old_placeholder_class = 'className="text-textMuted pointer-events-none select-none"'
-new_placeholder_class = 'className="text-text-muted pointer-events-none select-none"'
-
-content = content.replace(old_placeholder_class, new_placeholder_class)
-
-# Fix 2: Change cursor border class
-old_cursor_border = 'border-textDefault'
-new_cursor_border = 'border-text-default'
-
-content = content.replace(old_cursor_border, new_cursor_border)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed Tailwind class names:")
-print(" - Changed text-textMuted to text-text-muted")
-print(" - Changed border-textDefault to border-text-default")
-print(" - These should now map to the correct CSS variables")
-print(" - Should work properly in both light and dark modes")
diff --git a/fix_cursor_and_placeholder_styling.py b/fix_cursor_and_placeholder_styling.py
deleted file mode 100644
index 4aab54a444..0000000000
--- a/fix_cursor_and_placeholder_styling.py
+++ /dev/null
@@ -1,34 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing cursor and placeholder styling...")
-
-# Fix 1: Change cursor color from white to grey
-old_cursor_1 = 'className="animate-pulse border-l border-textStandard h-4 inline-block"'
-new_cursor_1 = 'className="animate-pulse border-l border-textSubtle h-4 inline-block"'
-
-content = content.replace(old_cursor_1, new_cursor_1)
-
-# Fix 2: Also fix the cursor at the end of renderContent
-old_cursor_2 = ''
-new_cursor_2 = ''
-
-content = content.replace(old_cursor_2, new_cursor_2)
-
-# Fix 3: Ensure placeholder text is using textPlaceholder (should already be correct)
-# Check if it's already using the right class
-if 'text-textPlaceholder' in content:
- print("โ Placeholder text already using textPlaceholder class")
-else:
- print("โ ๏ธ Placeholder text class might need fixing")
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed cursor styling:")
-print(" - Changed from border-textStandard (white) to border-textSubtle (grey)")
-print("โ Placeholder text should already be subtle (text-textPlaceholder)")
diff --git a/fix_cursor_blink_with_css.py b/fix_cursor_blink_with_css.py
deleted file mode 100644
index ef96d4a989..0000000000
--- a/fix_cursor_blink_with_css.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing cursor blink by using inline styles instead of Tailwind class...")
-
-# Replace animate-blink with inline style
-old_cursor_1 = 'className="animate-blink border-l-2 border-black h-4 inline-block"'
-new_cursor_1 = 'className="border-l-2 border-black h-4 inline-block" style={{ animation: "blink 1s step-end infinite" }}'
-
-content = content.replace(old_cursor_1, new_cursor_1)
-
-# Also fix the other cursor instance
-old_cursor_2 = ''
-new_cursor_2 = ''
-
-content = content.replace(old_cursor_2, new_cursor_2)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed cursor blinking by using inline CSS animation")
-print(" - Removed animate-blink class (not recognized by Tailwind)")
-print(" - Added inline style: animation: 'blink 1s step-end infinite'")
-print(" - Uses the @keyframes blink defined in main.css")
-print(" - Should now blink properly!")
diff --git a/fix_cursor_line_break_logic.py b/fix_cursor_line_break_logic.py
deleted file mode 100644
index 3286bcc80e..0000000000
--- a/fix_cursor_line_break_logic.py
+++ /dev/null
@@ -1,112 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing cursor positioning logic for line breaks...")
-
-# The issue is in how we're processing character by character
-# We need to handle newlines properly and render text as continuous flow
-# Let's rewrite the text processing logic
-
-old_text_processing = ''' // Add text before action with potential cursor
- if (beforeAction) {
- const textParts = [];
- for (let i = 0; i < beforeAction.length; i++) {
- const char = beforeAction[i];
- addCursorIfNeeded(currentPos);
- textParts.push(char);
- currentPos++;
- }
-
- parts.push(
-
- {textParts}
-
- );
- }'''
-
-new_text_processing = ''' // Add text before action with potential cursor
- if (beforeAction) {
- // Split text by cursor position to insert cursor at the right spot
- let textWithCursor = [];
- for (let i = 0; i < beforeAction.length; i++) {
- if (isFocused && cursorPosition === currentPos) {
- textWithCursor.push(
-
- );
- }
- textWithCursor.push(beforeAction[i]);
- currentPos++;
- }
-
- parts.push(
-
- {textWithCursor}
-
- );
- }'''
-
-content = content.replace(old_text_processing, new_text_processing)
-
-# Also fix the remaining text processing
-old_remaining_processing = ''' // Add remaining text with potential cursor
- const remainingText = value.slice(lastIndex);
- if (remainingText) {
- const textParts = [];
- for (let i = 0; i < remainingText.length; i++) {
- const char = remainingText[i];
- addCursorIfNeeded(currentPos);
- textParts.push(char);
- currentPos++;
- }
-
- parts.push(
-
- {textParts}
-
- );
- }'''
-
-new_remaining_processing = ''' // Add remaining text with potential cursor
- const remainingText = value.slice(lastIndex);
- if (remainingText) {
- let textWithCursor = [];
- for (let i = 0; i < remainingText.length; i++) {
- if (isFocused && cursorPosition === currentPos) {
- textWithCursor.push(
-
- );
- }
- textWithCursor.push(remainingText[i]);
- currentPos++;
- }
-
- parts.push(
-
- {textWithCursor}
-
- );
- }'''
-
-content = content.replace(old_remaining_processing, new_remaining_processing)
-
-# Remove the separate addCursorIfNeeded calls since we're handling it inline now
-content = content.replace(' // Add cursor before action if needed\n addCursorIfNeeded(currentPos);', '')
-content = content.replace(' // Add cursor at the end if needed\n addCursorIfNeeded(currentPos);', ''' // Add cursor at the end if needed
- if (isFocused && cursorPosition === currentPos) {
- parts.push(
-
- );
- }''')
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed cursor positioning logic:")
-print(" - Integrated cursor rendering directly into text processing")
-print(" - Cursor now appears inline with text characters")
-print(" - Should handle line breaks properly")
-print(" - Cursor stays at correct position within the text flow")
diff --git a/fix_cursor_placeholder_order.py b/fix_cursor_placeholder_order.py
deleted file mode 100644
index fdbb7ff652..0000000000
--- a/fix_cursor_placeholder_order.py
+++ /dev/null
@@ -1,48 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing cursor position to appear before placeholder text...")
-
-# Find the placeholder rendering and fix the cursor positioning
-old_placeholder_render = ''' // Show placeholder when there's no text content (regardless of focus state)
- if (!value.trim()) {
- return (
-
-
- {placeholder}
-
- {isFocused && (
-
- )}
-
- );
- }'''
-
-new_placeholder_render = ''' // Show placeholder when there's no text content (regardless of focus state)
- if (!value.trim()) {
- return (
-
- {isFocused && (
-
- )}
-
- {placeholder}
-
-
- );
- }'''
-
-content = content.replace(old_placeholder_render, new_placeholder_render)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed cursor and placeholder order:")
-print(" - Moved cursor before placeholder text in the DOM")
-print(" - Changed ml-0.5 to mr-0.5 (margin-right instead of margin-left)")
-print(" - Cursor now appears at the beginning of the line")
-print(" - Placeholder text appears after the cursor")
diff --git a/fix_cursor_positioning.py b/fix_cursor_positioning.py
deleted file mode 100644
index 36886ba0cc..0000000000
--- a/fix_cursor_positioning.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing cursor positioning to align with text...")
-
-# Fix 1: Update cursor styling to match text height and alignment
-old_cursor_1 = 'className="border-l-2 border-black h-4 inline-block" style={{ animation: "blink 1s step-end infinite" }}'
-new_cursor_1 = 'className="border-l-2 border-black inline-block" style={{ animation: "blink 1s step-end infinite", height: "1.2em", marginLeft: "1px" }}'
-
-content = content.replace(old_cursor_1, new_cursor_1)
-
-# Fix 2: Also fix the other cursor instance
-old_cursor_2 = ''
-new_cursor_2 = ''
-
-content = content.replace(old_cursor_2, new_cursor_2)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed cursor positioning:")
-print(" - Removed fixed h-4 height")
-print(" - Added height: '1.2em' to match text line height")
-print(" - Added marginLeft: '1px' for better spacing from text")
-print(" - Cursor should now align properly with text")
diff --git a/fix_cursor_to_black_blinking.py b/fix_cursor_to_black_blinking.py
deleted file mode 100644
index e3f47b238c..0000000000
--- a/fix_cursor_to_black_blinking.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Making cursor black and blinking like a regular cursor...")
-
-# Fix 1: Change cursor color from grey to black and use proper blinking animation
-old_cursor_1 = 'className="animate-pulse border-l border-textSubtle h-4 inline-block"'
-new_cursor_1 = 'className="animate-blink border-l-2 border-black h-4 inline-block"'
-
-content = content.replace(old_cursor_1, new_cursor_1)
-
-# Fix 2: Also fix the cursor at the end of renderContent
-old_cursor_2 = ''
-new_cursor_2 = ''
-
-content = content.replace(old_cursor_2, new_cursor_2)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Updated cursor styling:")
-print(" - Changed from border-textSubtle (grey) to border-black")
-print(" - Changed from animate-pulse to animate-blink")
-print(" - Made border thicker (border-l-2) for better visibility")
-print(" - Now behaves like a regular text cursor")
-
-# Now we need to add the custom blink animation to the CSS
-print("\n๐ Note: We need to add the animate-blink class to Tailwind config")
-print(" This will make the cursor blink on/off like a regular text cursor")
diff --git a/fix_cursor_vertical_alignment.py b/fix_cursor_vertical_alignment.py
deleted file mode 100644
index 364860089a..0000000000
--- a/fix_cursor_vertical_alignment.py
+++ /dev/null
@@ -1,30 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing cursor vertical alignment with text...")
-
-# Find all cursor instances and fix their styling
-old_cursor_style = 'style={{ animation: "blink 1s step-end infinite", height: "1.2em", marginLeft: "1px" }}'
-new_cursor_style = 'style={{ animation: "blink 1s step-end infinite", height: "1em", marginLeft: "1px", verticalAlign: "baseline" }}'
-
-content = content.replace(old_cursor_style, new_cursor_style)
-
-# Also need to ensure the cursor aligns with the text line height
-# Let's also adjust the className to help with alignment
-old_cursor_class = 'className="border-l-2 border-black inline-block"'
-new_cursor_class = 'className="border-l-2 border-black inline-block align-baseline"'
-
-content = content.replace(old_cursor_class, new_cursor_class)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed cursor vertical alignment:")
-print(" - Changed height from 1.2em to 1em (matches text height)")
-print(" - Added verticalAlign: 'baseline' to align with text baseline")
-print(" - Added align-baseline class for consistent alignment")
-print(" - Cursor should now be centered with the text line")
diff --git a/fix_dark_mode_cursor_and_text.py b/fix_dark_mode_cursor_and_text.py
deleted file mode 100644
index 40bcb83e97..0000000000
--- a/fix_dark_mode_cursor_and_text.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing dark mode cursor color and text color...")
-
-# Fix 1: Change cursor from black to theme-aware color
-# Find all cursor instances and replace border-black with border-textDefault
-old_cursor_class = 'className="border-l-2 border-black inline-block align-baseline absolute left-0"'
-new_cursor_class = 'className="border-l-2 border-textDefault inline-block align-baseline absolute left-0"'
-
-content = content.replace(old_cursor_class, new_cursor_class)
-
-# Also fix other cursor instances in the text processing
-content = content.replace('border-l-2 border-black inline-block', 'border-l-2 border-textDefault inline-block')
-
-# Fix 2: Change placeholder text color to match text-textMuted properly
-old_placeholder_color = 'className="text-textMuted pointer-events-none select-none"'
-new_placeholder_color = 'className="text-textMuted pointer-events-none select-none"'
-
-# The placeholder color is already correct, but let's make sure it's using the right class
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed dark mode styling:")
-print(" - Changed cursor from border-black to border-textDefault")
-print(" - Cursor will now be white in dark mode, black in light mode")
-print(" - Placeholder text already uses text-textMuted which adapts to theme")
-print(" - Both cursor and text should now work properly in dark mode")
diff --git a/fix_import_issue.py b/fix_import_issue.py
deleted file mode 100644
index 1ce1be42d3..0000000000
--- a/fix_import_issue.py
+++ /dev/null
@@ -1,38 +0,0 @@
-import re
-
-# Read the ChatInput file
-with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f:
- content = f.read()
-
-# Fix the import - change from default import to named import
-old_import = "import RichChatInput, { RichChatInputRef } from './RichChatInput';"
-new_import = "import { RichChatInput, RichChatInputRef } from './RichChatInput';"
-
-content = content.replace(old_import, new_import)
-
-print("Fixed RichChatInput import to use named export")
-
-# Write the modified content back
-with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f:
- f.write(content)
-
-# Also check if we need to fix the RichChatInput export
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- rich_content = f.read()
-
-# Make sure it has both named and default exports
-if 'export default RichChatInput;' not in rich_content:
- # Add default export if missing
- rich_content = rich_content.replace(
- 'RichChatInput.displayName = \'RichChatInput\';',
- 'RichChatInput.displayName = \'RichChatInput\';\n\nexport default RichChatInput;'
- )
-
- with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(rich_content)
-
- print("Added default export to RichChatInput")
-else:
- print("RichChatInput already has default export")
-
-print("Import/export issue fixed!")
diff --git a/fix_inline_message_display.py b/fix_inline_message_display.py
deleted file mode 100644
index a33a409452..0000000000
--- a/fix_inline_message_display.py
+++ /dev/null
@@ -1,87 +0,0 @@
-import re
-
-# Read the MessageContent file
-with open('ui/desktop/src/components/MessageContent.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing MessageContent to display pills inline...")
-
-# Replace the entire return statement to fix inline display
-old_return = ''' return (
-
- );'''
-
-content = content.replace(old_container, new_container)
-
-# Also need to fix how text parts are rendered to be truly inline
-# Find the text rendering sections and make sure they're inline
-old_text_span = 'className="whitespace-pre-wrap"'
-new_text_span = 'className="inline whitespace-pre-wrap"'
-
-content = content.replace(old_text_span, new_text_span)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed multi-line cursor positioning:")
-print(" - Changed container from flex to whitespace-pre-wrap")
-print(" - Added leading-relaxed for better line height")
-print(" - Made text spans explicitly inline")
-print(" - Cursor should now stay in correct position on line breaks")
diff --git a/fix_placeholder_behavior.py b/fix_placeholder_behavior.py
deleted file mode 100644
index 12cb6b2504..0000000000
--- a/fix_placeholder_behavior.py
+++ /dev/null
@@ -1,45 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing placeholder behavior to stay visible when focused...")
-
-# Find the renderContent function and fix the placeholder logic
-old_placeholder_logic = ''' const renderContent = useCallback(() => {
- if (!value.trim() && !isFocused) {
- return (
-
- {placeholder}
-
- );
- }'''
-
-new_placeholder_logic = ''' const renderContent = useCallback(() => {
- // Show placeholder when there's no text content (regardless of focus state)
- if (!value.trim()) {
- return (
-
-
- {placeholder}
-
- {isFocused && (
-
- )}
-
- );
- }'''
-
-content = content.replace(old_placeholder_logic, new_placeholder_logic)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed placeholder behavior:")
-print(" - Changed from text-textPlaceholder to text-textSubtle (matches icon color)")
-print(" - Placeholder now stays visible when input is focused")
-print(" - Only disappears when user actually types text")
-print(" - Cursor appears alongside placeholder when focused")
-print(" - Uses absolute positioning to overlay cursor on placeholder")
diff --git a/fix_placeholder_color_lighter.py b/fix_placeholder_color_lighter.py
deleted file mode 100644
index a86b3c0b6a..0000000000
--- a/fix_placeholder_color_lighter.py
+++ /dev/null
@@ -1,22 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Changing placeholder color back to lighter original color...")
-
-# Find the placeholder text and change it back to the original lighter color
-old_placeholder_color = 'className="text-textSubtle pointer-events-none select-none"'
-new_placeholder_color = 'className="text-textPlaceholder pointer-events-none select-none"'
-
-content = content.replace(old_placeholder_color, new_placeholder_color)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed placeholder color:")
-print(" - Changed from text-textSubtle (darker grey) back to text-textPlaceholder (lighter grey)")
-print(" - Now uses the same light color as the original empty text")
-print(" - Should be more subtle and less prominent")
diff --git a/fix_placeholder_color_medium.py b/fix_placeholder_color_medium.py
deleted file mode 100644
index 9e457b7eb1..0000000000
--- a/fix_placeholder_color_medium.py
+++ /dev/null
@@ -1,22 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Changing placeholder to a medium grey color...")
-
-# Find the placeholder text and change it to text-muted (neutral-400)
-old_placeholder_color = 'className="text-textPlaceholder pointer-events-none select-none"'
-new_placeholder_color = 'className="text-textMuted pointer-events-none select-none"'
-
-content = content.replace(old_placeholder_color, new_placeholder_color)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed placeholder color:")
-print(" - Changed from text-textPlaceholder (very light) to text-textMuted (medium grey)")
-print(" - Uses --color-neutral-400 which should be more visible")
-print(" - Should be a good balance between subtle and readable")
diff --git a/fix_placeholder_positioning.py b/fix_placeholder_positioning.py
deleted file mode 100644
index b94daa0ee5..0000000000
--- a/fix_placeholder_positioning.py
+++ /dev/null
@@ -1,49 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing placeholder positioning and visibility...")
-
-# Find the placeholder rendering logic and fix the positioning
-old_placeholder_render = ''' // Show placeholder when there's no text content (regardless of focus state)
- if (!value.trim()) {
- return (
-
-
- {placeholder}
-
- {isFocused && (
-
- )}
-
- );
- }'''
-
-new_placeholder_render = ''' // Show placeholder when there's no text content (regardless of focus state)
- if (!value.trim()) {
- return (
-
-
- {placeholder}
-
- {isFocused && (
-
- )}
-
- );
- }'''
-
-content = content.replace(old_placeholder_render, new_placeholder_render)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed placeholder positioning:")
-print(" - Removed absolute positioning that was causing cutoff")
-print(" - Added min-h-[1.5em] to ensure proper container height")
-print(" - Added flex items-center for proper vertical alignment")
-print(" - Used ml-0.5 instead of marginLeft for cursor spacing")
-print(" - Placeholder should now be visible and properly positioned")
diff --git a/fix_placeholder_text_shift.py b/fix_placeholder_text_shift.py
deleted file mode 100644
index 1f5c6c06b1..0000000000
--- a/fix_placeholder_text_shift.py
+++ /dev/null
@@ -1,57 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing placeholder text shift when cursor appears...")
-
-# Find the placeholder rendering and fix it to prevent text shifting
-old_placeholder_render = ''' // Show placeholder when there's no text content (regardless of focus state)
- if (!value.trim()) {
- return (
-
- {isFocused && (
-
- )}
-
- {placeholder}
-
-
- );
- }'''
-
-new_placeholder_render = ''' // Show placeholder when there's no text content (regardless of focus state)
- if (!value.trim()) {
- return (
-
-
- {placeholder}
-
- {isFocused && (
-
- )}
-
- );
- }'''
-
-content = content.replace(old_placeholder_render, new_placeholder_render)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed placeholder text shifting:")
-print(" - Made cursor absolutely positioned so it doesn't affect layout")
-print(" - Added left-0 to position cursor at the start")
-print(" - Added top: 50% and transform: translateY(-50%) for vertical centering")
-print(" - Placeholder text now stays in exact same position when cursor appears")
diff --git a/fix_regex_error.py b/fix_regex_error.py
deleted file mode 100644
index f952564365..0000000000
--- a/fix_regex_error.py
+++ /dev/null
@@ -1,34 +0,0 @@
-import re
-
-# Read the MessageContent file
-with open('ui/desktop/src/components/MessageContent.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing regex syntax error in MessageContent...")
-
-# Fix the broken regex - the newline replacement got split
-old_broken_html = ''' dangerouslySetInnerHTML={{
- __html: part.content
- .replace(/\*\*(.*?)\*\*/g, '$1')
- .replace(/\*(.*?)\*/g, '$1')
- .replace(/`(.*?)`/g, '$1')
- .replace(/
-/g, ' ')
- }}'''
-
-new_fixed_html = ''' dangerouslySetInnerHTML={{
- __html: part.content
- .replace(/\*\*(.*?)\*\*/g, '$1')
- .replace(/\*(.*?)\*/g, '$1')
- .replace(/`(.*?)`/g, '$1')
- .replace(/\\n/g, ' ')
- }}'''
-
-content = content.replace(old_broken_html, new_fixed_html)
-
-# Write the modified content back
-with open('ui/desktop/src/components/MessageContent.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed regex syntax error")
-print("Changed .replace(/\\n/g, ' ') - newline regex was broken across lines")
diff --git a/fix_richtextinput_integration.py b/fix_richtextinput_integration.py
deleted file mode 100644
index dcbf492793..0000000000
--- a/fix_richtextinput_integration.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import re
-
-# Read the ChatInput file
-with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f:
- content = f.read()
-
-# Find the RichChatInput onChange handler and update it to handle cursor position
-old_onchange = ''' onChange={(newValue, cursorPos) => {
- setDisplayValue(newValue);
- updateValue(newValue);
- debouncedSaveDraft(newValue);
- setHasUserTyped(true);
-
- // Check for mention/action triggers with the new cursor position
- if (cursorPos !== undefined) {
- checkForMention(newValue, cursorPos, textAreaRef.current!);
- }
- }}'''
-
-new_onchange = ''' onChange={(newValue, cursorPos) => {
- setDisplayValue(newValue);
- updateValue(newValue);
- debouncedSaveDraft(newValue);
- setHasUserTyped(true);
-
- // Check for mention/action triggers with the new cursor position
- if (cursorPos !== undefined) {
- checkForMention(newValue, cursorPos, {
- getBoundingClientRect: () => textAreaRef.current?.getBoundingClientRect?.() || new DOMRect(),
- selectionStart: cursorPos,
- selectionEnd: cursorPos,
- value: newValue,
- } as HTMLTextAreaElement);
- }
- }}'''
-
-content = content.replace(old_onchange, new_onchange)
-
-# Write the modified content back
-with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("Fixed RichChatInput onChange integration with cursor position handling")
diff --git a/fix_richtextinput_processing_loop.py b/fix_richtextinput_processing_loop.py
deleted file mode 100644
index 71f257a667..0000000000
--- a/fix_richtextinput_processing_loop.py
+++ /dev/null
@@ -1,169 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing RichChatInput processing loop to handle both actions and mentions...")
-
-# Find the entire processing loop section and replace it
-# Look for the section that starts with "Process all matches in order"
-old_processing_section = ''' // Process all matches in order
- for (const matchData of allMatches) {
- const { type, match, index, length, content } = matchData;
- console.log('โ Found action match:', match);
- const beforeAction = value.slice(lastIndex, match.index);
- const actionLabel = match[1];
- console.log('๐ Processing action:', { beforeAction, actionLabel, matchIndex: match.index });
-
- // Add text before action with potential cursor
- if (beforeAction) {
- // Split text by cursor position to insert cursor at the right spot
- let textWithCursor = [];
- for (let i = 0; i < beforeAction.length; i++) {
- if (isFocused && cursorPosition === currentPos) {
- textWithCursor.push(
-
- );
- }
- textWithCursor.push(beforeAction[i]);
- currentPos++;
- }
-
- parts.push(
-
- {textWithCursor}
-
- );
- }
-
-
-
- // Find matching action
- const actionEntry = Object.entries(ACTION_MAP).find(
- ([_, config]) => config.label === actionLabel
- );
-
- if (actionEntry) {
- const [actionId, config] = actionEntry;
- parts.push(
- handleRemoveAction(actionLabel)}
- />
- );
- } else {
- // If no matching action, render as text
- parts.push(
-
- {match[0]}
-
- );
- }
-
- currentPos += match[0].length;
- lastIndex = match.index + match[0].length;
- }'''
-
-new_processing_section = ''' // Process all matches in order
- for (const matchData of allMatches) {
- const { type, match, index, length, content } = matchData;
- console.log('โ Found match:', { type, content, index });
-
- // Add text before this match with potential cursor
- const beforeMatch = value.slice(lastIndex, index);
- if (beforeMatch) {
- let textWithCursor = [];
- for (let i = 0; i < beforeMatch.length; i++) {
- if (isFocused && cursorPosition === currentPos) {
- textWithCursor.push(
-
- );
- }
- textWithCursor.push(beforeMatch[i]);
- currentPos++;
- }
-
- parts.push(
-
- {textWithCursor}
-
- );
- }
-
- // Add cursor before match if needed
- if (isFocused && cursorPosition === currentPos) {
- parts.push(
-
- );
- }
-
- if (type === 'action') {
- // Handle action pills
- const actionLabel = content;
- const actionEntry = Object.entries(ACTION_MAP).find(
- ([_, config]) => config.label === actionLabel
- );
-
- console.log('๐ท๏ธ Creating action pill:', { actionLabel, actionEntry });
-
- if (actionEntry) {
- const [actionId, config] = actionEntry;
- parts.push(
- handleRemoveAction(actionLabel)}
- />
- );
- } else {
- // If no matching action, render as text
- parts.push(
-
- {match[0]}
-
- );
- }
- } else if (type === 'mention') {
- // Handle mention pills
- const fileName = content; // filename without @
- const filePath = `@${fileName}`; // full mention text
-
- console.log('๐ Creating mention pill:', { fileName, filePath });
-
- parts.push(
- handleRemoveMention(fileName)}
- />
- );
- }
-
- currentPos += length;
- lastIndex = index + length;
- }'''
-
-content = content.replace(old_processing_section, new_processing_section)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed RichChatInput processing loop:")
-print(" - Updated to use new combined action/mention processing")
-print(" - Added proper mention pill creation")
-print(" - Added debugging logs for both types")
-print(" - Should now render @filename as green pills")
diff --git a/fix_selection_alignment.py b/fix_selection_alignment.py
deleted file mode 100644
index 87b591eca9..0000000000
--- a/fix_selection_alignment.py
+++ /dev/null
@@ -1,118 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing selection alignment - making hidden textarea match visual display exactly...")
-
-# The issue is that the hidden textarea and visual display have different positioning/padding
-# We need to make them align perfectly
-
-# Update the hidden textarea to match the visual display exactly
-old_hidden_textarea_style = ''' style={{
- position: 'absolute',
- left: 0,
- top: 0,
- width: '100%',
- height: '100%',
- opacity: 0.1, // More visible for selection
- zIndex: 2, // Higher z-index to capture mouse events
- background: 'transparent',
- border: 'none',
- outline: 'none',
- resize: 'none',
- color: 'rgba(59, 130, 246, 0.1)', // Very light blue text
- caretColor: 'transparent', // Hide caret (we show our own)
- pointerEvents: 'auto', // Ensure it can receive mouse events
- fontFamily: 'inherit',
- fontSize: 'inherit',
- lineHeight: 'inherit',
- padding: 'inherit',
- }}'''
-
-new_hidden_textarea_style = ''' style={{
- position: 'absolute',
- left: 0,
- top: 0,
- width: '100%',
- height: '100%',
- opacity: 0.15, // Slightly more visible for selection
- zIndex: 2, // Higher z-index to capture mouse events
- background: 'transparent',
- border: 'none',
- outline: 'none',
- resize: 'none',
- color: 'rgba(59, 130, 246, 0.2)', // Slightly more visible blue text
- caretColor: 'transparent', // Hide caret (we show our own)
- pointerEvents: 'auto', // Ensure it can receive mouse events
- fontFamily: 'Cash Sans, sans-serif', // Match exact font
- fontSize: '0.875rem', // Match text-sm (14px)
- lineHeight: '1.5', // Match leading-relaxed
- padding: '0', // No padding to match visual display
- margin: '0',
- boxSizing: 'border-box',
- whiteSpace: 'pre-wrap', // Match visual display
- wordWrap: 'break-word',
- }}'''
-
-content = content.replace(old_hidden_textarea_style, new_hidden_textarea_style)
-
-# Also need to make sure the visual display has consistent styling
-old_visual_display = ''' {/* Visual display with action pills and cursor */}
-
- {renderContent()}
-
'''
-
-new_visual_display = ''' {/* Visual display with action pills and cursor */}
-
- {renderContent()}
-
'''
-
-content = content.replace(old_visual_display, new_visual_display)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed selection alignment:")
-print(" - Matched font family, size, and line height exactly")
-print(" - Removed padding/margin differences")
-print(" - Added consistent white-space and word-wrap")
-print(" - Selection should now align perfectly with visual text")
-print(" - No more 'holographic' offset effect")
diff --git a/fix_selection_visibility.py b/fix_selection_visibility.py
deleted file mode 100644
index c1d1cca575..0000000000
--- a/fix_selection_visibility.py
+++ /dev/null
@@ -1,124 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing selection visibility to show over visual content...")
-
-# The issue is that selection is happening on the hidden textarea but we need it visible over the visual layer
-# Let's make the hidden textarea slightly more visible and add a selection overlay
-
-# Update the hidden textarea to be slightly more visible during selection
-old_hidden_textarea_style = ''' style={{
- position: 'absolute',
- left: 0,
- top: 0,
- width: '100%',
- height: '100%',
- opacity: 0.01, // Nearly invisible but still selectable
- zIndex: 2, // Higher z-index to capture mouse events
- background: 'transparent',
- border: 'none',
- outline: 'none',
- resize: 'none',
- color: 'transparent', // Hide text but keep selection
- caretColor: 'transparent', // Hide caret (we show our own)
- pointerEvents: 'auto', // Ensure it can receive mouse events
- }}
- className="absolute inset-0 w-full h-full resize-none selection:bg-blue-500 selection:text-white"'''
-
-new_hidden_textarea_style = ''' style={{
- position: 'absolute',
- left: 0,
- top: 0,
- width: '100%',
- height: '100%',
- opacity: 0.1, // More visible for selection
- zIndex: 2, // Higher z-index to capture mouse events
- background: 'transparent',
- border: 'none',
- outline: 'none',
- resize: 'none',
- color: 'rgba(59, 130, 246, 0.1)', // Very light blue text
- caretColor: 'transparent', // Hide caret (we show our own)
- pointerEvents: 'auto', // Ensure it can receive mouse events
- fontFamily: 'inherit',
- fontSize: 'inherit',
- lineHeight: 'inherit',
- padding: 'inherit',
- }}
- className="absolute inset-0 w-full h-full resize-none selection:bg-blue-500 selection:text-white"'''
-
-content = content.replace(old_hidden_textarea_style, new_hidden_textarea_style)
-
-# Also update the CSS to make selection more prominent
-css_update = '''
-/* Enhanced text selection styling */
-.rich-text-input textarea::selection {
- background-color: #3b82f6 !important; /* Blue-500 with !important */
- color: white !important;
- opacity: 1 !important;
-}
-
-.rich-text-input textarea::-moz-selection {
- background-color: #3b82f6 !important; /* Blue-500 with !important */
- color: white !important;
- opacity: 1 !important;
-}
-
-/* Make sure selection is visible over visual content */
-.rich-text-input {
- position: relative;
-}
-
-.rich-text-input textarea {
- mix-blend-mode: multiply; /* Blend with background for better visibility */
-}
-'''
-
-# Update the main.css file
-with open('ui/desktop/src/styles/main.css', 'r') as f:
- css_content = f.read()
-
-# Replace the existing selection CSS with enhanced version
-old_selection_css = '''/* Text selection styling for RichChatInput */
-.rich-text-input textarea::selection {
- background-color: #3b82f6; /* Blue-500 */
- color: white;
-}
-
-.rich-text-input textarea::-moz-selection {
- background-color: #3b82f6; /* Blue-500 */
- color: white;
-}
-
-/* Global selection styling for better visibility */
-::selection {
- background-color: #3b82f6; /* Blue-500 */
- color: white;
-}
-
-::-moz-selection {
- background-color: #3b82f6; /* Blue-500 */
- color: white;
-}'''
-
-if old_selection_css in css_content:
- css_content = css_content.replace(old_selection_css, css_update)
-else:
- css_content += css_update
-
-with open('ui/desktop/src/styles/main.css', 'w') as f:
- f.write(css_content)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Enhanced selection visibility:")
-print(" - Increased textarea opacity to 0.1 for better selection visibility")
-print(" - Added light blue text color for better contrast")
-print(" - Added !important to selection CSS rules")
-print(" - Added mix-blend-mode for better visual blending")
-print(" - Selection should now be much more visible")
diff --git a/fix_text_selection_behavior.py b/fix_text_selection_behavior.py
deleted file mode 100644
index f2e9ce7fb9..0000000000
--- a/fix_text_selection_behavior.py
+++ /dev/null
@@ -1,133 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing text selection behavior to work like a normal text input...")
-
-# The main issue is that we need to make the hidden textarea more accessible
-# and reduce interference from the visual display layer
-
-# First, let's update the hidden textarea to be more interactive
-old_hidden_textarea_style = ''' style={{
- position: 'absolute',
- left: 0,
- top: 0,
- width: '100%',
- height: '100%',
- opacity: 0.01, // Nearly invisible but still selectable
- zIndex: 1,
- background: 'transparent',
- border: 'none',
- outline: 'none',
- resize: 'none',
- color: 'transparent', // Hide text but keep selection
- caretColor: 'transparent', // Hide caret (we show our own)
- }}'''
-
-new_hidden_textarea_style = ''' style={{
- position: 'absolute',
- left: 0,
- top: 0,
- width: '100%',
- height: '100%',
- opacity: 0.01, // Nearly invisible but still selectable
- zIndex: 2, // Higher z-index to capture mouse events
- background: 'transparent',
- border: 'none',
- outline: 'none',
- resize: 'none',
- color: 'transparent', // Hide text but keep selection
- caretColor: 'transparent', // Hide caret (we show our own)
- pointerEvents: 'auto', // Ensure it can receive mouse events
- }}'''
-
-content = content.replace(old_hidden_textarea_style, new_hidden_textarea_style)
-
-# Update the visual display to have lower z-index and not interfere with selection
-old_visual_display = ''' {/* Visual display with action pills and cursor */}
-
- {renderContent()}
-
'''
-
-new_visual_display = ''' {/* Visual display with action pills and cursor */}
-
- {renderContent()}
-
'''
-
-content = content.replace(old_visual_display, new_visual_display)
-
-# Remove the handleDisplayClick since we're not using it anymore
-old_handle_display_click = ''' const handleDisplayClick = useCallback((e: React.MouseEvent) => {
- // Don't focus if clicking on an action pill
- if ((e.target as Element).closest('.action-pill-wrapper')) {
- return;
- }
-
- // Focus the hidden textarea for text selection
- if (hiddenTextareaRef.current) {
- hiddenTextareaRef.current.focus();
-
- // For double/triple click, select text appropriately
- if (e.detail === 2) {
- // Double click - select word (let browser handle this)
- setTimeout(() => {
- if (hiddenTextareaRef.current) {
- hiddenTextareaRef.current.select();
- }
- }, 0);
- } else if (e.detail === 3) {
- // Triple click - select all
- setTimeout(() => {
- if (hiddenTextareaRef.current) {
- hiddenTextareaRef.current.select();
- }
- }, 0);
- }
- }
- }, []);'''
-
-new_handle_display_click = ''' // Removed handleDisplayClick - let the hidden textarea handle all mouse events naturally'''
-
-content = content.replace(old_handle_display_click, new_handle_display_click)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed text selection behavior:")
-print(" - Made hidden textarea capture all mouse events (higher z-index)")
-print(" - Made visual display non-interactive (pointerEvents: 'none')")
-print(" - Removed interfering click handlers")
-print(" - Should now behave like a normal text input for selection")
-print(" - Clicking, dragging, double-click, triple-click should all work normally")
diff --git a/fix_text_selection_functionality.py b/fix_text_selection_functionality.py
deleted file mode 100644
index 8d2f586a11..0000000000
--- a/fix_text_selection_functionality.py
+++ /dev/null
@@ -1,136 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Fixing text selection functionality (highlight, double-click, triple-click)...")
-
-# The issue is that we have a hidden textarea and a visual display layer
-# We need to make sure the visual layer doesn't interfere with text selection
-
-# Find the visual display div and update its properties
-old_display_div = ''' {/* Visual display with action pills and cursor */}
-
- {renderContent()}
-
'''
-
-new_display_div = ''' {/* Visual display with action pills and cursor */}
-
- {renderContent()}
-
'''
-
-content = content.replace(old_display_div, new_display_div)
-
-# Also need to update the hidden textarea to be more accessible for selection
-old_hidden_textarea = ''' className="absolute inset-0 w-full h-full opacity-0 pointer-events-auto resize-none"
- style={{
- position: 'absolute',
- left: 0,
- top: 0,
- width: '100%',
- height: '100%',
- opacity: 0,
- zIndex: 1,
- background: 'transparent',
- border: 'none',
- outline: 'none',
- resize: 'none',
- }}'''
-
-new_hidden_textarea = ''' className="absolute inset-0 w-full h-full resize-none"
- style={{
- position: 'absolute',
- left: 0,
- top: 0,
- width: '100%',
- height: '100%',
- opacity: 0.01, // Nearly invisible but still selectable
- zIndex: 1,
- background: 'transparent',
- border: 'none',
- outline: 'none',
- resize: 'none',
- color: 'transparent', // Hide text but keep selection
- caretColor: 'transparent', // Hide caret (we show our own)
- }}'''
-
-content = content.replace(old_hidden_textarea, new_hidden_textarea)
-
-# Update handleDisplayClick to handle selection events better
-old_handle_click = ''' const handleDisplayClick = useCallback((e: React.MouseEvent) => {
- // Don't focus if clicking on an action pill
- if ((e.target as Element).closest('.action-pill-wrapper')) {
- return;
- }
- hiddenTextareaRef.current?.focus();
- }, []);'''
-
-new_handle_click = ''' const handleDisplayClick = useCallback((e: React.MouseEvent) => {
- // Don't focus if clicking on an action pill
- if ((e.target as Element).closest('.action-pill-wrapper')) {
- return;
- }
-
- // Focus the hidden textarea for text selection
- if (hiddenTextareaRef.current) {
- hiddenTextareaRef.current.focus();
-
- // For double/triple click, select text appropriately
- if (e.detail === 2) {
- // Double click - select word (let browser handle this)
- setTimeout(() => {
- if (hiddenTextareaRef.current) {
- hiddenTextareaRef.current.select();
- }
- }, 0);
- } else if (e.detail === 3) {
- // Triple click - select all
- setTimeout(() => {
- if (hiddenTextareaRef.current) {
- hiddenTextareaRef.current.select();
- }
- }, 0);
- }
- }
- }, []);'''
-
-content = content.replace(old_handle_click, new_handle_click)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Fixed text selection functionality:")
-print(" - Added userSelect: 'text' to visual display")
-print(" - Made hidden textarea slightly visible (opacity: 0.01)")
-print(" - Added double-click and triple-click handling")
-print(" - Preserved pill functionality while enabling text selection")
-print(" - Should now support highlighting, double-click, and triple-click")
diff --git a/pr_description.md b/pr_description.md
new file mode 100644
index 0000000000..e87ad390ef
--- /dev/null
+++ b/pr_description.md
@@ -0,0 +1,80 @@
+# Rich Text Input with Action and Mention Pills
+
+This PR introduces a sophisticated rich text input system that replaces plain text with visual pills for actions and file mentions, creating a more intuitive and modern chat interface.
+
+## ๐ฏ Features
+
+### Visual Pills
+- **Action Pills**: Blue circles with white icons for `/` commands (e.g., `[Quick Task]`)
+- **Mention Pills**: Blue diamonds for `@` file references (e.g., `@filename.txt`)
+- **Consistent Styling**: White pill backgrounds with blue accent icons
+- **Theme Support**: Adapts to light/dark modes
+
+### User Experience
+- **Natural Text Flow**: Pills display inline with text content
+- **Text Selection**: Full support for click/drag, double-click, triple-click
+- **Backspace Removal**: Delete entire pills as single units
+- **Proper Cursor**: Black blinking cursor with correct positioning
+- **Multi-line Support**: Cursor stays aligned on line breaks
+
+### Components Added
+- `RichChatInput.tsx`: Main rich text input with pill rendering
+- `ActionPill.tsx`: Blue circle pills for actions
+- `MentionPill.tsx`: Blue diamond pills for file mentions
+- `MessageContent.tsx`: Enhanced message display with pills
+
+## ๐ง Technical Implementation
+
+### Architecture
+- **Hidden Textarea**: Handles actual input and selection
+- **Visual Display**: Renders pills and cursor overlay
+- **Perfect Alignment**: Synchronized font, padding, and positioning
+- **Event Handling**: Proper mouse/keyboard event delegation
+
+### Pattern Matching
+- **Actions**: `/action` โ `[Action Name]` โ Blue circle pill
+- **Mentions**: `@filename` โ Blue diamond pill
+- **Mixed Content**: Supports both types inline with text
+
+### Accessibility
+- **Keyboard Navigation**: Full keyboard support maintained
+- **Screen Readers**: Proper ARIA attributes and roles
+- **Selection**: Standard text selection behaviors preserved
+
+## ๐จ Visual Design
+
+### Before
+```
+Hello /quick-task and @file.txt world
+```
+
+### After
+```
+Hello [Quick Task] and @file.txt world
+ โ blue circle โ blue diamond
+```
+
+### Message History
+Pills appear in sent messages maintaining the same visual style and inline flow.
+
+## ๐งช Testing
+
+Tested extensively for:
+- โ Action pill creation via `/` command
+- โ File mention pills via `@` command
+- โ Text selection and highlighting
+- โ Cursor positioning and movement
+- โ Backspace pill removal
+- โ Multi-line text handling
+- โ Light/dark theme compatibility
+- โ Message history display
+
+## ๐ Impact
+
+This creates a modern chat interface similar to Slack/Discord with:
+- **Improved UX**: Visual pills are easier to understand than plain text
+- **Better Organization**: Clear distinction between actions and file references
+- **Enhanced Workflow**: Faster recognition of commands and mentions
+- **Professional Appearance**: Polished, modern interface design
+
+The implementation maintains full backward compatibility while significantly enhancing the user experience.
diff --git a/replace_textarea.py b/replace_textarea.py
deleted file mode 100644
index 5e1c456fbb..0000000000
--- a/replace_textarea.py
+++ /dev/null
@@ -1,60 +0,0 @@
-import re
-
-# Read the ChatInput file
-with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f:
- content = f.read()
-
-# Find and replace the textarea element with RichTextInput
-textarea_start = content.find('')
-if textarea_end == -1:
- print("Textarea end not found")
- exit(1)
-
-# Extract the old textarea
-old_textarea = content[textarea_start:textarea_end]
-print(f"Found textarea from {textarea_start} to {textarea_end}")
-
-# Create the new RichTextInput component
-new_richtextinput = ''' {
- setDisplayValue(newValue);
- setValue(newValue);
- setActions(newActions);
- debouncedSaveDraft(newValue);
- setHasUserTyped(true);
- checkForMention(newValue, textAreaRef.current?.selectionStart || 0, textAreaRef.current!);
- }}
- onKeyDown={handleKeyDown}
- onPaste={handlePaste}
- onFocus={() => setIsFocused(true)}
- onBlur={() => setIsFocused(false)}
- onCompositionStart={handleCompositionStart}
- onCompositionEnd={handleCompositionEnd}
- placeholder={isRecording ? '' : 'โโ/โโ to navigate messages'}
- disabled={isUserInputDisabled}
- style={{
- maxHeight: `${maxHeight}px`,
- overflowY: 'auto',
- opacity: isRecording ? 0 : 1,
- }}
- className="w-full outline-none border-none focus:ring-0 bg-transparent px-3 pt-3 pb-1.5 pr-20 text-sm resize-none text-textStandard placeholder:text-textPlaceholder"
- actions={actions}
- maxHeight={maxHeight}
- />'''
-
-# Replace the textarea with RichTextInput
-content = content[:textarea_start] + new_richtextinput + content[textarea_end:]
-
-# Write the modified content back
-with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("Textarea replaced with RichTextInput successfully")
diff --git a/simple_inline_pills.py b/simple_inline_pills.py
deleted file mode 100644
index 0cc0be2166..0000000000
--- a/simple_inline_pills.py
+++ /dev/null
@@ -1,50 +0,0 @@
-import re
-
-# Read the ChatInput file
-with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f:
- content = f.read()
-
-# Simple approach: Just remove the "Selected Actions Pills" section
-# Find the section that starts with {/* Selected Actions Pills */}
-start_marker = '{/* Selected Actions Pills */}'
-start_pos = content.find(start_marker)
-
-if start_pos != -1:
- # Find the end of this section - look for the closing div and brace
- # We need to find the matching closing brace for the conditional
- lines = content[start_pos:].split('\n')
- brace_count = 0
- end_line = 0
-
- for i, line in enumerate(lines):
- if i == 0: # First line with the comment
- continue
-
- # Count braces to find the end of the conditional
- open_braces = line.count('{')
- close_braces = line.count('}')
- brace_count += open_braces - close_braces
-
- # Look for the end pattern
- if ')}\n' in line or line.strip() == ')}':
- end_line = i + 1
- break
-
- if end_line > 0:
- # Calculate the end position
- end_pos = start_pos + len('\n'.join(lines[:end_line]))
-
- # Remove the section
- content = content[:start_pos] + content[end_pos:]
-
- print(f"Removed Selected Actions Pills section from position {start_pos} to {end_pos}")
- else:
- print("Could not find end of Selected Actions Pills section")
-else:
- print("Selected Actions Pills section not found")
-
-# Write the modified content back
-with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("ChatInput.tsx updated - Selected Actions Pills section removed")
diff --git a/test_action_flow.py b/test_action_flow.py
deleted file mode 100644
index 1fd1a5c761..0000000000
--- a/test_action_flow.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# Let's create a simple test to verify the action flow
-print("๐งช Testing Action Flow Components")
-print("=" * 50)
-
-# Check if files exist and have the right structure
-import os
-
-files_to_check = [
- 'ui/desktop/src/components/ChatInput.tsx',
- 'ui/desktop/src/components/RichChatInput.tsx',
- 'ui/desktop/src/components/ActionPill.tsx',
- 'ui/desktop/src/components/ActionPopover.tsx'
-]
-
-for file_path in files_to_check:
- if os.path.exists(file_path):
- print(f"โ {file_path} exists")
-
- with open(file_path, 'r') as f:
- content = f.read()
-
- if 'ChatInput.tsx' in file_path:
- if 'handleActionSelect' in content:
- print(" โ handleActionSelect function found")
- if 'actionPopover' in content:
- print(" โ actionPopover state found")
- if 'cursorPosition' in content:
- print(" โ cursorPosition handling found")
-
- elif 'RichChatInput.tsx' in file_path:
- if 'actionRegex' in content:
- print(" โ actionRegex found")
- if 'ActionPill' in content:
- print(" โ ActionPill import found")
- if 'renderContent' in content:
- print(" โ renderContent function found")
-
- elif 'ActionPill.tsx' in file_path:
- if 'ActionPillProps' in content:
- print(" โ ActionPillProps interface found")
-
- elif 'ActionPopover.tsx' in file_path:
- if 'onSelect' in content:
- print(" โ onSelect prop found")
- else:
- print(f"โ {file_path} missing")
-
-print("\n๐ Key Integration Points:")
-print("1. ChatInput imports RichChatInput โ ")
-print("2. RichChatInput imports ActionPill โ ")
-print("3. ChatInput has handleActionSelect โ ")
-print("4. ActionPopover calls handleActionSelect โ ")
-print("5. RichChatInput renders [Action] as pills โ ")
-
-print("\n๐ฏ Test Plan:")
-print("1. Type '/' in chat input")
-print("2. Action popover should appear")
-print("3. Click an action (e.g., 'Quick Task')")
-print("4. Should see '[Quick Task]' appear as a pill in the input")
-print("5. Cursor should be positioned after the pill")
-
-print("\n๐ Debug Steps:")
-print("1. Open browser dev tools")
-print("2. Look for console logs starting with ๐ฏ, ๐, ๐, etc.")
-print("3. Check if handleActionSelect is called")
-print("4. Check if text replacement happens")
-print("5. Check if RichChatInput re-renders with new value")
diff --git a/test_basic_functionality.py b/test_basic_functionality.py
deleted file mode 100644
index 56df53c110..0000000000
--- a/test_basic_functionality.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# Let's create a simple test to verify if the basic text replacement is working
-print("๐งช Testing Basic Text Replacement")
-print("=" * 50)
-
-# Read the handleActionSelect function
-with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f:
- content = f.read()
-
-# Check if the function exists and has the right structure
-if 'handleActionSelect' in content:
- print("โ handleActionSelect function found")
-
- # Check for key components
- if 'setDisplayValue(newValue)' in content:
- print("โ setDisplayValue call found")
- if 'setValue(newValue)' in content:
- print("โ setValue call found")
- if 'actionInfo.label' in content:
- print("โ actionInfo.label usage found")
- if 'lastSlashIndex' in content:
- print("โ slash detection logic found")
-
- # Extract the function for analysis
- start = content.find('const handleActionSelect = (actionId: string) => {')
- if start != -1:
- # Find the end of the function
- brace_count = 0
- pos = start
- while pos < len(content):
- if content[pos] == '{':
- brace_count += 1
- elif content[pos] == '}':
- brace_count -= 1
- if brace_count == 0:
- end = pos + 1
- break
- pos += 1
-
- function_code = content[start:end]
- print(f"\n๐ Function length: {len(function_code)} characters")
-
- # Check for potential issues
- if 'cursorPosition = 0' in function_code:
- print("โ ๏ธ WARNING: cursorPosition hardcoded to 0")
- if 'actionPopover.cursorPosition' in function_code:
- print("โ Using actionPopover.cursorPosition")
- if 'console.log' in function_code:
- print("โ Debug logging present")
-
-else:
- print("โ handleActionSelect function not found")
-
-print("\n๐ Checking RichChatInput integration...")
-
-# Check RichChatInput
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- rich_content = f.read()
-
-if 'actionRegex = /\\[([^\\]]+)\\]/g' in rich_content:
- print("โ Action regex pattern found")
-if 'ActionPill' in rich_content:
- print("โ ActionPill component imported")
-if 'renderContent' in rich_content:
- print("โ renderContent function found")
-
-print("\n๐ฏ Next Steps:")
-print("1. Open browser dev tools")
-print("2. Type '/' in chat input")
-print("3. Click an action")
-print("4. Look for these console messages:")
-print(" - ๐ฏ ActionPopover: handleItemClick called")
-print(" - ๐ฏ handleActionSelect called with:")
-print(" - ๐ Current state:")
-print(" - ๐ Text replacement:")
-print(" - ๐จ RichChatInput renderContent called")
-
-print("\n๐ก If no console logs appear:")
-print("- ActionPopover might not be calling onSelect")
-print("- handleActionSelect might not be connected")
-print("- Check for JavaScript errors in console")
diff --git a/test_mention_functionality.py b/test_mention_functionality.py
deleted file mode 100644
index 2005a6ca00..0000000000
--- a/test_mention_functionality.py
+++ /dev/null
@@ -1,63 +0,0 @@
-print("๐งช Testing Mention Pill Functionality")
-print("=" * 50)
-
-# Check if all files exist and have the right structure
-import os
-
-files_to_check = [
- 'ui/desktop/src/components/MentionPill.tsx',
- 'ui/desktop/src/components/RichChatInput.tsx',
- 'ui/desktop/src/components/MessageContent.tsx',
- 'ui/desktop/src/components/ChatInput.tsx'
-]
-
-for file_path in files_to_check:
- if os.path.exists(file_path):
- print(f"โ {file_path} exists")
-
- with open(file_path, 'r') as f:
- content = f.read()
-
- if 'MentionPill.tsx' in file_path:
- if 'MentionPillProps' in content:
- print(" โ MentionPillProps interface found")
- if 'fileName' in content and 'filePath' in content:
- print(" โ fileName and filePath props found")
-
- elif 'RichChatInput.tsx' in file_path:
- if 'import MentionPill' in content:
- print(" โ MentionPill import found")
- else:
- print(" โ MentionPill import missing!")
- if 'mentionRegex' in content:
- print(" โ mentionRegex found")
- if 'handleRemoveMention' in content:
- print(" โ handleRemoveMention function found")
-
- elif 'MessageContent.tsx' in file_path:
- if 'import MentionPill' in content:
- print(" โ MentionPill import found")
- else:
- print(" โ MentionPill import missing!")
- if 'mentionRegex' in content:
- print(" โ mentionRegex found")
-
- elif 'ChatInput.tsx' in file_path:
- if 'handleMentionFileSelect' in content:
- print(" โ handleMentionFileSelect function found")
- if '@${fileName}' in content:
- print(" โ @filename format creation found")
- else:
- print(f"โ {file_path} missing")
-
-print("\n๐ฏ Test Plan:")
-print("1. Type '@' in chat input")
-print("2. Select a file from the popover")
-print("3. Should see green pill with filename")
-print("4. Check browser console for debug logs")
-
-print("\n๐ Debug Steps:")
-print("1. Open browser dev tools")
-print("2. Look for console logs starting with ๐, ๐, โ ")
-print("3. Check if MentionPill component renders")
-print("4. Verify @filename pattern is detected")
diff --git a/update_chatinput_mention_handling.py b/update_chatinput_mention_handling.py
deleted file mode 100644
index 27d91aee97..0000000000
--- a/update_chatinput_mention_handling.py
+++ /dev/null
@@ -1,67 +0,0 @@
-import re
-
-# Read the ChatInput file
-with open('ui/desktop/src/components/ChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Updating ChatInput to convert @filename to pills when selected...")
-
-# Find the handleMentionFileSelect function and update it to create pill format
-old_mention_select = ''' const handleMentionFileSelect = (filePath: string) => {
- const beforeMention = displayValue.slice(0, mentionPopover.mentionStart);
- const afterMention = displayValue.slice(
- textAreaRef.current?.selectionStart || displayValue.length
- );
- const newValue = `${beforeMention}${filePath}${afterMention}`;
-
- setDisplayValue(newValue);
- setValue(newValue);
- setMentionPopover((prev) => ({ ...prev, isOpen: false }));
- textAreaRef.current?.focus();
-
- // Set cursor position after the inserted file path
- setTimeout(() => {
- if (textAreaRef.current) {
- // Cursor positioning handled by RichChatInput
- // Focus handled by RichChatInput
- }
- }, 0);
- };'''
-
-new_mention_select = ''' const handleMentionFileSelect = (filePath: string) => {
- const beforeMention = displayValue.slice(0, mentionPopover.mentionStart);
- const afterMention = displayValue.slice(
- textAreaRef.current?.selectionStart || displayValue.length
- );
-
- // Extract just the filename from the path for the pill
- const fileName = filePath.split('/').pop() || filePath;
- const mentionText = `@${fileName}`;
- const newValue = `${beforeMention}${mentionText} ${afterMention}`;
-
- setDisplayValue(newValue);
- setValue(newValue);
- setMentionPopover((prev) => ({ ...prev, isOpen: false }));
- textAreaRef.current?.focus();
-
- // Set cursor position after the inserted mention and space
- const newCursorPosition = beforeMention.length + mentionText.length + 1;
- setTimeout(() => {
- if (textAreaRef.current) {
- textAreaRef.current.setSelectionRange(newCursorPosition, newCursorPosition);
- textAreaRef.current.focus();
- }
- }, 0);
- };'''
-
-content = content.replace(old_mention_select, new_mention_select)
-
-# Write the modified content back
-with open('ui/desktop/src/components/ChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Updated ChatInput mention handling:")
-print(" - Modified handleMentionFileSelect to create @filename format")
-print(" - Extracts filename from full path for cleaner pills")
-print(" - Adds space after mention for better UX")
-print(" - Sets cursor position properly after insertion")
diff --git a/update_mention_pill_styling.py b/update_mention_pill_styling.py
deleted file mode 100644
index 5752a555bf..0000000000
--- a/update_mention_pill_styling.py
+++ /dev/null
@@ -1,31 +0,0 @@
-import re
-
-# Read the MentionPill file
-with open('ui/desktop/src/components/MentionPill.tsx', 'r') as f:
- content = f.read()
-
-print("Updating MentionPill styling to match ActionPill (white background, same spacing)...")
-
-# Update the variantClasses to match ActionPill styling
-old_variant_classes = ''' const variantClasses = {
- default: "bg-green-100 text-green-800 border-green-200 dark:bg-green-900 dark:text-green-200 dark:border-green-700",
- message: "bg-green-100 text-green-800 border-green-200 dark:bg-green-900 dark:text-green-200 dark:border-green-700"
- };'''
-
-new_variant_classes = ''' const variantClasses = {
- default: "bg-bgProminent text-textProminentInverse border-borderProminent",
- message: "bg-bgProminent text-textProminentInverse border-borderProminent"
- };'''
-
-content = content.replace(old_variant_classes, new_variant_classes)
-
-# Write the modified content back
-with open('ui/desktop/src/components/MentionPill.tsx', 'w') as f:
- f.write(content)
-
-print("โ Updated MentionPill styling:")
-print(" - Changed from green colors to theme-aware white background")
-print(" - Now uses bg-bgProminent text-textProminentInverse border-borderProminent")
-print(" - Same styling as ActionPill (white background, proper contrast)")
-print(" - Maintains same spacing and padding (px-2 py-1 text-xs)")
-print(" - Both pills now have consistent appearance")
diff --git a/update_message_content_for_mentions.py b/update_message_content_for_mentions.py
deleted file mode 100644
index 578578abb9..0000000000
--- a/update_message_content_for_mentions.py
+++ /dev/null
@@ -1,249 +0,0 @@
-import re
-
-# Read the MessageContent file
-with open('ui/desktop/src/components/MessageContent.tsx', 'r') as f:
- content = f.read()
-
-print("Updating MessageContent to support mention pills in sent messages...")
-
-# Add MentionPill import
-old_imports = """import React, { useMemo } from 'react';
-import MarkdownContent from './MarkdownContent';
-import ActionPill from './ActionPill';
-import { Zap, Code, FileText, Search, Play, Settings } from 'lucide-react';"""
-
-new_imports = """import React, { useMemo } from 'react';
-import MarkdownContent from './MarkdownContent';
-import ActionPill from './ActionPill';
-import MentionPill from './MentionPill';
-import { Zap, Code, FileText, Search, Play, Settings } from 'lucide-react';"""
-
-content = content.replace(old_imports, new_imports)
-
-# Update the parsedContent logic to handle both actions and mentions
-old_parsing_logic = ''' const parsedContent = useMemo(() => {
- // Find all [Action] patterns and replace them with pill components
- const actionRegex = /\[([^\]]+)\]/g;
- const parts: Array<{ type: 'text' | 'action'; content: string; actionId?: string }> = [];
- let currentIndex = 0;
- let match;
-
- while ((match = actionRegex.exec(content)) !== null) {
- // Add text before the action
- if (match.index > currentIndex) {
- parts.push({
- type: 'text',
- content: content.slice(currentIndex, match.index),
- });
- }
-
- // Add the action
- const actionLabel = match[1];
- const actionId = getActionIdFromLabel(actionLabel);
-
- parts.push({
- type: 'action',
- content: actionLabel,
- actionId: actionId,
- });
-
- currentIndex = match.index + match[0].length;
- }
-
- // Add remaining text
- if (currentIndex < content.length) {
- parts.push({
- type: 'text',
- content: content.slice(currentIndex),
- });
- }
-
- // If no actions found, return the original content as a single text part
- if (parts.length === 0) {
- parts.push({
- type: 'text',
- content: content,
- });
- }
-
- return parts;
- }, [content]);'''
-
-new_parsing_logic = ''' const parsedContent = useMemo(() => {
- // Find all [Action] and @mention patterns and replace them with pill components
- const actionRegex = /\[([^\]]+)\]/g;
- const mentionRegex = /@([^\s]+)/g;
- const parts: Array<{ type: 'text' | 'action' | 'mention'; content: string; actionId?: string; fileName?: string }> = [];
-
- // Find all matches and sort by position
- const allMatches = [];
-
- // Find all action matches
- let actionMatch;
- actionRegex.lastIndex = 0;
- while ((actionMatch = actionRegex.exec(content)) !== null) {
- allMatches.push({
- type: 'action',
- index: actionMatch.index,
- length: actionMatch[0].length,
- content: actionMatch[1]
- });
- }
-
- // Find all mention matches
- let mentionMatch;
- mentionRegex.lastIndex = 0;
- while ((mentionMatch = mentionRegex.exec(content)) !== null) {
- allMatches.push({
- type: 'mention',
- index: mentionMatch.index,
- length: mentionMatch[0].length,
- content: mentionMatch[1] // filename without @
- });
- }
-
- // Sort matches by position
- allMatches.sort((a, b) => a.index - b.index);
-
- let currentIndex = 0;
-
- // Process all matches in order
- for (const match of allMatches) {
- // Add text before this match
- if (match.index > currentIndex) {
- parts.push({
- type: 'text',
- content: content.slice(currentIndex, match.index),
- });
- }
-
- if (match.type === 'action') {
- // Add the action
- const actionLabel = match.content;
- const actionId = getActionIdFromLabel(actionLabel);
-
- parts.push({
- type: 'action',
- content: actionLabel,
- actionId: actionId,
- });
- } else if (match.type === 'mention') {
- // Add the mention
- parts.push({
- type: 'mention',
- content: match.content, // filename without @
- fileName: match.content,
- });
- }
-
- currentIndex = match.index + match.length;
- }
-
- // Add remaining text
- if (currentIndex < content.length) {
- parts.push({
- type: 'text',
- content: content.slice(currentIndex),
- });
- }
-
- // If no matches found, return the original content as a single text part
- if (parts.length === 0) {
- parts.push({
- type: 'text',
- content: content,
- });
- }
-
- return parts;
- }, [content]);'''
-
-content = content.replace(old_parsing_logic, new_parsing_logic)
-
-# Update the rendering logic to handle mention pills
-old_rendering = ''' {parsedContent.map((part, index) => {
- if (part.type === 'action' && part.actionId) {
- const actionInfo = getActionInfo(part.actionId);
- return (
-
- );
- } else if (part.content.trim()) {
- return (
- $1')
- .replace(/\*(.*?)\*/g, '$1')
- .replace(/`(.*?)`/g, '$1')
- .replace(/\\n/g, ' ')
- }}
- />
- );
- }
- return null;
- })}'''
-
-new_rendering = ''' {parsedContent.map((part, index) => {
- if (part.type === 'action' && part.actionId) {
- const actionInfo = getActionInfo(part.actionId);
- return (
-
- );
- } else if (part.type === 'mention' && part.fileName) {
- return (
-
- );
- } else if (part.content.trim()) {
- return (
- $1')
- .replace(/\*(.*?)\*/g, '$1')
- .replace(/`(.*?)`/g, '$1')
- .replace(/\\n/g, ' ')
- }}
- />
- );
- }
- return null;
- })}'''
-
-content = content.replace(old_rendering, new_rendering)
-
-# Write the modified content back
-with open('ui/desktop/src/components/MessageContent.tsx', 'w') as f:
- f.write(content)
-
-print("โ Updated MessageContent for mention pills:")
-print(" - Added MentionPill import")
-print(" - Updated parsing logic to detect both [Action] and @mention patterns")
-print(" - Added mention pill rendering in sent messages")
-print(" - Mentions will appear as green pills in message history")
diff --git a/update_pill_icons.py b/update_pill_icons.py
deleted file mode 100644
index 632a899ea4..0000000000
--- a/update_pill_icons.py
+++ /dev/null
@@ -1,70 +0,0 @@
-import re
-
-print("Updating pill icons: blue diamond for documents, blue circle for actions...")
-
-# First, update MentionPill to use blue diamond icon
-with open('ui/desktop/src/components/MentionPill.tsx', 'r') as f:
- mention_content = f.read()
-
-# Replace the File import and icon with a blue diamond
-old_mention_imports = "import { X, File } from 'lucide-react';"
-new_mention_imports = "import { X, Diamond } from 'lucide-react';"
-
-mention_content = mention_content.replace(old_mention_imports, new_mention_imports)
-
-# Replace the File icon with Diamond icon and add blue color
-old_mention_icon = '''
-
- {fileName}
- '''
-
-new_mention_icon = '''
-
- {fileName}
- '''
-
-mention_content = mention_content.replace(old_mention_icon, new_mention_icon)
-
-# Write the updated MentionPill
-with open('ui/desktop/src/components/MentionPill.tsx', 'w') as f:
- f.write(mention_content)
-
-print("โ Updated MentionPill:")
-print(" - Changed from File icon to Diamond icon")
-print(" - Added blue color (text-blue-500 fill-blue-500)")
-
-# Now update ActionPill to use blue circle icons
-with open('ui/desktop/src/components/ActionPill.tsx', 'r') as f:
- action_content = f.read()
-
-# We need to modify how the icon is rendered to add blue color
-# Find the icon rendering section
-old_action_icon = '''
- {icon}
- {label}
- '''
-
-new_action_icon = '''
-
-
-
- {icon}
-
-
- {label}
- '''
-
-action_content = action_content.replace(old_action_icon, new_action_icon)
-
-# Write the updated ActionPill
-with open('ui/desktop/src/components/ActionPill.tsx', 'w') as f:
- f.write(action_content)
-
-print("โ Updated ActionPill:")
-print(" - Added blue circle background for icons")
-print(" - Icons now appear as white symbols on blue circles")
-
-print("\n๐ฏ Result:")
-print(" - Document pills: Blue diamond icon + filename")
-print(" - Action pills: Blue circle with white action icon + label")
-print(" - Both maintain white pill background with consistent styling")
diff --git a/update_richtextinput_for_mentions.py b/update_richtextinput_for_mentions.py
deleted file mode 100644
index 3bae6b0ada..0000000000
--- a/update_richtextinput_for_mentions.py
+++ /dev/null
@@ -1,93 +0,0 @@
-import re
-
-# Read the RichChatInput file
-with open('ui/desktop/src/components/RichChatInput.tsx', 'r') as f:
- content = f.read()
-
-print("Updating RichChatInput to support mention pills...")
-
-# Add MentionPill import
-old_imports = "import { ActionPill } from './ActionPill';"
-new_imports = """import { ActionPill } from './ActionPill';
-import MentionPill from './MentionPill';"""
-
-content = content.replace(old_imports, new_imports)
-
-# Update the renderContent function to handle both actions and mentions
-# Find the while loop that processes actions and extend it to handle mentions too
-old_regex_section = ''' const parts: React.ReactNode[] = [];
- const actionRegex = /\[([^\]]+)\]/g;
- let lastIndex = 0;
- let match;
- let keyCounter = 0;
- let currentPos = 0; // Track position for cursor placement'''
-
-new_regex_section = ''' const parts: React.ReactNode[] = [];
- const actionRegex = /\[([^\]]+)\]/g;
- const mentionRegex = /@([^\s]+)/g; // Match @filename patterns
- let lastIndex = 0;
- let match;
- let keyCounter = 0;
- let currentPos = 0; // Track position for cursor placement'''
-
-content = content.replace(old_regex_section, new_regex_section)
-
-# Now we need to process both actions and mentions in the correct order
-# Find the existing while loop and replace it with a more comprehensive approach
-old_while_loop_start = ''' console.log('๐จ RichChatInput renderContent called with value:', value);
- console.log('๐ Looking for action patterns with regex:', actionRegex);
-
- while ((match = actionRegex.exec(value)) !== null) {'''
-
-new_while_loop_start = ''' console.log('๐จ RichChatInput renderContent called with value:', value);
- console.log('๐ Looking for action and mention patterns with regex:', { actionRegex, mentionRegex });
-
- // Find all actions and mentions, then sort by position
- const allMatches = [];
-
- // Find all action matches
- let actionMatch;
- actionRegex.lastIndex = 0; // Reset regex
- while ((actionMatch = actionRegex.exec(value)) !== null) {
- allMatches.push({
- type: 'action',
- match: actionMatch,
- index: actionMatch.index,
- length: actionMatch[0].length,
- content: actionMatch[1]
- });
- }
-
- // Find all mention matches
- let mentionMatch;
- mentionRegex.lastIndex = 0; // Reset regex
- while ((mentionMatch = mentionRegex.exec(value)) !== null) {
- allMatches.push({
- type: 'mention',
- match: mentionMatch,
- index: mentionMatch.index,
- length: mentionMatch[0].length,
- content: mentionMatch[1] // filename without @
- });
- }
-
- // Sort matches by position
- allMatches.sort((a, b) => a.index - b.index);
-
- console.log('๐ Found matches:', allMatches);
-
- // Process all matches in order
- for (const matchData of allMatches) {
- const { type, match, index, length, content } = matchData;'''
-
-content = content.replace(old_while_loop_start, new_while_loop_start)
-
-# Write the modified content back
-with open('ui/desktop/src/components/RichChatInput.tsx', 'w') as f:
- f.write(content)
-
-print("โ Updated RichChatInput imports and regex setup:")
-print(" - Added MentionPill import")
-print(" - Added mentionRegex to detect @filename patterns")
-print(" - Started updating processing logic to handle both actions and mentions")
-print(" - Next step: Update the processing loop to render mention pills")