Fix session persistence after page refresh

Root cause: loadManuallyCreatedProjects() was restoring projects with
stale session arrays from localStorage. When loadProjects() tried to
merge with fresh API data, the stale sessions would override.

Fix 1: In loadManuallyCreatedProjects(), reset the sessions array to
empty for each loaded project. This ensures sessions always come from
the API (authoritative source) rather than localStorage.

Fix 2: In createSessionInFolder(), remove the redundant initialize()
call after loadProjects(). initialize() would reload stale localStorage
data, undoing the fresh data fetched by loadProjects().

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
uroma
2026-01-22 14:49:36 +00:00
Unverified
parent 9107b3db85
commit c5dbb6c244
5 changed files with 105 additions and 61 deletions

View File

@@ -0,0 +1,43 @@
{
"summary": {
"iterations": 1,
"successful": 1,
"failed": 0,
"errors": 0,
"checkpoints": 0,
"rollbacks": 0
},
"iterations": [
{
"iteration": 1,
"duration": 187.0205898284912,
"success": true,
"error": "",
"timestamp": "2026-01-22T14:45:19.546647",
"trigger_reason": "initial",
"output_preview": "I'll start by reading the prompt file to understand the task better, then check for the scratchpad to see if there's previous progress.The scratchpad shows a different task was completed previously. This is the project isolation bug. Let me start fresh by analyzing the current codebase to understand the project isolation issue.Now let me examine the session tabs component to understand how sessions are being rendered:Now I understand the codebase. Let me create a scratchpad to track my analysis ",
"tokens_used": 110853,
"cost": 0.5985990000000001,
"tools_used": []
}
],
"cost": {
"total": 0.5985990000000001,
"by_tool": {
"claude": 0.5985990000000001
},
"history": [
{
"timestamp": 1769093119.5258083,
"tool": "claude",
"input_tokens": 88683,
"output_tokens": 22170,
"cost": 0.5985990000000001
}
]
},
"analysis": {
"avg_iteration_duration": 187.0205898284912,
"success_rate": 100.0
}
}

View File

@@ -1,65 +1,39 @@
# Project Isolation Bug - Scratchpad
# Session Persistence Bug - Scratchpad
## Task Overview
Fix project isolation bug where ALL sessions appear in every project's left sidebar instead of only that project's sessions.
## Files to Modify
- /home/uroma/obsidian-web-interface/public/claude-ide/project-manager.js (main logic)
- /home/uroma/obsidian-web-interface/public/claude-ide/chat-enhanced.js (left sidebar)
Fix bug where sessions disappear from manually created projects after page refresh.
## Root Cause Analysis
After analyzing the code:
When a session is created in a manually created project:
1. `createSessionInFolder()` creates the session via API
2. It calls `await this.loadProjects()` - fetches fresh session data from API
3. **BUG**: It then calls `await this.initialize()`
4. `initialize()` calls `loadManuallyCreatedProjects()` which RESTores projects with STALE session data from localStorage
5. Then `loadProjects()` is called again, but the damage is done
1. **project-manager.js line 365**: `switchProject()` calls `loadChatHistory(project.sessions)` - this passes the correct sessions
2. **chat-enhanced.js line 52**: `loadChatHistory()` accepts `sessionsToRender` parameter
3. **BUT** - When `loadChatHistory()` is called without parameters (initial load), it fetches ALL sessions from API
The problem is that `saveManuallyCreatedProjects()` saves the entire project object including its sessions array. When the page refreshes:
1. `loadManuallyCreatedProjects()` restores projects with their saved (stale) sessions
2. The merge logic in `loadProjects()` tries to add virtual sessions to these projects
3. BUT the session array from localStorage already exists and may be empty/stale
The issue: The left sidebar `loadChatHistory` function is being called in multiple places:
1. Initial page load (no filter) - loads ALL sessions
2. When switching projects (with filter) - should load only project sessions
3. When sessions are created/updated
4. After archiving/unarchiving sessions
5. After resuming sessions
## The Fix
The problem is that `loadChatHistory` caches and reuses all sessions, and the filtering mechanism wasn't working correctly.
The session arrays stored in localStorage for manually created projects are stale and should be ignored. The `loadManuallyCreatedProjects()` function should:
1. Load the project metadata (name, id, workingDir, manuallyCreated flag)
2. **NOT** load the sessions array - it should start empty
3. Let `loadProjects()` populate the sessions from the API
## Progress
This ensures sessions always come from the authoritative source (the backend API) rather than stale localStorage data.
### Iteration 1 - Analysis & Initial Fix - COMPLETED ✅
## Implementation
**Changes Made:**
Remove the `await this.initialize()` call from `createSessionInFolder()` after `loadProjects()`. The `loadProjects()` call already refreshes the data from the API, so we don't need to re-initialize.
1. **Modified `loadChatHistory()` in chat-enhanced.js** (lines 71-100):
- Added check for `window.projectManager.activeProjectId`
- If active project exists, use `activeProject.sessions` instead of fetching from API
- This ensures that even when `loadChatHistory()` is called without parameters, it respects the active project
## Testing Steps
2. **Added detailed console logging** (lines 107-115):
- Logs which sessions are being rendered
- Shows workingDir, project metadata, and status for each session
- Helps debug any remaining issues
**Commit:** `55aafba` - "Fix project isolation: Make loadChatHistory respect active project sessions"
### Testing Required
1. Create a new project (e.g., 'roman')
2. Add a session to 'roman' project
3. Check if only 'roman' sessions appear in left sidebar
4. Switch to another project
5. Verify only that project's sessions appear
### Potential Issues to Watch
1. **Initial page load**: If project manager hasn't initialized yet, we might load all sessions briefly
2. **Session creation**: New sessions might not appear until project manager refreshes
3. **Project switching timing**: Race conditions between loadChatHistory calls
### Next Steps
1. Test the current fix in browser
2. If issues remain, may need to:
- Add loading state to prevent showing wrong sessions during initialization
- Ensure project manager initializes before loadChatHistory runs
- Add event-based updates instead of polling
1. Create new project named 'test'
2. Start new session in 'test' project
3. Check that session appears in left sidebar
4. Refresh page
5. Verify session still appears in 'test' project

