diff --git a/extension/schemas/aspire-global-settings.schema.json b/extension/schemas/aspire-global-settings.schema.json index 03ccb0aa580..d83898bdf5c 100644 --- a/extension/schemas/aspire-global-settings.schema.json +++ b/extension/schemas/aspire-global-settings.schema.json @@ -109,70 +109,6 @@ "description": "Enable or disable experimental Rust language support for polyglot Aspire applications", "default": false }, - "minimumSdkCheckEnabled": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "string", - "enum": [ - "true", - "false" - ] - } - ], - "description": "Enable or disable minimum .NET SDK version checking before running Aspire applications", - "default": true - }, - "orphanDetectionWithTimestampEnabled": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "string", - "enum": [ - "true", - "false" - ] - } - ], - "description": "Enable or disable timestamp-based orphan process detection to clean up stale Aspire processes", - "default": true - }, - "packageSearchDiskCachingEnabled": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "string", - "enum": [ - "true", - "false" - ] - } - ], - "description": "Enable or disable disk caching for package search results to improve performance", - "default": true - }, - "runningInstanceDetectionEnabled": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "string", - "enum": [ - "true", - "false" - ] - } - ], - "description": "Enable or disable detection of already running Aspire instances to prevent conflicts", - "default": true - }, "showAllTemplates": { "anyOf": [ { diff --git a/extension/schemas/aspire-settings.schema.json b/extension/schemas/aspire-settings.schema.json index b15d09198d7..0eb45d95814 100644 --- a/extension/schemas/aspire-settings.schema.json +++ b/extension/schemas/aspire-settings.schema.json @@ -113,70 +113,6 @@ "description": "Enable or disable experimental Rust language support for polyglot Aspire applications", "default": false }, - "minimumSdkCheckEnabled": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "string", - "enum": [ - "true", - "false" - ] - } - ], - "description": "Enable or disable minimum .NET SDK version checking before running Aspire applications", - "default": true - }, - "orphanDetectionWithTimestampEnabled": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "string", - "enum": [ - "true", - "false" - ] - } - ], - "description": "Enable or disable timestamp-based orphan process detection to clean up stale Aspire processes", - "default": true - }, - "packageSearchDiskCachingEnabled": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "string", - "enum": [ - "true", - "false" - ] - } - ], - "description": "Enable or disable disk caching for package search results to improve performance", - "default": true - }, - "runningInstanceDetectionEnabled": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "string", - "enum": [ - "true", - "false" - ] - } - ], - "description": "Enable or disable detection of already running Aspire instances to prevent conflicts", - "default": true - }, "showAllTemplates": { "anyOf": [ { diff --git a/src/Aspire.Cli/Commands/AddCommand.cs b/src/Aspire.Cli/Commands/AddCommand.cs index 8e557adb593..adfdc50f524 100644 --- a/src/Aspire.Cli/Commands/AddCommand.cs +++ b/src/Aspire.Cli/Commands/AddCommand.cs @@ -26,7 +26,6 @@ internal sealed class AddCommand : BaseCommand private readonly IAddCommandPrompter _prompter; private readonly IDotNetSdkInstaller _sdkInstaller; private readonly ICliHostEnvironment _hostEnvironment; - private readonly IFeatures _features; private readonly IAppHostProjectFactory _projectFactory; private static readonly Argument s_integrationArgument = new("integration") @@ -52,7 +51,6 @@ public AddCommand(IPackagingService packagingService, IInteractionService intera _prompter = prompter; _sdkInstaller = sdkInstaller; _hostEnvironment = hostEnvironment; - _features = features; _projectFactory = projectFactory; Arguments.Add(s_integrationArgument); @@ -210,22 +208,19 @@ await Parallel.ForEachAsync(channels, cancellationToken, async (channel, ct) => // Stop any running AppHost instance before adding the package. // A running AppHost (especially in detach mode) locks project files, // which prevents 'dotnet add package' from modifying the project. - if (_features.IsFeatureEnabled(KnownFeatures.RunningInstanceDetectionEnabled, defaultValue: true)) - { - var runningInstanceResult = await project.FindAndStopRunningInstanceAsync( - effectiveAppHostProjectFile, - ExecutionContext.HomeDirectory, - cancellationToken); + var runningInstanceResult = await project.FindAndStopRunningInstanceAsync( + effectiveAppHostProjectFile, + ExecutionContext.HomeDirectory, + cancellationToken); - if (runningInstanceResult == RunningInstanceResult.InstanceStopped) - { - InteractionService.DisplayMessage(KnownEmojis.Information, AddCommandStrings.StoppedRunningInstance); - } - else if (runningInstanceResult == RunningInstanceResult.StopFailed) - { - InteractionService.DisplayError(AddCommandStrings.UnableToStopRunningInstances); - return ExitCodeConstants.FailedToAddPackage; - } + if (runningInstanceResult == RunningInstanceResult.InstanceStopped) + { + InteractionService.DisplayMessage(KnownEmojis.Information, AddCommandStrings.StoppedRunningInstance); + } + else if (runningInstanceResult == RunningInstanceResult.StopFailed) + { + InteractionService.DisplayError(AddCommandStrings.UnableToStopRunningInstances); + return ExitCodeConstants.FailedToAddPackage; } var success = await InteractionService.ShowStatusAsync( diff --git a/src/Aspire.Cli/Commands/AppHostLauncher.cs b/src/Aspire.Cli/Commands/AppHostLauncher.cs index fac027e55db..47b6b1d042f 100644 --- a/src/Aspire.Cli/Commands/AppHostLauncher.cs +++ b/src/Aspire.Cli/Commands/AppHostLauncher.cs @@ -6,7 +6,6 @@ using System.Globalization; using System.Text.Json; using Aspire.Cli.Backchannel; -using Aspire.Cli.Configuration; using Aspire.Cli.Interaction; using Aspire.Cli.Processes; using Aspire.Cli.Projects; @@ -24,7 +23,6 @@ namespace Aspire.Cli.Commands; internal sealed class AppHostLauncher( IProjectLocator projectLocator, CliExecutionContext executionContext, - IFeatures features, IInteractionService interactionService, IAuxiliaryBackchannelMonitor backchannelMonitor, ILogger logger, @@ -150,12 +148,11 @@ public async Task LaunchDetachedAsync( private async Task StopExistingInstancesAsync(FileInfo effectiveAppHostFile, CancellationToken cancellationToken) { - var runningInstanceDetectionEnabled = features.IsFeatureEnabled(KnownFeatures.RunningInstanceDetectionEnabled, defaultValue: true); var existingSockets = AppHostHelper.FindMatchingSockets( effectiveAppHostFile.FullName, executionContext.HomeDirectory.FullName); - if (runningInstanceDetectionEnabled && existingSockets.Length > 0) + if (existingSockets.Length > 0) { logger.LogDebug("Found {Count} running instance(s) for this AppHost, stopping them first.", existingSockets.Length); var manager = new RunningInstanceManager(logger, interactionService, timeProvider); diff --git a/src/Aspire.Cli/Commands/RunCommand.cs b/src/Aspire.Cli/Commands/RunCommand.cs index e3646880bb8..ed791e38c52 100644 --- a/src/Aspire.Cli/Commands/RunCommand.cs +++ b/src/Aspire.Cli/Commands/RunCommand.cs @@ -140,9 +140,6 @@ protected override async Task ExecuteAsync(ParseResult parseResult, Cancell Debug.Assert(_startDebugSessionOption is not null); startDebugSession = parseResult.GetValue(_startDebugSessionOption); } - var runningInstanceDetectionEnabled = _features.IsFeatureEnabled(KnownFeatures.RunningInstanceDetectionEnabled, defaultValue: true); - // Force option kept for backward compatibility but no longer used since prompt was removed - // var force = runningInstanceDetectionEnabled && parseResult.GetValue("--force"); // Validate that --format is only used with --detach if (format == OutputFormat.Json && !detach) @@ -198,19 +195,15 @@ protected override async Task ExecuteAsync(ParseResult parseResult, Cancell return ExitCodeConstants.FailedToFindProject; } - // Check for running instance if feature is enabled - if (runningInstanceDetectionEnabled) - { - // Even if we fail to stop we won't block the apphost starting - // to make sure we don't ever break flow. It should mostly stop - // just fine though. - var runningInstanceResult = await project.FindAndStopRunningInstanceAsync(effectiveAppHostFile, ExecutionContext.HomeDirectory, cancellationToken); + // Check for running instance — even if we fail to stop we won't + // block the apphost starting to make sure we don't ever break flow. + // It should mostly stop just fine though. + var runningInstanceResult = await project.FindAndStopRunningInstanceAsync(effectiveAppHostFile, ExecutionContext.HomeDirectory, cancellationToken); - // If in isolated mode and a running instance was stopped, warn the user - if (isolated && runningInstanceResult == RunningInstanceResult.InstanceStopped) - { - InteractionService.DisplayMessage(KnownEmojis.Warning, RunCommandStrings.IsolatedModeRunningInstanceWarning); - } + // If in isolated mode and a running instance was stopped, warn the user + if (isolated && runningInstanceResult == RunningInstanceResult.InstanceStopped) + { + InteractionService.DisplayMessage(KnownEmojis.Warning, RunCommandStrings.IsolatedModeRunningInstanceWarning); } // The completion sources are the contract between RunCommand and IAppHostProject diff --git a/src/Aspire.Cli/DotNet/DotNetCliExecutionFactory.cs b/src/Aspire.Cli/DotNet/DotNetCliExecutionFactory.cs index 4055006d29d..fbd85db507e 100644 --- a/src/Aspire.Cli/DotNet/DotNetCliExecutionFactory.cs +++ b/src/Aspire.Cli/DotNet/DotNetCliExecutionFactory.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.Globalization; using System.Runtime.InteropServices; -using Aspire.Cli.Configuration; using Aspire.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; @@ -14,7 +13,6 @@ namespace Aspire.Cli.DotNet; internal sealed class DotNetCliExecutionFactory( ILogger logger, IConfiguration configuration, - IFeatures features, CliExecutionContext executionContext) : IDotNetCliExecutionFactory { internal static int GetCurrentProcessId() => Environment.ProcessId; @@ -73,10 +71,7 @@ public IDotNetCliExecution CreateExecution(string[] args, IDictionary ComputeNuGetConfigHierarchySha256Async(DirectoryInfo w using var activity = telemetry.StartDiagnosticActivity(); string? rawKey = null; - bool cacheEnabled = useCache && features.IsFeatureEnabled(KnownFeatures.PackageSearchDiskCachingEnabled, defaultValue: true); - if (cacheEnabled) + var cacheEnabled = useCache; + if (useCache) { try { diff --git a/src/Aspire.Cli/DotNet/DotNetSdkInstaller.cs b/src/Aspire.Cli/DotNet/DotNetSdkInstaller.cs index 36b20947242..95d88d5c198 100644 --- a/src/Aspire.Cli/DotNet/DotNetSdkInstaller.cs +++ b/src/Aspire.Cli/DotNet/DotNetSdkInstaller.cs @@ -3,7 +3,6 @@ using System.Diagnostics; using System.Runtime.InteropServices; -using Aspire.Cli.Configuration; using Microsoft.Extensions.Configuration; using Semver; @@ -12,7 +11,7 @@ namespace Aspire.Cli.DotNet; /// /// Default implementation of that checks for dotnet on the system PATH. /// -internal sealed class DotNetSdkInstaller(IFeatures features, IConfiguration configuration) : IDotNetSdkInstaller +internal sealed class DotNetSdkInstaller(IConfiguration configuration) : IDotNetSdkInstaller { /// /// The minimum .NET SDK version required for Aspire. @@ -24,12 +23,6 @@ internal sealed class DotNetSdkInstaller(IFeatures features, IConfiguration conf { var minimumVersion = GetEffectiveMinimumSdkVersion(configuration); - if (!features.IsFeatureEnabled(KnownFeatures.MinimumSdkCheckEnabled, true)) - { - // If the feature is disabled, we assume the SDK is available - return (true, null, minimumVersion); - } - try { // Add --arch flag to ensure we only get SDKs that match the current architecture diff --git a/src/Aspire.Cli/KnownFeatures.cs b/src/Aspire.Cli/KnownFeatures.cs index 0531317439b..f478b7acd27 100644 --- a/src/Aspire.Cli/KnownFeatures.cs +++ b/src/Aspire.Cli/KnownFeatures.cs @@ -16,11 +16,8 @@ internal static class KnownFeatures { public static string FeaturePrefix => "features"; public static string UpdateNotificationsEnabled => "updateNotificationsEnabled"; - public static string MinimumSdkCheckEnabled => "minimumSdkCheckEnabled"; public static string ExecCommandEnabled => "execCommandEnabled"; - public static string OrphanDetectionWithTimestampEnabled => "orphanDetectionWithTimestampEnabled"; public static string ShowDeprecatedPackages => "showDeprecatedPackages"; - public static string PackageSearchDiskCachingEnabled => "packageSearchDiskCachingEnabled"; public static string StagingChannelEnabled => "stagingChannelEnabled"; public static string DefaultWatchEnabled => "defaultWatchEnabled"; public static string ShowAllTemplates => "showAllTemplates"; @@ -28,7 +25,6 @@ internal static class KnownFeatures public static string ExperimentalPolyglotJava => "experimentalPolyglot:java"; public static string ExperimentalPolyglotGo => "experimentalPolyglot:go"; public static string ExperimentalPolyglotPython => "experimentalPolyglot:python"; - public static string RunningInstanceDetectionEnabled => "runningInstanceDetectionEnabled"; private static readonly Dictionary s_featureMetadata = new() { @@ -37,31 +33,16 @@ internal static class KnownFeatures "Check if update notifications are disabled and set version check environment variable", DefaultValue: true), - [MinimumSdkCheckEnabled] = new( - MinimumSdkCheckEnabled, - "Enable or disable minimum .NET SDK version checking before running Aspire applications", - DefaultValue: true), - [ExecCommandEnabled] = new( ExecCommandEnabled, "Enable or disable the 'aspire exec' command for executing commands inside running resources", DefaultValue: false), - [OrphanDetectionWithTimestampEnabled] = new( - OrphanDetectionWithTimestampEnabled, - "Enable or disable timestamp-based orphan process detection to clean up stale Aspire processes", - DefaultValue: true), - [ShowDeprecatedPackages] = new( ShowDeprecatedPackages, "Show or hide deprecated packages in 'aspire add' search results", DefaultValue: false), - [PackageSearchDiskCachingEnabled] = new( - PackageSearchDiskCachingEnabled, - "Enable or disable disk caching for package search results to improve performance", - DefaultValue: true), - [StagingChannelEnabled] = new( StagingChannelEnabled, "Enable or disable access to the staging channel for early access to preview features and packages", @@ -95,12 +76,7 @@ internal static class KnownFeatures [ExperimentalPolyglotPython] = new( ExperimentalPolyglotPython, "Enable or disable experimental Python language support for polyglot Aspire applications", - DefaultValue: false), - - [RunningInstanceDetectionEnabled] = new( - RunningInstanceDetectionEnabled, - "Enable or disable detection of already running Aspire instances to prevent conflicts", - DefaultValue: true) + DefaultValue: false) }; /// diff --git a/tests/Aspire.Cli.Tests/Commands/RunCommandTests.cs b/tests/Aspire.Cli.Tests/Commands/RunCommandTests.cs index 11113158451..4300a9b1e24 100644 --- a/tests/Aspire.Cli.Tests/Commands/RunCommandTests.cs +++ b/tests/Aspire.Cli.Tests/Commands/RunCommandTests.cs @@ -1268,21 +1268,6 @@ public Task UseOrFindAppHostProjectFileAsync(FileInf } } - [Fact] - public void RunCommand_RunningInstanceDetectionFeatureFlag_DefaultsToFalse() - { - // Verify that the running instance detection feature flag defaults to false - // to ensure existing behavior is not changed unless explicitly enabled - using var workspace = TemporaryWorkspace.Create(outputHelper); - var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper); - var provider = services.BuildServiceProvider(); - - var features = provider.GetRequiredService(); - var isEnabled = features.IsFeatureEnabled(KnownFeatures.RunningInstanceDetectionEnabled, defaultValue: true); - - Assert.True(isEnabled, "Running instance detection should be enabled by default"); - } - [Fact] public async Task RunCommand_WithNoBuildOption_SkipsBuildAndPassesNoBuildAndNoRestoreToRunner() { diff --git a/tests/Aspire.Cli.Tests/DotNetSdkInstallerTests.cs b/tests/Aspire.Cli.Tests/DotNetSdkInstallerTests.cs index 1fc97211321..f7bf937ef07 100644 --- a/tests/Aspire.Cli.Tests/DotNetSdkInstallerTests.cs +++ b/tests/Aspire.Cli.Tests/DotNetSdkInstallerTests.cs @@ -16,7 +16,7 @@ public class DotNetSdkInstallerTests [Fact] public async Task CheckAsync_WhenDotNetIsAvailable_ReturnsTrue() { - var installer = new DotNetSdkInstaller(new MinimumSdkCheckFeature(), CreateEmptyConfiguration()); + var installer = new DotNetSdkInstaller(CreateEmptyConfiguration()); // This test assumes the test environment has .NET SDK installed var (success, _, _) = await installer.CheckAsync().DefaultTimeout(); @@ -27,10 +27,8 @@ public async Task CheckAsync_WhenDotNetIsAvailable_ReturnsTrue() [Fact] public async Task CheckAsync_WithMinimumVersion_WhenDotNetIsAvailable_ReturnsTrue() { - var features = new TestFeatures() - .SetFeature(KnownFeatures.MinimumSdkCheckEnabled, true); var configuration = CreateConfigurationWithOverride("8.0.0"); - var installer = new DotNetSdkInstaller(features, configuration); + var installer = new DotNetSdkInstaller(configuration); // This test assumes the test environment has .NET SDK installed with a version >= 8.0.0 var (success, _, _) = await installer.CheckAsync().DefaultTimeout(); @@ -41,10 +39,8 @@ public async Task CheckAsync_WithMinimumVersion_WhenDotNetIsAvailable_ReturnsTru [Fact] public async Task CheckAsync_WithActualMinimumVersion_BehavesCorrectly() { - var features = new TestFeatures() - .SetFeature(KnownFeatures.MinimumSdkCheckEnabled, true); var configuration = CreateConfigurationWithOverride(DotNetSdkInstaller.MinimumSdkVersion); - var installer = new DotNetSdkInstaller(features, configuration); + var installer = new DotNetSdkInstaller(configuration); // Use the actual minimum version constant and check the behavior var (success, _, _) = await installer.CheckAsync().DefaultTimeout(); @@ -57,10 +53,8 @@ public async Task CheckAsync_WithActualMinimumVersion_BehavesCorrectly() [Fact] public async Task CheckAsync_WithHighMinimumVersion_ReturnsFalse() { - var features = new TestFeatures() - .SetFeature(KnownFeatures.MinimumSdkCheckEnabled, true); var configuration = CreateConfigurationWithOverride("99.0.0"); - var installer = new DotNetSdkInstaller(features, configuration); + var installer = new DotNetSdkInstaller(configuration); // Use an unreasonably high version that should not exist var (success, _, _) = await installer.CheckAsync().DefaultTimeout(); @@ -71,10 +65,8 @@ public async Task CheckAsync_WithHighMinimumVersion_ReturnsFalse() [Fact] public async Task CheckAsync_WithInvalidMinimumVersion_ReturnsFalse() { - var features = new TestFeatures() - .SetFeature(KnownFeatures.MinimumSdkCheckEnabled, true); var configuration = CreateConfigurationWithOverride("invalid.version"); - var installer = new DotNetSdkInstaller(features, configuration); + var installer = new DotNetSdkInstaller(configuration); // Use an invalid version string var (success, _, _) = await installer.CheckAsync().DefaultTimeout(); @@ -82,27 +74,11 @@ public async Task CheckAsync_WithInvalidMinimumVersion_ReturnsFalse() Assert.False(success); } - [Fact] - public async Task CheckReturnsTrueIfFeatureDisabled() - { - var features = new TestFeatures() - .SetFeature(KnownFeatures.MinimumSdkCheckEnabled, false); - var configuration = CreateConfigurationWithOverride("invalid.version"); - var installer = new DotNetSdkInstaller(features, configuration); - - // Use an invalid version string - var (success, _, _) = await installer.CheckAsync().DefaultTimeout(); - - Assert.True(success); - } - [Fact] public async Task CheckAsync_UsesArchitectureSpecificCommand() { - var features = new TestFeatures() - .SetFeature(KnownFeatures.MinimumSdkCheckEnabled, true); var configuration = CreateConfigurationWithOverride("8.0.0"); - var installer = new DotNetSdkInstaller(features, configuration); + var installer = new DotNetSdkInstaller(configuration); // This test verifies that the architecture-specific command is used // Since the implementation adds --arch flag, it should still work correctly @@ -116,7 +92,7 @@ public async Task CheckAsync_UsesArchitectureSpecificCommand() public async Task CheckAsync_UsesOverrideMinimumSdkVersion_WhenConfigured() { var configuration = CreateConfigurationWithOverride("8.0.0"); - var installer = new DotNetSdkInstaller(new MinimumSdkCheckFeature(), configuration); + var installer = new DotNetSdkInstaller(configuration); // The installer should use the override version instead of the constant var (success, _, _) = await installer.CheckAsync().DefaultTimeout(); @@ -128,7 +104,7 @@ public async Task CheckAsync_UsesOverrideMinimumSdkVersion_WhenConfigured() [Fact] public async Task CheckAsync_UsesDefaultMinimumSdkVersion_WhenNotConfigured() { - var installer = new DotNetSdkInstaller(new MinimumSdkCheckFeature(), CreateEmptyConfiguration()); + var installer = new DotNetSdkInstaller(CreateEmptyConfiguration()); // Call the parameterless method that should use the default constant var (success, _, _) = await installer.CheckAsync().DefaultTimeout(); @@ -140,9 +116,7 @@ public async Task CheckAsync_UsesDefaultMinimumSdkVersion_WhenNotConfigured() [Fact] public async Task CheckAsync_UsesMinimumSdkVersion() { - var features = new TestFeatures() - .SetFeature(KnownFeatures.MinimumSdkCheckEnabled, true); - var installer = new DotNetSdkInstaller(features, CreateEmptyConfiguration()); + var installer = new DotNetSdkInstaller(CreateEmptyConfiguration()); // Call the parameterless method that should use the minimum SDK version var (success, _, _) = await installer.CheckAsync().DefaultTimeout(); @@ -154,10 +128,8 @@ public async Task CheckAsync_UsesMinimumSdkVersion() [Fact] public async Task CheckAsync_UsesOverrideVersion_WhenOverrideConfigured() { - var features = new TestFeatures() - .SetFeature(KnownFeatures.MinimumSdkCheckEnabled, true); var configuration = CreateConfigurationWithOverride("8.0.0"); - var installer = new DotNetSdkInstaller(features, configuration); + var installer = new DotNetSdkInstaller(configuration); // The installer should use the override version instead of the baseline constant var (success, _, _) = await installer.CheckAsync().DefaultTimeout(); @@ -278,14 +250,6 @@ private static IConfiguration CreateConfigurationWithOverride(string overrideVer } } -public class MinimumSdkCheckFeature(bool enabled = true) : IFeatures -{ - public bool IsFeatureEnabled(string featureName, bool defaultValue = false) - { - return featureName == KnownFeatures.MinimumSdkCheckEnabled ? enabled : false; - } -} - public class TestFeatures : IFeatures { private readonly Dictionary _features = new(); diff --git a/tests/Shared/Hex1bTestHelpers.cs b/tests/Shared/Hex1bTestHelpers.cs index 75795683204..13eac06dca7 100644 --- a/tests/Shared/Hex1bTestHelpers.cs +++ b/tests/Shared/Hex1bTestHelpers.cs @@ -279,14 +279,21 @@ internal static Hex1bTerminalInputSequenceBuilder ExecuteCallback( /// Handles the agent init confirmation prompt that appears after aspire init or aspire new. /// Declines the prompt so the command exits cleanly. /// + /// The sequence builder. + /// + /// How long to wait for the prompt. This must cover the time for project creation + /// (dotnet new) to finish plus the prompt appearing. Defaults to 120 seconds + /// to accommodate slow CI environments (e.g., when KinD clusters are running). + /// internal static Hex1bTerminalInputSequenceBuilder DeclineAgentInitPrompt( - this Hex1bTerminalInputSequenceBuilder builder) + this Hex1bTerminalInputSequenceBuilder builder, + TimeSpan? timeout = null) { var agentInitPrompt = new CellPatternSearcher() .Find("configure AI agent environments"); return builder - .WaitUntil(s => agentInitPrompt.Search(s).Count > 0, TimeSpan.FromSeconds(30)) + .WaitUntil(s => agentInitPrompt.Search(s).Count > 0, timeout ?? TimeSpan.FromSeconds(120)) .Wait(500) .Type("n") .Enter();