Fix multiple critical bugs: continueSessionInChat, projects link, mode buttons
Bug fixes: - Add missing showLoadingOverlay/hideLoadingOverlay functions to ide.js (previously only existed in sessions-landing.js, causing continueSessionInChat to fail) - Add loading overlay CSS styles to main style.css - Fix Projects button URL: /projects -> /claude/ide?view=projects - Add ?view= URL parameter handling in ide.js initialization - Add missing Native mode button to chat view (now has 3 modes: Chat, Native, Terminal) These fixes resolve: 1. "Continue in Chat" button not working in sessions view 2. Projects button in landing page nav taking to wrong URL 3. Missing "Native" mode button (user referred to as "Full Stack mode") 4. Loading overlay not displaying in IDE Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
991
docs/analysis/chat-ux-analysis.md
Normal file
991
docs/analysis/chat-ux-analysis.md
Normal file
@@ -0,0 +1,991 @@
|
||||
# Chat UX Flow Analysis & Comparison with OpenCode Desktop
|
||||
|
||||
**Date:** 2026-01-20
|
||||
**Current URL:** https://rommark.dev/claude/ide?project=L2hvbWUvdXJvbWEvb2JzaWRpYW4td2ViLWludGVyZmFjZS8ud29ya3RyZWVzL3Byb2plY3Qtb3JnYW5pemF0aW9u
|
||||
**Reference:** https://github.com/anomalyco/opencode.git
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
The current Claude Code Web IDE has a functional but basic chat interface that lacks the polished, friction-free experience of OpenCode desktop. Key issues include:
|
||||
|
||||
1. **No automatic session attachment** when opening with project URL parameters
|
||||
2. **Manual session creation required** - users must click "+ Start New Chat" before messaging
|
||||
3. **Poor visual feedback** for session state and attachment status
|
||||
4. **Missing context indicators** for working directory and project context
|
||||
5. **Confusing workflow** - multiple steps required to start chatting
|
||||
|
||||
**Impact:** Users opening project URLs cannot immediately start chatting, breaking the expected "open and work" flow.
|
||||
|
||||
---
|
||||
|
||||
## 1. Current State Review
|
||||
|
||||
### 1.1 Project URL Flow Analysis
|
||||
|
||||
**URL Format:**
|
||||
```
|
||||
/claude/ide?project=<base64_encoded_path>
|
||||
```
|
||||
|
||||
**What Works:**
|
||||
- URL parameter is parsed (`?project=...`)
|
||||
- Base64 decoding works correctly
|
||||
- Path resolution and security checks function properly
|
||||
- Files can be served from the decoded path
|
||||
|
||||
**What Doesn't Work:**
|
||||
- ❌ **No auto-session creation** - Opening a project URL doesn't create a chat session
|
||||
- ❌ **No immediate chat readiness** - User must manually create session before typing
|
||||
- ❌ **Missing context binding** - Project path isn't attached to session metadata
|
||||
- ❌ **No visual confirmation** - User doesn't know which project is "active"
|
||||
|
||||
### 1.2 Current User Flow
|
||||
|
||||
```
|
||||
1. User opens: /claude/ide?project=L2hvbWUvdXJvbWEv...
|
||||
↓
|
||||
2. IDE loads (default to dashboard view)
|
||||
↓
|
||||
3. User must click "Chat" or auto-switch to chat view
|
||||
↓
|
||||
4. User sees welcome screen with "No active sessions"
|
||||
↓
|
||||
5. User must click "+ Start New Chat"
|
||||
↓
|
||||
6. System creates session in default directory (/home/uroma/obsidian-vault)
|
||||
↓
|
||||
7. User can finally start typing
|
||||
```
|
||||
|
||||
**Problems:**
|
||||
- 5+ steps before user can chat
|
||||
- Project path from URL is ignored
|
||||
- Session created in wrong directory
|
||||
- No context continuity
|
||||
|
||||
### 1.3 Current Implementation Analysis
|
||||
|
||||
**File:** `/home/uroma/obsidian-web-interface/public/claude-ide/ide.js`
|
||||
|
||||
```javascript
|
||||
// Lines 18-46: URL parameter handling
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const sessionId = urlParams.get('session');
|
||||
const prompt = urlParams.get('prompt');
|
||||
|
||||
if (sessionId || prompt) {
|
||||
switchView('chat');
|
||||
setTimeout(() => {
|
||||
if (sessionId) {
|
||||
attachToSession(sessionId);
|
||||
}
|
||||
if (prompt) {
|
||||
// Auto-fill and send prompt
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
```
|
||||
|
||||
**Issues:**
|
||||
- ✅ Handles `?session=` parameter
|
||||
- ✅ Handles `?prompt=` parameter
|
||||
- ❌ **Does NOT handle `?project=` parameter**
|
||||
- ❌ No auto-session creation when project provided
|
||||
|
||||
**File:** `/home/uroma/obsidian-web-interface/public/claude-ide/chat-functions.js`
|
||||
|
||||
```javascript
|
||||
// Lines 93-144: startNewChat()
|
||||
async function startNewChat() {
|
||||
resetChatState();
|
||||
clearChatDisplay();
|
||||
appendSystemMessage('Creating new chat session...');
|
||||
|
||||
const res = await fetch('/claude/api/claude/sessions', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
workingDir: '/home/uroma/obsidian-vault', // ❌ HARDCODED
|
||||
metadata: { type: 'chat', source: 'web-ide' }
|
||||
})
|
||||
});
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**Issues:**
|
||||
- Working directory is hardcoded to `/home/uroma/obsidian-vault`
|
||||
- Doesn't check URL for project parameter
|
||||
- No way to override directory
|
||||
|
||||
---
|
||||
|
||||
## 2. OpenCode Desktop Comparison
|
||||
|
||||
### 2.1 OpenCode UX Patterns
|
||||
|
||||
From analyzing OpenCode's codebase and documentation:
|
||||
|
||||
**Key Features:**
|
||||
1. **Session-First Architecture**
|
||||
- Every interaction happens within a session context
|
||||
- Sessions are bound to working directories
|
||||
- Session state persists across UI views
|
||||
|
||||
2. **Seamless Project Integration**
|
||||
- Opening a project immediately creates/attaches session
|
||||
- Working directory is prominent in UI
|
||||
- Context usage displayed visually
|
||||
|
||||
3. **Multi-Session Management**
|
||||
- Tabs for switching between sessions
|
||||
- Visual indicators for active session
|
||||
- Session metadata (project, status, context)
|
||||
|
||||
4. **Input-First Design**
|
||||
- Chat input always accessible
|
||||
- Auto-focus on load
|
||||
- No barriers to messaging
|
||||
|
||||
5. **Rich Context Display**
|
||||
- Session context usage bar
|
||||
- LSP status indicator
|
||||
- Working directory breadcrumb
|
||||
- Provider/model selection
|
||||
|
||||
### 2.2 OpenCode Session Flow
|
||||
|
||||
```
|
||||
1. Open OpenCode with project path
|
||||
↓
|
||||
2. Auto-create session with working directory
|
||||
↓
|
||||
3. Show session in tab/list
|
||||
↓
|
||||
4. Display context:
|
||||
- Working directory
|
||||
- Context usage (tokens)
|
||||
- Session status
|
||||
↓
|
||||
5. Ready for input immediately
|
||||
```
|
||||
|
||||
**Time to first message:** ~2 seconds
|
||||
|
||||
---
|
||||
|
||||
## 3. Feature Gap Analysis
|
||||
|
||||
| Feature | Current Implementation | OpenCode Desktop | Priority |
|
||||
|---------|----------------------|------------------|----------|
|
||||
| **Auto-session on project URL** | ❌ Not implemented | ✅ Yes | **HIGH** |
|
||||
| **Working directory binding** | ❌ Hardcoded | ✅ Dynamic | **HIGH** |
|
||||
| **Session context indicator** | ⚠️ Basic (session ID) | ✅ Rich (dir, tokens, status) | MEDIUM |
|
||||
| **Visual session state** | ⚠️ Active/historical badges | ✅ Color-coded, animated | MEDIUM |
|
||||
| **Multi-session switching** | ⚠️ Sidebar list | ✅ Tabs + sidebar | LOW |
|
||||
| **Immediate chat readiness** | ❌ Requires manual creation | ✅ Auto-created | **HIGH** |
|
||||
| **Project metadata binding** | ❌ None | ✅ Project name, type | MEDIUM |
|
||||
| **Context usage display** | ❌ Not in chat view | ✅ Prominent bar | LOW |
|
||||
| **Terminal attachment** | ✅ Available | ✅ Integrated | LOW |
|
||||
| **File operations preview** | ✅ Available | ✅ Rich diff view | LOW |
|
||||
|
||||
---
|
||||
|
||||
## 4. UX Improvements Needed
|
||||
|
||||
### 4.1 Priority 1: Friction-Free Chat Start
|
||||
|
||||
**Problem:** User must click multiple times before chatting
|
||||
|
||||
**Solution:** Auto-create session on project URL
|
||||
|
||||
```javascript
|
||||
// Enhanced URL parameter handling
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const projectParam = urlParams.get('project');
|
||||
const sessionId = urlParams.get('session');
|
||||
const prompt = urlParams.get('prompt');
|
||||
|
||||
if (projectParam) {
|
||||
// Decode base64 project path
|
||||
const projectPath = decodeBase64(projectParam);
|
||||
|
||||
// Switch to chat view
|
||||
switchView('chat');
|
||||
|
||||
// Auto-create session with project directory
|
||||
autoCreateSession(projectPath);
|
||||
} else if (sessionId) {
|
||||
attachToSession(sessionId);
|
||||
}
|
||||
```
|
||||
|
||||
**Expected Flow:**
|
||||
```
|
||||
User opens URL → Auto-create session → Show loading → Ready to chat
|
||||
(2 seconds)
|
||||
```
|
||||
|
||||
### 4.2 Priority 2: Visual Session Indicators
|
||||
|
||||
**Problem:** User doesn't know which session/project is active
|
||||
|
||||
**Solution:** Prominent session status display
|
||||
|
||||
**UI Elements Needed:**
|
||||
1. **Working Directory Breadcrumb**
|
||||
```
|
||||
📁 /home/uroma/obsidian-web-interface/.worktrees/project-organization
|
||||
```
|
||||
|
||||
2. **Session Status Badge**
|
||||
```
|
||||
● Active Session | Running | Context: 12,450 / 200,000 tokens
|
||||
```
|
||||
|
||||
3. **Project Metadata**
|
||||
```
|
||||
Project: project-organization | Type: Git Worktree
|
||||
```
|
||||
|
||||
**CSS Implementation:**
|
||||
```css
|
||||
.session-status-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 12px 20px;
|
||||
background: #1a1a1a;
|
||||
border-bottom: 1px solid #333;
|
||||
}
|
||||
|
||||
.working-directory {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #4a9eff;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.context-usage {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 Priority 3: Enhanced Feedback
|
||||
|
||||
**Problem:** Unclear what's happening during session creation
|
||||
|
||||
**Solution:** Loading states and progress indicators
|
||||
|
||||
**States to Visualize:**
|
||||
1. **Creating Session** (0-1s)
|
||||
```
|
||||
⏳ Creating session...
|
||||
```
|
||||
|
||||
2. **Attaching to Directory** (1-2s)
|
||||
```
|
||||
📂 Attaching to /home/uroma/...
|
||||
```
|
||||
|
||||
3. **Ready** (2s+)
|
||||
```
|
||||
✅ Session ready! Start typing...
|
||||
```
|
||||
|
||||
**Animation:**
|
||||
```javascript
|
||||
async function autoCreateSession(projectPath) {
|
||||
// Show loading state
|
||||
showSessionCreationProgress();
|
||||
|
||||
appendSystemMessage({
|
||||
type: 'progress',
|
||||
icon: '⏳',
|
||||
text: `Creating session for ${getProjectName(projectPath)}...`
|
||||
});
|
||||
|
||||
// Create session
|
||||
const response = await fetch('/claude/api/claude/sessions', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
workingDir: projectPath,
|
||||
metadata: {
|
||||
project: getProjectName(projectPath),
|
||||
type: 'project-url',
|
||||
source: 'web-ide'
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// Update progress
|
||||
updateProgressMessage('📂 Attached to working directory');
|
||||
|
||||
// Ready state
|
||||
const data = await response.json();
|
||||
showReadyState(data.session);
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 Priority 4: Session Continuity
|
||||
|
||||
**Problem:** Losing session context when navigating
|
||||
|
||||
**Solution:** Persistent session state
|
||||
|
||||
**Implementation:**
|
||||
```javascript
|
||||
// Save session state to localStorage
|
||||
function saveSessionState(session) {
|
||||
localStorage.setItem('currentSession', JSON.stringify({
|
||||
id: session.id,
|
||||
workingDir: session.workingDir,
|
||||
metadata: session.metadata,
|
||||
timestamp: Date.now()
|
||||
}));
|
||||
}
|
||||
|
||||
// Restore on page load
|
||||
function restoreSessionState() {
|
||||
const saved = localStorage.getItem('currentSession');
|
||||
if (saved) {
|
||||
const session = JSON.parse(saved);
|
||||
// Only restore if recent (< 1 hour)
|
||||
if (Date.now() - session.timestamp < 3600000) {
|
||||
attachToSession(session.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Implementation Recommendations
|
||||
|
||||
### 5.1 Code Changes Required
|
||||
|
||||
#### A. Enhanced URL Parameter Handling
|
||||
**File:** `public/claude-ide/ide.js`
|
||||
|
||||
**Location:** Lines 18-46 (DOMContentLoaded handler)
|
||||
|
||||
**Changes:**
|
||||
```javascript
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initNavigation();
|
||||
connectWebSocket();
|
||||
|
||||
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
|
||||
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 {
|
||||
// Default: Check for saved session
|
||||
const savedSession = restoreSessionState();
|
||||
if (savedSession) {
|
||||
switchView('chat');
|
||||
setTimeout(() => {
|
||||
attachToSession(savedSession.id);
|
||||
}, 500);
|
||||
} else {
|
||||
switchView('chat');
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### B. New Session Initialization Function
|
||||
**File:** `public/claude-ide/chat-functions.js`
|
||||
|
||||
**Add after line 144:**
|
||||
```javascript
|
||||
// Initialize from Project URL
|
||||
async function initializeFromProjectURL(projectParam, initialPrompt = null) {
|
||||
try {
|
||||
// Decode base64 path
|
||||
const projectPath = decodeBase64(projectParam);
|
||||
|
||||
// Show loading message
|
||||
appendSystemMessage({
|
||||
type: 'loading',
|
||||
icon: '⏳',
|
||||
text: `Creating session for project...`
|
||||
});
|
||||
|
||||
// Create session with project directory
|
||||
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'
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to create session: ${res.status}`);
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (data.success) {
|
||||
attachedSessionId = data.session.id;
|
||||
chatSessionId = 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
|
||||
loadChatView();
|
||||
|
||||
// Show success message
|
||||
appendSystemMessage({
|
||||
type: 'success',
|
||||
icon: '✅',
|
||||
text: `Session ready! Working in ${extractProjectName(projectPath)}`
|
||||
});
|
||||
|
||||
// Auto-send initial prompt if provided
|
||||
if (initialPrompt) {
|
||||
setTimeout(() => {
|
||||
const input = document.getElementById('chat-input');
|
||||
if (input) {
|
||||
input.value = decodeURIComponent(initialPrompt);
|
||||
sendChatMessage();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error initializing from project URL:', error);
|
||||
appendSystemMessage({
|
||||
type: 'error',
|
||||
icon: '❌',
|
||||
text: `Failed to create session: ${error.message}`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Decode base64 string
|
||||
function decodeBase64(str) {
|
||||
try {
|
||||
return Buffer.from(str, 'base64').toString('utf-8');
|
||||
} catch (error) {
|
||||
console.error('Base64 decode error:', error);
|
||||
throw new Error('Invalid project path encoding');
|
||||
}
|
||||
}
|
||||
|
||||
// Extract project name from path
|
||||
function extractProjectName(path) {
|
||||
const parts = path.split('/');
|
||||
return parts[parts.length - 1] || 'Untitled Project';
|
||||
}
|
||||
|
||||
// Update session UI with context
|
||||
function updateSessionUI(session) {
|
||||
// Update session ID
|
||||
document.getElementById('current-session-id').textContent = session.id;
|
||||
|
||||
// Update title
|
||||
document.getElementById('chat-title').textContent = session.project || 'New Chat';
|
||||
|
||||
// Add or update session status bar
|
||||
let statusBar = document.querySelector('.session-status-bar');
|
||||
if (!statusBar) {
|
||||
statusBar = document.createElement('div');
|
||||
statusBar.className = 'session-status-bar';
|
||||
document.getElementById('chat-header').after(statusBar);
|
||||
}
|
||||
|
||||
statusBar.innerHTML = `
|
||||
<div class="working-directory">
|
||||
<span>📁</span>
|
||||
<span>${session.workingDir}</span>
|
||||
</div>
|
||||
<div class="session-indicator">
|
||||
<span class="status-dot"></span>
|
||||
<span>Active Session</span>
|
||||
<span>•</span>
|
||||
<span>${session.status}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Save to localStorage for persistence
|
||||
saveSessionState(session);
|
||||
}
|
||||
```
|
||||
|
||||
#### C. Enhanced Session Status Bar
|
||||
**File:** `public/claude-ide/chat-enhanced.css`
|
||||
|
||||
**Add after line 476:**
|
||||
```css
|
||||
/* ============================================
|
||||
Session Status Bar
|
||||
============================================ */
|
||||
|
||||
.session-status-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 12px 20px;
|
||||
background: #1a1a1a;
|
||||
border-bottom: 1px solid #333;
|
||||
flex-wrap: wrap;
|
||||
animation: slideDown 0.3s ease;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
.working-directory span:first-child {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.context-usage {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.context-usage-bar {
|
||||
width: 100px;
|
||||
height: 4px;
|
||||
background: #333;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.context-usage-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #4a9eff, #51cf66);
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
System Message Enhancements
|
||||
============================================ */
|
||||
|
||||
.chat-message.system {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 12px 20px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.chat-message.system .chat-message-bubble {
|
||||
background: #1a1a1a;
|
||||
border: 1px solid #333;
|
||||
border-radius: 8px;
|
||||
padding: 10px 16px;
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.chat-message.system.loading .chat-message-bubble {
|
||||
border-color: #ffa94d;
|
||||
color: #ffa94d;
|
||||
}
|
||||
|
||||
.chat-message.system.success .chat-message-bubble {
|
||||
border-color: #51cf66;
|
||||
color: #51cf66;
|
||||
}
|
||||
|
||||
.chat-message.system.error .chat-message-bubble {
|
||||
border-color: #ff6b6b;
|
||||
color: #ff6b6b;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Session List Enhancements
|
||||
============================================ */
|
||||
|
||||
.chat-history-item {
|
||||
position: relative;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.chat-history-item.active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 3px;
|
||||
height: 60%;
|
||||
background: #4a9eff;
|
||||
border-radius: 0 3px 3px 0;
|
||||
animation: slideIn 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
height: 0;
|
||||
}
|
||||
to {
|
||||
height: 60%;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-history-item .working-dir-hint {
|
||||
font-size: 11px;
|
||||
color: #888;
|
||||
margin-top: 4px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
```
|
||||
|
||||
#### D. HTML Structure Updates
|
||||
**File:** `public/claude-ide/index.html`
|
||||
|
||||
**Update chat header (lines 130-139):**
|
||||
```html
|
||||
<div class="chat-header" id="chat-header">
|
||||
<div class="chat-session-info">
|
||||
<h2 id="chat-title">New Chat</h2>
|
||||
<span class="chat-session-id" id="current-session-id"></span>
|
||||
</div>
|
||||
<div class="chat-actions">
|
||||
<button class="btn-secondary btn-sm" onclick="showSessionInfo()" title="Session Info">ℹ️</button>
|
||||
<button class="btn-secondary btn-sm" onclick="clearChat()" title="Clear chat">Clear</button>
|
||||
<button class="btn-secondary btn-sm" onclick="showChatSettings()" title="Settings">⚙️</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Session status bar (inserted dynamically) -->
|
||||
```
|
||||
|
||||
### 5.2 Backend Changes (if needed)
|
||||
|
||||
**File:** `server.js`
|
||||
|
||||
**No changes required** - existing session creation endpoint already supports:
|
||||
- Custom `workingDir` parameter
|
||||
- `metadata` object for project info
|
||||
- Session management
|
||||
|
||||
---
|
||||
|
||||
## 6. Implementation Priority List
|
||||
|
||||
### Phase 1: Critical (Week 1)
|
||||
**Goal:** Make project URLs work immediately
|
||||
|
||||
1. ✅ **Auto-session creation on project URL**
|
||||
- Implement `initializeFromProjectURL()`
|
||||
- Update URL parameter handling
|
||||
- Test with sample project URLs
|
||||
|
||||
2. ✅ **Working directory binding**
|
||||
- Pass project path to session creation
|
||||
- Store in session metadata
|
||||
- Display in UI
|
||||
|
||||
**Estimated time:** 4-6 hours
|
||||
|
||||
### Phase 2: Enhanced UX (Week 1-2)
|
||||
**Goal:** Improve visual feedback
|
||||
|
||||
3. ✅ **Session status bar**
|
||||
- Add HTML structure
|
||||
- Implement CSS styling
|
||||
- Wire up data updates
|
||||
|
||||
4. ✅ **Loading states**
|
||||
- Show creation progress
|
||||
- Visual indicators for states
|
||||
- Error handling messages
|
||||
|
||||
**Estimated time:** 3-4 hours
|
||||
|
||||
### Phase 3: Polish (Week 2)
|
||||
**Goal:** Match OpenCode experience
|
||||
|
||||
5. ✅ **Session persistence**
|
||||
- Save state to localStorage
|
||||
- Restore on page load
|
||||
- Handle expiry
|
||||
|
||||
6. ✅ **Enhanced system messages**
|
||||
- Styled loading/success/error states
|
||||
- Better icons and animations
|
||||
- Clear action feedback
|
||||
|
||||
**Estimated time:** 2-3 hours
|
||||
|
||||
### Phase 4: Nice-to-Have (Week 3+)
|
||||
**Goal:** Exceed expectations
|
||||
|
||||
7. ⚠️ **Context usage display**
|
||||
- Token counting
|
||||
- Visual progress bar
|
||||
- Warning when near limit
|
||||
|
||||
8. ⚠️ **Quick project switcher**
|
||||
- Dropdown for recent projects
|
||||
- Keyboard shortcuts
|
||||
- Project history
|
||||
|
||||
**Estimated time:** 4-6 hours
|
||||
|
||||
---
|
||||
|
||||
## 7. Testing Checklist
|
||||
|
||||
### Manual Testing
|
||||
|
||||
- [ ] **Project URL Flow**
|
||||
- [ ] Open IDE with `?project=` parameter
|
||||
- [ ] Verify session auto-created
|
||||
- [ ] Check working directory is correct
|
||||
- [ ] Confirm project metadata saved
|
||||
|
||||
- [ ] **Session Persistence**
|
||||
- [ ] Create session
|
||||
- [ ] Refresh page
|
||||
- [ ] Verify session restored
|
||||
- [ ] Check localStorage
|
||||
|
||||
- [ ] **Visual Feedback**
|
||||
- [ ] Status bar displays correctly
|
||||
- [ ] Loading animations work
|
||||
- [ ] Error messages show properly
|
||||
- [ ] Success indicators visible
|
||||
|
||||
- [ ] **Multi-Session**
|
||||
- [ ] Create multiple sessions
|
||||
- [ ] Switch between them
|
||||
- [ ] Verify each maintains state
|
||||
- [ ] Check sidebar updates
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- [ ] Invalid base64 in project URL
|
||||
- [ ] Non-existent project path
|
||||
- [ ] Path outside allowed directories
|
||||
- [ ] Session creation failure
|
||||
- [ ] WebSocket connection issues
|
||||
- [ ] Rapid page refreshes
|
||||
|
||||
---
|
||||
|
||||
## 8. Success Metrics
|
||||
|
||||
### Quantitative
|
||||
|
||||
- **Time to First Message**
|
||||
- Current: ~30 seconds (manual setup)
|
||||
- Target: < 5 seconds (auto-create)
|
||||
- Measurement: Page load to first valid send
|
||||
|
||||
- **Steps to Chat**
|
||||
- Current: 5+ steps
|
||||
- Target: 1 step (open URL)
|
||||
- Measurement: User actions required
|
||||
|
||||
- **Error Rate**
|
||||
- Current: Unknown
|
||||
- Target: < 5% failed session creations
|
||||
- Measurement: Failed / total attempts
|
||||
|
||||
### Qualitative
|
||||
|
||||
- **User Feedback**
|
||||
- "I can start working immediately"
|
||||
- "I know which project I'm working in"
|
||||
- "The interface feels responsive"
|
||||
|
||||
- **Comparison to OpenCode**
|
||||
- Feature parity on core flows
|
||||
- Competitive visual polish
|
||||
- Unique web advantages (URLs, sharing)
|
||||
|
||||
---
|
||||
|
||||
## 9. Open Questions
|
||||
|
||||
1. **Session Expiry**
|
||||
- How long should sessions persist?
|
||||
- Should we auto-expire inactive sessions?
|
||||
- Recommendation: 1 hour for persistence, 24 hours for session files
|
||||
|
||||
2. **Project URL Format**
|
||||
- Is base64 encoding the best approach?
|
||||
- Should we support short codes/slugs?
|
||||
- Recommendation: Keep base64, add slug option for sharing
|
||||
|
||||
3. **Multi-Session Limits**
|
||||
- How many concurrent sessions?
|
||||
- Memory management?
|
||||
- Recommendation: Max 5 active sessions, auto-close oldest
|
||||
|
||||
4. **Context Usage**
|
||||
- Should we show real-time token usage?
|
||||
- How to count tokens accurately?
|
||||
- Recommendation: Add in Phase 4, estimate initially
|
||||
|
||||
---
|
||||
|
||||
## 10. Next Steps
|
||||
|
||||
1. **Review this document** with team
|
||||
2. **Prioritize phases** based on resources
|
||||
3. **Create development branch** for chat UX improvements
|
||||
4. **Implement Phase 1** (auto-session creation)
|
||||
5. **Test with real projects**
|
||||
6. **Iterate based on feedback**
|
||||
|
||||
---
|
||||
|
||||
## Appendix A: Example URLs
|
||||
|
||||
### Current URL
|
||||
```
|
||||
https://rommark.dev/claude/ide?project=L2hvbWUvdXJvbWEvb2JzaWRpYW4td2ViLWludGVyZmFjZS8ud29ya3RyZWVzL3Byb2plY3Qtb3JnYW5pemF0aW9u
|
||||
```
|
||||
|
||||
### Decoded Path
|
||||
```
|
||||
/home/uroma/obsidian-web-interface/.worktrees/project-organization
|
||||
```
|
||||
|
||||
### Future URL with Prompt
|
||||
```
|
||||
https://rommark.dev/claude/ide?project=L2hvbWUvdXJvbWEv...&prompt=Explain%20the%20architecture
|
||||
```
|
||||
|
||||
### Future URL with Session
|
||||
```
|
||||
https://rommark.dev/claude/ide?session=session-abc123&prompt=Continue%20working
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Appendix B: OpenCode Reference Links
|
||||
|
||||
- **Repository:** https://github.com/anomalyco/opencode
|
||||
- **Session Management:** `/tmp/opencode/packages/app/src/pages/session.tsx`
|
||||
- **Session Components:** `/tmp/opencode/packages/app/src/components/session/`
|
||||
- **UI Components:** `/tmp/opencode/packages/ui/src/components/`
|
||||
|
||||
---
|
||||
|
||||
**Document Version:** 1.0
|
||||
**Last Updated:** 2026-01-20
|
||||
**Author:** Claude (Sonnet 4.5)
|
||||
**Status:** Ready for Review
|
||||
Reference in New Issue
Block a user