From 7f6aa7539c9d631023a94c36c816fab1f27a5922 Mon Sep 17 00:00:00 2001 From: hatayama Date: Sun, 19 Jul 2026 14:11:16 +0900 Subject: [PATCH] Fix setup wizard skill installation fallback Use the first-install target UI when no existing skill folders are detected, and share the resolved mode with the install workflow so the enabled button creates the selected folder. --- Assets/Tests/Editor/SetupWizardWindowTests.cs | 16 ++++++++++ .../Setup/SetupWizardSkillsStepPresenter.cs | 32 +++++++++++-------- .../SetupWizardSkillsWorkflowController.cs | 9 ++++-- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/Assets/Tests/Editor/SetupWizardWindowTests.cs b/Assets/Tests/Editor/SetupWizardWindowTests.cs index 6071929260..85d65621cb 100644 --- a/Assets/Tests/Editor/SetupWizardWindowTests.cs +++ b/Assets/Tests/Editor/SetupWizardWindowTests.cs @@ -462,6 +462,22 @@ public void FilterInstallableSkillTargets_ExcludesTargetsWithoutSkillsDirectory( Assert.That(installableTargets[1].DirName, Is.EqualTo(".codex")); } + [TestCase(true, 0, true)] + [TestCase(false, 0, true)] + [TestCase(false, 1, false)] + public void ResolveUseFirstInstallSkillsUi_ReturnsExpectedMode( + bool shouldUseFirstInstallSkillsUi, + int installableTargetCount, + bool expected) + { + // Verifies that empty installable target results fall back to the first-install skill UI. + bool actual = SetupWizardSkillsStepPresenter.ResolveUseFirstInstallSkillsUi( + shouldUseFirstInstallSkillsUi, + installableTargetCount); + + Assert.That(actual, Is.EqualTo(expected)); + } + [Test] public void ShouldUseFirstInstallSkillsUi_WhenVersionWasNeverSeen_ReturnsTrue() { diff --git a/Packages/src/Editor/Presentation/Setup/SetupWizardSkillsStepPresenter.cs b/Packages/src/Editor/Presentation/Setup/SetupWizardSkillsStepPresenter.cs index 1a74f5bf9a..5644b3eee4 100644 --- a/Packages/src/Editor/Presentation/Setup/SetupWizardSkillsStepPresenter.cs +++ b/Packages/src/Editor/Presentation/Setup/SetupWizardSkillsStepPresenter.cs @@ -65,13 +65,17 @@ internal void Update( bool groupSkillsUnderUnityCliLoop, bool isInstallingSkills) { + List installableTargets = FilterInstallableSkillTargets(targets); + bool useFirstInstallSkillsUi = ResolveUseFirstInstallSkillsUi( + shouldUseFirstInstallSkillsUi, + installableTargets.Count); _skillsTargetList.Clear(); ViewDataBinder.SetVisible( _skillsTargetRow, - ShouldShowSkillsTargetRowForSetupWizard(shouldUseFirstInstallSkillsUi)); + ShouldShowSkillsTargetRowForSetupWizard(useFirstInstallSkillsUi)); ViewDataBinder.SetVisible( _skillsTargetList, - ShouldShowSkillsTargetListForSetupWizard(canManageSkills, shouldUseFirstInstallSkillsUi)); + ShouldShowSkillsTargetListForSetupWizard(canManageSkills, useFirstInstallSkillsUi)); if (!canManageSkills) { @@ -84,7 +88,7 @@ internal void Update( return; } - if (shouldUseFirstInstallSkillsUi) + if (useFirstInstallSkillsUi) { SkillSetupTargetInfo selectedTargetInfo = GetSelectedSkillTargetInfo( targets, @@ -102,8 +106,6 @@ internal void Update( return; } - List installableTargets = FilterInstallableSkillTargets(targets); - foreach (SkillSetupTargetInfo target in installableTargets) { VisualElement item = new(); @@ -126,15 +128,6 @@ internal void Update( _skillsTargetList.Add(item); } - if (installableTargets.Count == 0) - { - UpdateSkillsStatusLabel( - "Create a tool folder to enable skill installation (.claude/, .agents/, etc.)"); - _installSkillsButton.SetEnabled(false); - _installSkillsButton.text = "Install Skills"; - return; - } - bool isCheckingSkills = installableTargets.Any( t => t.InstallState == SkillInstallState.Checking); if (isCheckingSkills) @@ -175,6 +168,17 @@ internal static List FilterInstallableSkillTargets( .ToList(); } + /// + /// Resolves whether the setup wizard should show the first-install skill UI. + /// + internal static bool ResolveUseFirstInstallSkillsUi( + bool shouldUseFirstInstallSkillsUi, + int installableTargetCount) + { + Debug.Assert(installableTargetCount >= 0, "installableTargetCount must not be negative"); + return shouldUseFirstInstallSkillsUi || installableTargetCount == 0; + } + internal static bool ShouldShowSkillsTargetRowForSetupWizard(bool shouldUseFirstInstallSkillsUi) { return shouldUseFirstInstallSkillsUi; diff --git a/Packages/src/Editor/Presentation/Setup/SetupWizardSkillsWorkflowController.cs b/Packages/src/Editor/Presentation/Setup/SetupWizardSkillsWorkflowController.cs index 20b32bbc2b..a19e20ff6a 100644 --- a/Packages/src/Editor/Presentation/Setup/SetupWizardSkillsWorkflowController.cs +++ b/Packages/src/Editor/Presentation/Setup/SetupWizardSkillsWorkflowController.cs @@ -225,12 +225,17 @@ private async Task HandleInstallSkillsAsync(CancellationToken ct) CancelSkillInstallStateRefresh(); string projectRoot = UnityCliLoopPathResolver.GetProjectRoot(); List targets = DetectDisplayedSkillTargets(projectRoot); - List installableTargets = _shouldUseFirstInstallSkillsUi + List filteredTargets = + SetupWizardSkillsStepPresenter.FilterInstallableSkillTargets(targets); + bool useFirstInstallSkillsUi = SetupWizardSkillsStepPresenter.ResolveUseFirstInstallSkillsUi( + _shouldUseFirstInstallSkillsUi, + filteredTargets.Count); + List installableTargets = useFirstInstallSkillsUi ? SetupWizardSkillsStepPresenter.GetFirstInstallableSkillTargets( targets, _skillsTarget, !_installSkillsFlat) - : SetupWizardSkillsStepPresenter.FilterInstallableSkillTargets(targets); + : filteredTargets; if (installableTargets.Count == 0) return; bool shouldShowSkillsInstalledDialog =