# Unity CLI v1.0.0-beta.3

### Added

- Progress now also reports to the terminal application itself via the `OSC 9;4` escape sequence: on Windows Terminal the taskbar icon fills with install/download progress while `unity install` runs, and spinners show as indeterminate progress — no need to keep the window focused. Emitted only on an interactive terminal (the same gate as the live progress bars), never in piped or machine-consumed output, and always cleared on exit (success, failure, and Ctrl+C). Terminals that don't support the sequence ignore it.

- `unity run --command <name>` executes a registered `[CliCommand]` Editor command headlessly in one invocation: the CLI starts the Editor in batch mode, waits for the project's Pipeline server, runs the command with arguments after `--` parsed against the command's `[CliArg]` schema (no hand-written `Environment.GetCommandLineArgs()` parsing), prints the return value, and shuts the Editor down. The Editor log — including `Debug.Log` output — streams to stderr, `--format json` emits a result envelope containing the return value, a failed command exits non-zero, and a running Editor with the project open is reused (and left running) instead of spawning a second one. Requires the com.unity.pipeline package (`unity pipeline install`).

- `UNITY_NO_CONSENT_PROMPT` (any value) suppresses the one-time first-run analytics consent prompt without recording a choice — the narrow switch for wrapper scripts that run on an interactive terminal but must never absorb a prompt. Unlike `UNITY_NON_INTERACTIVE`, it changes nothing else about command behavior (no module auto-include, no EULA hard-errors, no skipped confirmations). Analytics stay off until you explicitly run `unity analytics opt-in`.
- Expanded the optional (opt-in, default off) usage analytics: when you have run `unity analytics opt-in`, the CLI now also records which commands run (registered command names only — never your arguments, paths, or project names), editor uninstalls, project open/create (editor version and template id only), CLI self-upgrade/uninstall outcomes, `unity shell` and `unity mcp` session usage, and `unity doctor` / `unity bug` results. Nothing changes when you are opted out (the default): no events are sent. `unity analytics status` shows your current choice.
- `unity bug` can now run non-interactively. Supply the report through flags — `--title`, `--description`, `--steps` (repeatable, one line per value), `--reproducibility <first-time|sometimes|always>`, and `--email` (defaults to your Unity account email when signed in; otherwise required) — and the command submits without prompting, so it works from scripts, CI, and piped shells. On a terminal, any flags you pass skip their prompts and the remaining fields still ask. A non-interactive run with missing or invalid fields fails fast with a usage error (exit code 2) listing the exact flags to add, instead of the previous "requires an interactive terminal" refusal.

