Summary
Microsoft.Maui.DevFlow.Agent can remain unreachable in a Microsoft.Maui.Platforms.MacOS AppKit head when startup work blocks the main thread after DidFinishLaunching.
The registration path queues DevFlowAgentService.Start(...) through the MAUI dispatcher, then prints that the agent started before the queued delegate binds the HTTP listener. If the AppKit main thread does not return to the run loop promptly, the broker has no agent and the configured port does not listen even though startup appears successful.
Environment
Microsoft.Maui.DevFlow.Agent: 0.25.0-dev
- Package repository commit:
386a02dab30129d034473be2aa7f43ba234e02f3
- DevFlow CLI:
0.1.0-preview.12.26368.2+229f764fd688754497fe5822213e7b13b4e9caa3
- TFM:
net11.0-macos
- SDK:
11.0.100-preview.7.26381.103
- macOS:
26.6, Apple Silicon
- Platform package:
Microsoft.Maui.Platforms.MacOS
Reproduction
- Create a macOS AppKit MAUI head using
Microsoft.Maui.Platforms.MacOS.
- Register DevFlow in Debug:
builder.AddMauiDevFlowAgent(options => options.Port = 9225);
builder.AddMauiBlazorDevFlowTools();
- Start the DevFlow broker.
- Launch the app with startup work that can hold the AppKit main thread after
DidFinishLaunching, such as SecureStorage/Keychain access or local database initialization.
- Run:
maui devflow diagnose
maui devflow -ap 9225 agent status
lsof -nP -iTCP:9225 -sTCP:LISTEN
Actual behavior
- The app process remains alive.
- The broker reports
agent_count=0.
- Port
9225 is closed.
agent status returns Cannot connect to agent at localhost:9225.
- The registration implementation queues
service.Start(app, app.Dispatcher) through app.Dispatcher.Dispatch(...) and prints Agent started on port N immediately after queuing, not after the HTTP listener binds.
This makes the debugging agent unavailable precisely while the UI thread is blocked.
Expected behavior
- The agent HTTP listener starts before later AppKit startup work can block the run loop.
- The success log appears only after the listener is bound.
- Broker registration and direct
agent status become available reliably.
Verified workaround
A Debug-only bridge resolves the already-registered DevFlowAgentService after base.DidFinishLaunching(...) returns and starts it synchronously on the AppKit main thread:
public override void DidFinishLaunching(NSNotification notification)
{
base.DidFinishLaunching(notification);
#if DEBUG
var service = Services?.GetService<DevFlowAgentService>();
var app = Application.Current;
var dispatcher = app?.Dispatcher ?? Dispatcher.GetForCurrentThread();
if (service is { IsRunning: false } && app is not null)
{
service.Start(app, dispatcher);
}
#endif
}
The existing broker registration is reused; no second service or broker registration is created. Start is idempotent when the upstream queued delegate later runs.
With this workaround verified in a real app:
- Broker reports one agent.
- Port
9225 listens.
agent status identifies the correct project, net11.0-macos, and macOS.
- Native UI, screenshots, logs, and Blazor WebView CDP commands work.
Suggested fix
For the macOS AppKit registration path, start the already-created service synchronously when the lifecycle callback is already on the AppKit main thread, or otherwise await/confirm listener startup before logging success. StartServerOnly could remain a fallback when Application.Current is unavailable.
Summary
Microsoft.Maui.DevFlow.Agentcan remain unreachable in aMicrosoft.Maui.Platforms.MacOSAppKit head when startup work blocks the main thread afterDidFinishLaunching.The registration path queues
DevFlowAgentService.Start(...)through the MAUI dispatcher, then prints that the agent started before the queued delegate binds the HTTP listener. If the AppKit main thread does not return to the run loop promptly, the broker has no agent and the configured port does not listen even though startup appears successful.Environment
Microsoft.Maui.DevFlow.Agent:0.25.0-dev386a02dab30129d034473be2aa7f43ba234e02f30.1.0-preview.12.26368.2+229f764fd688754497fe5822213e7b13b4e9caa3net11.0-macos11.0.100-preview.7.26381.10326.6, Apple SiliconMicrosoft.Maui.Platforms.MacOSReproduction
Microsoft.Maui.Platforms.MacOS.DidFinishLaunching, such as SecureStorage/Keychain access or local database initialization.Actual behavior
agent_count=0.9225is closed.agent statusreturnsCannot connect to agent at localhost:9225.service.Start(app, app.Dispatcher)throughapp.Dispatcher.Dispatch(...)and printsAgent started on port Nimmediately after queuing, not after the HTTP listener binds.This makes the debugging agent unavailable precisely while the UI thread is blocked.
Expected behavior
agent statusbecome available reliably.Verified workaround
A Debug-only bridge resolves the already-registered
DevFlowAgentServiceafterbase.DidFinishLaunching(...)returns and starts it synchronously on the AppKit main thread:The existing broker registration is reused; no second service or broker registration is created.
Startis idempotent when the upstream queued delegate later runs.With this workaround verified in a real app:
9225listens.agent statusidentifies the correct project,net11.0-macos, and macOS.Suggested fix
For the macOS AppKit registration path, start the already-created service synchronously when the lifecycle callback is already on the AppKit main thread, or otherwise await/confirm listener startup before logging success.
StartServerOnlycould remain a fallback whenApplication.Currentis unavailable.