Closes #631. Closes #804. Bug A (thinking card below answer / double render / stuck cursor): trailing rAF after 'done' inserted a duplicate live-turn wrapper into already-settled DOM. Fixed via _streamFinalized flag + cancelAnimationFrame in all terminal handlers (done/apperror/cancel/_handleStreamError) + _scheduleRender guard. All three reported symptoms were the same root cause. Bug B (accumulator reset): original fix reset assistantText/reasoningText inside _wireSSE on reconnect. Reverted — server uses one-shot queue.Queue(), no replay on reconnect, reset would wipe valid pre-drop content causing data loss. Bug A fix alone resolves all symptoms. #804 (blank page workspace): syncWorkspaceDisplays uses S._profileDefaultWorkspace as fallback; workspace chip enabled when hasWorkspace (not hasSession); promptNewFile/promptNewFolder/ switchToWorkspace/promptWorkspacePath auto-create session on blank page; boot.js hydrates _profileDefaultWorkspace from /api/settings before any session exists. Opus max-effort review + Nathan independent review + full browser QA. 1765/1765 tests.
This commit is contained in:
@@ -537,8 +537,12 @@ function getWorkspaceFriendlyName(path){
|
||||
|
||||
function syncWorkspaceDisplays(){
|
||||
const hasSession=!!(S.session&&S.session.workspace);
|
||||
const ws=hasSession?S.session.workspace:'';
|
||||
const label=hasSession?getWorkspaceFriendlyName(ws):t('no_workspace');
|
||||
// Fall back to the profile default workspace when no session is active yet.
|
||||
// S._profileDefaultWorkspace is set during boot and profile switches from /api/settings.
|
||||
const defaultWs=(typeof S._profileDefaultWorkspace==='string'&&S._profileDefaultWorkspace)||'';
|
||||
const ws=hasSession?S.session.workspace:(defaultWs||'');
|
||||
const hasWorkspace=!!(ws);
|
||||
const label=hasWorkspace?getWorkspaceFriendlyName(ws):t('no_workspace');
|
||||
|
||||
const sidebarName=$('sidebarWsName');
|
||||
const sidebarPath=$('sidebarWsPath');
|
||||
@@ -548,13 +552,13 @@ function syncWorkspaceDisplays(){
|
||||
const composerChip=$('composerWorkspaceChip');
|
||||
const composerLabel=$('composerWorkspaceLabel');
|
||||
const composerDropdown=$('composerWsDropdown');
|
||||
if(!hasSession && composerDropdown) composerDropdown.classList.remove('open');
|
||||
if(!hasWorkspace && composerDropdown) composerDropdown.classList.remove('open');
|
||||
// Only show workspace label once boot has finished to prevent
|
||||
// flash of "No workspace" before the saved session finishes loading.
|
||||
if(composerLabel) composerLabel.textContent=S._bootReady?label:'';
|
||||
if(composerChip){
|
||||
composerChip.disabled=!hasSession;
|
||||
composerChip.title=hasSession?ws:t('no_workspace');
|
||||
composerChip.disabled=!hasWorkspace;
|
||||
composerChip.title=hasWorkspace?ws:t('no_workspace');
|
||||
composerChip.classList.toggle('active',!!(composerDropdown&&composerDropdown.classList.contains('open')));
|
||||
}
|
||||
}
|
||||
@@ -738,7 +742,16 @@ async function removeWorkspace(path){
|
||||
}
|
||||
|
||||
async function promptWorkspacePath(){
|
||||
if(!S.session)return;
|
||||
// Opus review Q6: if called from blank page (no session), auto-create one first.
|
||||
if(!S.session){
|
||||
const ws=(typeof S._profileDefaultWorkspace==='string'&&S._profileDefaultWorkspace)||'';
|
||||
if(!ws)return;
|
||||
try{
|
||||
const r=await api('/api/session/new',{method:'POST',body:JSON.stringify({workspace:ws})});
|
||||
if(r&&r.session){S.session=r.session;S.messages=[];if(typeof syncTopbar==='function')syncTopbar();if(typeof renderMessages==='function')renderMessages();if(typeof renderSessionList==='function')await renderSessionList();}
|
||||
}catch(e){showToast(t('workspace_switch_failed')+e.message);return;}
|
||||
if(!S.session)return;
|
||||
}
|
||||
const value=await showPromptDialog({
|
||||
title:t('workspace_switch_prompt_title'),
|
||||
message:t('workspace_switch_prompt_message'),
|
||||
@@ -764,7 +777,17 @@ async function promptWorkspacePath(){
|
||||
}
|
||||
|
||||
async function switchToWorkspace(path,name){
|
||||
if(!S.session)return;
|
||||
// Opus review Q6: if called from blank page, auto-create a session bound to
|
||||
// the requested workspace so the switch doesn't silently no-op.
|
||||
if(!S.session){
|
||||
const ws=path||(typeof S._profileDefaultWorkspace==='string'&&S._profileDefaultWorkspace)||'';
|
||||
if(!ws){showToast(t('no_workspace'));return;}
|
||||
try{
|
||||
const r=await api('/api/session/new',{method:'POST',body:JSON.stringify({workspace:ws})});
|
||||
if(r&&r.session){S.session=r.session;S.messages=[];if(typeof syncTopbar==='function')syncTopbar();if(typeof renderMessages==='function')renderMessages();if(typeof renderSessionList==='function')await renderSessionList();}
|
||||
}catch(e){if(typeof setStatus==='function')setStatus(t('switch_failed')+e.message);return;}
|
||||
if(!S.session)return;
|
||||
}
|
||||
if(S.busy){
|
||||
showToast(t('workspace_busy_switch'));
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user