Skip to content

Commit 7a2b6b8

Browse files
bkudiessCopilot
andcommitted
refactor(tray): extract final App orchestration owners
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 378197f commit 7a2b6b8

26 files changed

Lines changed: 3293 additions & 745 deletions

.editorconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ dotnet_diagnostic.REACTOR_DIALOG_001.severity = none
148148
[src/OpenClaw.Tray.WinUI/App.xaml.cs]
149149
dotnet_diagnostic.REACTOR_DIALOG_001.severity = none
150150

151+
[src/OpenClaw.Tray.WinUI/App.ActivationRouter.cs]
152+
dotnet_diagnostic.REACTOR_DIALOG_001.severity = none
153+
151154
[src/OpenClaw.Tray.WinUI/Helpers/**/*.cs]
152155
dotnet_diagnostic.REACTOR_DIALOG_001.severity = none
153156

docs/ARCHITECTURE.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ These are the canonical homes. Do not reintroduce private copies elsewhere.
7373
| Tray-menu semantic composition and connection-toggle state | `TrayMenuPresenter` + `ConnectionTogglePresenter` | authoritative |
7474
| App-owned non-tray window creation, reuse, focus, theme, and lifetime | `IWindowManager` + `WindowManager` | authoritative |
7575
| Tray icon, popup coordination, live status, and callback lifetime | `ITrayController` + `TrayController` | authoritative |
76+
| Deep-link/protocol/toast/forwarded activation normalization, current-user IPC, and semantic activation plans | `IActivationRouter` + `ActivationRouter` | authoritative |
77+
| Post-save settings change effect ordering, detached snapshot comparison, and reentrancy | `ISettingsChangeCoordinator` + `SettingsChangeCoordinator` | authoritative |
78+
| Exactly-once ordered app shutdown sequencing | `IAppShutdownCoordinator` + `AppShutdownCoordinator` | authoritative |
79+
| App composition-root startup sequencing | `AppBootstrapper` (planned) | planned |
7680
| Capability UI metadata | `NodeCapabilityUiCatalog` (planned) | planned |
7781
| Capability registration/gating | `NodeCapabilityRegistrationPolicy` (planned) | planned |
7882
| Local MCP exposure policy | `McpCapabilityPolicy` (planned) | planned |
@@ -83,7 +87,7 @@ These are the canonical homes. Do not reintroduce private copies elsewhere.
8387

