Skip to content

Tags: nrwl/nx

Tags

23.0.0-beta.16

Toggle 23.0.0-beta.16's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(testing)!: migrate @nx/jest to local dist build (#35713)

## Current Behavior

`@nx/jest` builds into the shared `dist/packages/jest` directory at the
workspace root and compiles with `commonjs` module resolution. It
exposes no `exports` map, and first-party packages (`@nx/detox`,
`@nx/node`) reach into `@nx/jest/src/*` for internal utilities. It also
still re-exports the long-deprecated `jestProjectGenerator` alias.

## Expected Behavior

`@nx/jest` builds locally into `packages/jest/dist/` with `nodenext`
module resolution and an `exports` map, matching the already-migrated
`nx`, `devkit`, and `js` packages.

- `tsconfig.lib.json` / `tsconfig.spec.json` switched to the nodenext +
local-`dist` pattern.
- `package.json` gains an `exports` map (`.`, `./plugin`, `./preset`,
`./plugins/resolver`, `./internal`, plus the JSON configs),
`typesVersions`, and a `files` field.
- `project.json` gains `release` (`preserveLocalDependencyProtocols`,
`manifestRootsToUpdate`) and `nx-release-publish` configuration.
- `executors.json` / `generators.json` / `migrations.json` factory and
schema paths repointed to `./dist/src/...`.
- `assets.json` outputs to the local `dist/` and copies
`src/**/schema.json`.
- `src/utils/versions.ts` resolves its own `package.json` via a
`@nx/jest` self-reference instead of a `../../` relative path, which
breaks once source compiles into `dist/`.
- The `@nx/jest:jest` executor imports its `schema.json` statically
rather than via a dynamic `await import`.
- A curated `@nx/jest/internal` entry (mirroring `@nx/devkit/internal`)
replaces deep `@nx/jest/src/*` imports for first-party consumers;
`@nx/detox` and `@nx/node` are routed through it.
- A migration (`rewrite-jest-internal-subpath-imports`) rewrites user
`@nx/jest/src/*` imports: named imports/exports of public symbols go to
`@nx/jest`, everything else to `@nx/jest/internal`.
- A migration (`rewrite-jest-project-generator`) rewrites
`jestProjectGenerator` imported from `@nx/jest` to
`configurationGenerator`.

The `dist-build-migration` skill is also updated to document the
symbol-aware routing rule for the migration step.

### Breaking Changes

- The deprecated `jestProjectGenerator` export is removed — its "removed
in Nx v22" notice is two majors overdue. It was always just an alias for
`configurationGenerator`; the `rewrite-jest-project-generator` migration
rewrites existing usages automatically.

## Related Issue(s)

Tracked by Linear NXC-3592 — `[M4] [Epic] Migrate @nx/jest to local
dist`. No GitHub issue.

<details>
<summary>Pre-create review (run before PR open)</summary>

### Critical

- The subpath-import migration originally rewrote every `@nx/jest/src/*`
import to `@nx/jest/internal`, which would silently break consumers
importing a public symbol (e.g. `findJestConfig`) that way. **Fixed** —
the migration now partitions named imports/exports: public symbols route
to `@nx/jest`, internals to `@nx/jest/internal`, splitting mixed
declarations into two.

### Important

- `export { ... } from '@nx/jest/src/*'` and additional `jest`/`vi` mock
helpers were not handled by the initial migration. **Fixed** — export
declarations are now partitioned like imports, and all eight mock-helper
methods are covered with tests.

### Suggestions

- `versions.ts` self-resolve and the inferred `build-base` target were
flagged; both verified correct (matches the `@nx/js` pattern;
`build-base` is inferred by `@nx/js/typescript` from
`tsconfig.lib.json`).
- Softened an over-broad "used only" comment in `eslint.config.mjs`.

</details>

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>

23.0.0-beta.15

Toggle 23.0.0-beta.15's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(core): restore nx/src/index entrypoint for Nx Cloud client compat…

