diff --git a/Assets/Tests/Editor/SetupWizardWindowTests.cs b/Assets/Tests/Editor/SetupWizardWindowTests.cs index 95e31b66b..6fcc5febb 100644 --- a/Assets/Tests/Editor/SetupWizardWindowTests.cs +++ b/Assets/Tests/Editor/SetupWizardWindowTests.cs @@ -779,6 +779,58 @@ public void GetSkillsButtonTextForSetupWizard_ReturnsExpectedLabel( Assert.That(label, Is.EqualTo(expectedLabel)); } + [Test] + public void ShouldShowSkillsInstalledDialog_WhenTargetsAreMissing_ReturnsTrue() + { + // Verifies that Setup Wizard keeps the success dialog for first install. + List targets = new() + { + CreateSkillTarget( + hasSkillsDirectory: true, + SkillInstallState.Missing) + }; + + bool shouldShowDialog = SetupWizardWindow.ShouldShowSkillsInstalledDialog(targets); + + Assert.That(shouldShowDialog, Is.True); + } + + [Test] + public void ShouldShowSkillsInstalledDialog_WhenAnyTargetIsOutdated_ReturnsFalse() + { + // Verifies that Setup Wizard suppresses the success dialog for skill updates. + List targets = new() + { + CreateSkillTarget( + hasSkillsDirectory: true, + SkillInstallState.Missing), + CreateSkillTarget( + hasSkillsDirectory: true, + SkillInstallState.Outdated) + }; + + bool shouldShowDialog = SetupWizardWindow.ShouldShowSkillsInstalledDialog(targets); + + Assert.That(shouldShowDialog, Is.False); + } + + [Test] + public void ShouldShowSkillsInstalledDialog_WhenAnyTargetUsesDifferentLayout_ReturnsFalse() + { + // Verifies that Setup Wizard suppresses the success dialog for skill layout updates. + List targets = new() + { + CreateSkillTarget( + hasSkillsDirectory: true, + SkillInstallState.Missing, + hasDifferentLayoutSkills: true) + }; + + bool shouldShowDialog = SetupWizardWindow.ShouldShowSkillsInstalledDialog(targets); + + Assert.That(shouldShowDialog, Is.False); + } + [TestCase(SkillInstallState.Installed, false, true, "setup-target-item__status--installed")] [TestCase(SkillInstallState.Checking, false, true, "setup-target-item__status--checking")] [TestCase(SkillInstallState.Outdated, false, true, "setup-target-item__status--outdated")] diff --git a/Assets/Tests/Editor/UnityCliLoopSettingsWindowCliActionTests.cs b/Assets/Tests/Editor/UnityCliLoopSettingsWindowCliActionTests.cs index 8c8c208dc..756b2eb76 100644 --- a/Assets/Tests/Editor/UnityCliLoopSettingsWindowCliActionTests.cs +++ b/Assets/Tests/Editor/UnityCliLoopSettingsWindowCliActionTests.cs @@ -1,6 +1,7 @@ using NUnit.Framework; using UnityEngine; +using io.github.hatayama.UnityCliLoop.Domain; using io.github.hatayama.UnityCliLoop.Presentation; namespace io.github.hatayama.UnityCliLoop.Tests.Editor @@ -131,6 +132,36 @@ public void IsCliUpdateNeeded_UsesDispatcherMinimumVersion( Assert.That(result, Is.EqualTo(expected)); } + [TestCase(SkillInstallState.Missing, false, true)] + [TestCase(SkillInstallState.Outdated, false, false)] + [TestCase(SkillInstallState.Missing, true, false)] + public void ShouldShowSkillsInstalledDialog_ReturnsExpectedValue( + SkillInstallState installState, + bool hasDifferentLayoutSkills, + bool expected) + { + // Verifies that Settings keeps the success dialog for first install only. + SkillSetupTargetInfo targetInfo = CreateSkillTarget(installState, hasDifferentLayoutSkills); + + bool result = UnityCliLoopSettingsWindow.ShouldShowSkillsInstalledDialog(targetInfo); + + Assert.That(result, Is.EqualTo(expected)); + } + + private static SkillSetupTargetInfo CreateSkillTarget( + SkillInstallState installState, + bool hasDifferentLayoutSkills) + { + return new SkillSetupTargetInfo( + "Claude Code", + ".claude", + "--claude", + hasSkillsDirectory: true, + hasExistingSkills: true, + hasDifferentLayoutSkills, + installState); + } + private static UnityCliLoopSettingsWindow.CliPrimaryButtonAction ParseAction(string action) { return (UnityCliLoopSettingsWindow.CliPrimaryButtonAction) diff --git a/Packages/src/Editor/Presentation/Setup/SetupWizardWindow.cs b/Packages/src/Editor/Presentation/Setup/SetupWizardWindow.cs index 9e8600c8e..e1fdffff5 100644 --- a/Packages/src/Editor/Presentation/Setup/SetupWizardWindow.cs +++ b/Packages/src/Editor/Presentation/Setup/SetupWizardWindow.cs @@ -779,6 +779,15 @@ internal static bool HasSkillUpdateForSetupWizard( || target.HasDifferentLayoutSkills)); } + internal static bool ShouldShowSkillsInstalledDialog( + IEnumerable targets) + { + Debug.Assert(targets != null, "targets must not be null"); + return targets.All(target => + target.InstallState != SkillInstallState.Outdated + && !target.HasDifferentLayoutSkills); + } + internal static bool ShouldUseFirstInstallSkillsUi(string lastSeenSetupWizardVersion) { return string.IsNullOrEmpty(lastSeenSetupWizardVersion); @@ -1316,6 +1325,7 @@ private async void HandleInstallSkills() : FilterInstallableSkillTargets(targets); if (installableTargets.Count == 0) return; + bool shouldShowSkillsInstalledDialog = ShouldShowSkillsInstalledDialog(installableTargets); _isInstallingSkills = true; UpdateSkillsStep(true, targets); @@ -1325,7 +1335,10 @@ await _skillSetupUseCase.InstallSkillFilesAsync( installableTargets, !_installSkillsFlat, CancellationToken.None); - EditorDialogHelper.ShowSkillsInstalledDialog(); + if (shouldShowSkillsInstalledDialog) + { + EditorDialogHelper.ShowSkillsInstalledDialog(); + } } finally { diff --git a/Packages/src/Editor/Presentation/UnityCliLoopSettingsWindow.cs b/Packages/src/Editor/Presentation/UnityCliLoopSettingsWindow.cs index 275130f7a..9dc105773 100644 --- a/Packages/src/Editor/Presentation/UnityCliLoopSettingsWindow.cs +++ b/Packages/src/Editor/Presentation/UnityCliLoopSettingsWindow.cs @@ -736,6 +736,16 @@ private SkillInstallState GetSelectedTargetInstallState(bool includeFreshnessChe private SkillInstallState GetSelectedTargetInstallState( string projectRoot, bool includeFreshnessCheck) + { + SkillSetupTargetInfo targetInfo = GetSelectedTargetInfo(projectRoot, includeFreshnessCheck); + return string.IsNullOrEmpty(targetInfo.DirName) + ? SkillInstallState.Missing + : targetInfo.InstallState; + } + + private SkillSetupTargetInfo GetSelectedTargetInfo( + string projectRoot, + bool includeFreshnessCheck) { SkillsTargetSelection selection = SkillsTargetSelectionResolver.Resolve( _skillsTarget, @@ -746,9 +756,7 @@ private SkillInstallState GetSelectedTargetInstallState( SkillSetupTargetInfo targetInfo = targets .FirstOrDefault(target => target.DirName == selection.DirectoryName); - return string.IsNullOrEmpty(targetInfo.DirName) - ? SkillInstallState.Missing - : targetInfo.InstallState; + return targetInfo; } private void CancelSkillInstallStateRefresh() @@ -967,6 +975,12 @@ internal static bool IsCliUpdateNeeded(string cliVersion, bool cliIsDispatcher) return EvaluateCliSetupCompatibility(cliVersion, cliIsDispatcher).NeedsUpdate; } + internal static bool ShouldShowSkillsInstalledDialog(SkillSetupTargetInfo targetInfo) + { + return targetInfo.InstallState != SkillInstallState.Outdated + && !targetInfo.HasDifferentLayoutSkills; + } + private static CliSetupCompatibilityState EvaluateCliSetupCompatibility( string cliVersion, bool cliIsDispatcher) @@ -1019,6 +1033,10 @@ private async void HandleInstallSkills() return; } + string projectRoot = UnityCliLoopPathResolver.GetProjectRoot(); + SkillSetupTargetInfo selectedTargetInfo = + GetSelectedTargetInfo(projectRoot, includeFreshnessCheck: true); + bool shouldShowSkillsInstalledDialog = ShouldShowSkillsInstalledDialog(selectedTargetInfo); CancelSkillInstallStateRefresh(); _isInstallingSkills = true; RefreshCliSetupSection(); @@ -1040,7 +1058,10 @@ await _skillSetupUseCase.InstallSkillFilesAsync( new List { target }, !_installSkillsFlat, CancellationToken.None); - EditorDialogHelper.ShowSkillsInstalledDialog(); + if (shouldShowSkillsInstalledDialog) + { + EditorDialogHelper.ShowSkillsInstalledDialog(); + } } finally {