diff --git a/skills/unity-cli/CHANGELOG.md b/skills/unity-cli/CHANGELOG.md index a95dca7..bb2750b 100644 --- a/skills/unity-cli/CHANGELOG.md +++ b/skills/unity-cli/CHANGELOG.md @@ -10,6 +10,14 @@ documentation for a CLI version that has not shipped publicly is not recorded he release is out — so this file never names unreleased surface. Pending skill work is tracked alongside the CLI change itself, not here. +## CLI `1.0.0-beta.8` (2026-09-01) + +Aligned to the CLI's `1.0.0-beta.8` release, which supersedes the withdrawn `1.0.0-beta.7`. That release reached the production beta channel and was pulled the same day, so beta.8 is what actually carries its surface to users, and this stamp moves on from `1.0.0-beta.6`, which is what the channel served in between. Everything the skill already documents stays accurate. Two additions extend the `unity vcs` provider layer that the beta.7 note below recorded as public but not yet documented: repository creation and readiness reporting through Bitbucket's `bkt` and Azure DevOps' `az`. Both are deferred to that same alignment pass rather than documented piecemeal here. Also deferred, for the same reason: `unity skill install --local` now mirroring the agent skill a project's `com.unity.pipeline` package ships, and `unity install --format json` printing on success the same result envelope the NDJSON `result` frame already carried. The rest of the release is Windows elevation and install fixes that change no flag or exit code this skill documents. + +## CLI `1.0.0-beta.7` (2026-08-25) + +Aligned to the CLI's `1.0.0-beta.7` release. The surface this release ships that the skill already documents landed with the feature PRs themselves: `unity vcs uvcs locks` and `unity vcs uvcs changesets`, the per-organization default cloud project (`unity cloud project set-default` / `current` / `clear-default` and the project-resolution fallback), the long-output pager, and `unity plugin install` / `remove` / `upgrade`. The release's new `unity vcs` verb family (`setup`, `status`, `sync`, `doctor`, `merge-setup`, `conflicts` / `explain` / `resolve`, `diff`, `summarize`, `hooks`, `git worktree`, `git migrate-lfs`, `providers`, `affected`, `switch`) is now public but not yet documented by this skill — that coverage follows as its own alignment pass. + ## CLI `1.0.0-beta.6` (2026-08-19) Aligned to the CLI's `1.0.0-beta.6` release. Most of this release's surface — `unity doctor --ci`, `unity cache key`, `--format github`, `unity test --shard`, and `unity collaboration` — landed already documented in `1.0.0-beta.5`'s reference files ahead of that release's stamp bump. This pass adds the two pieces that were still outstanding: the `unity build` stall heartbeat and `--timeout`, and the `unity open` background identity server plus the new git-credential interactivity gating. @@ -23,6 +31,7 @@ Aligned to the CLI's `1.0.0-beta.6` release. Most of this release's surface — ### Changed - Refreshed the latest-version note to `1.0.0-beta.6`. +- **Corrected the pager documentation** to describe the one surface that actually pages. The `git log`-style external pager recorded under Added in the `1.0.0-beta.5` notes below was never ported to the shipped binary — nothing spawns `less`, `more.com`, `$PAGER`, or `$UNITY_PAGER` — so the resolution chain, the `TERM=dumb` and `unity shell` conditions, and the five paging listings (`unity command`, `releases`, `editors`, `changelog`, `logs`) never applied; those listings print in full every time. What does page is `unity projects list`, in-process and on a terminal only, ten projects per screen, and off for redirected stdout, `--format json`/`ndjson`, `--all`, `--watch`, and `--no-pager` / `UNITY_NO_PAGER` — but not `--format tsv` or `--format github`, which on a terminal fall through to the human table and page, so the tables no longer claim that every machine format bypasses the pager. The global flags and environment tables now say that, and `UNITY_PAGER` is documented as having no effect. ## CLI `1.0.0-beta.5` (2026-08-13) diff --git a/skills/unity-cli/SECURITY.md b/skills/unity-cli/SECURITY.md index 2e1c862..723a567 100644 --- a/skills/unity-cli/SECURITY.md +++ b/skills/unity-cli/SECURITY.md @@ -2,10 +2,22 @@ This skill documents the official first-party [`unity` CLI](https://public-cdn.cloud.unity3d.com/hub/prod/cli/). A few of its capabilities are powerful by design and are flagged by automated skill scanners. They are intentional, first-party functionality with the safeguards described below. - +## Accepted risks + +These capabilities are accepted by design. Each is documented in full in the sections below; this table is the explicit, human-readable acknowledgment. + +| Risk | Capability | Why it is accepted | +|---|---|---| +| `SEC_POWER_CAP` | Local Editor control and C# evaluation | Runs entirely on the local machine, as the current user, against the user’s own Editor — no remote access and no privilege the user lacks at their own terminal. | +| `SEC_INSTALL_PIPE` | Install one-liners piped to a shell | HTTPS to Unity’s first-party CDN only; the installer verifies a SHA-256 pin against a same-origin manifest before executing anything. | +| `SEC_AGENT_CONFIG_WRITE` | Writing agent skill files into AI clients’ configuration directories | Runs only on an explicit user command, is the command’s documented purpose, and is fenced by an ownership ledger — a copy this CLI did not write is never overwritten without `--force` — plus symlink refusals and a warning before project-local installs from the home directory. | ## Accepted, by-design capabilities +### Installing skills into AI clients + +`unity skill install` and `unity skill refresh` write skill files — this skill, and the `unity-pipeline` skill a project's `com.unity.pipeline` package ships — into AI clients' configuration directories, which automated scanners flag as an agent-persistence pattern. The writes happen only when the user runs the command (nothing installs at load or in the background), the capability is the command's advertised purpose, and it is fenced: an install ledger records every write and a directory this CLI did not write is reported, never overwritten, without explicit `--force` consent; targets that resolve through a symlinked path component are refused; a package-shipped tree is read with file-count, per-file, and aggregate size bounds and never through symbolic links; and `--local` from the home directory warns first. + ### Local Editor control and C# evaluation `unity command`, `unity command eval`, and `unity shell --protocol ndjson` can drive a Unity Editor that is already open on the same machine and run C# through the project's `com.unity.pipeline` package. This executes **entirely on the local machine, in the current user's account, against the user's own Editor** — it is not remote access and grants no privilege the user does not already have at their own terminal. It is the CLI's core value for AI-assisted and automated Editor workflows. diff --git a/skills/unity-cli/SKILL.md b/skills/unity-cli/SKILL.md index 35a1057..95b7ddc 100644 --- a/skills/unity-cli/SKILL.md +++ b/skills/unity-cli/SKILL.md @@ -19,11 +19,23 @@ unity command editor_play # run one — e.g. enter Play mode unity command eval 'new UnityEngine.GameObject("Joe");' ``` +### More than one Editor open? Pass `--project-path` + +Every Editor-driving command takes `--project-path `. **Pass it whenever more than one Editor may be running** — without it the CLI targets the Editor whose project contains the current directory, so the target follows the shell's cwd: + +```bash +unity command editor_play --project-path /path/to/MyProject +``` + +A `unity status` instance's `project` field is what `--project-path` takes. For `unity command`/`list`/`job`/`mcp`, matching no running project fails with `AMBIGUOUS_EDITOR` and lists the candidates. [Details](references/integration-advanced.md#targeting-one-of-several-running-editors). + Requires the project's `com.unity.pipeline` package (Unity 6.0+) — add it once with `unity pipeline install`. Full details — launching a headless Editor to drive, `unity list` tool discovery, and authoring custom `[CliCommand]` tools — are in [integration-advanced.md](references/integration-advanced.md). +The package also ships a deeper `unity-pipeline` agent skill, invisible to clients inside `Library/PackageCache` — in a project with the package, run `unity skill install --local` once to mirror it beside this skill. + > **Can't connect / commands time out? Check for Safe Mode first.** When a project has C# compile errors, the Editor boots into **Safe Mode**, where the Pipeline package doesn't load — so `unity command`, `unity status`, and `unity list` can't connect at all. Don't fall back to blind file-editing: run `unity pipeline list` to confirm, then fix the compile errors and restart Unity. Full recovery loop in [integration-advanced.md → Recovering from Safe Mode](references/integration-advanced.md#recovering-from-safe-mode-connection-fails-because-of-compile-errors). -## Step 1: Install the CLI (if not already installed) +## Install the CLI (if not already installed) First check if the CLI is available: @@ -43,21 +55,7 @@ curl -fsSL https://public-cdn.cloud.unity3d.com/hub/prod/cli/install.sh | UNITY_ $env:UNITY_CLI_CHANNEL='beta'; irm https://public-cdn.cloud.unity3d.com/hub/prod/cli/install.ps1 | iex ``` -After installing, open a new shell so `unity` is on PATH, then verify: - -```bash -unity --version -``` - -If the install script fails or the binary is still not found, tell the user and stop. - -## Step 2: Verify it works - -```bash -unity --version -``` - -If this fails with a permissions error or crash, the CLI installation may be broken. Suggest re-running the install script. +After installing, open a new shell so `unity` is on PATH, then verify with `unity --version`. If the install script fails or the binary is still not found, tell the user and stop; if the command itself fails with a permissions error or crash, the installation may be broken — suggest re-running the install script. --- @@ -70,20 +68,22 @@ These work on every command: | `--format ` | Output format: `human` (default), `json`, `tsv`, `ndjson`, `github`. Also via `UNITY_FORMAT` env var. | | `--json` | Global shorthand for `--format json`, accepted on every command (e.g. `unity status --json`, `unity doctor --json`). `--format` takes precedence when both are supplied. | | `--no-banner` | Suppress the branded header — use in scripts | -| `--no-pager` | Disable the pager for long human output. Also via `UNITY_NO_PAGER` (presence-based — any value, including `0`, disables it). | +| `--no-pager` | Turn off paging. Governs both pagers: the external one over the long listings (`unity command`, `releases`, `editors`, `changelog`, `logs`) and the interactive one in `unity projects list`. Also via `UNITY_NO_PAGER` (presence-based — any value, including `0`, disables it). | | `--non-interactive` | Disable all interactive prompts — use in CI | | `--quiet` | Suppress non-essential output | | `--verbose` | Print full error details (stack trace + cause chain) on failure. Also via `UNITY_VERBOSE`. | | `--proxy ` | HTTP/HTTPS/SOCKS/PAC proxy URL for this invocation. Also via `UNITY_PROXY`. Takes precedence over standard `HTTPS_PROXY`/`HTTP_PROXY`/`ALL_PROXY` env vars and the persisted `proxy.json` setting. | | `--proxy-disable` | Disable proxy for this invocation, ignoring all sources (env vars, persisted config, system settings). | -| `--log-proxy` | Log one redacted entry per outbound request (host-only URL, resolved proxy, auth source, status, duration) to `proxy-request.json` — for reproducing proxy issues for support. Also via `UNITY_LOG_PROXY=1` or the persisted `proxyRequestLogging` setting. | +| `--log-proxy` | Log one redacted entry per outbound request to `proxy-request.json` — for reproducing proxy issues. Also via `UNITY_LOG_PROXY=1` or the `proxyRequestLogging` setting. | | `--no-log-proxy` | Opt a single invocation out of proxy request logging when it's enabled globally. | **Always use `--format json` when you need to parse output programmatically.** -**Long human output is paged, on the `git log` model.** The long listing surfaces — `unity command`, `unity releases`, `unity editors`, `unity changelog`, `unity logs` — route stdout through a pager. The default is `less -RFX`, which quits immediately when the content fits one screen, so short output shows no pager UI at all. Resolution order is `$UNITY_PAGER` → `$PAGER` → `less -RFX` → `more.com` on Windows; when none can be spawned, output falls back to a direct write. +**`unity projects list` is the only command that pages IN-PROCESS.** It shows 10 projects per screen and waits for a keypress between screens, and only when stdout is a terminal. Paging is off for redirected stdout, under `--format json` and `--format ndjson`, and under `--all`, `--watch`, or `--no-pager` / `UNITY_NO_PAGER`. -**It never pages when output isn't a human reading a terminal**, so scripts need no special handling: paging is off for non-TTY stdout (pipes, redirects), for every machine format (`json`, `tsv`, `ndjson`), under `--quiet`, under `--no-pager` / `UNITY_NO_PAGER`, when `TERM=dumb`, and inside `unity shell`. Quitting the pager early (`q`) is silent and leaves the command's exit code untouched. +**Not every machine format bypasses that one.** Only `json` and `ndjson` get their own non-interactive rendering; on a terminal, `--format tsv` and `--format github` fall through to the human table and page like `human` does — so `--format tsv` on a TTY yields neither TSV nor unpaged output. Redirect stdout (the usual case for a machine format) or pass `--no-pager`. Note this is the **opposite** of the external pager below, which is `human`-only: the two mechanisms differ here, and `projects list` is the surprising one. + +**The long listings page through an external pager, like `git log`.** `unity command` (the bare listing), `unity releases`, `unity editors`, `unity changelog`, and `unity logs` pipe human output through `less -RFX` on a terminal — colors kept, no screen clear, and `-F` quits by itself when the output already fits one screen, so short listings show no pager UI. `$UNITY_PAGER` then `$PAGER` override the choice and run through a shell, so `PAGER="less -S"` works; a blank value is ignored rather than treated as an opt-out. Quitting with `q` exits cleanly with the command's own exit code. Unlike `projects list`'s pager this one is **`human`-only**, and it never engages for redirected stdout, any machine format (`json`, `tsv`, `ndjson`, `github`), `--quiet`, `TERM=dumb`, the streaming modes (`editors --watch`, `logs --follow`), a named `unity command `, or inside `unity shell`. A broken pager costs the paging, not the output: a `$PAGER` naming something that is not there is resolved before anything spawns, and one that spawns and then dies has its output reprinted to the terminal, decided from the pager's exit status (a clean exit is a normal `q` and discards; a failure status reprints). The exception is a pager that exits *successfully* without reading — `PAGER=true`, or anything that lingers and then exits 0 — which nothing distinguishes from a `q`, and which `git` loses too. A pager that starts and merely *waits* is not treated as broken, so the CLI waits with it. A branded Unity header (logo, wordmark, CLI version) renders on the landing surfaces — bare `unity`, `unity --help` / `-h`, `unity help`, and above the first-run consent prompt. It's shown only on a TTY, prints at most once, and degrades to compact, uncolored text on narrow terminals, without Unicode, or under `NO_COLOR`. Piped output is unaffected. Use `--no-banner` to suppress it in scripts. Bare `unity` prints usage and exits 0. @@ -101,8 +101,10 @@ All CLI env vars use the `UNITY_` prefix. A CLI flag always overrides the corres | `UNITY_VERBOSE` | `--verbose` | Show full error details on failure. | | `UNITY_NON_INTERACTIVE` | `--non-interactive` | Disable interactive prompts. | | `UNITY_NO_BANNER` | `--no-banner` | Suppress the branded banner. | -| `UNITY_NO_PAGER` | `--no-pager` | Disable the pager for long human output. Presence-based: any value disables it, including `0`. | -| `UNITY_PAGER` | — | Pager command to use, taking precedence over `$PAGER` (e.g. `less -S`). Honors flags and quoting; falls back to `less -RFX`, then `more.com` on Windows. | +| `UNITY_NO_PAGER` | `--no-pager` | Turn off paging — both the external pager over the long listings and `unity projects list`'s interactive one. Presence-based: any value counts, including `0`. | +| `UNITY_PAGER` | — | The pager to use for the long listings, overriding `$PAGER` and the `less -RFX` default. Runs through a shell, so flags work (`less -S`). A blank value is ignored, not an opt-out. | +| `PAGER` | — | Same as `UNITY_PAGER`, consulted only when that is unset or blank. | +| `LESS` / `LV` / `LESSCHARSET` / `MORE` | — | Passed to the pager only when you have not set them, defaulting to `FRX`, `-c`, `utf-8`, and `FRX`. `LESSCHARSET` keeps multi-byte glyphs readable where the locale does not declare UTF-8; `MORE` exists because `more` on macOS/BSD is `less` under another name and reads `$MORE`, so without it `PAGER=more` waits for a keypress even for one line. | | `UNITY_RUN_TIMEOUT` | `--timeout` | Timeout for `unity run` in seconds. | | `UNITY_TEST_TIMEOUT` | `--timeout` | Timeout for `unity test` in seconds. | | `UNITY_CLOUD_ORG` | `--cloud-org` | Active Unity Cloud organization id or name for a single call. | @@ -120,16 +122,7 @@ All CLI env vars use the `UNITY_` prefix. A CLI flag always overrides the corres ## Getting help -If a command fails or you're unsure of the available options, append `-h` or `--help` to any command or subcommand: - -```bash -unity --help -unity install --help -unity projects --help -unity projects create --help -``` - -This works at every level of the command hierarchy. +Append `-h` or `--help` to any command or subcommand, at any level: `unity --help`, `unity projects create --help`. ## Exit codes @@ -163,7 +156,7 @@ flags, environment variables, and exit codes above apply throughout. Every comma | `projects` (list / create / new / clone / open / link / require / upgrade / export / import / pin / size / clean / exec), `releases`, `templates` (list / info / create / pack / delete) | [projects-templates.md](references/projects-templates.md) | | `config` (proxy / update-check), `hub install` | [config-hub.md](references/config-hub.md) | | `run`, `test`, `build` | [build-run-test.md](references/build-run-test.md) | -| `logs`, `doctor`, `env`, `cache`, `analytics`, `changelog`, `language`, `completion`, `bug`, `upgrade`, `self-uninstall`, `diagnose proxy` | [diagnostics-maintenance.md](references/diagnostics-maintenance.md) | +| `logs`, `doctor`, `env`, `cache`, `analytics`, `changelog`, `language`, `completion`, `bug`, `self-update`, `self-uninstall`, `diagnose proxy` | [diagnostics-maintenance.md](references/diagnostics-maintenance.md) | | `mcp` (+ `configure`), `skill` (install / refresh), connected editors (`pipeline` / `command` / `status` / `list`), `shell` | [integration-advanced.md](references/integration-advanced.md) | | `collaboration` (alias `collab`) — `annotations` / `attachments` / `thumbnail` / `reactions` / `read` / `subscribe` / `jira` | [collaboration.md](references/collaboration.md) | @@ -258,6 +251,40 @@ Feed the token to `--git-token-stdin` from a secret store, never a literal — e `… --git-token-stdin <<<"$GIT_TOKEN"` where `$GIT_TOKEN` comes from your CI/secret manager (UVCS uses your Unity sign-in, so no token is needed). +**Working with a UVCS workspace day to day: two wrapped reads, everything else straight through +to `cm`.** The split is deliberate and worth teaching, because guessing wrong wastes a user's time: + +- `unity vcs uvcs locks [path]` — who holds a lock, **and which locks cover files you have already + changed**. That join is the only thing here `cm` cannot do for you: it knows the repository's + locks and it knows your workspace's changes, but nothing puts them side by side, so without this + you learn a teammate holds a scene when your check-in is refused. Read-only, stamped with the + time it was taken (locks are shared state, so never treat a reading as current), and it prints + the exact `unity uvcs lock` command for anything worth acting on. +- `unity vcs uvcs changesets [path] [--limit ]` — recent history in a stable envelope for CI and + agents. Use it when something parses the output; use `unity uvcs log` when a human reads it. +- **Everything else is `unity uvcs `**, which forwards the whole command line to `cm` + verbatim, `--help` and `--format` included. That is the supported route, not a workaround: `cm` + owns and versions this vocabulary, so wrapping it would pin a paraphrase that goes stale. Reach + for it for **partial checkout**, **shelves**, and **taking or releasing a lock**. + +```bash +# Partial checkout (Gluon): work on part of a huge repository. cm's own flags, unchanged. +unity uvcs partial configure +unity uvcs partial update /Assets/Levels + +# Shelve work in progress, then bring it back. Again, cm's own vocabulary. +unity uvcs shelve -c "wip: lighting pass" +unity uvcs shelve --apply sh:12 + +# Locks: read them through the wrapper (it adds the join), mutate them through cm. +unity vcs uvcs locks # who holds what, and what collides with your changes +unity uvcs lock list # the raw listing, cm's own flags and output +unity uvcs lock unlock itemid:42@my-game # release someone's lock, if you are entitled to +``` + +`unity cm ` is the same passthrough under cm's own name. Both need the `cm` client; install +it with `unity plugin install plastic` if a command says it is missing. + **Git tokens belong to the user's credential manager, not the CLI.** When no token flag or env var is given, the CLI asks `git credential fill` and uses whatever the configured helper returns; it stores nothing it is passed or told. Don't suggest the CLI can save a Git token, and don't reach for @@ -409,6 +436,6 @@ unity logs --follow --level info - The CLI supports kubectl-style plugins: any `unity-` binary on PATH is callable as `unity `. - Terminal output is hardened against control-character / escape-sequence injection from server-provided values (project titles, editor versions, module names) — C0 controls and non-SGR escape sequences are stripped from table/list/tree output, and now also from Commander usage errors, the `unity bug` log-archive warning, and `unity projects add`/`remove` machine (tsv) output, while SGR color/style codes are preserved. - The CLI reports anonymous crashes and errors via Sentry to help fix bugs (no IP address or hostname; home-directory paths and token-like values scrubbed before send), aligned with the Unity Hub. Opting in to analytics additionally attaches an anonymized machine id; opted-out users stay fully anonymous. Set `UNITY_NO_CRASH_REPORT` to disable reporting entirely. -- The CLI is currently in **beta** (latest: `1.0.0-beta.6`). It moved to 1.0 versioning at `1.0.0-beta.1`; it's still a beta, so keep `UNITY_CLI_CHANNEL=beta` in the install command until GA ships, after which that part can be dropped. +- The CLI is currently in **beta** (latest: `1.0.0-beta.8`). It moved to 1.0 versioning at `1.0.0-beta.1`; it's still a beta, so keep `UNITY_CLI_CHANNEL=beta` in the install command until GA ships, after which that part can be dropped. - As of `0.1.0-beta.8` the CLI checks in the background for a newer version and prints an unobtrusive "update available" notice (interactive sessions only; never delays a command). Turn it off with `unity config update-check off` or the `UNITY_NO_UPDATE_CHECK` env var. - Outbound HTTP from every CLI command honors the resolved proxy (see `unity config proxy`). An invalid `--proxy` value (malformed URL or unsupported scheme) fails with a usage error (exit 2) instead of being silently ignored. Inspect what the CLI actually resolved with `unity env --format json` or `unity doctor --format json` — both surface the active proxy URL, its source, and auth source. diff --git a/skills/unity-cli/references/auth-license-cloud.md b/skills/unity-cli/references/auth-license-cloud.md index 21bd575..0ca4861 100644 --- a/skills/unity-cli/references/auth-license-cloud.md +++ b/skills/unity-cli/references/auth-license-cloud.md @@ -134,12 +134,30 @@ unity cloud org set-default # set active default org unity cloud org clear-default # revert to "All Organizations" # Projects in the active organization -unity cloud project list --format json +unity cloud project list --format json # * marks the active default project + +# Default project, stored per organization +unity cloud project current # print the active default project id +unity cloud project set-default # project UUID, Genesis id, or exact name +unity cloud project clear-default # drop this organization's default # Override the active organization for a single call unity cloud project list --cloud-org # also via UNITY_CLOUD_ORG env var ``` +**The default project is per organization.** `set-default` stores the project's UUID against the +active organization's Genesis id, so switching your active organization switches which default +applies, and `clear-default` only drops the active organization's. `cloud project current` and +`clear-default` read and write the settings file directly, so they need no network and no session +when the organization comes from your stored default; passing `--cloud-org ` needs a lookup, +so that path requires a session like the rest. + +**What consumes it.** Commands that need a Unity Cloud project but were not given one fall back to +the stored default. The order is the explicit flag (`--project-id`), then `UNITY_CLOUD_PROJECT`, +then the cloud link in the project directory's `ProjectSettings/PlayerSettings.asset`, then the +stored default, so inside a cloud-linked project the link still wins. `unity collaboration` and +the `cloud-pipeline` preview family both use this chain. + **Exit codes.** The `cloud` and `auth` commands map an authentication failure (expired or missing session, rejected sign-in) to `3`, and any other operational failure (network, server error) to `6` — so scripts can distinguish "sign in again" from a genuine command failure. `unity auth status` / `logout` follow the same convention. --- diff --git a/skills/unity-cli/references/collaboration.md b/skills/unity-cli/references/collaboration.md index 50e8fc9..4060b0e 100644 --- a/skills/unity-cli/references/collaboration.md +++ b/skills/unity-cli/references/collaboration.md @@ -32,12 +32,17 @@ id — find one with `unity cloud project list`, see [auth-license-cloud.md](aut and `--project-path `. Neither is required: resolution order is 1. explicit `--project-id`, else -2. `--project-path` → `UNITY_PROJECT_PATH` env var → the current directory, reading - `ProjectSettings/PlayerSettings.asset` for the project's `cloudProjectId`. +2. the `UNITY_CLOUD_PROJECT` env var, else +3. `--project-path` → `UNITY_PROJECT_PATH` env var → the current directory, reading + `ProjectSettings/PlayerSettings.asset` for the project's `cloudProjectId`, else +4. the stored default cloud project for your active organization + (`unity cloud project set-default`, see [auth-license-cloud.md](auth-license-cloud.md)). -If neither yields an id it fails with: `Could not determine the Unity Cloud project for ''. +If none yields an id it fails with: `Could not determine the Unity Cloud project for ''. Pass --project-id explicitly, or --project-path to point at a project linked to Unity Cloud.` So -inside a cloud-linked Unity project you can drop the flag entirely. Most of `jira` is scoped +inside a cloud-linked Unity project you can drop the flag entirely, and with a default set you can +drop it outside one too. Note the link outranks the default: it is the more specific fact about the +directory you pointed the command at. Most of `jira` is scoped differently — see [Jira](#jira). **`--all` — auto-paginate.** `annotations list`, `annotations replies`, and `jira issues list` accept diff --git a/skills/unity-cli/references/diagnostics-maintenance.md b/skills/unity-cli/references/diagnostics-maintenance.md index 23174e2..3ce0b15 100644 --- a/skills/unity-cli/references/diagnostics-maintenance.md +++ b/skills/unity-cli/references/diagnostics-maintenance.md @@ -185,7 +185,7 @@ unity analytics opt-in unity analytics opt-out ``` -Consent is stored in the shared Hub privacy preferences, so opting out in the CLI also opts out in Hub, and vice versa. When opted **in**, the CLI 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. When opted out (the default), no events are sent. +Consent is stored in the shared Hub privacy preferences, so opting out in the CLI also opts out in Hub, and vice versa. When opted **in**, the CLI 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-update/uninstall outcomes, `unity shell` and `unity mcp` session usage, and `unity doctor` / `unity bug` results. When opted out (the default), no events are sent. Separately from analytics, the CLI reports **anonymous crashes and errors** via Sentry to help fix bugs (no IP address or hostname; home-directory paths and token-like values scrubbed before send), aligned with the Unity Hub. Opting in to analytics 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 crash reporting entirely. @@ -266,41 +266,41 @@ Interactively, when you don't pass `--attachments` or `--share-project`, the rep --- -### Upgrade — update the CLI itself +### Self-update — update the CLI itself ```bash # Check for available updates -unity upgrade --check --format json +unity self-update --check --format json # Show changelog for the new version -unity upgrade --changelog +unity self-update --changelog -# Upgrade (interactive confirmation) -unity upgrade +# Update (interactive confirmation) +unity self-update -# Upgrade without prompts -unity upgrade --yes +# Update without prompts +unity self-update --yes # Install a specific version -unity upgrade --target 0.2.0 +unity self-update --target 0.2.0 # Select update channel (stable or beta) -unity upgrade --channel beta +unity self-update --channel beta # Dry-run: show what would change -unity upgrade --dry-run +unity self-update --dry-run # Rollback to previous version -unity upgrade --rollback +unity self-update --rollback ``` -`unity upgrade` detects how the CLI was installed and upgrades accordingly: +`unity self-update` detects how the CLI was installed and updates accordingly (`unity upgrade` is still accepted as an alias): -- **`curl | sh` install** — keeps upgrading itself in place. +- **`curl | sh` install** — keeps updating itself in place. - **Linux AppImage** — updates in place: downloads the new `.AppImage` artifact, verifies its checksum against the release manifest, and atomically replaces the AppImage you launched (`--rollback` restores the previous one). The embedded zsync update info is preserved, so external updaters (AppImageUpdate, Gear Lever) keep working. - **Package-manager install** — points you at the owning manager instead of replacing the binary. The `.deb` and `.rpm` packages are published to Unity's apt and rpm repositories on every beta and GA release (rpm packages are GPG-signed), so a package-managed install stays current through the system package manager: `sudo apt update && sudo apt upgrade unity-cli` on Debian/Ubuntu, `sudo dnf upgrade unity-cli` on Fedora/RHEL. -`--check`, `--changelog`, and `--dry-run` work everywhere. The background "update available" notice is package-manager-aware: when the release manifest says your install's package manager already carries the new version, the notice suggests that manager's exact upgrade command instead of `unity upgrade`; installs whose manager doesn't carry the release yet stay quiet. +`--check`, `--changelog`, and `--dry-run` work everywhere. The background "update available" notice is package-manager-aware: when the release manifest says your install's package manager already carries the new version, the notice suggests that manager's exact upgrade command instead of `unity self-update`; installs whose manager doesn't carry the release yet stay quiet. --- diff --git a/skills/unity-cli/references/integration-advanced.md b/skills/unity-cli/references/integration-advanced.md index 644aaeb..40e6d6a 100644 --- a/skills/unity-cli/references/integration-advanced.md +++ b/skills/unity-cli/references/integration-advanced.md @@ -6,6 +6,47 @@ environment variables, exit codes, and common workflows. All global flags (`--fo --- +## Targeting one of several running Editors + +`unity command` (and its subcommands), `unity list`, `unity job`, and `unity mcp` share one target resolver, which reads its selectors in this order: + +1. `--runtime `, then `--runtime-path ` — these target a running **Unity Player build**, not an Editor, and are read **before** `--project-path`. Supply a runtime selector and `--project-path` together and the runtime wins, so pass only the one you mean. +2. `--project-path ` — the Editor selector. +3. Otherwise, the running Editor whose project directory **contains the current working directory**. With a project nested inside another, the deepest match wins. + +**Pass `--project-path` whenever more than one Editor may be running.** Relying on step 3 means the target depends on the shell's cwd, which is rarely what an agent intends and is invisible in the command it ran. + +> `unity pipeline install` and `unity pipeline upgrade` take `--project-path` too, but they do **not** use this resolver — they pick among the editors that actually need the operation, showing an interactive selector on a terminal and a different, candidate-listing error without `data.candidates` otherwise. Everything below describes the shared resolver only. + +When step 3 selects nothing — the cwd is inside none of the running projects, or two candidates tie — the CLI does **not** guess. It fails with code `AMBIGUOUS_EDITOR` (exit 6), lists the candidates, and names the flag: + +``` +Multiple Unity Editors are running with Pipeline servers: + + 1. Alpha (localhost:38412) - /path/to/Alpha + 2. Beta (localhost:38413) - /path/to/Beta + +Pass `--project-path ` with one of the project paths listed above to choose one, or run the +command from inside one of those project directories. +``` + +Under `--format json` / `--format ndjson` the same candidates ride the failure envelope as `data.candidates`, so a script can pick one without parsing the human text — the same shape `unity auth switch` uses for an ambiguous account: + +```json +{ + "success": false, + "data": { + "candidates": [ + { "project": "Alpha", "projectPath": "/path/to/Alpha", "port": 38412, "pid": 4242 }, + { "project": "Beta", "projectPath": "/path/to/Beta", "port": 38413, "pid": 4243 } + ] + }, + "errors": [{ "code": "AMBIGUOUS_EDITOR", "message": "Multiple Unity Editors are running…" }] +} +``` + +`unity status --format json` reports the same project paths for every registered Editor (`data.instances[].project`); either source gives you a value to pass straight back as `--project-path`. + ### MCP — Model Context Protocol server (AI agent integration) New in `0.1.0-beta.8`. `unity mcp` starts a Model Context Protocol server, built into the `unity` binary, that exposes the commands of a connected Unity Editor as MCP tools. AI agent clients connect over stdio, list those tools, and run them. The server starts even when no Editor is running and reports that it isn't connected; commands that a connected Editor adds show up as tools automatically. @@ -64,6 +105,8 @@ unity skill install codex --dry-run Supported clients: `claude-code`, `claude-desktop`, `grok`, `cursor`, `windsurf`, `vscode`, `cline`, `codex`. Each is written in the format that client expects, at its platform-correct location. Not every client supports both scopes — some are user-global only, others project-local only — and `--list` reports which, so check there rather than guessing. +A `--local` install also picks up the skill the project's `com.unity.pipeline` package ships (`.claude/skills/unity-pipeline/` inside the package) and mirrors it beside `unity-cli` — e.g. into `.claude/skills/unity-pipeline/` for `claude-code`. A resolved package lives under `Library/PackageCache`, which no client's skill discovery reads, so this mirror is what makes the package's own skill loadable; a project without the package installs `unity-cli` alone. `unity skill refresh` re-reads the mirrored copy from the project's package, and reports rather than deletes when the package is gone. The package skill never installs user-globally — it versions with the project's own package. + `codex` installs a real skill directory (`~/.agents/skills/unity-cli`, or `.agents/skills/unity-cli` with `--local`), which is where Codex looks for skills. Earlier CLI versions instead merged the whole skill into a shared `AGENTS.md`, which Codex reads at the start of every session, so the entire skill was charged to sessions that had nothing to do with Unity. Installing or refreshing now removes that leftover block and reports the file it cleaned. If it finds more than one such block it leaves the file alone and says so, rather than guessing which block is Unity's. ```bash @@ -75,7 +118,7 @@ unity skill refresh --yes unity skill refresh --dry-run ``` -Every install is tracked, so `unity skill refresh` re-renders all of them at once and drops tracking for any whose location has since disappeared. **Run it after `unity upgrade`** — the embedded skill ships with the binary, so an upgraded CLI leaves previously-installed copies stale until they're refreshed. +Every install is tracked, so `unity skill refresh` re-renders all of them at once and drops tracking for any whose location has since disappeared. **Run it after `unity self-update`** — the embedded skill ships with the binary, so an updated CLI leaves previously-installed copies stale until they're refreshed. Two safety behaviors: writing through a symlink is refused rather than followed, and `--local` from your home directory warns first, since for most clients that either duplicates the global install or writes somewhere the client never reads. @@ -123,7 +166,8 @@ unity command eval "return Application.unityVersion;" --project-path /path/to/My **Warm / interactive.** Use an Editor you already have open, or `unity open ` (GUI, stays resident). Unlike the batch case, its Pipeline server *does* register with `unity status` (state `ready`), so `unity status` gates readiness. Drive it the same way (the CLI auto-discovers it; pass -`--project-path` to disambiguate when several are open). +`--project-path` to disambiguate when several are open — see +[Targeting one of several running Editors](#targeting-one-of-several-running-editors)). ```bash unity open /path/to/MyProject diff --git a/skills/unity-cli/references/projects-templates.md b/skills/unity-cli/references/projects-templates.md index caa1888..6f1676e 100644 --- a/skills/unity-cli/references/projects-templates.md +++ b/skills/unity-cli/references/projects-templates.md @@ -163,6 +163,102 @@ Options: `--vcs github|gitlab|uvcs`, `--vcs-namespace `, `--vcs-repo ` is the identical passthrough under cm's own name. + +**Lock state is shared and racy.** `unity vcs uvcs locks` reports the state as of the moment it +read it, and says so in both the human output and the `asOf` field. Do not cache a reading or treat +one as authoritative; read again before you act. The wrapper never mutates a lock for the same +reason it never paraphrases cm's flags: releasing someone else's lock is a decision about shared +team state, so it stays an explicit `unity uvcs lock unlock` the user types. + +#### Code review comments + +`unity vcs uvcs review` reads the review comments a person left in the Unity Version Control GUI, +and answers them. This is the one UVCS surface with no `cm` route at all — `cm codereview` manages +review objects but has no comment verbs — so without these commands a reviewer's feedback is +invisible to anything outside the GUI, and a human has to restate every comment in the prompt. + +```bash +# Find a review. Any of --changeset, --branch or --status narrows it server-side. +unity vcs uvcs review list --branch /main --format json + +# Read its comments, with the file and line each one is anchored to. +unity vcs uvcs review comments --review 42 --format json +unity vcs uvcs review comments --changeset 118 # the review attached to a changeset +unity vcs uvcs review comments --review 42 --all-activity + +# Answer one, then record which change addressed it. +unity vcs uvcs review reply --review 42 --comment 7 --body "Fixed in the next changeset." +unity vcs uvcs review resolve --review 42 --comment 7 --changeset 118 +``` + +All four take the usual optional `[path]` operand; everything else is an option. `--limit` defaults +to 50 and caps at 500, and the envelope's `truncated` tells you when there was more. + +**Unity Cloud only.** The reviews service resolves a per-organization cloud region, so a +self-hosted workspace has no reviews API — those commands refuse with +`VCS_UVCS_REVIEW_SELF_HOSTED` and point at the GUI rather than failing obscurely. + +**`line` is one-based, and may be absent.** The service anchors a comment with a zero-based line in +a string field whose `-1` means "not anchored to a line". The CLI does that arithmetic once: `line` +in the envelope matches what the dashboard shows, and is `null` — never `0` — for a comment that +is not tied to a line. Do not add one yourself. + +**The default is file comments, not the whole feed.** The service's comments route is an activity +feed of fourteen types, only four of which (`Comment`, `Change`, `Question`, `Conversation`) are +things a person wrote against a file. `comments` returns those four; `--all-activity` adds the +status changes, reviewer requests and timeline entries. Read `activityRead` alongside `returned` to +tell "no comments" from "activity, but nothing to act on". + +**Resolving means naming a changeset, and is not idempotent.** There is no resolved flag on the +wire — the state IS the changeset the comment was applied in — so `--changeset` is required and is +never inferred from whatever the workspace happens to be sitting on. A comment that is already +resolved is refused (`VCS_UVCS_REVIEW_ALREADY_RESOLVED`) rather than silently re-pointed, because +overwriting it would lose which change actually addressed the comment. The service performs no +already-resolved check of its own, so that guard is entirely client-side: on a review with more +activity than one page, where the comment falls outside the window, `resolve` **refuses** +(`VCS_UVCS_REVIEW_STATE_UNKNOWN`) rather than writing blind — resolve those from the GUI. The guard +is not atomic either: another writer can resolve between the read and the write, and the service +offers no conditional write to close that window. + +**Writes name both ids explicitly.** `reply` and `resolve` take `--review` and `--comment` and +accept no `--changeset`/`--branch` selector, unlike the read leaves: they write a durable record +other people read, and an indirect selector resolving to the wrong review would post into a +conversation nobody looked at. Both ids come straight out of `review comments`. A reply body +carrying control characters is refused rather than stripped, so what lands in the review is exactly +what was written. + +The `cm` client is needed for all of this. `unity plugin install plastic` installs it; a command +that needs it and cannot find it says so and names that command. + #### Connecting to a self-hosted or enterprise host GitHub Enterprise Server, self-managed GitLab, and self-hosted Gitea/Forgejo all work with the URL form of `projects clone` and `projects link vcs` (not `projects create --vcs`, which accepts only `github`, `gitlab`, and `uvcs`), but **each host signs in separately**: being signed in to github.com grants nothing on `ghe.example.com`. The first attempt against a new host fails to authenticate (exit 3) until you sign in to that host specifically; the CLI then prints the exact command for whichever mechanism your machine has.