…ibility (#35712)

## Current Behavior

Under Nx 23.0.0, the Nx Cloud agent client crashes when running tasks:

```
TypeError: runContinuousTasks is not a function
    at AgentTaskManager.invokeContinuousTasks
    at AgentTaskManager.reconcileContinuousTasks
    at AgentTaskManager.invokeTasks
    at executeTasksV3
```

The Nx Cloud client probes the nx task APIs by `require`-ing
`nx/src/index` (for the legacy `initTasksRunner`) and
`nx/src/tasks-runner/init-tasks-runner` (for the modern
`runDiscreteTasks` / `runContinuousTasks`) inside a single shared
`try/catch`.

PR #35708 removed the deprecated `initTasksRunner` API and **deleted
`packages/nx/src/index.ts` entirely** — even though that PR's own commit
message stated the file would be kept as an empty module so the `nx/src`
subpath export mapping stays valid. With the file gone, `nx/src/index`
no longer resolves (`./src/*` maps to `./dist/src/index.js`, which is
never built). The `require('nx/src/index')` throws, the client's shared
`catch` swallows it, and `runContinuousTasks` is never assigned — later
crashing when invoked.

`runContinuousTasks` itself was never removed; it still lives in
`packages/nx/src/tasks-runner/init-tasks-runner.ts` and is unreachable
here only because the earlier `nx/src/index` probe throws.

## Expected Behavior

`packages/nx/src/index.ts` is restored as an empty ES module, so the
`nx/src/index` entrypoint resolves again via the existing `./src/*`
mapping in `package.json` exports (no `package.json` change needed). The
deprecated `initTasksRunner` export stays removed — consumers still get
`undefined` for it — but the `require` no longer throws, so the Nx Cloud
client proceeds to load `runContinuousTasks` / `runDiscreteTasks`
correctly.

This restores compatibility for already-published/cached Nx Cloud client
bundles without requiring them to be updated.

## Related Issue(s)

Internal: NXC-4307 (follow-up to #35708)

<!-- polygraph-session-start -->
---
[View session information
↗](https://snapshot.app.trypolygraph.com/orgs/69cdc268b6aa527e4129c2b4/sessions/master-1efdcf12-fbbd-49c0-954c-3637c415400a-d8a02644)
<!-- polygraph-session-end -->

---------

Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>

23.0.0-beta.14

Toggle 23.0.0-beta.14's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(core): do not drop target defaults in 23.0.0 array migration (#35711

)

## Current Behavior

The `convert-target-defaults-to-array` migration (Nx 23) converts the
legacy
record-shape `targetDefaults` in `nx.json` to the new array shape.

It declared a `projectGraph` parameter and classified each record key
against
the graph, dropping any key whose target name / executor wasn't found in
the
workspace. But the migration runner always invokes migrations as
`fn(tree, {})`
— the second argument is an empty object, never a project graph.

`{}` is truthy, so it was treated as a real (but empty) graph. Every
non-glob
key then matched neither a target name nor an executor, and the
migration
dropped it. As a result, upgrading to Nx 23 deletes every named
`targetDefaults`
entry (`build`, `test`, `lint`, …) and keeps only glob entries —
silently
breaking `build` (lost `dependsOn`) and `test` (lost env/options) across
the
workspace.

## Expected Behavior

The migration is a pure shape conversion and never drops entries:

- The entry point takes an honest `(tree)` signature — it no longer
pretends to
  receive a project graph it is never given.
- Every legacy key produces at least one array entry. Globs and plain
(non-`:`)
keys become `{ target: key }`; `:` keys are disambiguated by the project
graph
(`target`, `executor`, or both), falling back to the syntactic heuristic
  (`:` → executor) when the graph has no signal.
- The project graph is built internally, and only when a `:`-style key
actually
  needs disambiguating.
- The pure conversion is exposed as `convertTargetDefaultsRecordToArray`
so the
disambiguation logic is unit-testable with injected graphs, without
standing
  up a workspace or the migration runner.

## Related Issue(s)

N/A — caught while upgrading the Nx repo itself to `23.0.0-beta.13`.

23.0.0-beta.13

Toggle 23.0.0-beta.13's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(js): build to local dist and use nodenext (#35538)

## Current Behavior

`@nx/js` builds to the shared workspace-root `dist/packages/js/`
directory, uses CommonJS `module`/`moduleResolution`, has no `exports`
map, and relies on `.npmignore`-style filtering through assets.json
copies. This makes the package layout diverge from the new pattern
already adopted by `nx` and `@nx/devkit`.

## Expected Behavior

`@nx/js` follows the same local-dist build pattern as `nx` and
`@nx/devkit`:

- Builds to `packages/js/dist/` instead of `dist/packages/js/`.
- `tsconfig.lib.json` uses `module`/`moduleResolution: "nodenext"` with
`composite`, `rootDir: "."`, and `declarationDir: "dist"`.
- `package.json` declares an `exports` map with the `@nx/nx-source`
condition (workspace consumers resolve to `.ts` source, published
consumers get built `.js`), plus a `./src/*` wildcard so the ~296
existing internal imports of `@nx/js/src/...` keep working.
- `typesVersions` added for legacy `moduleResolution: "node"` consumers.
- Adopts an explicit `files` field on `package.json` instead of
asset-copying the root JSONs.
- `generators.json`, `executors.json`, `migrations.json` factory/schema
paths rewritten `./src/...` → `./dist/src/...` (matches `nx`). Workspace
dev still works via the `tryResolveFromSource` fallback in
`packages/nx/src/config/schema-utils.ts`.
- `README.md` → `readme-template.md`; build command writes the rendered
README to `packages/js/README.md`. Root `.gitignore` now ignores
`packages/js/README.md` and `packages/js/**/*.d.ts` (with
`!packages/js/src/**/schema.d.ts` exception for committed schema
declarations).
- ESLint flat config ignores `dist` and `**/*.d.ts`.
- `project.json` adds `release.version` config (with
`preserveLocalDependencyProtocols: false` so the not-yet-migrated
`@nx/workspace` dep is substituted to a concrete version at version-time
rather than left as `workspace:*` for pnpm publish to resolve from the
un-bumped source `packages/workspace/package.json`) and
`nx-release-publish.packageRoot`. The `build` target keeps its existing
`dependsOn: ["build-base"]` (cannot use `^build` because js's
`implicitDependencies` create a cycle through `eslint` /
`eslint-plugin`).
- `scripts/nx-release.ts`: adds `packages/js` to `packagesToReset` so
the source `packages/js/package.json` is restored after release.

## Related Issue(s)

Part of the ongoing migration of Nx packages to the local-dist build
layout (following `nx` and `@nx/devkit`).

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>

23.0.0-beta.12

Toggle 23.0.0-beta.12's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(misc): stop inferring `projects: 'self'` in `dependsOn` entries (#…

…35686)

## Current Behavior

The `@nx/cypress`, `@nx/jest`, `@nx/playwright` and `@nx/gradle` plugins
infer atomized CI `dependsOn` entries that include `projects: 'self'`.
That value is the default for `projects` and is no longer supported as
an explicit value.

## Expected Behavior

The plugins infer the same atomized CI `dependsOn` entries without
setting `projects: 'self'`.

22.7.2

Toggle 22.7.2's commit message

Verified

This commit was signed with the committer’s verified signature.
FrozenPandaz Jason Jean
chore(core): refresh stale TUI snapshots on 22.7.x

PR #35640 introduced these tests with snapshots that assumed PR
#35540's Task::new helper, but #35540 is master-only. On 22.7.x the
test setup still produces task1/task2/task3 ids (not app1:build etc.)
and the selection arrow placement differs slightly. Regenerated the
three affected snapshots to match current 22.7.x behavior; tests now
pass cleanly.

23.0.0-beta.11

Toggle 23.0.0-beta.11's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
chore(gradle): bump gradle project graph plugin version to 0.1.21 (#3…

…5678)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
The Gradle project graph plugin is at version 0.1.20.

## Expected Behavior
The Gradle project graph plugin is bumped to version 0.1.21, with the
corresponding migration files created
so that users upgrading Nx will automatically get the new plugin
version.


## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

23.0.0-beta.10

Toggle 23.0.0-beta.10's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
chore(core)!: build @nx/workspace to local dist and use nodenext (#35643

)

## Current Behavior

`@nx/workspace` builds to the shared workspace-root
`dist/packages/workspace/` directory, uses CommonJS
`module`/`moduleResolution`, and has no `exports` map. Other Nx packages
and external plugins reach into `@nx/workspace/src/*` subpaths for
internal utilities.

## Expected Behavior

`@nx/workspace` follows the same local-dist build pattern as `nx` and
`@nx/devkit`:

- Builds to `packages/workspace/dist/` instead of
`dist/packages/workspace/`.
- `tsconfig.lib.json` uses `module`/`moduleResolution: "nodenext"` with
`composite`, `rootDir: "."`, `declarationDir: "dist"`.
- `package.json` declares an `exports` map matching `@nx/devkit`'s
locked-down surface — only named entry points, no `./src/*` wildcard.
- `generators.json` / `executors.json` factory/schema paths rewritten
`./src/...` → `./dist/src/...`. Workspace dev still works via the
`tryResolveFromSource` fallback in
`packages/nx/src/config/schema-utils.ts`.
- `README.md` → `readme-template.md`; build command writes the rendered
README to `packages/workspace/README.md`.
- `project.json` adds `release.version` config
(`preserveLocalDependencyProtocols: true`, matching nx/devkit).
- `scripts/nx-release.ts`: adds `packages/workspace` to
`packagesToReset`.

Internal-leak cleanup so the locked-down exports map doesn't break
first-party callers:

- `TypeScriptCompilationOptions` + `compileTypeScript` moved from
`@nx/workspace` to `@nx/js` (the package that owns TypeScript
compilation).
- `@nx/remix` inlines `directoryExists` (was a one-line re-export
wrapper).
- `@nx/rspack` drops the Nx 15.7-era
`@nx/workspace/src/utils/create-ts-config` fallback.
- e2e helpers source `angularDevkitVersion` from `@nx/angular/src/utils`
instead.
- `@nx/workspace` and `@nx/remix` no longer declare `@nx/workspace` deps
they don't use.
- Adds a preflight step to the `dist-build-migration` skill that warns
about `workspace:*` deps on not-yet-migrated packages.

## Breaking Changes

**`@nx/workspace/src/*` subpath imports are no longer supported.** The
`exports` map no longer declares a `./src/*` wildcard. ~150 public
consumers across GitHub use these subpaths today (the largest cluster is
`src/utilities/fileutils` with ~60 hits). Migration:

- `@nx/workspace/src/utilities/fileutils` (`directoryExists`,
`fileExists`, `isRelativePath`, `createDirectory`) — these are thin
re-exports from `nx/src/utils/fileutils`. Inline with `node:fs`
(`statSync(p).isDirectory()` for `directoryExists`) or import from
`@nx/devkit` where equivalent.
- `@nx/workspace/src/utilities/typescript/compilation` — moved to
`@nx/js`. Internal callers should import from there; if you were
depending on the type externally, copy it or use the equivalent from
`@nx/js`.
- `@nx/workspace/src/utils/versions` — values are duplicated across
packages; reimplement against the version of Nx you're targeting.
- Other subpaths — check the `@nx/workspace`'s public `index.ts`
re-exports first; otherwise reimplement.

**`@nx/workspace/tasks-runners/default` now throws when invoked.** This
module was an alias for `nx/src/tasks-runner/default-tasks-runner`. The
Nx 17 (`use-minimal-config-for-tasks-runner-options`) and Nx 21
(`remove-custom-tasks-runner`) migrations rewrite/remove legacy
`tasksRunnerOptions` entries. If your `nx.json` still references
`@nx/workspace/tasks-runners/default`, replace it with
`nx/tasks-runners/default`.

## Related Issue(s)

Part of the ongoing migration of Nx packages to the local-dist build
layout (following `nx` and `@nx/devkit`).

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>

23.0.0-beta.9

Toggle 23.0.0-beta.9's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(misc)!: deprecate executors with inferred-plugin replacements (#…

…35576)

