feat: restore Wolai workspace navigation and assets

This commit is contained in:
Agent Board
2026-07-15 23:12:15 +08:00
parent 31a160fcc5
commit 6f9c7d3b58
48 changed files with 6734 additions and 517 deletions
@@ -138,6 +138,39 @@ export const createDocumentSessionRuntime = (dependencies = {}) => {
|| localMarkdownRelativePathFromDocumentId(session?.documentId)
);
const localFolderNavigationFallbackUrl = (session, reason) => {
const url = new URL('/', window.location.origin);
url.searchParams.set('sourceKind', 'local_folder');
if (session?.rootUri) url.searchParams.set('rootUri', session.rootUri);
url.searchParams.set('treeView', 'filetree');
const relativePath = sessionRelativePath(session);
const currentScope = String(new URL(window.location.href).searchParams.get('fileTreeScope') || '').trim();
const parentScope = relativePath.includes('/') ? relativePath.split('/').slice(0, -1).join('/') : '';
const scope = currentScope || parentScope;
if (scope) url.searchParams.set('fileTreeScope', scope);
if (session?.documentId) url.searchParams.set('missingPage', session.documentId);
if (reason) url.searchParams.set('routeGuard', reason);
return url;
};
const navigateLocalMarkdownDeletedFallback = (session, reason = 'local_markdown_deleted') => {
if (!session || session.sessionKind === 'resource') return false;
if (session.saveTimer) {
window.clearTimeout(session.saveTimer);
session.saveTimer = 0;
}
if (session.externalRefreshTimer) {
window.clearTimeout(session.externalRefreshTimer);
session.externalRefreshTimer = 0;
}
session.externalChangePending = false;
session.hasExternalConflict = false;
session.bufferDirtyState = 'Deleted';
clearSessionConflictSurface(session);
window.location.assign(localFolderNavigationFallbackUrl(session, reason).toString());
return true;
};
const localFolderEventItems = (payload) => {
if (!payload || typeof payload !== 'object') return [];
const changedPaths = Array.isArray(payload.changedPaths)
@@ -151,6 +184,7 @@ export const createDocumentSessionRuntime = (dependencies = {}) => {
relativePath: String(item.relativePath || item.relative_path || item.path || '').trim(),
documentId: String(item.documentId || item.document_id || '').trim(),
eventKind: String(item.eventKind || item.event_kind || item.changeType || item.change_type || '').trim(),
changeType: String(item.changeType || item.change_type || '').trim(),
selfWriteEcho: Boolean(item.selfWriteEcho || item.self_write_echo),
fileVersion: String(item.fileVersion || item.file_version || item.observedFileVersion || item.observed_file_version || '').trim(),
observedFileVersion: String(item.observedFileVersion || item.observed_file_version || '').trim(),
@@ -1167,19 +1201,7 @@ export const createDocumentSessionRuntime = (dependencies = {}) => {
const bufferState = await fetchSessionBufferState(session);
const dirtyState = String(bufferState?.dirtyState || session.bufferDirtyState || '').trim();
if (dirtyState === 'Deleted') {
session.lastExternalConflictEnvelope = {
code: 'local_markdown_deleted',
documentId: session.documentId,
rootUri: session.rootUri || null,
currentDiskVersion: bufferState?.fileVersion || session.conflictDetectionKey || session.fileVersion || null,
editorBaseVersion: session.conflictDetectionKey || session.fileVersion || null,
externalActor: bufferState?.externalActor || null,
dirtyState,
bufferFileVersion: bufferState?.fileVersion || session.fileVersion || null,
message: '当前本地 Markdown 文件已被删除,请恢复文件或关闭当前标签',
suggestedActions: ['keep_editor', 'open_diff'],
};
markSessionExternalConflict(session, session.lastExternalConflictEnvelope.message);
navigateLocalMarkdownDeletedFallback(session);
return;
}
if (session.hasExternalConflict) {
@@ -1209,13 +1231,24 @@ export const createDocumentSessionRuntime = (dependencies = {}) => {
cache: 'no-store',
headers: { accept: 'application/json' },
});
const payload = await response.json().catch(() => null);
if (!response.ok) {
const errorCode = String(payload?.error?.code || payload?.code || '').trim();
if (session.sourceKind === 'local_folder' && (response.status === 404 || errorCode === 'local_markdown_not_found')) {
navigateLocalMarkdownDeletedFallback(session, 'local_markdown_not_found');
return;
}
const conflictEnvelope = conflictEnvelopeFromResponse(payload);
if (response.status === 409 && conflictEnvelope) {
session.lastExternalConflictEnvelope = conflictEnvelope;
markSessionExternalConflict(session, conflictMessageFromEnvelope(session, conflictEnvelope));
return;
}
if (session.sourceKind === 'local_folder') {
markSessionExternalConflict(session, externalConflictMessage);
}
return;
}
const payload = await response.json();
const conflictEnvelope = conflictEnvelopeFromResponse(payload);
if (response.status === 409 && conflictEnvelope) {
session.lastExternalConflictEnvelope = conflictEnvelope;
@@ -1404,6 +1437,11 @@ export const createDocumentSessionRuntime = (dependencies = {}) => {
|| (!documentId && relativePath && relativeTarget && relativePath === relativeTarget)
);
if (!targetsCurrentDocument) return;
const changeType = String(item.changeType || '').trim();
if (changeType === 'deleted') {
navigateLocalMarkdownDeletedFallback(targetSession);
return;
}
if (item.selfWriteEcho === true) {
targetSession.externalChangePending = false;
targetSession.lastSelfSaveSignalAt = Date.now();