diff --git a/desktop/src/features/communities/useCommunityInit.ts b/desktop/src/features/communities/useCommunityInit.ts index afa69f913..d5d59a90b 100644 --- a/desktop/src/features/communities/useCommunityInit.ts +++ b/desktop/src/features/communities/useCommunityInit.ts @@ -210,13 +210,42 @@ export function useCommunityInit( // imported key. `loadCommunities()` strips lingering `nsec` fields from // legacy entries; this site refuses to apply one even if present. try { - await applyCommunity( + const applyResult = await applyCommunity( activeCommunity.relayUrl, undefined, activeCommunity.token, activeCommunity.reposDir, getOverrides().agentManagedProfiles === true, ); + + if (!applyResult.applied) { + // Drain failed; old scope is still active. Treat as a fatal apply + // error: park on the loading gate so the user can retry by switching + // workspaces again. + const reason = applyResult.degraded.join("; "); + console.error( + "[useCommunityInit] workspace apply blocked by drain failure:", + reason, + ); + if (!cancelled) { + setResult({ + isReady: false, + needsSetup: false, + appliedKey: null, + error: `Workspace switch failed (agents could not stop): ${reason}`, + }); + } + return; + } + + // Workspace applied. Log any post-commit degradation (informational — + // the workspace IS active; these are best-effort post-commit steps). + if (applyResult.degraded.length > 0) { + console.warn( + "[useCommunityInit] workspace applied with degradation:", + applyResult.degraded, + ); + } } catch (error) { // A bad `repos_dir` no longer reaches here — `apply_workspace` treats // it as non-fatal (relay/keys apply, bad value not persisted, REPOS diff --git a/desktop/src/shared/api/tauri.ts b/desktop/src/shared/api/tauri.ts index 69e2e455e..d25bfc8ee 100644 --- a/desktop/src/shared/api/tauri.ts +++ b/desktop/src/shared/api/tauri.ts @@ -1142,14 +1142,27 @@ export async function cancelPairing(): Promise { await invokeTauri("cancel_pairing"); } +/** + * Result from `apply_workspace` / `applyCommunity`. + * + * - `applied: true` — new scope committed; post-commit failures surface in + * `degraded` (informational — workspace IS active). + * - `applied: false` — drain failed; old scope still active; `degraded` names + * what could not be stopped or restored by compensation. + */ +export interface WorkspaceApplyResult { + applied: boolean; + degraded: string[]; +} + export async function applyCommunity( relayUrl: string, nsec?: string, token?: string, reposDir?: string, agentManagedProfiles?: boolean, -): Promise { - await invokeTauri("apply_workspace", { +): Promise { + return invokeTauri("apply_workspace", { relayUrl, nsec: nsec ?? null, token: token ?? null,