## Current Behavior

Most Nx executors that have an inferred-plugin alternative
(`@nx/<pkg>/plugin`) and a `convert-to-inferred` generator are still
wired up like first-class citizens. There is no signal — at scaffold
time, schema browsing, or task execution — that they are on a path to
removal, and the existing `cypress`/`detox` deprecation messages are
inconsistent with the canonical pattern shipped most recently.

## Expected Behavior

Every executor that has an inferred-plugin migration target is now
deprecated through three surfaces, matching the canonical pattern:

- **Runtime warning.** The executor logs that it is deprecated, will be
removed in Nx v24, and points at `nx g @nx/<pkg>:convert-to-inferred`.
- **Schema-root `x-deprecated`.** Surfaces in editor / Nx Console / `nx
show project` views.
- **Generation-time warning.** When a generator is about to scaffold a
target that uses one of these executors because the corresponding
inferred plugin isn't registered, it warns at generation time and points
at the same migration path.

All warnings link to
<https://nx.dev/docs/guides/tasks--caching/convert-to-inferred>.

### Executors deprecated in this PR

| Package | Executors |
|---|---|
| `@nx/webpack` | `webpack`, `dev-server` |
| `@nx/vite` | `build`, `dev-server`, `preview-server` |
| `@nx/rollup` | `rollup` |
| `@nx/next` | `build`, `server` |
| `@nx/remix` | `build`, `serve` |
| `@nx/jest` | `jest` |
| `@nx/playwright` | `playwright` |
| `@nx/eslint` | `lint` |
| `@nx/storybook` | `storybook`, `build` |
| `@nx/rspack` | `rspack`, `dev-server` |
| `@nx/expo` | `build`, `export`, `install`, `prebuild`, `run`, `serve`,
`start`, `submit` |
| `@nx/react-native` | `build-android`, `build-ios`, `bundle`,
`pod-install`, `run-android`, `run-ios`, `start`, `upgrade` |
| `@nx/vitest` | `test` |

