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.