diff --git a/Packages/src/Editor/CliOnlyTools~/FocusWindow/Skill/SKILL.md b/Packages/src/Editor/CliOnlyTools~/FocusWindow/Skill/SKILL.md index 515bfa29c3..e2ca7a23bb 100644 --- a/Packages/src/Editor/CliOnlyTools~/FocusWindow/Skill/SKILL.md +++ b/Packages/src/Editor/CliOnlyTools~/FocusWindow/Skill/SKILL.md @@ -13,10 +13,6 @@ Bring Unity Editor window to front using OS-level commands. uloop focus-window ``` -## Parameters - -None. - ## Global Options | Option | Description | @@ -36,11 +32,7 @@ Returns JSON with: - `success`: Whether the focus operation succeeded - `message`: Status message (e.g. `Unity Editor window focused (PID: 12345)`, or the failure reason such as `Unity project not found` / `No running Unity process found for this project` / `Failed to focus Unity window: `) -These are the only two fields. There is no PID, window-handle, or platform field returned to the caller. - ## Notes - **Works even when Unity is busy** (compiling, domain reload, etc.) -- Uses OS-level commands (osascript on macOS, PowerShell on Windows) - Useful before `uloop capture-unity-window` to ensure the target window is visible -- Brings the main Unity Editor window to the foreground diff --git a/Packages/src/Editor/CliOnlyTools~/Launch/Skill/SKILL.md b/Packages/src/Editor/CliOnlyTools~/Launch/Skill/SKILL.md index 2bf0e0929b..7bbee3d3e5 100644 --- a/Packages/src/Editor/CliOnlyTools~/Launch/Skill/SKILL.md +++ b/Packages/src/Editor/CliOnlyTools~/Launch/Skill/SKILL.md @@ -47,22 +47,24 @@ uloop launch --quit ## Output -- Prints detected Unity version -- Prints project path +May print status/progress lines before the final JSON payload, such as project path, detected Unity version, or readiness wait messages. + +The final JSON payload includes: +- `success`: whether the command completed +- `ready`: whether Unity CLI Loop is ready for commands +- `serverReady`: whether the Unity CLI Loop server accepted requests +- `projectIpcReady`: whether the project IPC path accepted tool requests +- `alreadyRunning`: whether an existing Unity process was reused +- `launched`: whether this command launched a Unity process +- `restarted`: whether this command stopped an existing process and launched a new one +- `quit`: whether this command stopped Unity without launching a new process +- `previousProcessId`: process ID stopped by restart or quit, when available +- `currentProcessId`: current Unity process ID, when available +- `projectRoot`: resolved project root +- `message`: readiness summary + +## Notes + - If Unity is already running, focuses the existing window and verifies tool readiness -- If the process scan is blocked by the environment (e.g. sandboxed `ps`), plain launch falls back to probing the project IPC; when Unity responds it reports `alreadyRunning: true` without focusing the window instead of failing. `--restart` and `--quit` still fail because they need the process id -- If launching or restarting, prints when it is waiting for Unity CLI Loop server readiness -- If launching or restarting, waits until Unity finishes startup and the CLI can connect to the project -- Successful launch, restart, existing-process, and quit paths return JSON with: - - `success`: whether the command completed - - `ready`: whether Unity CLI Loop is ready for commands - - `serverReady`: whether the Unity CLI Loop server accepted requests - - `projectIpcReady`: whether the project IPC path accepted tool requests - - `alreadyRunning`: whether an existing Unity process was reused - - `launched`: whether this command launched a Unity process - - `restarted`: whether this command stopped an existing process and launched a new one - - `quit`: whether this command stopped Unity without launching a new process - - `previousProcessId`: process ID stopped by restart or quit, when available - - `currentProcessId`: current Unity process ID, when available - - `projectRoot`: resolved project root - - `message`: readiness summary +- If process scan is blocked (e.g. sandboxed `ps`), plain launch falls back to IPC probing; `--restart` and `--quit` still fail because they need the process id +- The command waits until Unity finishes startup and the CLI can connect before returning diff --git a/Packages/src/Editor/CliOnlyTools~/PausePoint/Skill/SKILL.md b/Packages/src/Editor/CliOnlyTools~/PausePoint/Skill/SKILL.md index 2ac9b2c58b..14699e0deb 100644 --- a/Packages/src/Editor/CliOnlyTools~/PausePoint/Skill/SKILL.md +++ b/Packages/src/Editor/CliOnlyTools~/PausePoint/Skill/SKILL.md @@ -47,7 +47,6 @@ Use `generation`, `enabledAtUtc`, and the hit sequence fields from the hit or st - Consider a pause point during E2E passes when transition-frame evidence would add confidence, even if durable state, logs, or screenshots can later confirm the final result. - Use this before reaching for `Time.timeScale`, sleeps, repeated polling, or after-the-fact `execute-dynamic-code`; those checks can supplement the paused-frame proof, but they are not substitutes. - If the value you need is a method local, an intermediate calculation, or a branch reason that `execute-dynamic-code` cannot reach, add a focused `Debug.Log` immediately before the marker and read it with `get-logs` while paused. Do not count the breakpoint check complete until the matching log has been read. -- Good pause points include after input is consumed, a command is accepted, a state mutation is committed, an evaluation step resolves, a tracked value changes, a UI/domain state syncs, or a success/failure/end condition is entered. - Treat the pause like a lightweight breakpoint for one important transition: combine nearby debug logs with paused-frame inspection to confirm the variables and component state at that point. - Do not treat `simulate-* success=true`, generic action logs, sleeps/retries, testing-only counters, or `Time.timeScale` changes as paused-frame proof. - Skip this only for ordinary persistent-state checks when you are not validating simulated input delivery, event ordering, or transition-frame fidelity. diff --git a/Packages/src/Editor/FirstPartyTools/ClearConsole/Skill/SKILL.md b/Packages/src/Editor/FirstPartyTools/ClearConsole/Skill/SKILL.md index 5c633ca30b..3cb9e2be3f 100644 --- a/Packages/src/Editor/FirstPartyTools/ClearConsole/Skill/SKILL.md +++ b/Packages/src/Editor/FirstPartyTools/ClearConsole/Skill/SKILL.md @@ -45,5 +45,4 @@ Returns JSON with: - `errorCount` (number): Errors cleared - `warningCount` (number): Warnings cleared - `logCount` (number): Info logs cleared -- `message` (string): Description of the result; carries the failure summary when the operation fails (e.g. `"Failed to clear console: ..."`) -- `errorMessage` (string): Currently always empty for this tool — read `message` for failure details +- `message` (string): Description of the result. On failure, this field carries the error summary. diff --git a/Packages/src/Editor/FirstPartyTools/ControlPlayMode/Skill/SKILL.md b/Packages/src/Editor/FirstPartyTools/ControlPlayMode/Skill/SKILL.md index 662c027629..bfdb9e9bc9 100644 --- a/Packages/src/Editor/FirstPartyTools/ControlPlayMode/Skill/SKILL.md +++ b/Packages/src/Editor/FirstPartyTools/ControlPlayMode/Skill/SKILL.md @@ -57,9 +57,6 @@ Returns JSON with the current play mode state: ## Notes -- Play action starts the game in the Unity Editor (also resumes from pause) -- Stop action exits play mode and returns to edit mode. If Play Mode was already stopped, `changed` is `false`, `wasAlreadyStopped` is `true`, and `message` is `Play mode was already stopped`. -- Pause action pauses the game while remaining in play mode -- Step action advances exactly one frame and leaves play mode paused (the Editor's Next Frame button; independent of Time.timeScale). Requires PlayMode to be running; repeat to walk transitions frame by frame -- Useful for automated testing workflows +- Stop on an already-stopped Editor sets `changed: false`, `wasAlreadyStopped: true` +- Step is independent of `Time.timeScale`; requires PlayMode to be running - The command waits for the requested state before returning. Increase `--timeout-seconds` for projects with slow PlayMode entry. diff --git a/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/SKILL.md b/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/SKILL.md index 45ce0d1acc..1b2c08ebf9 100644 --- a/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/SKILL.md +++ b/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/SKILL.md @@ -18,8 +18,7 @@ This tool can inspect reachable Unity state, such as GameObjects, components, pu 1. Read the relevant reference file(s) from the Code Examples section below 2. Construct C# code based on the reference examples 3. Execute with `--code` or `--code-file` using the active shell's quoting guidance -4. If execution fails, adjust code and retry -5. Report the execution result +4. Report the execution result ## Parameters @@ -48,8 +47,7 @@ Returns JSON: - `result`: string — value of the snippet's `return` statement (empty when omitted) - `logs`: string[] — execution messages from the dynamic-code tool; read Unity Console `Debug.Log` output with `get-logs` - `compilationErrors`: object[] — Roslyn diagnostics with `message`, `line`, `column`, `errorCode`, optional `hint` and `suggestions` -- `errorMessage`: string — top-level failure summary (empty on success) -- `error`: string — alias of `errorMessage` +- `error` / `errorMessage`: string — top-level failure summary (empty on success) - `updatedCode`: string|null — the wrapped form actually compiled (handy when debugging using-statement reordering) - `diagnosticsSummary`: string|null — compact summary when diagnostics are available - `diagnostics`: object[] — structured diagnostics; same shape as `compilationErrors`, usually populated together with it diff --git a/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/asset-operations.md b/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/asset-operations.md index 31ddf7adc1..0dfc3876b9 100644 --- a/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/asset-operations.md +++ b/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/asset-operations.md @@ -2,54 +2,25 @@ Code examples for AssetDatabase operations using `execute-dynamic-code`. -## Find Assets by Type +## Find Assets ```csharp using UnityEditor; using System.Collections.Generic; -string[] prefabGuids = AssetDatabase.FindAssets("t:Prefab"); -List paths = new List(); - -foreach (string guid in prefabGuids) -{ - paths.Add(AssetDatabase.GUIDToAssetPath(guid)); -} -return $"Found {paths.Count} prefabs"; -``` - -## Find Assets by Name +// By type +string[] guids = AssetDatabase.FindAssets("t:Prefab"); +// By name +// string[] guids = AssetDatabase.FindAssets("Player"); +// By type in folder +// string[] guids = AssetDatabase.FindAssets("t:Prefab", new[] { "Assets/Prefabs" }); -```csharp -using UnityEditor; -using System.Collections.Generic; - -string searchName = "Player"; -string[] guids = AssetDatabase.FindAssets(searchName); List paths = new List(); - -foreach (string guid in guids) -{ - paths.Add(AssetDatabase.GUIDToAssetPath(guid)); -} -return $"Found {paths.Count} assets matching '{searchName}'"; -``` - -## Find Assets in Folder - -```csharp -using UnityEditor; -using System.Collections.Generic; - -string folder = "Assets/Prefabs"; -string[] guids = AssetDatabase.FindAssets("t:Prefab", new[] { folder }); -List paths = new List(); - foreach (string guid in guids) { paths.Add(AssetDatabase.GUIDToAssetPath(guid)); } -return $"Found {paths.Count} prefabs in {folder}"; +return $"Found {paths.Count} assets"; ``` ## Duplicate Asset @@ -76,7 +47,7 @@ string error = AssetDatabase.MoveAsset(sourcePath, destPath); return string.IsNullOrEmpty(error) ? $"Moved to {destPath}" : $"Error: {error}"; ``` -## Rename Asset +## Rename Asset (no Undo) ```csharp using UnityEditor; diff --git a/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/cleanup-operations.md b/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/cleanup-operations.md index 40eec9a52f..1c2e023f0a 100644 --- a/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/cleanup-operations.md +++ b/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/cleanup-operations.md @@ -78,56 +78,27 @@ Undo.CollapseUndoOperations(undoGroup); return $"Removed {totalRemoved} missing scripts from scene"; ``` -## Detect Missing References in Component +## Scan for Missing References + +Scans the entire scene by default. Set `scanSelectionOnly` to `true` only when the task asks for the selected GameObject. ```csharp using UnityEditor; +bool scanSelectionOnly = false; GameObject selected = Selection.activeGameObject; -if (selected == null) +if (scanSelectionOnly && selected == null) { return "No GameObject selected"; } -List missingRefs = new List(); - -Component[] components = selected.GetComponents(); -foreach (Component comp in components) -{ - if (comp == null) continue; - - SerializedObject so = new SerializedObject(comp); - SerializedProperty prop = so.GetIterator(); - - while (prop.NextVisible(true)) - { - if (prop.propertyType == SerializedPropertyType.ObjectReference) - { - if (prop.objectReferenceValue == null && prop.objectReferenceInstanceIDValue != 0) - { - missingRefs.Add($"{comp.GetType().Name}.{prop.name}"); - } - } - } -} +GameObject[] targets = scanSelectionOnly + ? new[] { selected } + : Object.FindObjectsByType(FindObjectsSortMode.None); -if (missingRefs.Count == 0) -{ - return "No missing references found"; -} - -return $"Missing references: {string.Join(", ", missingRefs)}"; -``` - -## Scan Scene for Missing References - -```csharp -using UnityEditor; - -GameObject[] allObjects = Object.FindObjectsByType(FindObjectsSortMode.None); List results = new List(); -foreach (GameObject obj in allObjects) +foreach (GameObject obj in targets) { Component[] components = obj.GetComponents(); foreach (Component comp in components) @@ -152,10 +123,10 @@ foreach (GameObject obj in allObjects) if (results.Count == 0) { - return "No missing references found in scene"; + return "No missing references found"; } -return $"Missing references ({results.Count}): {string.Join(", ", results.Take(10))}..."; +return $"Missing references ({results.Count}): {string.Join(", ", results.Take(10))}"; ``` ## Find Unused Materials in Project @@ -196,31 +167,6 @@ foreach (string guid in materialGuids) return $"Found {unusedMaterials.Count} materials not referenced by prefabs. Verify scene and other asset references manually before deleting."; ``` -## Find Empty GameObjects - -```csharp -using UnityEditor; - -GameObject[] allObjects = Object.FindObjectsByType(FindObjectsSortMode.None); -List emptyObjects = new List(); - -foreach (GameObject obj in allObjects) -{ - Component[] components = obj.GetComponents(); - if (components.Length == 1 && obj.transform.childCount == 0) - { - emptyObjects.Add(obj.name); - } -} - -if (emptyObjects.Count == 0) -{ - return "No empty GameObjects found"; -} - -return $"Empty objects ({emptyObjects.Count}): {string.Join(", ", emptyObjects.Take(20))}"; -``` - ## Find Duplicate Names in Hierarchy ```csharp @@ -311,17 +257,13 @@ if (negativeScale.Count == 0) return $"Negative scale objects: {string.Join(", ", negativeScale.Take(10))}"; ``` -## Remove Empty Leaf GameObjects +## Find Empty Leaf GameObjects ```csharp using UnityEditor; GameObject[] allObjects = Object.FindObjectsByType(FindObjectsSortMode.None); - -int undoGroup = Undo.GetCurrentGroup(); -Undo.SetCurrentGroupName("Remove Empty Leaves"); - -int removedCount = 0; +List emptyObjects = new List(); foreach (GameObject obj in allObjects) { if (obj == null) continue; @@ -329,13 +271,16 @@ foreach (GameObject obj in allObjects) Component[] components = obj.GetComponents(); if (components.Length == 1 && obj.transform.childCount == 0) { - Undo.DestroyObjectImmediate(obj); - removedCount++; + emptyObjects.Add(obj.name); } } -Undo.CollapseUndoOperations(undoGroup); -return $"Removed {removedCount} empty leaf GameObjects"; +if (emptyObjects.Count == 0) +{ + return "No empty leaf GameObjects found"; +} + +return $"Empty leaf GameObjects ({emptyObjects.Count}): {string.Join(", ", emptyObjects.Take(20))}"; ``` ## Find Large Meshes diff --git a/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/playmode-ui-controls.md b/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/playmode-ui-controls.md index f7bda52218..f33e3e68c9 100644 --- a/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/playmode-ui-controls.md +++ b/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/playmode-ui-controls.md @@ -18,57 +18,34 @@ return $"Set InputField text to: {input.text}"; ## Set Slider Value -```csharp -using UnityEngine.UI; - -Slider slider = GameObject.Find("Canvas/VolumeSlider")?.GetComponent(); -if (slider == null) return "Slider not found"; - -float oldValue = slider.value; -slider.value = 0.75f; -return $"Slider changed from {oldValue} to {slider.value}"; -``` - -## Set Slider Value with Bounds Check - ```csharp using UnityEngine.UI; using System.Linq; Slider[] sliders = Object.FindObjectsByType(FindObjectsSortMode.None); -Slider target = sliders.FirstOrDefault(s => s.gameObject.name == "HealthBar"); -if (target == null) return $"HealthBar not found. Available: {string.Join(", ", sliders.Select(s => s.gameObject.name))}"; +Slider target = sliders.FirstOrDefault(s => s.gameObject.name == "VolumeSlider"); +if (target == null) return $"VolumeSlider not found. Available: {string.Join(", ", sliders.Select(s => s.gameObject.name))}"; -float targetValue = 0.5f; +float targetValue = 0.75f; float clamped = Mathf.Clamp(targetValue, target.minValue, target.maxValue); target.value = clamped; return $"Set {target.gameObject.name} to {clamped} (range: {target.minValue}-{target.maxValue})"; ``` -## Toggle On/Off - -```csharp -using UnityEngine.UI; - -Toggle toggle = GameObject.Find("Canvas/MuteToggle")?.GetComponent(); -if (toggle == null) return "Toggle not found"; - -bool oldValue = toggle.isOn; -toggle.isOn = !toggle.isOn; -return $"Toggle changed from {oldValue} to {toggle.isOn}"; -``` +## Set Toggle Value -## Set Toggle to Specific Value +Assign a specific value for deterministic setup. Use `!toggle.isOn` only when the task explicitly asks to flip the current value. ```csharp using UnityEngine.UI; using System.Linq; Toggle[] toggles = Object.FindObjectsByType(FindObjectsSortMode.None); -Toggle target = toggles.FirstOrDefault(t => t.gameObject.name == "SoundToggle"); -if (target == null) return $"SoundToggle not found. Available: {string.Join(", ", toggles.Select(t => t.gameObject.name))}"; +Toggle target = toggles.FirstOrDefault(t => t.gameObject.name == "MuteToggle"); +if (target == null) return $"MuteToggle not found. Available: {string.Join(", ", toggles.Select(t => t.gameObject.name))}"; -target.isOn = true; +bool targetValue = true; +target.isOn = targetValue; return $"Set {target.gameObject.name} to {target.isOn}"; ``` diff --git a/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/scene-operations.md b/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/scene-operations.md index d34db4c49f..d5e17890d4 100644 --- a/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/scene-operations.md +++ b/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/scene-operations.md @@ -64,13 +64,6 @@ if (obj == null) return $"Found: {obj.name} at {obj.transform.position}"; ``` -## Find GameObjects by Tag - -```csharp -GameObject[] enemies = GameObject.FindGameObjectsWithTag("Enemy"); -return $"Found {enemies.Length} GameObjects with tag 'Enemy'"; -``` - ## Set Parent ```csharp diff --git a/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/scriptableobject.md b/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/scriptableobject.md index debc01b9f8..1827a4fb5a 100644 --- a/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/scriptableobject.md +++ b/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/scriptableobject.md @@ -33,32 +33,7 @@ return $"Created {so.GetType().Name} at {path}"; ## Modify ScriptableObject with SerializedObject -```csharp -using UnityEditor; - -string path = "Assets/Data/MyData.asset"; -ScriptableObject so = AssetDatabase.LoadAssetAtPath(path); - -if (so == null) -{ - return $"Asset not found at {path}"; -} - -SerializedObject serializedObj = new SerializedObject(so); -SerializedProperty prop = serializedObj.FindProperty("myField"); - -if (prop != null) -{ - prop.stringValue = "New Value"; - serializedObj.ApplyModifiedProperties(); - EditorUtility.SetDirty(so); - AssetDatabase.SaveAssets(); - return "Property updated"; -} -return "Property 'myField' not found"; -``` - -## Set Int/Float/Bool Properties +Use `FindProperty` with the matching typed setter (`stringValue`, `intValue`, `floatValue`, `boolValue`, etc.). ```csharp using UnityEditor; diff --git a/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/selection-operations.md b/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/selection-operations.md index 629c57d8b2..c23f5587f3 100644 --- a/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/selection-operations.md +++ b/Packages/src/Editor/FirstPartyTools/ExecuteDynamicCode/Skill/references/selection-operations.md @@ -65,12 +65,15 @@ Selection.objects = enemies; return $"Selected {enemies.Length} enemies"; ``` -## Get Top-Level Transforms Only +## Get Transforms by Selection Mode + +`SelectionMode.TopLevel` excludes children, `Deep` includes children, `Editable` excludes locked/immutable objects. ```csharp using UnityEditor; using System.Collections.Generic; +// TopLevel | Deep | Editable Transform[] transforms = Selection.GetTransforms(SelectionMode.TopLevel); if (transforms.Length == 0) { @@ -82,45 +85,13 @@ foreach (Transform t in transforms) { names.Add(t.name); } -return $"Top-level: {string.Join(", ", names)}"; -``` - -## Get Deep Selection (Including Children) - -```csharp -using UnityEditor; - -Transform[] transforms = Selection.GetTransforms(SelectionMode.Deep); -if (transforms.Length == 0) -{ - return "No transforms selected"; -} - -return $"Deep selection count: {transforms.Length}"; -``` - -## Get Editable Objects Only - -```csharp -using UnityEditor; -using System.Collections.Generic; - -Transform[] transforms = Selection.GetTransforms(SelectionMode.Editable); -if (transforms.Length == 0) -{ - return "No editable transforms selected"; -} - -List names = new List(); -foreach (Transform t in transforms) -{ - names.Add(t.name); -} -return $"Editable: {string.Join(", ", names)}"; +return $"Selected ({transforms.Length}): {string.Join(", ", names)}"; ``` ## Get Selected Assets +Use `Selection.GetFiltered` when you need the object reference, or `Selection.assetGUIDs` when you need GUIDs. + ```csharp using UnityEditor; using System.Collections.Generic; @@ -139,26 +110,6 @@ foreach (Object asset in selectedAssets) return $"Assets: {string.Join(", ", paths)}"; ``` -## Get Selected Asset GUIDs - -```csharp -using UnityEditor; -using System.Collections.Generic; - -string[] guids = Selection.assetGUIDs; -if (guids.Length == 0) -{ - return "No assets selected"; -} - -List paths = new List(); -foreach (string guid in guids) -{ - paths.Add(AssetDatabase.GUIDToAssetPath(guid)); -} -return $"Selected assets: {string.Join(", ", paths)}"; -``` - ## Select All Children of Selected Object ```csharp diff --git a/Packages/src/Editor/FirstPartyTools/FindGameObjects/Skill/SKILL.md b/Packages/src/Editor/FirstPartyTools/FindGameObjects/Skill/SKILL.md index 620c44e32c..24edd909a3 100644 --- a/Packages/src/Editor/FirstPartyTools/FindGameObjects/Skill/SKILL.md +++ b/Packages/src/Editor/FirstPartyTools/FindGameObjects/Skill/SKILL.md @@ -77,7 +77,7 @@ Returns JSON with: - `tag` (string): GameObject tag - `layer` (number): Layer index - `components` (array): Each entry has `type` (short name, e.g., `Rigidbody`), `fullTypeName` (e.g., `UnityEngine.Rigidbody`), and `properties` (array of Inspector-visible `{name, type, value}` pairs) -- `totalFound` (number): Number of results returned inline, or number exported for multi-selection file output. For search modes, this is after `--max-results` clipping and serialization. +- `totalFound` (number): Results returned (after `--max-results` clipping). For multi-selection file export, this is the number exported. - `errorMessage` (string): Top-level failure summary (empty on success) - `processingErrors` (array): Selected-mode per-GameObject serialization failures, each `{gameObjectName, gameObjectPath, error}`. Omitted/null or empty on clean runs. diff --git a/Packages/src/Editor/FirstPartyTools/GetLogs/Skill/SKILL.md b/Packages/src/Editor/FirstPartyTools/GetLogs/Skill/SKILL.md index 2ecb25aff7..57d1d97f62 100644 --- a/Packages/src/Editor/FirstPartyTools/GetLogs/Skill/SKILL.md +++ b/Packages/src/Editor/FirstPartyTools/GetLogs/Skill/SKILL.md @@ -8,8 +8,6 @@ description: "Read current Unity Console entries from a running Editor. Use duri Retrieve logs from Unity Console. -When a pause-point marker pauses Unity and the value you need is a method local, intermediate calculation, or branch reason, read the focused `Debug.Log` entry added immediately before the marker before resuming PlayMode. Use `--search-text ` so the marker and its log are checked as one breakpoint-style proof. - ## Usage ```bash @@ -54,10 +52,7 @@ uloop get-logs --search-text "Missing.*Component" --use-regex Returns JSON with: - `totalCount` (number): Total logs available before max-count clipping - `displayedCount` (number): Logs returned in this response (≤ `--max-count`) -- `logType` (string): The `--log-type` filter that was applied -- `maxCount` (number): The `--max-count` cap that was applied -- `searchText` (string): The `--search-text` filter that was applied (empty when omitted) -- `includeStackTrace` (boolean): Whether stack traces are included in `logs[]` +- Input filters (`logType`, `maxCount`, `searchText`, `includeStackTrace`) are echoed back in the response - `logs` (array): Each entry has: - `type` (string): `"Error"`, `"Warning"`, or `"Log"` - `message` (string): Log message body diff --git a/Packages/src/Editor/FirstPartyTools/RecordInput/Skill/SKILL.md b/Packages/src/Editor/FirstPartyTools/RecordInput/Skill/SKILL.md index 6b1c530f38..a76d38cb33 100644 --- a/Packages/src/Editor/FirstPartyTools/RecordInput/Skill/SKILL.md +++ b/Packages/src/Editor/FirstPartyTools/RecordInput/Skill/SKILL.md @@ -39,8 +39,7 @@ Replay injects input frame-by-frame, so the game must also be deterministic to p ## Prerequisites - Unity must be in **PlayMode** -- **Input System package** must be installed (`com.unity.inputsystem`) -- Use this only when the project already uses the New Input System. +- **Input System package** (`com.unity.inputsystem`) must be installed; this tool only works with the New Input System. ## Output @@ -52,4 +51,4 @@ The CLI prints JSON with: - `totalFrames`: Number of frames recorded (nullable int; populated on `Stop` only) - `durationSeconds`: Recording duration in seconds (nullable float; populated on `Stop` only) -The CLI output contains only these six payload fields. Internal metadata such as `ver` is removed before printing. There is no `recordingId`, `startTimestamp`, `keysCaptured`, or per-frame data in the response — frame data lives only in the JSON file at `outputPath`. +Frame data lives only in the JSON file at `outputPath`; internal metadata fields are not included in the response. diff --git a/Packages/src/Editor/FirstPartyTools/ReplayInput/Skill/SKILL.md b/Packages/src/Editor/FirstPartyTools/ReplayInput/Skill/SKILL.md index d69e1ad07e..81793dbc8e 100644 --- a/Packages/src/Editor/FirstPartyTools/ReplayInput/Skill/SKILL.md +++ b/Packages/src/Editor/FirstPartyTools/ReplayInput/Skill/SKILL.md @@ -43,8 +43,7 @@ Replay injects the exact same input frame-by-frame, but the game must also be de ## Prerequisites - Unity must be in **PlayMode** -- **Input System package** must be installed (`com.unity.inputsystem`) -- Use this only when the project already uses the New Input System. +- **Input System package** (`com.unity.inputsystem`) must be installed; this tool only works with the New Input System. ## Output @@ -57,5 +56,3 @@ Returns JSON with: - `totalFrames`: Total frames in the recording (nullable int) - `progress`: Replay progress (nullable float in 0.0 – 1.0) - `isReplaying`: Whether replay is currently active (nullable bool) - -These are the only eight fields. There is no `loopCount`, `elapsedSeconds`, `overlayVisible`, or per-frame inspection data in the response. diff --git a/Packages/src/Editor/FirstPartyTools/RunTests/Skill/SKILL.md b/Packages/src/Editor/FirstPartyTools/RunTests/Skill/SKILL.md index ba6909c219..7660586e11 100644 --- a/Packages/src/Editor/FirstPartyTools/RunTests/Skill/SKILL.md +++ b/Packages/src/Editor/FirstPartyTools/RunTests/Skill/SKILL.md @@ -8,11 +8,11 @@ description: "Run Unity Test Runner and report detailed results. Use for EditMod Execute Unity Test Runner. When tests fail, NUnit XML results with error messages and stack traces are automatically saved. Read the XML file at `xmlPath` for detailed failure diagnosis. -Before running `uloop run-tests`, run `uloop compile` for the same Unity project when the current task created, deleted, renamed, moved, or edited C# source files, test files, `.asmdef`, `.asmref`, package manifest files, or scripting define settings. This refreshes the AssetDatabase, lets Unity discover new tests, and surfaces compile errors before test execution. You may skip this compile step when rerunning tests without code or assembly-definition changes since the last successful compile. +Before running tests, run `uloop compile` first if you created, deleted, renamed, moved, or edited C# files, test files, `.asmdef`/`.asmref`, or package manifests since the last successful compile. This refreshes the AssetDatabase and surfaces compile errors before test execution. Before executing tests, `uloop run-tests` saves unsaved loaded Scene changes and unsaved current Prefab Stage changes by default. If saving fails, it returns `success: false`, keeps `testCount` at `0`, lists the unsaved items in `message`, and does not start the Unity Test Runner. -When a run returns `status: "NoTestsFound"` or `noTestsFound: true`, no matching tests were discovered. This is not the same as a failed test case: `hasFailures` remains `false`, `failedCount` remains `0`, and `noTestsFoundExplanation` explains the zero-discovery state for agents. When an unfiltered `--filter-type all` run also has `message` set to the no-tests message, read the `message` for asmdef hints. `run-tests` only appends those hints when it detects likely test assembly configuration issues; exact, regex, and assembly filter misses keep the plain no-tests message. +`NoTestsFound` means zero tests matched — not a test failure. Check `noTestsFoundExplanation` and `message` for asmdef hints. ## Usage diff --git a/Packages/src/Editor/FirstPartyTools/Screenshot/Skill/SKILL.md b/Packages/src/Editor/FirstPartyTools/Screenshot/Skill/SKILL.md index d10d199ea2..bc721a5ee7 100644 --- a/Packages/src/Editor/FirstPartyTools/Screenshot/Skill/SKILL.md +++ b/Packages/src/Editor/FirstPartyTools/Screenshot/Skill/SKILL.md @@ -67,9 +67,6 @@ uloop screenshot --window-name Project --match-mode prefix # Save screenshot to a specific directory uloop screenshot --output-directory /tmp/screenshots - -# Combine options -uloop screenshot --window-name Scene --resolution-scale 0.5 --output-directory /tmp/screenshots ``` ## Output diff --git a/Packages/src/Editor/FirstPartyTools/SimulateKeyboard/Skill/SKILL.md b/Packages/src/Editor/FirstPartyTools/SimulateKeyboard/Skill/SKILL.md index 6cb374cc93..7b65d6b135 100644 --- a/Packages/src/Editor/FirstPartyTools/SimulateKeyboard/Skill/SKILL.md +++ b/Packages/src/Editor/FirstPartyTools/SimulateKeyboard/Skill/SKILL.md @@ -42,16 +42,11 @@ uloop simulate-keyboard --action --key [options] Use `Press` for edge-triggered keyboard code such as `Keyboard.current.spaceKey.wasPressedThisFrame`. `KeyDown` emits one initial press edge, then only keeps the key held. It does not keep `wasPressedThisFrame` true while the key remains held. If a successful `Press` or `KeyDown` leaves `Keyboard.current..isPressed` true but runtime state does not change, do not immediately rewrite the user's runtime code to `isPressed`. First verify that the target component is active during the command, that it polls input in the configured Input System update phase, and that a missed `KeyDown` edge is followed by `KeyUp` before retrying. -Use `KeyDown` / `KeyUp` when the scenario intentionally needs a held key. - ### Pause Point Inspection (Standard for E2E) -- Use `UloopPausePoint.Pause("")` with `uloop-wait-for-pause-point` as the standard frame proof when this input drives a state transition you are verifying. Final logs, screenshots, and durable state supplement the paused-frame check but do not replace it. -- Put the marker at a natural state transition after the app consumed the key, such as after a command is accepted, a state mutation is committed, an evaluation step resolves, or a dependent component is updated. Do not place it immediately after sending `simulate-keyboard`. -- If the key handler has local variables, intermediate calculations, or branch reasons that `execute-dynamic-code` cannot inspect after the fact, log just those values near `UloopPausePoint.Pause("")` and read them with `uloop-get-logs` while Unity is paused. A pause point hit proves the line was reached, not the frame-local values. -- Treat `simulate-keyboard success=true`, generic action logs, and final durable counters as useful evidence, but not as paused-frame proof. -- If the response has `interruptedByPausePoint: true`, Unity is paused for inspection and the tool released its held input bookkeeping. If a `UloopPausePoint.Pause` marker caused the pause, `pausePointId` and `pausePointHitCount` identify it. Use `uloop get-logs`, `uloop get-hierarchy`, `uloop find-game-objects`, or `uloop execute-dynamic-code` before resuming. -- Use distinct marker ids for strict phases, for example `input-read`, `state-updated`, and `result-committed`. +For standard frame proof when this input drives a state transition, follow the `uloop-wait-for-pause-point` skill. Place markers after the app consumed the key, not immediately after `simulate-keyboard`. + +- If `interruptedByPausePoint: true`, Unity is paused and input bookkeeping was released. `pausePointId` and `pausePointHitCount` identify the marker. `pressEdgeObserved` is still reported on pause-point interruptions. ### KeyDown/KeyUp Rules @@ -103,6 +98,5 @@ Returns JSON with: ## Prerequisites - Unity must be in **PlayMode** -- **Input System package** must be installed (`com.unity.inputsystem`) -- Use this only when the project already uses the New Input System. +- **Input System package** (`com.unity.inputsystem`) must be installed; this tool only works with the New Input System. - Game code must read input via Input System API (e.g. `Keyboard.current[Key.W].isPressed`), not legacy `Input.GetKey()` diff --git a/Packages/src/Editor/FirstPartyTools/SimulateMouseInput/Skill/SKILL.md b/Packages/src/Editor/FirstPartyTools/SimulateMouseInput/Skill/SKILL.md index 12b73569e4..8bc5b09e69 100644 --- a/Packages/src/Editor/FirstPartyTools/SimulateMouseInput/Skill/SKILL.md +++ b/Packages/src/Editor/FirstPartyTools/SimulateMouseInput/Skill/SKILL.md @@ -50,11 +50,9 @@ uloop simulate-mouse-input --action [options] ### Pause Point Inspection (Standard for E2E) -- Use `UloopPausePoint.Pause("")` with `uloop-wait-for-pause-point` as the standard frame proof when this input drives a state transition you are verifying. Final logs, screenshots, and durable state supplement the paused-frame check but do not replace it. -- Place the pause point at a natural state transition after the app consumed the mouse input, such as after a command is accepted, a state mutation is committed, an evaluation step resolves, a tracked value changes, or a dependent component is updated. Do not place it immediately after sending `simulate-mouse-input`. -- If the mouse handler has local variables, intermediate calculations, or branch reasons that `execute-dynamic-code` cannot inspect after the fact, log just those values near `UloopPausePoint.Pause("")` and read them with `uloop-get-logs` while Unity is paused. A pause point hit proves the line was reached, not the frame-local values. -- If the response has `interruptedByPausePoint: true`, Unity is paused for inspection and the tool released its held input bookkeeping. `pausePointId` and `pausePointHitCount` identify the pause point that paused Unity. Use `uloop get-logs`, `uloop get-hierarchy`, `uloop find-game-objects`, or `uloop execute-dynamic-code` before resuming. -- Use distinct ids for strict phases, for example `input-read`, `state-updated`, and `result-committed`. +For standard frame proof when this input drives a state transition, follow the `uloop-wait-for-pause-point` skill. Place markers after the app consumed the mouse input, not immediately after `simulate-mouse-input`. + +- If `interruptedByPausePoint: true`, Unity is paused and input bookkeeping was released. `pausePointId` and `pausePointHitCount` identify the marker. - Remove temporary pause-point/log instrumentation before final validation when it was added only for inspection. ### Global Options (optional) @@ -66,14 +64,16 @@ uloop simulate-mouse-input --action [options] ## When to use this vs simulate-mouse-ui +All rows below assume the New Input System is installed. + | Scenario | Tool | |----------|------| | Click a Unity UI Button (IPointerClickHandler) | `simulate-mouse-ui` | -| Runtime logic reads `Mouse.current.leftButton` | `simulate-mouse-input` when the project uses the New Input System | -| Runtime logic reads right-click | `simulate-mouse-input --button Right` when the project uses the New Input System | +| Runtime logic reads `Mouse.current.leftButton` | `simulate-mouse-input` | +| Runtime logic reads right-click | `simulate-mouse-input --button Right` | | Drag a UI slider | `simulate-mouse-ui --action Drag` | -| Runtime logic reads `Mouse.current.delta` | `simulate-mouse-input --action MoveDelta` when the project uses the New Input System | -| Runtime logic reads `Mouse.current.scroll` | `simulate-mouse-input --action Scroll` when the project uses the New Input System | +| Runtime logic reads `Mouse.current.delta` | `simulate-mouse-input --action MoveDelta` | +| Runtime logic reads `Mouse.current.scroll` | `simulate-mouse-input --action Scroll` | ## Examples @@ -103,9 +103,8 @@ uloop simulate-mouse-input --action SmoothDelta --delta-x 300 --delta-y 0 --dura ## Prerequisites - Unity must be in **PlayMode** -- **Input System package** must be installed (`com.unity.inputsystem`) +- **Input System package** (`com.unity.inputsystem`) must be installed; this tool only works with the New Input System. - Game code must read input via Input System API (e.g. `Mouse.current.leftButton.wasPressedThisFrame`) -- Use this only when the project already uses the New Input System. ## Output @@ -121,4 +120,4 @@ Returns JSON with: - `pausePointHitCount`: The hit count for that `UloopPausePoint.Pause("")` - `pausePointHits` (array, nullable): Every marker hit during this input as `{id, hitCount}` entries, in hit order. Read this when one input may trigger several markers; `pausePointId` only names the latest one -There is no `deltaX`, `deltaY`, `scrollX`, `scrollY`, `duration`, or hit-element field in the response — only the issued action, button, target position, and Pause Point interruption state are echoed back. Verify visual outcome with a follow-up screenshot. +Verify visual outcome with a follow-up screenshot. diff --git a/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/Skill/SKILL.md b/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/Skill/SKILL.md index f5e2799aec..8a9a797b6b 100644 --- a/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/Skill/SKILL.md +++ b/Packages/src/Editor/FirstPartyTools/SimulateMouseUi/Skill/SKILL.md @@ -57,7 +57,6 @@ uloop simulate-mouse-ui --action --x --y [options] - `DragStart` must be called before `DragMove` or `DragEnd` - `DragEnd` must be called to release an active drag — failing to call it leaves drag state stuck - Calling `DragMove` or `DragEnd` without an active drag returns an error -- `Drag`, `DragStart`, `DragMove`, and `DragEnd` only support `--button Left` ### Global Options (all optional, mutually exclusive) @@ -78,11 +77,8 @@ uloop simulate-mouse-ui --action --x --y [options] ## Pause Point Inspection (Standard for E2E) -- Use `UloopPausePoint.Pause("")` with `uloop wait-for-pause-point` as the standard frame proof when this input drives a state transition you are verifying. Final logs, screenshots, and durable state supplement the paused-frame check but do not replace it. -- Place the pause point at a natural transition after the app consumed the UI event, such as after a command is accepted, a state mutation is committed, a tracked value changes, a UI/domain state syncs, or a success/failure/end condition is entered. -- If the UI handler has local variables, intermediate calculations, or branch reasons that `uloop execute-dynamic-code` cannot inspect after the fact, log just those values near `UloopPausePoint.Pause("")` and read them with `uloop get-logs` while Unity is paused. A pause point hit proves the line was reached, not the frame-local values. -- Treat `uloop simulate-mouse-ui` `success=true`, generic action logs, and final durable counters as useful evidence, not paused-frame proof. -- If a `UloopPausePoint.Pause` pauses Unity, inspect with `uloop get-logs`, `uloop get-hierarchy`, `uloop find-game-objects`, or `uloop execute-dynamic-code` before resuming. +For standard frame proof when this UI input drives a state transition, follow the `uloop-wait-for-pause-point` skill. Place markers after the app consumed the UI event, not immediately after `simulate-mouse-ui`. + - Remove temporary pause-point/log instrumentation before final validation when it was added only for inspection. ## Examples @@ -138,6 +134,6 @@ Returns JSON with: - `endPositionX`: Drag end X coordinate (nullable float; populated for drag actions only) - `endPositionY`: Drag end Y coordinate (nullable float; populated for drag actions only) -These are the only eight fields. There is no `button`, `duration`, `dragSpeed`, raycast list, or pointer-event log in the response — verify the visual outcome with a follow-up `uloop screenshot --capture-mode rendering --annotate-elements`. +Verify the visual outcome with a follow-up `uloop screenshot --capture-mode rendering --annotate-elements`. Note: Click and LongPress on empty space (no UI element) still return `success = true` with `hitGameObjectName = null`. Drag actions on empty space return `success = false`.