View File

@@ -22,13 +22,25 @@ User creates new project (e.g., 'roman') and clicks 'Start new session' → ALL
## Progress
### Iteration 1 - Fixed loadChatHistory to respect active project ✅
Modified `loadChatHistory()` in chat-enhanced.js to check for active project before fetching all sessions from API. When active project exists, it uses `activeProject.sessions` instead. Added detailed console logging for debugging.
Modified `loadChatHistory()` in chat-enhanced.js to check for active project before fetching all sessions from API. When active project exists, it uses `activeProject.sessions` instead.
**Commit:** 55aafba
### Next Steps
- Test in browser to verify isolation works
- May need additional fixes for initialization timing issues
### Iteration 2 - Fixed virtual workingDir handling ✅
Modified `addSessionToProject()` in project-manager.js to correctly extract projectKey from virtual workingDirs (`/virtual/projects/{key}`) instead of converting slashes to dashes.
**Commit:** ec790a2
### Iteration 3 - Added debugging logging ✅
Added extensive console logging to track session assignment and project isolation.
**Commit:** 9107b3d
## Status
**ALL FIXES IMPLEMENTED** - Ready for browser testing. The fixes address:
1. loadChatHistory now respects active project filter
2. Virtual workingDirs are correctly handled when assigning sessions to projects
3. Detailed logging helps identify any remaining issues
<!-- Ralph will continue iterating until task is complete -->

View File

@@ -0,0 +1,5 @@
{
"sessionId": "session-1769089576431-k4vxmig17",
"failureType": "browser_sse_error",
"error": "[SSEClient] Connection error for session session-1769092903155-9yow2fvzf: {\"isTrusted\":true}"
}

View File

@@ -51,6 +51,8 @@ class ProjectManager {
/**
* Load manually created projects from localStorage
* CRITICAL FIX: Reset sessions array to avoid stale data from localStorage
* Sessions will be populated by loadProjects() from the API
*/
loadManuallyCreatedProjects() {
try {
@@ -66,8 +68,15 @@ class ProjectManager {
projectsData.forEach(projectData => {
const projectKey = projectData.id.replace('project-', '');
this.projects.set(projectKey, projectData);
console.log('[ProjectManager] Loaded project:', projectData.name, 'with', projectData.sessions.length, 'sessions');
// CRITICAL FIX: Reset sessions to empty array to avoid stale localStorage data
// Sessions will be populated from API by loadProjects()
const sanitizedProject = {
...projectData,
sessions: [], // Reset sessions - will be loaded from API
activeSessionId: null // Reset active session
};
this.projects.set(projectKey, sanitizedProject);
console.log('[ProjectManager] Loaded project:', projectData.name, 'sessions reset to empty (will load from API)');
});
} else {
console.log('[ProjectManager] No manually created projects found in storage');
@@ -533,16 +542,17 @@ class ProjectManager {
const data = await res.json();
if (data.success || data.id) {
// Reload projects and switch to new session
// CRITICAL FIX: Only call loadProjects() - do NOT call initialize()
// initialize() would reload stale data from localStorage
await this.loadProjects();
await this.initialize();
this.renderProjectTabs();
// Find the new session and switch to it
const session = data.session || data;
for (const project of this.projects.values()) {
const foundSession = project.sessions.find(s => s.id === session.id);
if (foundSession) {
this.switchProject(project.id);
await this.switchProject(project.id);
break;
}
}