Improve the archived workspace restore flow (#2002)

* fix(app): restore missing workspaces from History

Workspace and agent archival are separate lifecycles. Carry restore intent from History so closed agents can reopen archived workspaces without changing ordinary navigation.

* fix(app): wait for workspace hydration before restore

* fix(app): preserve History agent unarchive

* fix(app): reopen archived History agents outside active directory

History entries are not merged into the active session maps. Carry the row archive state through explicit restore intent so live workspaces still reopen without broadening ordinary navigation.

* fix(app): ignore stale History archive state for active agents

A cached History row can outlive a successful reopen. When the workspace exists, live session state now wins so an active agent is not interrupted by another refresh.

* fix(app): reopen every selected archived History agent

History entries without workspace IDs returned before restoration, and a second archived agent sharing an in-flight workspace restore was dropped. Preserve both agent-only and deferred reopen intent.

* fix(app): require explicit workspace recovery

* fix: preserve workspace recovery contracts

* fix: preserve workspace recovery compatibility

* fix: preserve recovered workspace session state

* fix: preserve terminal navigation timing

* fix(server): preserve successful workspace recovery

* fix: preserve workspace recovery intent
This commit is contained in:
Mohamed Boudra
2026-07-16 17:22:37 +02:00
committed by GitHub
parent d42ab91971
commit 5da6548aff
47 changed files with 1769 additions and 823 deletions
+2 -1
View File
@@ -489,7 +489,8 @@ describe("translation resources", () => {
expect(en.workspace.route.hostOffline).toBe("{{hostName}} is offline");
expect(en.workspace.route.cannotReachHost).toBe("Cannot reach {{hostName}}");
expect(en.workspace.route.hostStatus).toBe("Host status: {{status}}");
expect(en.workspace.route.missing).toBe("Workspace not found");
expect(en.workspace.route.recovery.archivedTitle).toBe("Workspace archived");
expect(en.workspace.route.recovery.unavailableTitle).toBe("Workspace unavailable");
expect(en.message.compaction.loading).toBe("Compacting...");
expect(en.message.compaction.auto).toBe("Context automatically compacted");
expect(en.message.compaction.manual).toBe("Context manually compacted");
+12 -3
View File
@@ -335,15 +335,24 @@ export const ar: TranslationResources = {
workspace: {
route: {
loading: "جارٍ تحميل مساحة العمل",
restoring: "جارٍ استعادة مساحة العمل",
restoreFailed: "تعذّر استعادة مساحة العمل هذه — ربما تم نقل المجلد أو حذفه",
connecting: "الاتصال",
hostOffline: "{{hostName}}غير متواجد حالياً",
cannotReachHost: "لا يمكن الوصول إلى{{hostName}}",
hostStatus: "حالة Host:{{status}}",
missing: "لم يتم العثور على Workspace",
needsHostUpgrade: "قم بتحديث مضيفك لاستعادة مساحة العمل هذه",
manageHost: "إدارة المضيف",
recovery: {
archivedTitle: "مساحة العمل مؤرشفة",
restoreDescription:
"تمت أرشفة {{workspaceName}} وإزالة شجرة العمل الخاصة بها. استعد الفرع {{branch}} لفتحها مجددًا.",
unarchiveDescription: "{{workspaceName}} مؤرشفة. ألغِ أرشفتها لفتحها مجددًا.",
restoreAction: "استعادة",
unarchiveAction: "إلغاء الأرشفة",
restoringTitle: "جارٍ استعادة مساحة العمل",
restoringAction: "جارٍ الاستعادة...",
unavailableTitle: "مساحة العمل غير متاحة",
checkFailedTitle: "تعذر التحقق من مساحة العمل",
},
},
hoverCard: {
scriptsAccessibility: "البرامج النصية Workspace",
+12 -4
View File
@@ -334,16 +334,24 @@ export const en = {
workspace: {
route: {
loading: "Loading workspace",
restoring: "Restoring workspace",
restoreFailed:
"Couldn't restore this workspace — the directory may have been moved or deleted",
connecting: "Connecting",
hostOffline: "{{hostName}} is offline",
cannotReachHost: "Cannot reach {{hostName}}",
hostStatus: "Host status: {{status}}",
missing: "Workspace not found",
needsHostUpgrade: "Update your host to restore this workspace",
manageHost: "Manage host",
recovery: {
archivedTitle: "Workspace archived",
restoreDescription:
"{{workspaceName}} was archived and its worktree was removed. Restore branch {{branch}} to open it again.",
unarchiveDescription: "{{workspaceName}} is archived. Unarchive it to open it again.",
restoreAction: "Restore",
unarchiveAction: "Unarchive",
restoringTitle: "Restoring workspace",
restoringAction: "Restoring...",
unavailableTitle: "Workspace unavailable",
checkFailedTitle: "Couldn't check workspace",
},
},
hoverCard: {
scriptsAccessibility: "Workspace scripts",
+13 -4
View File
@@ -338,16 +338,25 @@ export const es: TranslationResources = {
workspace: {
route: {
loading: "Cargando espacio de trabajo",
restoring: "Restaurando espacio de trabajo",
restoreFailed:
"No se pudo restaurar este espacio de trabajo — es posible que el directorio se haya movido o eliminado",
connecting: "Conectando",
hostOffline: "{{hostName}}está desconectado",
cannotReachHost: "No se puede alcanzar{{hostName}}",
hostStatus: "Estado deHost:{{status}}",
missing: "Workspaceno encontrado",
needsHostUpgrade: "Actualiza tu host para restaurar este espacio de trabajo",
manageHost: "Administrar host",
recovery: {
archivedTitle: "Espacio de trabajo archivado",
restoreDescription:
"{{workspaceName}} se archivó y se eliminó su worktree. Restaura la rama {{branch}} para volver a abrirlo.",
unarchiveDescription:
"{{workspaceName}} está archivado. Desarchívalo para volver a abrirlo.",
restoreAction: "Restaurar",
unarchiveAction: "Desarchivar",
restoringTitle: "Restaurando espacio de trabajo",
restoringAction: "Restaurando...",
unavailableTitle: "Espacio de trabajo no disponible",
checkFailedTitle: "No se pudo comprobar el espacio de trabajo",
},
},
hoverCard: {
scriptsAccessibility: "GuionesWorkspace",
+12 -4
View File
@@ -338,16 +338,24 @@ export const fr: TranslationResources = {
workspace: {
route: {
loading: "Chargement de l'espace de travail",
restoring: "Restauration de l'espace de travail",
restoreFailed:
"Impossible de restaurer cet espace de travail — le répertoire a peut-être été déplacé ou supprimé",
connecting: "De liaison",
hostOffline: "{{hostName}}est hors ligne",
cannotReachHost: "Impossible d'atteindre{{hostName}}",
hostStatus: "StatutHost:{{status}}",
missing: "Workspaceintrouvable",
needsHostUpgrade: "Mettez à jour votre hôte pour restaurer cet espace de travail",
manageHost: "Gérer l'hôte",
recovery: {
archivedTitle: "Espace de travail archivé",
restoreDescription:
"{{workspaceName}} a été archivé et son worktree supprimé. Restaurez la branche {{branch}} pour le rouvrir.",
unarchiveDescription: "{{workspaceName}} est archivé. Désarchivez-le pour le rouvrir.",
restoreAction: "Restaurer",
unarchiveAction: "Désarchiver",
restoringTitle: "Restauration de l'espace de travail",
restoringAction: "Restauration...",
unavailableTitle: "Espace de travail indisponible",
checkFailedTitle: "Impossible de vérifier l'espace de travail",
},
},
hoverCard: {
scriptsAccessibility: "ScriptsWorkspace",
+13 -4
View File
@@ -338,16 +338,25 @@ export const ja: TranslationResources = {
workspace: {
route: {
loading: "ワークスペースを読み込み中",
restoring: "ワークスペースを復元中",
restoreFailed:
"このワークスペースを復元できませんでした。ディレクトリが移動または削除された可能性があります。",
connecting: "接続中",
hostOffline: "{{hostName}}はオフラインです",
cannotReachHost: "{{hostName}}に到達できません",
hostStatus: "ホストの状態: {{status}}",
missing: "ワークスペースが見つかりません",
needsHostUpgrade: "このワークスペースを復元するにはホストを更新してください",
manageHost: "ホストを管理",
recovery: {
archivedTitle: "ワークスペースはアーカイブ済みです",
restoreDescription:
"{{workspaceName}} はアーカイブされ、worktree が削除されました。ブランチ {{branch}} を復元して再度開きます。",
unarchiveDescription:
"{{workspaceName}} はアーカイブされています。再度開くにはアーカイブを解除してください。",
restoreAction: "復元",
unarchiveAction: "アーカイブを解除",
restoringTitle: "ワークスペースを復元中",
restoringAction: "復元中...",
unavailableTitle: "ワークスペースを利用できません",
checkFailedTitle: "ワークスペースを確認できませんでした",
},
},
hoverCard: {
scriptsAccessibility: "ワークスペーススクリプト",
+13 -4
View File
@@ -338,16 +338,25 @@ export const ptBR: TranslationResources = {
workspace: {
route: {
loading: "Carregando workspace",
restoring: "Restaurando workspace",
restoreFailed:
"Não foi possível restaurar este workspace — o diretório pode ter sido movido ou excluído",
connecting: "Conectando",
hostOffline: "{{hostName}} está offline",
cannotReachHost: "Não é possível acessar {{hostName}}",
hostStatus: "Status do host: {{status}}",
missing: "Workspace não encontrado",
needsHostUpgrade: "Atualize o host para restaurar este workspace",
manageHost: "Gerenciar host",
recovery: {
archivedTitle: "Workspace arquivado",
restoreDescription:
"{{workspaceName}} foi arquivado e sua worktree foi removida. Restaure a branch {{branch}} para abri-lo novamente.",
unarchiveDescription:
"{{workspaceName}} está arquivado. Desarquive-o para abri-lo novamente.",
restoreAction: "Restaurar",
unarchiveAction: "Desarquivar",
restoringTitle: "Restaurando workspace",
restoringAction: "Restaurando...",
unavailableTitle: "Workspace indisponível",
checkFailedTitle: "Não foi possível verificar o workspace",
},
},
hoverCard: {
scriptsAccessibility: "Scripts do workspace",
+13 -4
View File
@@ -337,16 +337,25 @@ export const ru: TranslationResources = {
workspace: {
route: {
loading: "Загрузка рабочей области",
restoring: "Восстановление рабочей области",
restoreFailed:
"Не удалось восстановить эту рабочую область — каталог мог быть перемещён или удалён",
connecting: "Подключение",
hostOffline: "{{hostName}}не в сети",
cannotReachHost: "Невозможно связаться с{{hostName}}",
hostStatus: "Статус Host:{{status}}",
missing: "Workspace не найден",
needsHostUpgrade: "Обновите хост, чтобы восстановить эту рабочую область",
manageHost: "Управление хостом",
recovery: {
archivedTitle: "Рабочая область в архиве",
restoreDescription:
"{{workspaceName}} была архивирована, а её worktree удалён. Восстановите ветку {{branch}}, чтобы открыть её снова.",
unarchiveDescription:
"{{workspaceName}} находится в архиве. Разархивируйте её, чтобы открыть снова.",
restoreAction: "Восстановить",
unarchiveAction: "Разархивировать",
restoringTitle: "Восстановление рабочей области",
restoringAction: "Восстановление...",
unavailableTitle: "Рабочая область недоступна",
checkFailedTitle: "Не удалось проверить рабочую область",
},
},
hoverCard: {
scriptsAccessibility: "Скрипты Workspace",
+12 -3
View File
@@ -335,15 +335,24 @@ export const zhCN: TranslationResources = {
workspace: {
route: {
loading: "正在加载 workspace",
restoring: "正在恢复 workspace",
restoreFailed: "无法恢复此 workspace — 目录可能已被移动或删除",
connecting: "正在连接",
hostOffline: "{{hostName}} 已离线",
cannotReachHost: "无法连接 {{hostName}}",
hostStatus: "Host 状态:{{status}}",
missing: "Workspace 未找到",
needsHostUpgrade: "更新你的 Host 以恢复此 workspace",
manageHost: "管理 Host",
recovery: {
archivedTitle: "Workspace 已归档",
restoreDescription:
"{{workspaceName}} 已归档,其 worktree 已移除。恢复分支 {{branch}} 以重新打开。",
unarchiveDescription: "{{workspaceName}} 已归档。取消归档以重新打开。",
restoreAction: "恢复",
unarchiveAction: "取消归档",
restoringTitle: "正在恢复 workspace",
restoringAction: "正在恢复...",
unavailableTitle: "Workspace 不可用",
checkFailedTitle: "无法检查 workspace",
},
},
hoverCard: {
scriptsAccessibility: "Workspace scripts",