### Generation-time warnings wired in

- `@nx/<pkg>:configuration` for webpack, vite, rollup, jest, playwright,
storybook, rspack, vitest
- `@nx/<pkg>:application` for next, expo, react-native
- `@nx/eslint:lint-project` legacy fallback path
- `@nx/react:application` (webpack, rspack branches) and
`@nx/react:library` (rollup legacy fallback) — warning text is inlined
rather than imported. Two distinct reasons:
- **rspack:** `@nx/react` does not declare a tsconfig project reference
to `@nx/rspack`, so the deep import would not even type-check.
- **webpack and rollup:** the project reference exists, so the deep
import compiles, but `@nx/webpack` and `@nx/rollup` only expose
`./index.js` in their package `exports` field. The import would resolve
in source but throw `Cannot find module
'@nx/<pkg>/src/utils/deprecation'` at runtime in published packages.
- `@nx/react-native:web-configuration` (webpack) — inline for the same
reason as the rspack case (no project reference).

### Scope notes

- `@nx/vite:test` is intentionally **not** included — it is being
removed entirely by PR #35517 (deprecation messaging would ship as dead
code). `@nx/vitest:test` is now in scope: the `convert-to-inferred`
generator for `@nx/vitest` is in place, so the deprecation has a real
migration target.
- `@nx/cypress`/`@nx/detox` already shipped earlier; this PR retitles
their generation-time messages to the new wording (drop the redundant
"register the plugin first" guidance, swap "Scaffolding" for
"Generating") and points the detox URL at the general
convert-to-inferred guide.
- `@nx/react-native:storybook` is intentionally **not** included. The
companion `@nx/react-native:storybook-configuration` generator was
already removed in v21 and no generator has emitted this target since
Jan 2024 (RN 0.73 upgrade). It will be removed outright in a follow-up
PR rather than going through the deprecate-now / remove-in-v24 cycle.
- `@nx/webpack:ssr-dev-server`, `@nx/expo:build-list`,
`@nx/expo:sync-deps`, `@nx/expo:update`, `@nx/expo:ensure-symlink`,
`@nx/react-native:sync-deps`, and `@nx/react-native:ensure-symlink` are
intentionally left as-is — none are covered by `convert-to-inferred` and
they have no clean replacement (Nx-specific glue or non-migrating
utilities).
- `@nx/esbuild:esbuild` and `@nx/nuxt:*` ship neither an inferred plugin
nor a `convert-to-inferred` generator yet, so they're out of scope.
- Per-package READMEs, introduction-doc banners, per-package "migration
recipe" pages, and `migrations.json` entries are intentionally skipped
per the canonical pattern (NXC-4422). The runtime warning carries the
migration story.

