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:
43
.agent/metrics/metrics_20260122_144519.json
Normal file
43
.agent/metrics/metrics_20260122_144519.json
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,65 +1,39 @@
|
|||||||
# Project Isolation Bug - Scratchpad
|
# Session Persistence Bug - Scratchpad
|
||||||
|
|
||||||
## Task Overview
|
## Task Overview
|
||||||
Fix project isolation bug where ALL sessions appear in every project's left sidebar instead of only that project's sessions.
|
Fix bug where sessions disappear from manually created projects after page refresh.
|
||||||
|
|
||||||
## 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)
|
|
||||||
|
|
||||||
## Root Cause Analysis
|
## 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
|
The problem is that `saveManuallyCreatedProjects()` saves the entire project object including its sessions array. When the page refreshes:
|
||||||
2. **chat-enhanced.js line 52**: `loadChatHistory()` accepts `sessionsToRender` parameter
|
1. `loadManuallyCreatedProjects()` restores projects with their saved (stale) sessions
|
||||||
3. **BUT** - When `loadChatHistory()` is called without parameters (initial load), it fetches ALL sessions from API
|
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:
|
## The Fix
|
||||||
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 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):
|
## Testing Steps
|
||||||
- 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
|
|
||||||
|
|
||||||
2. **Added detailed console logging** (lines 107-115):
|
1. Create new project named 'test'
|
||||||
- Logs which sessions are being rendered
|
2. Start new session in 'test' project
|
||||||
- Shows workingDir, project metadata, and status for each session
|
3. Check that session appears in left sidebar
|
||||||
- Helps debug any remaining issues
|
4. Refresh page
|
||||||
|
5. Verify session still appears in 'test' project
|
||||||
**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
|
|
||||||
|
|||||||
20
PROMPT.md
20
PROMPT.md
@@ -22,13 +22,25 @@ User creates new project (e.g., 'roman') and clicks 'Start new session' → ALL
|
|||||||
## Progress
|
## Progress
|
||||||
|
|
||||||
### Iteration 1 - Fixed loadChatHistory to respect active project ✅
|
### 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
|
**Commit:** 55aafba
|
||||||
|
|
||||||
### Next Steps
|
### Iteration 2 - Fixed virtual workingDir handling ✅
|
||||||
- Test in browser to verify isolation works
|
Modified `addSessionToProject()` in project-manager.js to correctly extract projectKey from virtual workingDirs (`/virtual/projects/{key}`) instead of converting slashes to dashes.
|
||||||
- May need additional fixes for initialization timing issues
|
|
||||||
|
**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 -->
|
<!-- Ralph will continue iterating until task is complete -->
|
||||||
|
|
||||||
|
|||||||
5
logs/chat-monitor/failure-1769093185058.json
Normal file
5
logs/chat-monitor/failure-1769093185058.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"sessionId": "session-1769089576431-k4vxmig17",
|
||||||
|
"failureType": "browser_sse_error",
|
||||||
|
"error": "[SSEClient] Connection error for session session-1769092903155-9yow2fvzf: {\"isTrusted\":true}"
|
||||||
|
}
|
||||||
@@ -51,6 +51,8 @@ class ProjectManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Load manually created projects from localStorage
|
* 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() {
|
loadManuallyCreatedProjects() {
|
||||||
try {
|
try {
|
||||||
@@ -66,8 +68,15 @@ class ProjectManager {
|
|||||||
|
|
||||||
projectsData.forEach(projectData => {
|
projectsData.forEach(projectData => {
|
||||||
const projectKey = projectData.id.replace('project-', '');
|
const projectKey = projectData.id.replace('project-', '');
|
||||||
this.projects.set(projectKey, projectData);
|
// CRITICAL FIX: Reset sessions to empty array to avoid stale localStorage data
|
||||||
console.log('[ProjectManager] Loaded project:', projectData.name, 'with', projectData.sessions.length, 'sessions');
|
// 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 {
|
} else {
|
||||||
console.log('[ProjectManager] No manually created projects found in storage');
|
console.log('[ProjectManager] No manually created projects found in storage');
|
||||||
@@ -533,16 +542,17 @@ class ProjectManager {
|
|||||||
|
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (data.success || data.id) {
|
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.loadProjects();
|
||||||
await this.initialize();
|
this.renderProjectTabs();
|
||||||
|
|
||||||
// Find the new session and switch to it
|
// Find the new session and switch to it
|
||||||
const session = data.session || data;
|
const session = data.session || data;
|
||||||
for (const project of this.projects.values()) {
|
for (const project of this.projects.values()) {
|
||||||
const foundSession = project.sessions.find(s => s.id === session.id);
|
const foundSession = project.sessions.find(s => s.id === session.id);
|
||||||
if (foundSession) {
|
if (foundSession) {
|
||||||
this.switchProject(project.id);
|
await this.switchProject(project.id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user