From c1c1b87c9eefebe13a74d70144ecbf242ab5e06a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Mar 2026 14:30:45 +0000 Subject: [PATCH 1/4] Initial plan From ea0f7e18e9070e6839fba47a723ecfb4aa4e5954 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Mar 2026 14:44:48 +0000 Subject: [PATCH 2/4] Print proxy URL with assigned port when starting Dev Proxy in detach mode Co-authored-by: waldekmastykarz <11164679+waldekmastykarz@users.noreply.github.com> --- DevProxy/Program.cs | 6 +++++- DevProxy/Proxy/ProxyEngine.cs | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/DevProxy/Program.cs b/DevProxy/Program.cs index 78912573..9e3f7feb 100644 --- a/DevProxy/Program.cs +++ b/DevProxy/Program.cs @@ -107,11 +107,15 @@ static async Task StartDetachedProcessAsync(string[] args) await Task.Delay(200); var state = await StateManager.LoadStateAsync(); - if (state != null) + if (state is { Port: > 0 }) { + var apiUri = new Uri(state.ApiUrl); + var proxyUrl = $"http://{apiUri.Host}:{state.Port}"; + await Console.Out.WriteLineAsync("Dev Proxy started in background."); await Console.Out.WriteLineAsync(); await Console.Out.WriteLineAsync($" PID: {state.Pid}"); + await Console.Out.WriteLineAsync($" Proxy URL: {proxyUrl}"); await Console.Out.WriteLineAsync($" API URL: {state.ApiUrl}"); await Console.Out.WriteLineAsync($" Log file: {state.LogFile}"); await Console.Out.WriteLineAsync(); diff --git a/DevProxy/Proxy/ProxyEngine.cs b/DevProxy/Proxy/ProxyEngine.cs index 6f353a8f..0b153a6b 100755 --- a/DevProxy/Proxy/ProxyEngine.cs +++ b/DevProxy/Proxy/ProxyEngine.cs @@ -6,6 +6,7 @@ using DevProxy.Abstractions.Proxy; using DevProxy.Abstractions.Utils; using DevProxy.Commands; +using DevProxy.State; using Microsoft.VisualStudio.Threading; using System.Collections.Concurrent; using System.Diagnostics; @@ -141,6 +142,20 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) ProxyServer.AddEndPoint(_explicitEndPoint); await ProxyServer.StartAsync(cancellationToken: stoppingToken); + // Update config with actual port (resolves port 0 to OS-assigned port) + _config.Port = _explicitEndPoint.Port; + + // Update state file with actual port so detach parent gets the resolved port + if (DevProxyCommand.IsInternalDaemon) + { + var state = await StateManager.LoadStateAsync(stoppingToken); + if (state is not null) + { + state.Port = _config.Port; + await StateManager.SaveStateAsync(state, stoppingToken); + } + } + // run first-run setup on macOS FirstRunSetup(); From 9dff9203ac4f22c839e4d88adcf9e04f088ec290 Mon Sep 17 00:00:00 2001 From: Waldek Mastykarz Date: Thu, 5 Mar 2026 16:09:49 +0100 Subject: [PATCH 3/4] Update DevProxy/Program.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- DevProxy/Program.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/DevProxy/Program.cs b/DevProxy/Program.cs index 9e3f7feb..a7fbf784 100644 --- a/DevProxy/Program.cs +++ b/DevProxy/Program.cs @@ -109,9 +109,16 @@ static async Task StartDetachedProcessAsync(string[] args) var state = await StateManager.LoadStateAsync(); if (state is { Port: > 0 }) { - var apiUri = new Uri(state.ApiUrl); - var proxyUrl = $"http://{apiUri.Host}:{state.Port}"; + Uri? apiUri = null; + if (!string.IsNullOrWhiteSpace(state.ApiUrl)) + { + Uri.TryCreate(state.ApiUrl, UriKind.Absolute, out apiUri); + } + // Build proxy URL in a way that correctly handles IPv6 hosts. + string hostForProxy = apiUri?.Host ?? IPAddress.Loopback.ToString(); + var proxyUriBuilder = new UriBuilder(Uri.UriSchemeHttp, hostForProxy, state.Port); + var proxyUrl = proxyUriBuilder.Uri.ToString().TrimEnd('/'); await Console.Out.WriteLineAsync("Dev Proxy started in background."); await Console.Out.WriteLineAsync(); await Console.Out.WriteLineAsync($" PID: {state.Pid}"); From 6d703fb55e2f4141626e2a32d097a414be3e0f35 Mon Sep 17 00:00:00 2001 From: Waldek Mastykarz Date: Wed, 11 Mar 2026 11:00:47 +0100 Subject: [PATCH 4/4] Fix API URL showing port 0 when using --api-port 0 in detach mode After Kestrel binds, read the actual API address from IServerAddressesFeature and update the state file. The parent process now also waits for a resolved API URL before printing the detach output. --- DevProxy/Commands/DevProxyCommand.cs | 18 ++++++++++++++++++ DevProxy/Program.cs | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/DevProxy/Commands/DevProxyCommand.cs b/DevProxy/Commands/DevProxyCommand.cs index 77d464c0..e9b7ea92 100644 --- a/DevProxy/Commands/DevProxyCommand.cs +++ b/DevProxy/Commands/DevProxyCommand.cs @@ -1,6 +1,7 @@ using DevProxy.Abstractions.Plugins; using DevProxy.Abstractions.Proxy; using DevProxy.Abstractions.Utils; +using DevProxy.State; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; using System.CommandLine; @@ -314,6 +315,13 @@ private async Task InvokeAsync(ParseResult parseResult, CancellationToken c var serverAddresses = _app.Services.GetRequiredService().Features.Get(); var address = serverAddresses?.Addresses.FirstOrDefault() ?? $"http://{_proxyConfiguration.IPAddress}:{_proxyConfiguration.ApiPort}"; _logger.LogInformation("Dev Proxy API listening on {Address}...", address); + + // Update state file with the actual Kestrel API address + // (resolves port 0 to OS-assigned port) + if (IsInternalDaemon) + { + _ = UpdateStateWithApiUrlAsync(address); + } }); await _app.RunAsync(cancellationToken); @@ -716,4 +724,14 @@ private async Task CheckForNewVersionAsync() ); } } + + private static async Task UpdateStateWithApiUrlAsync(string apiUrl) + { + var state = await StateManager.LoadStateAsync(); + if (state is not null) + { + state.ApiUrl = apiUrl; + await StateManager.SaveStateAsync(state); + } + } } \ No newline at end of file diff --git a/DevProxy/Program.cs b/DevProxy/Program.cs index 7fbd322c..fb6db2a1 100644 --- a/DevProxy/Program.cs +++ b/DevProxy/Program.cs @@ -136,7 +136,7 @@ await Console.Error.WriteLineAsync( await Task.Delay(200); var state = await StateManager.LoadStateAsync(); - if (state is { Port: > 0 }) + if (state is { Port: > 0 } && !string.IsNullOrEmpty(state.ApiUrl) && !state.ApiUrl.EndsWith(":0", StringComparison.Ordinal)) { Uri? apiUri = null; if (!string.IsNullOrWhiteSpace(state.ApiUrl))