## Related Issue(s)

Fixes NXC-4423.
Fixes NXC-4296.
Fixes NXC-4294.
Fixes NXC-4290.
Fixes NXC-4285.
Fixes NXC-4283.
Fixes NXC-4286.
Fixes NXC-4297.
Fixes NXC-4293.
Fixes NXC-4292.
Fixes NXC-4282.
Fixes NXC-4287.
Fixes NXC-4295.
Fixes NXC-4447.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>

23.0.0-beta.8

Toggle 23.0.0-beta.8's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
chore(repo): provision build toolchain via mise in publish workflow (#…

…35593)

## Current Behavior

The `publish` workflow's matrix builds (Linux/macOS/Windows native
binaries via N-API) install Java, Node.js, and pnpm manually inside each
runner/container. With `@nx/dotnet` now in `nx.json`, these builds also
need .NET to be available before the project graph can be loaded — and
there's no .NET install on any of the matrix entries today, so the
workflow fails at the `pnpm nx run-many --target=build-native` step.

The macOS and `armv7-unknown-linux-gnueabihf` matrix entries already use
`mise-action` and `mise.toml`, but the four Linux *docker* entries
(Debian + Alpine, x64 + arm64) bypass mise entirely and provision tools
through hand-rolled `apt-get` / `apk` / `nodesource` / `npm i -g pnpm`
steps.