8488
| If you are editing… | Do not grow it. Extract toward… |
8589
| --- | --- |
86-
| `src/OpenClaw.Tray.WinUI/App.xaml.cs` | use the authoritative `IWindowManager` and `ITrayController`; remaining A3 extraction targets are `IActivationRouter`, `ISettingsChangeCoordinator`, and `AppBootstrapper` |
90+
| `src/OpenClaw.Tray.WinUI/App.xaml.cs` | use the authoritative `IWindowManager`, `ITrayController`, `IActivationRouter`, `ISettingsChangeCoordinator`, and `IAppShutdownCoordinator`; the remaining A3 extraction target is startup sequencing into `AppBootstrapper` (planned/deferred) |
8791
| `src/OpenClaw.Tray.WinUI/Windows/HubWindow.xaml.cs` | navigation/catalog policy → `HubPageRegistry`; notification banner projection → `AppNotificationInfoBarPresenter`; keep Frame, NavigationView, back-stack mutation, control application, and route side effects in the view |
8892
| `src/OpenClaw.Tray.WinUI/Services/TrayMenuRenderer.cs` | semantic composition → `TrayMenuPresenter`; connection toggle projection → `ConnectionTogglePresenter`; keep WinUI control construction and callback application in the renderer |
8993
| `src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs` | `ChatSendQueue`, `ChatBridgeEventPump`, `ChatHistoryLoader`, `ChatSnapshotProjector`, `AttachmentMetadataStore` |
@@ -137,11 +141,16 @@ leading and trailing pipe. Columns, in order:
137141
| managed-local-provenance | authoritative | scattered connection, setup, browser, and reconnect call sites | implicit loopback trust and duplicated strong-credential listener checks | ManagedLocalGatewayPortProvenanceService | callers request inspection, authorization, or conflict repair only | unknown or changed listener owners never receive strong credentials or destructive remediation | ManagedLocalGatewayPortProvenanceServiceTests.InteractiveCredentialGate_ExpectedCacheThenOwnerChanges_FailsClosed | behavioral | - |
138142
| managed-local-repair | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs and direct reconnect callbacks | repair eligibility, restart budgets, port remediation, and reconnect verification | ManagedLocalGatewayAutoRepairMonitor + ManagedLocalGatewayRepairCoordinator | App composition and dependency callbacks only | explicit disconnect and gateway switches abort repair before restart or reconnect | ManagedLocalGatewayRepairCoordinatorTests.UserDisconnectedIntent_AbortsBeforeProbeOrRestart | behavioral | - |
139143
| app-managed-local-repair-closed | closed | src/OpenClaw.Tray.WinUI/App.xaml.cs | managed-local repair loops, probing, restart budgeting, and verification implementation | ManagedLocalGatewayAutoRepairMonitor + ManagedLocalGatewayRepairCoordinator | service construction, callback adapters, and lifetime wiring only | App remains the composition root and does not regain repair implementation | AppRefactorContractTests.ManagedLocalGatewayRepair_StaysDelegatedToDedicatedOwners | source-shape | when App no longer constructs the managed-local repair services directly |
140-
| app-window-manager | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | Hub, Chat, status, setup, canvas request, and runtime-anchor window creation, reuse, focus, theme, owner, and lifetime mechanics | IWindowManager + WindowManager | App owns composition, route and service-policy callbacks, setup restart policy, pairing approval dialog workflow and shell, activation routing, settings coordination, and final shutdown call ordering | distinct window types and exact routes are preserved; Hub close resets navigation scope; setup replacement waits for cleanup; shutdown closes owned windows once before provider disposal | WindowManagerTests.CloseForShutdown_GatesCreationAndClosesOwnedWindowsOnce | source-shape | when App is replaced as the WinUI composition root |
144+
| app-window-manager | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | Hub, Chat, status, setup, canvas request, and runtime-anchor window creation, reuse, focus, theme, owner, and lifetime mechanics | IWindowManager + WindowManager | App owns composition, typed activation-plan application through WindowManager, service-policy callback adapters, setup restart policy, pairing approval dialog workflow and shell, and shutdown-plan callback construction | distinct window types and exact routes are preserved; Hub close resets navigation scope; setup replacement waits for cleanup; shutdown closes owned windows once before provider disposal | WindowManagerTests.CloseForShutdown_GatesCreationAndClosesOwnedWindowsOnce | source-shape | when App is replaced as the WinUI composition root |
141145
| app-window-surface-ownership-closed | closed | src/OpenClaw.Tray.WinUI/App.xaml.cs | concrete non-tray window fields, constructors, show/hide/focus/theme/close mechanics, and window event lifetime | IWindowManager + WindowManager | interface forwarding, immutable request construction, route and policy callbacks, and setup restart dialog policy only | App cannot regain a parallel Hub, Chat, status, setup, canvas-request, or runtime-anchor owner | AppSurfaceOwnershipContractTests.App_DelegatesConcreteTrayAndWindowOwnership | source-shape | when App is replaced as the WinUI composition root |
142-
| app-tray-controller | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | tray icon creation, tray popup coordination, click routing, tooltip and live-toggle refresh, theme, callbacks, and disposal | ITrayController + TrayController | App captures immutable snapshots, implements semantic action callbacks, triggers refresh from authoritative state, and preserves startup and shutdown call ordering | one tray icon and root menu are reused; A1 presenters retain semantics; TrayMenuWindow retains native popup mechanics; callbacks detach and resources dispose once | TrayControllerTests.Dispose_UnsubscribesAndDisposesEachResourceOnce | source-shape | when the WinUI tray surface is replaced |
146+
| app-tray-controller | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | tray icon creation, tray popup coordination, click routing, tooltip and live-toggle refresh, theme, callbacks, and disposal | ITrayController + TrayController | App captures immutable snapshots, implements semantic action callbacks, triggers refresh from authoritative state, preserves startup construction order, and constructs shutdown-plan callbacks | one tray icon and root menu are reused; A1 presenters retain semantics; TrayMenuWindow retains native popup mechanics; callbacks detach and resources dispose once | TrayControllerTests.Dispose_UnsubscribesAndDisposesEachResourceOnce | source-shape | when the WinUI tray surface is replaced |
143147
| app-tray-surface-ownership-closed | closed | src/OpenClaw.Tray.WinUI/App.xaml.cs | concrete tray icon, root menu, weak live-control state, event subscriptions, popup build coordination, and resource disposal | ITrayController + TrayController | immutable snapshot and action callbacks plus state-change triggers only | App cannot regain tray controls or popup lifetime and TrayController cannot duplicate A1 semantic projection or TrayMenuWindow native mechanics | AppSurfaceOwnershipContractTests.App_DelegatesConcreteTrayAndWindowOwnership | source-shape | when the WinUI tray surface is replaced |
144-
| app-activation-router | planned | src/OpenClaw.Tray.WinUI/App.xaml.cs | deep-link/toast/single-instance activation | IActivationRouter | composition/delegation only | activation routes land on the same UI/actions; current-user pipe security preserved | none | review-only | extracted in Phase 3 |
148+
| app-activation-router | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | deep-link/protocol/toast/forwarded activation normalization, current-user IPC, input guards, and confirmation decisions | IActivationRouter + ActivationRouter | App.ActivationRouter.cs implements IActivationPlanSink only and applies exactly one typed semantic plan through existing A2 owners and services | launch, protocol, toast, and forwarded activation resolve to the same routes; current-user IPC, oversized-payload rejection, and confirmation/redaction semantics are preserved | ActivationRouterTests.ForwardThenListen_DispatchesRouteFromForwardedDeepLink | behavioral | - |
149+
| app-activation-router-closed | closed | src/OpenClaw.Tray.WinUI/App.xaml.cs | concrete deep-link IPC, toast argument routing, and single-instance forwarding production logic | IActivationRouter + ActivationRouter | App.ActivationRouter.cs implements IActivationPlanSink only, dispatching one typed plan per activation | App does not regain a parallel activation production path outside ActivationRouter | AppRefactorContractTests.ToastActivation_RoutesOnUiThread | source-shape | when App is replaced as the WinUI composition root |
150+
| app-settings-change-coordinator | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | detached snapshot comparison, SettingsChangeClassifier use, and the full post-save effect order | ISettingsChangeCoordinator + SettingsChangeCoordinator | App implements narrow connection/runtime/surface effect ports and triggers ApplyAsync from one explicit post-save call | browser proxy sync, reconnect, MCP, hotkey, autostart, telemetry, and surface notification order is preserved; MCP-only behavior and credential precedence are unaffected | SettingsChangeCoordinatorTests.ApplyAsync_GatewayUrlChange_RunsFullReconnectWithPrepare | behavioral | - |
151+
| app-settings-change-coordinator-closed | closed | src/OpenClaw.Tray.WinUI/App.xaml.cs | OnSettingsSaved impact classification, reconnect switch, and inline effect ordering | ISettingsChangeCoordinator + SettingsChangeCoordinator | App.SettingsChangeCoordinator.cs implements effect-port adapters only; OnSettingsSaved forwards to ApplyAsync | App does not regain a parallel settings-change orchestration path outside SettingsChangeCoordinator | PresentationSeamContractTests.App_AppliesToolCallVisibilityFromPersistedSettings | source-shape | when App is replaced as the WinUI composition root |
152+
| app-shutdown-coordinator | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | first-wins shared shutdown task, ordered step execution, and per-step log/catch/continue | IAppShutdownCoordinator + AppShutdownCoordinator | App builds the immutable step plan from services it owns, including activation null-before-await and failure-safe captured-resource nulling, and constructs the BeginShutdown/ExitApplication actions | shutdown steps run in the same order exactly once even under concurrent callers; each step logs and continues past failure; Exit is called exactly once after all steps | AppShutdownCoordinatorTests.ShutdownAsync_RunsBeginStepsThenExit_InOrder | behavioral | - |
153+
| app-shutdown-coordinator-closed | closed | src/OpenClaw.Tray.WinUI/App.xaml.cs | the _isExiting bool guard, SafeShutdownStep/SafeShutdownStepAsync helpers, and inline ExitApplicationAsync body | IAppShutdownCoordinator + AppShutdownCoordinator | App.AppShutdownCoordinator.cs builds the step plan only; ExitApplicationAsync forwards to ShutdownAsync | App does not regain a parallel exactly-once shutdown guard or step-execution loop outside AppShutdownCoordinator | AppRefactorContractTests.Shutdown_Order_PreservesAwaitedTeardownBeforeExit | source-shape | when App is replaced as the WinUI composition root |
145154
| chat-send-queue | planned | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | send queue/admission/abort state | ChatSendQueue | - | queued send/abort/generation semantics preserved | none | review-only | extracted in Phase 4 |
146155
| gateway-pending-requests | planned | src/OpenClaw.Shared/OpenClawGatewayClient.cs | request-id -> method/completion tracking | PendingRequestRegistry | - | request ids never leak after disconnect; thread-safe | none | review-only | extracted in Phase 4 |
147156
| connect-envelope | planned | src/OpenClaw.Shared/OpenClawGatewayClient.cs + WindowsNodeClient.cs | connect message + auth precedence + signature version | ConnectEnvelopeBuilder | - | credential precedence never downgrades a device token; v3->v2 fallback preserved | none | review-only | extracted in Phase 4 |

0 commit comments

Comments
 (0)