- `unity upgrade` now updates AppImage installs in place: it downloads the new `.AppImage` release artifact, verifies its checksum against the release manifest, and atomically replaces the AppImage file you launched (`--rollback` restores the previous one). The background update notice now also appears on AppImage installs. AppImages also keep their embedded zsync update information, so external updaters like AppImageUpdate and Gear Lever keep working.
- Crash and error reporting via Sentry, aligned with the Unity Hub's posture: anonymous error events (no IP address, no hostname, home-directory paths and token-like values scrubbed before send) help us find and fix CLI bugs. Analytics opt-in (`unity analytics opt-in`) additionally attaches an anonymized machine id so crash-free-user rates can be computed; opted-out users stay fully anonymous. Set `UNITY_NO_CRASH_REPORT` to disable reporting entirely.
- `unity install <version> --list-components` lists the locally installed editor's modules and exits without installing — an alias for `unity modules list <version>`.
- `unity shell` now persists command history across sessions — press ↑/↓ to recall previous commands. History is stored under the CLI data directory (capped at the most recent 1000 entries), and secret-bearing flag values (`--android-keystore-password`, `--client-secret`, `--serial`, `--git-token`, and the other keystore/token flags) are masked to `***` before being written to disk.
- `unity shell` gains tab completion: press Tab to complete command names, subcommands, option flags, and option values (for example `--format`) against the live command tree, plus the shell's own builtins.
- `unity shell` gains ephemeral session context and defaults so you can stop repeating flags: `use project <path>` / `use org <id>` set an active project/organization for later commands, and `set format <fmt>` / `set verbose on|off` / `set banner on|off` set default global options for the session. `unset <key>` clears one and `context` shows the current state; every setting is per-session and still overridable by a per-command flag. `UNITY_PROJECT_PATH` and `UNITY_CLOUD_ORG` are now also honored as environment variables by the project-path and cloud-pipeline commands.
- `unity shell --protocol ndjson` adds a machine/agent mode: a framed NDJSON request/response protocol over stdio on the same warm process. A caller pipes one JSON request per line (a pre-tokenized `argv` array or a raw `command` string, with an optional `id`) and reads exactly one JSON result per line — an echoed `id`, the in-band `exitCode`, and the standard result envelope — so an automated consumer runs a command, reads one parseable result, and repeats without paying startup per command or scraping the human prompt. Commands run headlessly (an interactive prompt fails fast), and malformed lines or unknown commands produce an error frame rather than ending the session. See `docs/shell-machine-protocol.md`.
- `unity editors running` — list running Unity Editor instances and the project each has open, with the editor version and process id per instance. Detection is cross-platform (process table plus each project's Pipeline lockfile), and the version falls back to the project's `ProjectSettings/ProjectVersion.txt` for editors without the Pipeline package. An empty list is a normal result (exit 0). Supports the global `--format human|json|tsv|ndjson` (and `--json`).
- `unity projects size [project]` — report a project's on-disk footprint broken down by top-level folder (Assets, Library, Packages, …) with a total, so you can see what `unity projects clean` would reclaim. `--all` summarizes every registered project sorted largest-first. Human output uses readable units (KB/MB/GB); `--json` (and `--format ndjson`) emit raw bytes.
- `unity editor module remove` (also `unity editors module remove`) — remove installed modules from an editor by id (`-m`/`--module`, repeatable). Prompts to confirm before deleting the module files; `-y`/`--yes` skips the prompt and is required in non-interactive mode. Supports `-a`/`--architecture` to disambiguate side-by-side installs and the global `--format human|json|tsv|ndjson`.
- `unity lang --set` accepts common spellings of a language code — BCP-47 (`ja-JP`), locale (`ja_JP`), a bare language (`ja`), or a bare region (`jp`) — and resolves them to the matching catalog language, case-insensitively, when the match is unambiguous (`zh` still asks you to pick `zh_cn` or `zh_tw`).

### Changed

- `unity language` now shares the Hub's language catalog: display names come from the JS Intl API (CLDR data) instead of a hand-maintained list, and languages appear in the Hub's order (alphabetical by code) in every output format and in the interactive picker. English is no longer pinned first; the names themselves are unchanged.
- `unity command <name>` now shows the target command's full documentation (description and parameters) instead of a generic tip when a parameter or argument fails validation.
- The `Examples`/`Tips` blocks in `--help` output (`unity build`, `run`, `test`, `uninstall`, `templates`, `projects`, `editors info`/`path`, `open`) are now localized like the rest of the help text — the surrounding prose follows your language setting while the example command lines stay verbatim.
- Unified the project and organization flag names so the same concept is spelled the same way on every command. `--project-path` is now the canonical flag for a Unity project path (a handful of commands, including `unity status` and the `unity cloud-pipeline` subcommands, previously used `--project`), and `--cloud-org` is canonical for a Unity Cloud organization (`unity cloud-pipeline` previously used `--org`). The help text now shows one name per concept. The old `--project` and `--org` spellings keep working exactly where they did before, as hidden aliases — nothing breaks. `unity status` also now honors the `UNITY_PROJECT_PATH` environment variable (previously ignored there), so with a `use project` session context active in `unity shell` its output filters to that project.
- On Linux, `install.sh` now installs the binary to `~/.local/bin/unity` (the XDG-conventional user bin directory, on PATH by default on most distros) instead of `~/.unity/bin/unity` — for most users the installer no longer edits shell config files. Re-running the installer migrates an existing `~/.unity` install: the old binary is removed and its env files are replaced with harmless stubs so shell configs that still source them keep working. Setting `UNITY_CLI_HOME` still selects the previous `<dir>/bin` layout, and existing installs keep upgrading in place at their current location. `unity self-uninstall` understands both layouts: in a bare-binary install it removes only the binary (plus `unity upgrade` backup files, now cleaned up in every layout) and leaves the shared bin directory alone.

- `--json` is now accepted on every command as a global shorthand for `--format json`, not just the handful of commands that declared it individually. Commands like `unity status --json`, `unity doctor --json`, and `unity cloud status --json` now behave consistently instead of erroring with "unknown option". `--format` still takes precedence when both are supplied.
- Piped/scripted `unity shell` sessions now return a meaningful exit code: the first command that failed (or 0 when every command succeeded), instead of always exiting 0. This makes a `… | unity shell` batch usable in automation with `$?`. Interactive sessions still exit 0. The interactive prompt also gains a heavy-angle terminator (`❯`) on Unicode-capable terminals, falling back to `>` elsewhere.

### Security

- Commander usage errors (unknown options, invalid option values) and the `unity bug` log-archive warning now strip dangerous terminal control sequences (CSI/OSC escapes, control characters — harmless SGR styling is preserved) and embedded newlines before printing, closing two remaining paths where externally influenced text (raw argv, tool error output) reached the terminal unsanitized and could spoof, corrupt, or inject extra lines into it. Usage errors now always print as a single line.
- `unity projects add` and `unity projects remove` now strip dangerous terminal control sequences (CSI/OSC escapes, control characters — harmless SGR styling is preserved) from the project path they echo in `tsv` (machine) output, matching `unity projects list`. A registered path containing raw escape sequences can no longer spoof or corrupt the terminal when it is printed.

### Fixed

- `unity upgrade` on Windows no longer flashes a console window about a second after the command exits. The background helper that swaps in the new binary ran without a console (a side effect of spawning it detached, which makes Windows ignore the hide-window flag), so its internal 1-second wait opened a brand-new visible terminal window — once per retry when antivirus briefly held the binary open. The helper now runs in its own hidden console, and the swap, retry, and cleanup behavior is unchanged. The `unity self-uninstall` cleanup helper had the same flash and gets the same fix.
- Non-English locales caught up with the English string catalog again: the 195 strings added since the last translation sync — the `unity command` surface, the Pipeline and MCP commands, and the newer `unity projects` subcommands — were untranslated in all nine locales, so those commands answered in English. A new test now fails the build whenever any locale drifts out of key parity with English, so this class of gap can't accumulate silently again.
- An invalid `--proxy <url>` (a malformed URL or an unsupported scheme) now fails with a usage error (exit code 2) instead of being silently ignored while the command connects directly with no warning. A valid proxy URL is applied as before, and `UNITY_PROXY` and OS proxy settings are unaffected.
- The "Recent log" section of `unity doctor` no longer prints raw NDJSON logger lines or the current run's own startup logging. Each entry now renders as a readable `time [level] module: message` row (long multi-line messages are cut at the first line — the full text stays in the log file), and entries written by the doctor run itself — typically ~20 lines of service-startup chatter like `Command 'cm' not found in PATH` — are excluded, so the tail shows the activity that preceded the run. Machine formats (`json`, `tsv`) keep the raw log lines.
- `unity analytics opt-in` and `unity analytics opt-out` now permanently answer the first-run consent prompt. Previously the prompt tracked only whether it had been shown, so a choice recorded from a script (where the prompt never appears) was asked again on the next interactive run — forcing wrapper scripts to edit the settings file by hand to stay prompt-free.
- Opening a browser link on Linux without `xdg-open` (for example the `unity auth login` sign-in page on a minimal distro) no longer surfaces a confusing "Cannot read properties of undefined (reading 'unref')" error and an unhandled `spawn xdg-open ENOENT` rejection. The command now reports the real error through its normal warning path — `unity auth login` prints the sign-in URL so you can open it manually and keeps waiting for the browser hand-off.
- Under WSL, the CLI now opens URLs and paths through Windows interop — `wslview` when installed, falling back to `rundll32.exe` for URLs and `wslpath` + `explorer.exe` for paths, and finally `xdg-open` — instead of requiring `xdg-open` inside the Linux distro, so `unity auth login` opens the sign-in page in your Windows browser on a stock WSL Ubuntu install.
- The CLI now terminates on SIGTERM (plain `kill`, CI runner timeouts, `timeout`(1)) with the conventional exit code 143 instead of ignoring it. An internal cleanup handler was cancelling the OS default kill action without exiting, so long-running commands — most visibly the `unity auth login` browser wait — survived SIGTERM and had to be SIGKILLed. SIGTERM during `unity auth login` now cancels the sign-in cleanly, exactly like Ctrl-C (which exits 130).
- `unity open <path> --editor-version <version>` (and `--editor-path`) no longer fails with "Not a Unity project" when the project has no `ProjectSettings/ProjectVersion.txt` — common for demo and sample projects that gitignore the file. With an explicit editor flag the CLI now opens the project after checking the folder contains an `Assets` directory, prints a warning, and lets the Editor recreate the version file. Without an explicit flag the version file is still required, and `unity projects add` still requires it too.
- `unity status` and `unity pipeline list` now detect a running Editor whose project path contains a space (for example `/Users/dev/My Project`) on macOS and Linux; discovery previously truncated the path at the first space and reported no running instances.
- Non-English locales caught up with the full English string catalog, so CLI output renders localized instead of silently falling back to English. Japanese, Korean, and both Chinese locales were missing 513 translations each — including the entire error-reporting scaffolding, so every error message rendered in English — and German, Spanish, French, Brazilian Portuguese, and Russian were missing 281 each. Three orphaned keys no longer present in English were removed from the affected locales.
- `unity command eval` and `unity command eval_file` now exit non-zero (6) when the Editor reports an eval failure — a compilation error or a missing file. Previously the successful HTTP round-trip was treated as success: the CLI printed "Command executed successfully", buried the failure inside the JSON payload, and exited 0, giving CI scripts and agents a false success. The failure is now surfaced on stderr with the compiler diagnostics, matching the standalone `unity eval` behavior.
- `unity mcp` now marks failed `eval` / `eval_file` tool calls as errors (MCP `isError: true`) when the Editor reports an eval failure such as a compilation error. Previously the failure was returned as a successful tool result, so connected agents (Claude Desktop, Cursor, VS Code) saw a false success with the failure buried in the JSON payload. The full envelope, including compiler diagnostics, is still returned so agents can self-correct.
- Editor and module downloads no longer fail with a DNS error (for example `getaddrinfo ENOTFOUND wpad`) when the OS proxy settings point at an automatic proxy configuration (PAC) URL that can't be reached. The CLI now probes the OS-detected PAC script once at startup: when it loads, traffic keeps routing through the proxies it selects per request; when it doesn't, connections go direct instead of failing. A PAC URL configured explicitly (`--proxy`, `UNITY_PROXY`, or proxy settings) is honored as before. (via `@unity/hub-proxy` 0.3.1)
- `unity upgrade` no longer fails with `EXDEV: cross-device link not permitted` when the system temp directory is on a different filesystem than the install directory (common with tmpfs `/tmp`, containers, and separate `/home` mounts). The downloaded binary is now staged next to the install path and swapped in atomically when a direct cross-filesystem move isn't possible.
- `unity projects create` and `unity projects new` no longer hand a corrupt template archive to the editor (which fails with an opaque "Failed to resolve project template: Failed to decompress" error). Template downloads are verified against their published checksum, and a corrupt archive is detected and removed before the editor launches so the next run redownloads it.
- The Windows install one-liner (`irm https://public-cdn.cloud.unity3d.com/hub/prod/cli/install.ps1 | iex`) failed for every user with "The assignment expression is not valid" — `install.ps1` was published with a UTF-8 byte-order mark, which Windows PowerShell 5.1 hands to the parser as junk characters ahead of the script's `param(...)` block. The BOM is removed and a regression test keeps both install scripts BOM-free.
- `unity mcp` no longer breaks permanently after an Editor script recompile. The Editor's Pipeline server rotates its auth token on every domain reload; `tools/call` now retries once with a freshly discovered token when it hits a 401, instead of caching the stale token for the rest of the MCP session and failing every subsequent call until the client reconnected.
- `unity editors --installed` — and every command that lists installed editors — no longer stalls for minutes on Windows when antivirus real-time scanning intercepts a freshly installed editor. The scan now reads editor metadata with small, time-limited reads instead of a synchronous whole-file inspection, falls back to the install folder name (and an unknown architecture) when a read can't finish in time, and remembers the result so each editor binary is inspected only once per install.
- On Windows, the CLI could crash at exit (a libuv teardown assertion, surfaced as a non-zero exit code) right after a command completed successfully — most visibly `unity upgrade --check`, which failed the nightly CLI E2E job every night since 2026-06-11. The CLI now settles in-flight background work (the cloud-config refresh), tears down its HTTP clients, and drains pending thread-pool I/O before exiting.
- `unity open <path> --editor-version <version>` no longer starts a multi-gigabyte editor download without asking. When the requested editor is not installed, a terminal session now confirms before installing, and a non-interactive session (piped stdio, CI, `--non-interactive`) fails fast with the `unity install` command to run instead.
- `unity run --command` now matches the running editor's project path case-insensitively on Windows, so a differently-cased path (for example `d:\projects\mygame` vs `D:\Projects\MyGame`) no longer launches a second editor instead of reusing the running one.
