# Chat UX Improvements - Implementation Guide **Quick Start Guide for Implementing Chat UX Enhancements** --- ## Phase 1: Auto-Session Creation (CRITICAL) ### Step 1: Update URL Parameter Handling **File:** `/home/uroma/obsidian-web-interface/public/claude-ide/ide.js` **Find lines 18-46** and replace with: ```javascript document.addEventListener('DOMContentLoaded', () => { initNavigation(); connectWebSocket(); // Check URL params for session, project, or prompt const urlParams = new URLSearchParams(window.location.search); const projectParam = urlParams.get('project'); const sessionId = urlParams.get('session'); const prompt = urlParams.get('prompt'); if (projectParam) { // NEW: Handle project parameter - auto-create session console.log('Project parameter detected:', projectParam); switchView('chat'); setTimeout(() => { initializeFromProjectURL(projectParam, prompt); }, 500); } else if (sessionId || prompt) { // EXISTING: Handle session/prompt parameters switchView('chat'); setTimeout(() => { if (sessionId) { attachToSession(sessionId); } if (prompt) { setTimeout(() => { const input = document.getElementById('chat-input'); if (input) { input.value = decodeURIComponent(prompt); sendChatMessage(); } }, 1000); } }, 500); } else { // NEW: Check for saved session before defaulting const savedSession = getSessionFromStorage(); if (savedSession) { console.log('Restoring saved session:', savedSession.id); switchView('chat'); setTimeout(() => { attachToSession(savedSession.id); }, 500); } else { // Default to chat view switchView('chat'); } } }); ``` ### Step 2: Add New Functions to chat-functions.js **File:** `/home/uroma/obsidian-web-interface/public/claude-ide/chat-functions.js` **Add at the end of the file (before the window exports):** ```javascript // ============================================ // Project URL Auto-Session Creation // ============================================ /** * Initialize chat session from project URL parameter * @param {string} projectParam - Base64 encoded project path * @param {string} initialPrompt - Optional initial prompt to auto-send */ async function initializeFromProjectURL(projectParam, initialPrompt = null) { console.log('[initializeFromProjectURL] Starting...', { projectParam, initialPrompt }); try { // Decode base64 path let projectPath; try { projectPath = atob(projectParam); console.log('[initializeFromProjectURL] Decoded path:', projectPath); } catch (error) { console.error('[initializeFromProjectURL] Base64 decode error:', error); appendSystemMessage('❌ Invalid project path encoding'); return; } // Validate path looks reasonable if (!projectPath.startsWith('/')) { throw new Error('Invalid project path (must be absolute)'); } // Show loading message appendSystemMessage('⏳ Creating session for project...'); // Create session with project directory console.log('[initializeFromProjectURL] Creating session...'); const res = await fetch('/claude/api/claude/sessions', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ workingDir: projectPath, metadata: { project: extractProjectName(projectPath), type: 'project-url', source: 'web-ide' } }) }); console.log('[initializeFromProjectURL] Session creation response:', res.status); if (!res.ok) { const errorText = await res.text(); throw new Error(`HTTP ${res.status}: ${errorText}`); } const data = await res.json(); console.log('[initializeFromProjectURL] Session data:', data); if (data.success) { attachedSessionId = data.session.id; chatSessionId = data.session.id; console.log('[initializeFromProjectURL] Session created:', data.session.id); // Update UI with project info updateSessionUI({ id: data.session.id, workingDir: projectPath, project: extractProjectName(projectPath), status: 'running' }); // Subscribe to session subscribeToSession(data.session.id); // Reload sidebar to show new session loadChatView(); // Show success message appendSystemMessage(`✅ Session ready! Working in ${escapeHtml(extractProjectName(projectPath))}`); // Auto-send initial prompt if provided if (initialPrompt) { console.log('[initializeFromProjectURL] Auto-sending initial prompt'); setTimeout(() => { const input = document.getElementById('chat-input'); if (input) { input.value = decodeURIComponent(initialPrompt); sendChatMessage(); } }, 1000); } } else { console.error('[initializeFromProjectURL] Session creation failed:', data); appendSystemMessage('❌ Failed to create session: ' + (data.error || 'Unknown error')); } } catch (error) { console.error('[initializeFromProjectURL] Error:', error); appendSystemMessage('❌ Failed to create session: ' + error.message); } } /** * Extract project name from file path */ function extractProjectName(path) { const parts = path.split('/'); const name = parts[parts.length - 1] || 'Untitled Project'; return name; } /** * Update session UI with context information */ function updateSessionUI(session) { console.log('[updateSessionUI] Updating UI with session:', session); // Update session ID display const sessionIdEl = document.getElementById('current-session-id'); if (sessionIdEl) { sessionIdEl.textContent = session.id; } // Update title const chatTitleEl = document.getElementById('chat-title'); if (chatTitleEl) { chatTitleEl.textContent = session.project || 'New Chat'; } // Create or update session status bar let statusBar = document.querySelector('.session-status-bar'); if (!statusBar) { // Create status bar if it doesn't exist statusBar = document.createElement('div'); statusBar.className = 'session-status-bar'; // Insert after chat header const chatHeader = document.getElementById('chat-header'); if (chatHeader && chatHeader.parentNode) { chatHeader.parentNode.insertBefore(statusBar, chatHeader.nextSibling); } } // Update status bar content if (statusBar) { statusBar.innerHTML = `
📁 ${escapeHtml(truncatePath(session.workingDir, 50))}
Active ${session.status || 'running'}
`; } // Save to localStorage for persistence saveSessionState(session); } /** * Truncate path for display */ function truncatePath(path, maxLength) { if (path.length <= maxLength) return path; return '...' + path.slice(-(maxLength - 3)); } /** * Save session state to localStorage */ function saveSessionState(session) { try { const state = { id: session.id, workingDir: session.workingDir, project: session.project, timestamp: Date.now() }; localStorage.setItem('claude_chat_session', JSON.stringify(state)); console.log('[saveSessionState] Session saved:', state.id); } catch (error) { console.error('[saveSessionState] Error saving session:', error); } } /** * Get session state from localStorage */ function getSessionFromStorage() { try { const saved = localStorage.getItem('claude_chat_session'); if (!saved) return null; const session = JSON.parse(saved); // Only restore if recent (< 1 hour) const age = Date.now() - session.timestamp; if (age > 3600000) { console.log('[getSessionFromStorage] Session too old, removing'); localStorage.removeItem('claude_chat_session'); return null; } console.log('[getSessionFromStorage] Found saved session:', session.id); return session; } catch (error) { console.error('[getSessionFromStorage] Error:', error); return null; } } /** * Clear session state from localStorage */ function clearSessionState() { try { localStorage.removeItem('claude_chat_session'); console.log('[clearSessionState] Session cleared'); } catch (error) { console.error('[clearSessionState] Error:', error); } } ``` ### Step 3: Add CSS for Session Status Bar **File:** `/home/uroma/obsidian-web-interface/public/claude-ide/chat-enhanced.css` **Add at the end of the file:** ```css /* ============================================ Session Status Bar (NEW) ============================================ */ .session-status-bar { display: flex; align-items: center; gap: 16px; padding: 10px 20px; background: linear-gradient(180deg, #1a1a1a 0%, #151515 100%); border-bottom: 1px solid #333; flex-wrap: wrap; animation: slideDown 0.3s ease; margin: 0; } @keyframes slideDown { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } .working-directory { display: flex; align-items: center; gap: 8px; padding: 6px 12px; background: rgba(74, 158, 255, 0.1); border: 1px solid #4a9eff; border-radius: 6px; color: #4a9eff; font-size: 13px; font-weight: 500; cursor: pointer; transition: all 0.2s ease; } .working-directory:hover { background: rgba(74, 158, 255, 0.15); transform: translateY(-1px); } .working-directory span:first-child { font-size: 16px; line-height: 1; } .working-dir-path { max-width: 400px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .session-indicator { display: flex; align-items: center; gap: 6px; padding: 4px 12px; background: rgba(81, 207, 102, 0.1); border: 1px solid #51cf66; border-radius: 4px; color: #51cf66; font-size: 12px; font-weight: 500; } .status-dot { width: 8px; height: 8px; background: #51cf66; border-radius: 50%; animation: pulse 2s ease-in-out infinite; } @keyframes pulse { 0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(81, 207, 102, 0.7); } 50% { opacity: 0.6; box-shadow: 0 0 0 4px rgba(81, 207, 102, 0); } } /* Responsive adjustments */ @media (max-width: 768px) { .session-status-bar { padding: 8px 12px; gap: 8px; } .working-dir-path { max-width: 150px; } .session-indicator { font-size: 11px; padding: 3px 8px; } } ``` ### Step 4: Update HTML to Support Session Info Button **File:** `/home/uroma/obsidian-web-interface/public/claude-ide/index.html` **Find line 136** (in chat-actions div) and add the new button: ```html
``` **Add this new function to chat-functions.js:** ```javascript /** * Show session information modal */ function showSessionInfo() { if (!attachedSessionId) { appendSystemMessage('ℹ️ No active session. Start a new chat to begin.'); return; } // Fetch session details fetch(`/claude/api/claude/sessions/${attachedSessionId}`) .then(res => res.json()) .then(data => { if (data.session) { const session = data.session; const info = ` Session Information: 📁 Working Directory: ${session.workingDir} 🆔 Session ID: ${session.id} ⚡ Status: ${session.status} 📅 Created: ${new Date(session.createdAt).toLocaleString()} 📊 Context Usage: ${session.context ? session.context.totalTokens + ' / ' + session.context.maxTokens + ' tokens' : 'N/A'} 🏷️ Metadata: ${Object.entries(session.metadata || {}).map(([k, v]) => `• ${k}: ${v}`).join('\n') || 'None'} `; appendSystemMessage(info); } }) .catch(error => { console.error('Error fetching session info:', error); appendSystemMessage('❌ Failed to load session information'); }); } ``` --- ## Testing ### Test 1: Project URL Auto-Session 1. **Build a test URL:** ```bash # Encode path echo -n "/home/uroma/obsidian-vault" | base64 # Result: L2hvbWUvdXJvbWEvb2JzaWRpYW4tdmF1bHQ= ``` 2. **Open in browser:** ``` http://localhost:3010/claude/ide?project=L2hvbWUvdXJvbWEvb2JzaWRpYW4tdmF1bHQ= ``` 3. **Expected results:** - ✅ Page loads to chat view - ✅ Session auto-created - ✅ Status bar shows working directory - ✅ "Session ready" message appears - ✅ Can immediately type and send message ### Test 2: Session Persistence 1. **Create a session** 2. **Refresh the page** 3. **Expected results:** - ✅ Session automatically restored - ✅ Status bar shows session info - ✅ Can continue chatting ### Test 3: Error Handling 1. **Invalid base64:** ``` http://localhost:3010/claude/ide?project=invalid-base64! ``` Expected: "Invalid project path encoding" message 2. **Non-existent path:** ``` # Encode a fake path echo -n "/fake/path" | base64 ``` Expected: Error from server, displayed to user --- ## Quick Reference ### Base64 Encoding Commands ```bash # Linux/Mac echo -n "/path/to/project" | base64 # With output URL-safe echo -n "/path/to/project" | base64 | tr '+/' '-_' | tr -d '=' ``` ### Browser Console Testing ```javascript // Check session state localStorage.getItem('claude_chat_session') // Clear session state localStorage.removeItem('claude_chat_session') // Check WebSocket connection window.ws.readyState // Manually trigger session creation initializeFromProjectURL('L2hvbWUvdXJvbWEvb2JzaWRpYW4tdmF1bHQ=') ``` --- ## Rollback Plan If issues occur: 1. **Revert ide.js** - Remove project parameter handling 2. **Revert chat-functions.js** - Remove new functions 3. **Revert CSS** - Remove session-status-bar styles 4. **Clear localStorage** - Users may need to clear saved state ```bash # Git commands git checkout HEAD -- public/claude-ide/ide.js git checkout HEAD -- public/claude-ide/chat-functions.js git checkout HEAD -- public/claude-ide/chat-enhanced.css ``` --- ## Success Criteria ✅ **Project URL opens directly to chat** ✅ **Session created automatically** ✅ **Working directory displayed** ✅ **User can immediately type** ✅ **Session persists across refresh** ✅ **Error messages are clear** ✅ **No console errors** --- **Next Steps:** 1. Implement Phase 1 changes 2. Test thoroughly 3. Deploy to staging 4. Gather user feedback 5. Proceed to Phase 2 **Estimated Time:** 2-3 hours for full Phase 1 implementation