diff --git a/Assets/Tests/Editor/ThirdPartyToolMigrationWizardWindowTests.cs b/Assets/Tests/Editor/ThirdPartyToolMigrationWizardWindowTests.cs index a4c4e1897..f1fb1273c 100644 --- a/Assets/Tests/Editor/ThirdPartyToolMigrationWizardWindowTests.cs +++ b/Assets/Tests/Editor/ThirdPartyToolMigrationWizardWindowTests.cs @@ -464,6 +464,20 @@ public void ShouldRemoveMigrationSkill_ReturnsExpectedValue( Assert.That(shouldRemove, Is.EqualTo(expected)); } + [TestCase(SkillInstallState.Installed, true)] + [TestCase(SkillInstallState.Outdated, true)] + [TestCase(SkillInstallState.Checking, true)] + [TestCase(SkillInstallState.Missing, false)] + public void ShouldShowTemporarySkillNote_ReturnsExpectedValue( + SkillInstallState installState, + bool expected) + { + // Verifies the temporary skill note shows for every non-missing install state. + bool shouldShow = ThirdPartyToolMigrationWizardStateRules.ShouldShowTemporarySkillNote(installState); + + Assert.That(shouldShow, Is.EqualTo(expected)); + } + [TestCase(0, 1, 1, 4, 1000, 100, true)] [TestCase(10, 50, 1, 4, 1000, 100, false)] [TestCase(10, 110, 1, 4, 1000, 100, true)] diff --git a/Packages/src/Editor/Presentation/Setup/ThirdPartyToolMigrationWizardStateRules.cs b/Packages/src/Editor/Presentation/Setup/ThirdPartyToolMigrationWizardStateRules.cs index 1076ce24d..a1581f953 100644 --- a/Packages/src/Editor/Presentation/Setup/ThirdPartyToolMigrationWizardStateRules.cs +++ b/Packages/src/Editor/Presentation/Setup/ThirdPartyToolMigrationWizardStateRules.cs @@ -99,5 +99,15 @@ internal static bool ShouldRefreshAfterInterruptedMigration( { return isMigrationCompletionPending && !isCancellationRequested; } + + /// + /// Returns whether the temporary V3 migration skill note should be visible. + /// + internal static bool ShouldShowTemporarySkillNote(SkillInstallState installState) + { + // C# scan results are not a completion signal for this skill (docs/scripts remain + // in scope), so only the install state decides whether the temporary note shows. + return installState != SkillInstallState.Missing; + } } } diff --git a/Packages/src/Editor/Presentation/Setup/ThirdPartyToolMigrationWizardText.cs b/Packages/src/Editor/Presentation/Setup/ThirdPartyToolMigrationWizardText.cs index da1c3d710..5449b6c1e 100644 --- a/Packages/src/Editor/Presentation/Setup/ThirdPartyToolMigrationWizardText.cs +++ b/Packages/src/Editor/Presentation/Setup/ThirdPartyToolMigrationWizardText.cs @@ -19,6 +19,8 @@ internal static class ThirdPartyToolMigrationWizardText "that call uloop.\nThe skill teaches your AI agent how to search, inspect context, and update only " + "real V2 CLI usage. This window only installs or removes it."; internal const string AiMigrationSkillUsageFoldoutTitle = "Prompt for your AI agent"; + internal const string AiMigrationSkillTemporaryNoteText = + "This skill is temporary. Remove it once your docs and scripts are migrated to V3 CLI syntax."; internal const string AiMigrationSkillPromptText = "Use the v3-cli-invocation-migration skill in this project to update Unity CLI Loop V2 CLI usage " + "for V3.\n\n" + diff --git a/Packages/src/Editor/Presentation/Setup/ThirdPartyToolMigrationWizardView.cs b/Packages/src/Editor/Presentation/Setup/ThirdPartyToolMigrationWizardView.cs index 68ead776f..48c5d54eb 100644 --- a/Packages/src/Editor/Presentation/Setup/ThirdPartyToolMigrationWizardView.cs +++ b/Packages/src/Editor/Presentation/Setup/ThirdPartyToolMigrationWizardView.cs @@ -22,6 +22,7 @@ internal sealed class ThirdPartyToolMigrationWizardView private readonly Button _migrateButton; private readonly EnumField _migrationSkillTargetField; private readonly Button _migrationSkillButton; + private readonly TextField _migrationSkillTemporaryNoteTextField; private readonly Button _refreshButton; private readonly Button _closeButton; @@ -33,6 +34,7 @@ private ThirdPartyToolMigrationWizardView( Button migrateButton, EnumField migrationSkillTargetField, Button migrationSkillButton, + TextField migrationSkillTemporaryNoteTextField, Button refreshButton, Button closeButton) { @@ -43,6 +45,9 @@ private ThirdPartyToolMigrationWizardView( Debug.Assert(migrateButton != null, "migrateButton must not be null"); Debug.Assert(migrationSkillTargetField != null, "migrationSkillTargetField must not be null"); Debug.Assert(migrationSkillButton != null, "migrationSkillButton must not be null"); + Debug.Assert( + migrationSkillTemporaryNoteTextField != null, + "migrationSkillTemporaryNoteTextField must not be null"); Debug.Assert(refreshButton != null, "refreshButton must not be null"); Debug.Assert(closeButton != null, "closeButton must not be null"); @@ -53,6 +58,7 @@ private ThirdPartyToolMigrationWizardView( _migrateButton = migrateButton; _migrationSkillTargetField = migrationSkillTargetField; _migrationSkillButton = migrationSkillButton; + _migrationSkillTemporaryNoteTextField = migrationSkillTemporaryNoteTextField; _refreshButton = refreshButton; _closeButton = closeButton; } @@ -87,7 +93,7 @@ internal static ThirdPartyToolMigrationWizardView Create( Button migrateButton = CreateMigrateButton(migrationButtonRow); (Button refreshButton, Button closeButton) = CreateCSharpMigrationActionSection(mainScrollView); CreateSectionDivider(mainScrollView); - (EnumField migrationSkillTargetField, Button migrationSkillButton) = + (EnumField migrationSkillTargetField, Button migrationSkillButton, TextField temporaryNoteTextField) = CreateAiMigrationSkillSection(mainScrollView); CreateFooter(mainScrollView); @@ -99,6 +105,7 @@ internal static ThirdPartyToolMigrationWizardView Create( migrateButton, migrationSkillTargetField, migrationSkillButton, + temporaryNoteTextField, refreshButton, closeButton); view.BindEvents(refresh, migrate, migrationSkillTargetChanged, toggleMigrationSkill, close); @@ -116,6 +123,9 @@ internal void SetMigrationSkillState( installState); _migrationSkillTargetField.SetEnabled(!isUpdating); _migrationSkillButton.SetEnabled(!isUpdating); + ViewDataBinder.SetVisible( + _migrationSkillTemporaryNoteTextField, + ThirdPartyToolMigrationWizardStateRules.ShouldShowTemporarySkillNote(installState)); } internal void ShowNotCheckedState(bool isMigrating) @@ -284,7 +294,7 @@ private static void CreateSectionDivider(ScrollView mainScrollView) mainScrollView.Add(divider); } - private static (EnumField migrationSkillTargetField, Button migrationSkillButton) + private static (EnumField migrationSkillTargetField, Button migrationSkillButton, TextField temporaryNoteTextField) CreateAiMigrationSkillSection(ScrollView mainScrollView) { VisualElement migrationSkillSection = new VisualElement(); @@ -334,9 +344,18 @@ private static (EnumField migrationSkillTargetField, Button migrationSkillButton migrationSkillButton.AddToClassList("setup-button"); migrationSkillButton.AddToClassList("setup-button--primary"); buttonRow.Add(migrationSkillButton); + + TextField temporaryNoteTextField = CreateSelectableText( + ThirdPartyToolMigrationWizardText.AiMigrationSkillTemporaryNoteText, + "setup-step__description-label"); + actionSection.Add(temporaryNoteTextField); + // Missing is the default create-time install state; hide until SetMigrationSkillState + // reports an installed or outdated skill. + ViewDataBinder.SetVisible(temporaryNoteTextField, false); + CreateMigrationSkillUsageFoldout(actionSection); CreateMigrationSkillPromptCopyButton(actionSection); - return (migrationSkillTargetField, migrationSkillButton); + return (migrationSkillTargetField, migrationSkillButton, temporaryNoteTextField); } private static void CreateMigrationSkillUsageFoldout(VisualElement content) diff --git a/Packages/src/TemporarySkills~/v3-cli-invocation-migration/Skill/SKILL.md b/Packages/src/TemporarySkills~/v3-cli-invocation-migration/Skill/SKILL.md index bfad39dbe..100e39c33 100644 --- a/Packages/src/TemporarySkills~/v3-cli-invocation-migration/Skill/SKILL.md +++ b/Packages/src/TemporarySkills~/v3-cli-invocation-migration/Skill/SKILL.md @@ -18,6 +18,10 @@ syntax in agent-facing docs and automation. 4. Edit only files that clearly contain V2 `uloop` option syntax. 5. Repeat the searches after editing and report any remaining V2 candidates with the reason each one was left unchanged. +6. After every Required Search Pass reports zero remaining V2 candidates, + tell the user this temporary skill has finished its job and can be + removed with `uloop skills uninstall-v3-migration --` (for + example `--claude` or `--codex`). Do not uninstall the skill yourself. Prefer `rg` for searches when available. If `rg` is unavailable, use the best available project search tool. Candidate discovery should be repository search plus context inspection, not a generated candidate list.