## Expected Behavior

- All four Linux docker matrix entries now install `mise` from a
signed/distro source (apt repo at `https://mise.jdx.dev/deb` for Debian,
`apk add mise` from Alpine `community` for Alpine) and provision their
entire toolchain — Node.js, Java, .NET, Maven, corepack — from
`mise.toml`. This drops ~30 lines of bespoke install logic per entry and
keeps versions in lockstep with the non-docker matrix entries, which
already use `mise-action`.
- Windows entries gain `choco install dotnet-9.0-sdk -y` alongside the
existing OpenJDK install (mise's Windows .NET path is broken upstream —
see [jdx/mise#4738](jdx/mise#4738)).
- The FreeBSD build sets `NX_DOTNET_DISABLE=true` (added to both the
`env:` block and the `cross-platform-actions/action`
`environment_variables` allowlist so the var actually crosses into the
FreeBSD VM) to opt out of the plugin entirely.
- `NODE_VERSION` is now forwarded into `docker run` so containers honor
the workflow's pinned Node version through `mise.toml`'s tera template
instead of falling back to its `24.11.0` default.
- `mise` itself is installed only via signed repositories — no `curl
https://mise.run | sh` — so a hijacked DNS lookup against `mise.run`
cannot drop a malicious script into our publish pipeline.

## Related Issue(s)

N/A — workflow fix triggered by `@nx/dotnet` being added to `nx.json`.