Fix remote mode worktree operations and close session render crash#226
Merged
Fix remote mode worktree operations and close session render crash#226
Conversation
Remote mode (mobile) fixes: - Add atomic create_session_with_worktree bridge command - Fix DeleteGroup to use bridge for worktree removal in remote mode - Fix CreateGroupFromPresetAsync to use bridge for worktree creation - Add push_organization bridge message for multi-agent team sync - Only send history for active session on initial bridge connect - Add _recentlyClosedRemoteSessions guard against stale broadcasts - Plumb deleteBranch through RemoveWorktreePayload Desktop close session crash fix: - Replace Blazor-rendered close dialog with JS-rendered dialog - Root cause: portaling Blazor elements to document.body broke DOM index tracking, causing render batch corruption on component removal - JS dialog (window.showCloseSessionDialog) creates/destroys DOM elements outside Blazor's tree, avoiding desync entirely Includes 4 new tests for remote mode close session behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
3226bea to
06ef716
Compare
Code review fixes: - Fix JS showCloseSessionDialog to use PascalCase property names matching C# CloseDialogResult record (Confirmed, DeleteWorktree, DeleteBranch). Blazor JSON deserialization is case-sensitive. - Wrap Organization.Sessions.Add in InvokeOnUI() in CreateSessionWithWorktreeAsync (was called from background thread) - Wrap Organization assignment in InvokeOnUI() in WsBridgeServer PushOrganization handler (was called from WebSocket thread) - Change InvokeOnUI from private to internal for WsBridgeServer access Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
06ef716 to
a908849
Compare
Agents should always add new commits on top, never amend, unless explicitly asked. This preserves history for reviewers and other agents. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add InvokeOnUIAsync() for awaitable UI thread marshaling - WsBridgeServer CreateSessionWithWorktree: await UI thread completion before broadcasting state, ensuring clients receive consistent data - WsBridgeServer PushOrganization: await UI thread before broadcasting - Mobile OnOrganizationStateReceived: move Organization assignment inside InvokeOnUI so sidebar sees the new session immediately Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address review findings: - PushOrganization: move SaveOrganization/FlushSaveOrganization inside InvokeOnUIAsync callback so serialization of Organization.Sessions happens on the UI thread, preventing races with UI-thread mutations - CreateSessionWithWorktree: marshal entire CreateSessionWithWorktreeAsync call onto UI thread via InvokeOnUIAsync(Func<Task>) since the non-remote path calls ReconcileOrganization which mutates Organization.Sessions - Add InvokeOnUIAsync(Func<Task>) overload for marshaling async operations to the UI thread while preserving async/await yield behavior Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PureWeen
added a commit
that referenced
this pull request
Feb 26, 2026
Previous fix removed the JS DOM portal but kept the dialog in Blazor's render tree. The overlay showed but the dialog was clipped/invisible due to ancestor overflow constraints that position:fixed alone can't escape in WebView with scoped CSS. Adopt the approach from PR #226: render the close-confirmation dialog entirely via JS (window.showCloseSessionDialog), creating DOM elements imperatively and appending to document.body. Blazor never tracks these elements, so no render batch desync on open/close/delete. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PureWeen
added a commit
that referenced
this pull request
Feb 26, 2026
Previous fix removed the JS DOM portal but kept the dialog in Blazor's render tree. The overlay showed but the dialog was clipped/invisible due to ancestor overflow constraints that position:fixed alone can't escape in WebView with scoped CSS. Adopt the approach from PR #226: render the close-confirmation dialog entirely via JS (window.showCloseSessionDialog), creating DOM elements imperatively and appending to document.body. Blazor never tracks these elements, so no render batch desync on open/close/delete. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PureWeen
added a commit
that referenced
this pull request
Feb 26, 2026
Previous fix removed the JS DOM portal but kept the dialog in Blazor's render tree. The overlay showed but the dialog was clipped/invisible due to ancestor overflow constraints that position:fixed alone can't escape in WebView with scoped CSS. Adopt the approach from PR #226: render the close-confirmation dialog entirely via JS (window.showCloseSessionDialog), creating DOM elements imperatively and appending to document.body. Blazor never tracks these elements, so no render batch desync on open/close/delete. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PureWeen
added a commit
that referenced
this pull request
Feb 27, 2026
Previous fix removed the JS DOM portal but kept the dialog in Blazor's render tree. The overlay showed but the dialog was clipped/invisible due to ancestor overflow constraints that position:fixed alone can't escape in WebView with scoped CSS. Adopt the approach from PR #226: render the close-confirmation dialog entirely via JS (window.showCloseSessionDialog), creating DOM elements imperatively and appending to document.body. Blazor never tracks these elements, so no render batch desync on open/close/delete. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PureWeen
added a commit
that referenced
this pull request
Feb 27, 2026
Previous fix removed the JS DOM portal but kept the dialog in Blazor's render tree. The overlay showed but the dialog was clipped/invisible due to ancestor overflow constraints that position:fixed alone can't escape in WebView with scoped CSS. Adopt the approach from PR #226: render the close-confirmation dialog entirely via JS (window.showCloseSessionDialog), creating DOM elements imperatively and appending to document.body. Blazor never tracks these elements, so no render batch desync on open/close/delete. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes remote mode (mobile) worktree operations from PR #205 and a desktop Blazor render crash when closing sessions with worktrees.
Remote Mode Fixes
create_session_with_worktreebridge command replaces multi-step orchestration that caused race conditionspush_organizationmessage keeps mobile in sync after multi-agent team creation_recentlyClosedRemoteSessionspreventsSyncRemoteSessionsfrom re-adding closed sessionsdeleteBranchfield plumbed throughRemoveWorktreePayloadDesktop Close Session Crash Fix
document.bodyvia JS to escapeoverflow:hiddenon sidebar ancestors. This broke Blazor's index-based DOM tracking — when theSessionListItemcomponent was removed during session close, Blazor tried toremoveChildon nodes that were no longer in its DOM tree, causing render batch corruption (Received unexpected acknowledgement for render batch N).window.showCloseSessionDialog) that creates/destroys DOM elements entirely outside Blazor's tree. The JS function returns a Promise with the user's choices. Blazor never tracks these elements, so no desync occurs.Tests