From 1f6121f501af3a6c198709d78feeb6b4cffe5159 Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Fri, 28 Aug 2026 23:49:53 +0000 Subject: [PATCH 1/2] fix: keep installed binaries on full reset --- .../Tui/InitExistingInstallViewModelTests.cs | 7 ++++++- .../Tui/InitExistingInstallViewModel.cs | 14 +++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Netclaw.Cli.Tests/Tui/InitExistingInstallViewModelTests.cs b/src/Netclaw.Cli.Tests/Tui/InitExistingInstallViewModelTests.cs index 77ee26868..7fcc477f1 100644 --- a/src/Netclaw.Cli.Tests/Tui/InitExistingInstallViewModelTests.cs +++ b/src/Netclaw.Cli.Tests/Tui/InitExistingInstallViewModelTests.cs @@ -103,6 +103,9 @@ public async Task FullReset_AfterBothConfirmations_DeletesEverything() { File.WriteAllText(_paths.NetclawConfigPath, "{}"); File.WriteAllText(_paths.SqliteDbPath, "db"); + // bin/ holds the installed binaries; a full reset must purge data but keep it. + var binaryPath = Path.Combine(_paths.BinDirectory, "netclaw"); + File.WriteAllText(binaryPath, "binary"); var vm = Create(); string? route = null; @@ -113,7 +116,9 @@ public async Task FullReset_AfterBothConfirmations_DeletesEverything() Select(vm, 1); // Yes → perform await WaitForProgressAsync(vm, 3); - Assert.False(Directory.Exists(_paths.BasePath)); + Assert.False(Directory.Exists(_paths.ConfigDirectory), "Config should be purged."); + Assert.False(File.Exists(_paths.SqliteDbPath), "Memory db should be purged."); + Assert.True(File.Exists(binaryPath), "Installed binaries in bin/ must survive a full reset."); await CompleteResetAsync(vm); Assert.Equal(InitExistingInstallViewModel.WizardRoute, route); } diff --git a/src/Netclaw.Cli/Tui/InitExistingInstallViewModel.cs b/src/Netclaw.Cli/Tui/InitExistingInstallViewModel.cs index 86b5d3012..ba43466cc 100644 --- a/src/Netclaw.Cli/Tui/InitExistingInstallViewModel.cs +++ b/src/Netclaw.Cli/Tui/InitExistingInstallViewModel.cs @@ -236,7 +236,19 @@ private async Task RunResetAsync(CancellationToken ct) if (_scope == ResetScopeKind.Full) { - _deleteDirectory(_paths.BasePath); + // Purge everything under BasePath except bin/ — the installed binaries + // live there and deleting them would brick the CLI mid-reset. + foreach (var entry in Directory.GetDirectories(_paths.BasePath)) + { + var name = Path.GetFileName(entry); + if (string.Equals(name, "bin", StringComparison.OrdinalIgnoreCase)) + continue; + + _deleteDirectory(entry); + } + + foreach (var file in Directory.GetFiles(_paths.BasePath)) + File.Delete(file); } else { From 37c592a9f1d0a5f567ca71677bf0c213d53dff1a Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Sat, 29 Aug 2026 12:21:26 +0000 Subject: [PATCH 2/2] fix: rekey reset failure fakes to ConfigDirectory --- src/Netclaw.Cli.Tests/Tui/InitExistingInstallPageTests.cs | 2 +- .../Tui/InitExistingInstallViewModelTests.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Netclaw.Cli.Tests/Tui/InitExistingInstallPageTests.cs b/src/Netclaw.Cli.Tests/Tui/InitExistingInstallPageTests.cs index 75a852eb5..d9261e072 100644 --- a/src/Netclaw.Cli.Tests/Tui/InitExistingInstallPageTests.cs +++ b/src/Netclaw.Cli.Tests/Tui/InitExistingInstallPageTests.cs @@ -42,7 +42,7 @@ public async Task ProgressScreen_RendersQueuedUpdates_AndOnlyCtrlQExits() (_, _) => Task.FromResult(new DaemonResult(true, "Daemon stopped.")), path => { - if (path == _paths.BasePath) + if (path == _paths.ConfigDirectory) { deleteStarted.TrySetResult(); releaseDelete.Task.GetAwaiter().GetResult(); diff --git a/src/Netclaw.Cli.Tests/Tui/InitExistingInstallViewModelTests.cs b/src/Netclaw.Cli.Tests/Tui/InitExistingInstallViewModelTests.cs index 7fcc477f1..7ca481799 100644 --- a/src/Netclaw.Cli.Tests/Tui/InitExistingInstallViewModelTests.cs +++ b/src/Netclaw.Cli.Tests/Tui/InitExistingInstallViewModelTests.cs @@ -297,7 +297,7 @@ public async Task Dispose_WhileDeleteIsRunning_CancelsCompletionNavigation() var releaseDelete = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var vm = Create(DaemonStopped, path => { - if (path == _paths.BasePath) + if (path == _paths.ConfigDirectory) { deleteStarted.TrySetResult(); releaseDelete.Task.GetAwaiter().GetResult(); @@ -355,7 +355,7 @@ public async Task ResetFailure_AfterBlockedQuit_ClearsQuitDisabledStatus() var releaseDelete = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var vm = Create(DaemonStopped, path => { - if (path == _paths.BasePath) + if (path == _paths.ConfigDirectory) { deleteStarted.TrySetResult(); releaseDelete.Task.GetAwaiter().GetResult();