Compare commits

..

1260 Commits

Author SHA1 Message Date
nx-cloud[bot] dfa7015413 fix(js): handle batch ensure-package in tests
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
2026-04-22 00:00:34 +00:00
Craigory Coppola 9fe9f52a6c Merge branch 'master' into chore/multi-ensure-pkg 2026-04-18 07:01:24 -04:00
Steven Nance af5643f1a9 chore(repo): remove unused browser installs and system deps from main-linux CI (#35337)
## Current Behavior

The `main-linux` orchestrator job in `.github/workflows/ci.yml` installs
several system packages, Chrome, and Playwright browsers on every run:

```yaml
- name: Install dependencies
  run: |
    sudo apt-get update
    sudo apt-get install -y ca-certificates lsof libvips-dev libglib2.0-dev libgirepository1.0-dev

- name: Install Chrome
  uses: browser-actions/setup-chrome@...

- name: Install Playwright
  run: pnpm playwright install --with-deps
```

None of these are actually used by tasks the orchestrator executes. The
orchestrator runs `format:check`, `sync:check`, `conformance:check`,
`check-imports`, `check-lock-files`, `check-codeowners`, and kicks off
`nx affected` -- which distributes all
`lint`/`test`/`build`/`e2e`/`e2e-ci` tasks to Nx agents per
`.nx/workflows/dynamic-changesets.yaml`.

Historically these steps were copy-pasted during the CircleCI to GHA
migration (5b9d43f9) without evaluating whether the orchestrator
actually needed them. Tracing each back to its origin:

- **`lsof`** (added in c9cd67ea) -- only used by `kill-port` in e2e
tests (`e2e/next`, `e2e/storybook`, etc.), which run on agents.
- **`libvips-dev` / `libglib2.0-dev` / `libgirepository1.0-dev`** (added
in cfcedb48 for storybook/Next.js image tests) -- only needed if `sharp`
falls back to a source build. Sharp ships prebuilt binaries for
linux-x64 and is only reached via `astro-docs`/Next.js builds, which run
on agents.
- **`ca-certificates`** -- already present on `ubuntu-latest`.
- **`browser-actions/setup-chrome`** -- no orchestrator-local task uses
Chrome. No Karma/Puppeteer tests run here. Browser-driven tests run on
agents, which get Chromium via Playwright.
- **`pnpm playwright install --with-deps`** -- only needed by browser
tests, which run on agents (agents install Playwright themselves, see
`.nx/workflows/agents.yaml` lines 51-54).

## Expected Behavior

The `main-linux` orchestrator skips the unnecessary install steps,
saving ~30-60s per CI run with no functional change. Nx agents continue
to install these packages themselves when they need them.

The macOS React Native job (`main-macos`) keeps its Playwright install
because those e2e tests run directly on the macOS runner, not on agents.

## Related Issue(s)

N/A -- cleanup.
2026-04-17 18:05:59 -04:00
Louie Weng fb79edbb03 fix(gradle): recognize Kotlin compile tasks in inferred input extensions (#35335)
## Current Behavior

`inferExtensionsFromInputProperties` uses `is AbstractCompile` to
determine when to add `.class` as an inferred input extension. As a
result, Kotlin compile tasks are silently excluded from the `.class`
branch, producing incomplete inferred inputs in the Nx project graph for
Kotlin projects.

## Expected Behavior

All Kotlin compile tasks should be recognized alongside
`AbstractCompile` tasks and produce `.class` as an inferred input
extension, regardless of which Gradle plugin hierarchy they belong to.
Java-only projects are unaffected.

## Related Issue(s)

<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
2026-04-17 16:57:52 -04:00
Jason Jean a7d955016f chore(repo): update nx to 22.7.0-beta.15 (#35319)
Updating Nx from 22.7.0-beta.12 to 22.7.0-beta.15

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-17 16:37:25 -04:00
Craigory Coppola 8f47bf2a6a fix(core): recognize json inputs in TS task hasher fallback (#35334) 2026-04-17 14:56:06 -04:00
Craigory Coppola e4b7a3d9e7 fix(core): use v8 serialization in pseudo-IPC channel (#35332)
## Current Behavior

The pseudo-IPC channel (used when Rust forks a Node wrapper that then
re-forks the Node task process) and the plugin isolation channel (used
between the main Nx process and its plugin-worker subprocesses) both
serialize every message with `JSON.stringify` / `JSON.parse`. That means
payloads such as `Buffer`, `Date`, `Error`, `undefined`, or objects with
cycles can't flow over these channels, even though the daemon
client/server already supports them via the shared `serialize()` helper
in `daemon/socket-utils.ts` (v8 with JSON fallback).

Notably, `Error` objects over the plugin channel currently flatten to
`{}` under JSON, losing stack and message.

The read-side `isJsonMessage ? JSON.parse :
v8.deserialize(Buffer.from(..., 'binary'))` detection was also
duplicated across three files.

## Expected Behavior

Pseudo-IPC and plugin isolation both use the same opt-in v8/JSON
serialization convention as the daemon channel, so non-JSON-safe
payloads flow through consistently. Default behavior is unchanged — v8
serialization is gated by `isV8SerializerEnabled()` and falls back to
JSON otherwise.

The duplicated read-side detection is hoisted into a single
`parseMessage<T>()` helper next to `isJsonMessage` in
`utils/consume-messages-from-socket.ts`. Round-trip coverage for the
helper is added.

Commits:
1. `fix(core): use v8 serialization in pseudo-IPC channel` — matches
daemon wire format on the pseudo-IPC server/client.
2. `refactor(core): hoist parseMessage helper for socket payloads` —
deduplicates the parse pattern and adds unit tests.
3. `refactor(core): adopt parseMessage/serialize in plugin isolation
IPC` — applies the same convention to the internal plugin-worker channel
(not public API).

## Related Issue(s)

N/A

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
2026-04-17 14:20:14 -04:00
Jack Hsu b7f7c8bd3c chore(misc): update docs version script (#35313)
Add support for `--redirect-to-prod` flag for 16, 17, 18 which we do not
have versioned docs for. Also update README.md with more details on how
Netlify and Squarespace are used to support versions docs.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2026-04-17 11:49:16 -04:00
Jack Hsu 52c3626b67 cleanup(nx-dev): pare nx-dev down to /ai-chat, /api, /courses only (#35315)
## Current Behavior

`nx-dev` is a monolithic Next.js app still serving blog, docs,
changelog, pricing, podcast, resources-library, whitepaper pages, etc. —
all of which now live in `astro-docs` (docs), `nx-blog` (blog), or have
been deprecated. The top-level `docs/` folder (~333MB) duplicates
content already in astro-docs, and 20+ `nx-dev/*` UI/feature libraries
are maintained despite only a handful being reachable from a live route.

## Expected Behavior

`nx-dev` only serves:

- `/ai-chat` — the AI chat UI
- `/api/query-ai-handler` — streaming chat endpoint
- `/api/query-ai-embeddings` — doc-search endpoint used by the Nx MCP
doc search tool
- `/courses` — video courses landing + detail + lesson pages (moved into
nx-dev from `docs/courses`)

### Changes

- Deleted routes: `/blog`, `/podcast`, `/pricing`, `/changelog`,
`/resources-library`, `/whitepaper-fast-ci`, `/500`, `/brands`, and
every other page that previously rendered here.
- Deleted `nx-dev/*` libraries not reachable from the surviving routes:
`feature-feedback`, `ui-podcast`, `ui-pricing`, `ui-resources` (plus a
handful of now-unused transitive helpers).
- Moved `docs/courses/` → `nx-dev/nx-dev/courses-content/` so the
top-level `docs/` folder could be deleted. Updated `CoursesApi` to
accept a configurable `authorsPath`.
- Deleted the entire top-level `docs/` folder (~333MB of stale content).
- Removed consumers of `docs/`:
- Removed `blog-description` and `blog-cover-image` conformance rules +
their registrations in `nx.json`.
- Removed
`scripts/documentation/{map-link-checker,internal-link-checker,prebuild-banner}.ts`.
  - Removed `check-documentation-map` npm script.
- Removed `validateCrossSiteLinks` from `astro-docs/validate-links.ts`.
- `tools/documentation/create-embeddings` no longer includes
`docs/*.json` in its tsconfig; default `--mode` is now `astro`.
- Simplified `feature-ai`: dropped `feature-analytics`, `ui-common`, and
`ui-markdoc` deps. AI markdown rendering now uses a minimal inline
renderer on top of `@markdoc/markdoc` core.
- Simplified `_app.tsx`, `_document.tsx`, and `app/layout.tsx`: no more
`bannerCollection`, `GlobalSearchHandler`, `FrontendObservability`, or
GTM scripts.
- `/ai-chat` uses an inline minimal header instead of the full marketing
Header.

### Verification

- `pnpm nx build nx-dev`  — emits all four routes above (`Route (app)`
for `/courses/*`; `Route (pages)` for `/ai-chat`, `/api/query-ai-*`).
- `/_redirects` still copied into `.next/` for Netlify.
- `/docs/*`, `/llms.txt`, `/llms-full.txt` rewrites to astro-docs
preserved.

## Related Issue(s)

Fixes DOC-478

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2026-04-17 11:48:26 -04:00
Jason Jean b1717a687d fix(core): await queued processTask promises before cache.getBatch (#35322)
## Current Behavior

Nx Cloud agents crash on warm-cache runs with:

```
Error: Failed to convert JavaScript value `Null` into rust type `String`
    at DbCache.getBatch (.../cache.js:115:41)
    at TaskOrchestrator.fetchCacheHits (.../task-orchestrator.js:270:47)
    at TaskOrchestrator.resolveCachedTasks (.../task-orchestrator.js:564:38)
    at runDiscreteTasks (.../init-tasks-runner.js:133:42)
  code: 'StringExpected'
```

Regression introduced by #35172 (warm-cache perf optimization). Cloud
agents call `runDiscreteTasks` with `task.hash = null` (they
intentionally null hashes — see `ocean/.../execute-tasks-v3.ts`).
`init-tasks-runner.ts::createOrchestrator` queues `processTask` promises
via fire-and-forget `processAllScheduledTasks()`, but `runDiscreteTasks`
immediately calls `resolveCachedTasks` which doesn't await them.
`cache.getBatch(tasks.map(t => t.hash))` then receives nulls and the
napi binding rejects them.

## Expected Behavior

`resolveCachedTasks` awaits the queued `processTask` promises (which set
`task.hash` via `hashTask`) before passing hashes into `cache.getBatch`.

The single-task `runTaskDirectly` path already awaits
`this.processedTasks.get(task.id)` for the same reason — this fix
mirrors that pattern in the bulk path.

Bonus: a second tiny commit changes coordinator step 1's pre-hash guard
from `unhashed.length > 1` to `> 0`. The `> 1` micro-optimization
silently skipped cache lookup for single-task cycles, because
`resolveCachedTasksBulk` filters candidates by `task.hash &&` — a
length-1 unhashed task got dropped and ran without a cache check. Cost
more in lost cache hits than it saved in batch setup.

## Related Issue(s)

Surfaced internally; no GitHub issue.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-17 11:48:16 -04:00
Jason Jean 30bdd1c6f3 fix(repo): switch agent apt mirror to azure to avoid canonical sync races (#35324)
## Current Behavior

CI agents launched by `.nx/workflows/agents.yaml` are failing during the
`Install system deps` step on a majority of agents:

```
E: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/jammy-updates/main/binary-amd64/Packages.gz
File has unexpected size (4263778 != 4263737). Mirror sync in progress? [IP: 91.189.92.22 80]
```

`archive.ubuntu.com` is serving a `Packages.gz` whose size/hash doesn't
match its own `InRelease` metadata while the canonical mirror is
mid-sync. Apt detects the mismatch and refuses to use the index. Without
that index, `apt-get install` fails to find packages and the agent dies
before any task runs. Every agent hits the same mirror, so every agent
fails simultaneously — taking down distributed CI runs.

This is currently affecting both PR CI and master CI on staging
(confirmed via `gh run` and Nx Cloud CIPE status).

## Expected Behavior

`apt-get update` succeeds reliably on agent provisioning, regardless of
canonical-mirror sync races.

Switch the agent's apt sources from `archive.ubuntu.com` /
`security.ubuntu.com` to `azure.archive.ubuntu.com` via a one-line `sed`
on `/etc/apt/sources.list`. Azure's mirror is what GitHub Actions
runners use by default — historically much more stable than canonical
for the "many concurrent CI agents hammering one mirror" workload that
triggers the sync race.

## Related Issue(s)

No GitHub issue — surfaced today via the linked CI failures.
2026-04-17 14:08:37 +00:00
Ben Snyder 576fb82d8e fix(core): support pnpm multi-document lockfiles (#35271)
## Current Behavior

Before this change, `nx/js/dependencies-and-lockfile` assumed
`pnpm-lock.yaml` contained a single YAML document.

When `pnpm-workspace.yaml` enables `managePackageManagerVersions: true`,
pnpm 11 writes a package-manager metadata document before the workspace
lock document. Nx then fails while building the project graph with:

```text
An error occurred while processing files for the nx/js/dependencies-and-lockfile plugin.
- pnpm-lock.yaml: expected a single document in the stream, but found more
```

## Expected Behavior

After this change, Nx reads multi-document pnpm lockfiles, selects the
workspace lockfile document, and continues parsing dependencies
normally.

This allows monorepos to keep pnpm 11 package-manager metadata enabled
while still running Nx commands such as `bun x nx sync` without
disabling `managePackageManagerVersions`.

## Related Issue(s)

Fixes Issue https://github.com/nrwl/nx/issues/35270

## Validation

- `pnpm exec jest
packages/nx/src/plugins/js/lock-file/pnpm-parser.spec.ts --config
packages/nx/jest.config.cts --runInBand`
- Verified `getPnpmLockfileNodes` against the repository multi-document
`pnpm-lock.yaml` via direct source invocation

---------

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2026-04-17 14:49:28 +02:00
Caleb Ukle e39c3df758 fix(core): allow controlling migrate fallback installation concurrency (#35312)
- fix(core): allow controlling migration dep install concurrency

there are cases where parallel installs of a migration dependencies can
cause concurrent writes to package managers cache which can cause fs
errors of files overwriting each others peer deps. this most often
occurs when a migration for a 3rd party plugin is hosted in a private
registry that doesn't support custom metadata e.g. GH npm registry.

This is now controllable via the `NX_MIGRATE_INSTALL_CONCURRENCY` env
var. if it's not set then the default behavior of running all installs
in parallel still occurs

- docs(core): add `NX_MIGRATE_INSTALL_CONCURRENCY` env var info
2026-04-17 08:10:12 +02:00
Jay Bell 4d15754626 feat(core): add page up/down to tui shortcuts (#34525)
Co-authored-by: Craigory Coppola <craigorycoppola@gmail.com>
2026-04-16 21:00:40 -04:00
Jason Jean c8b59c9d24 fix(repo): resolve FreeBSD build OOM and disk exhaustion (#35309)
## Current Behavior

The FreeBSD native build in the publish workflow fails with "filesystem
full" or OOM. Two issues:

1. **Jest plugin OOM**: PR #35231 changed `createNodes` to load all jest
configs upfront in a sequential `for` loop before hash computation. Each
`loadConfigFile` registers a ts-node transpiler via `registerTsProject`
(`packages/nx/src/plugins/js/utils/register.js`), whose dedup is
refcounted. Serial register/unregister cycles drive refCount to 0
between iterations and delete the Map entry — but ts-node's
`transpilerCleanup` is a no-op, so the service stays alive in
`require.extensions`. The next iteration creates a fresh ts-node
service. Across 96 TS jest configs under `NX_PREFER_TS_NODE=true` (set
for the FreeBSD build), 96 ts-node services stack and OOM at V8's ~2GB
heap limit.

2. **Core dump fills disk**: When the jest plugin OOMs, FreeBSD writes a
2.3GB `node.core` file to the workspace root, filling the remaining 4GB
of free disk space before cargo can run.

### Failing runs

- [beta.13 publish (Apr
15)](https://github.com/nrwl/nx/actions/runs/24480325293/job/71547815608)
— `filesystem full` during project graph, cargo never ran
- [Canary after beta.12 (Apr
10)](https://github.com/nrwl/nx/actions/runs/24260184601/job/70841801347)
— jest plugin OOM at 2GB heap, `node.core` filled disk
- [Diagnostics
run](https://github.com/nrwl/nx/actions/runs/24490680528/job/71574929552)
— confirmed 2.3GB `node.core` file in workspace root

### Passing run (with pnpm patch)

- [Fix validation run (Apr
16)](https://github.com/nrwl/nx/actions/runs/24508325992/job/71632565433)
— jest plugin no longer OOMs, cargo compiles successfully (validated an
earlier lazy-load form of the patch; the current form uses parallel load
but is equivalent for FreeBSD's resource envelope)

## Expected Behavior

The FreeBSD build completes successfully. The jest plugin loads configs
in parallel so the ts-node transpiler dedup holds across all
registrations and only one service is created.

### Changes

**Jest plugin memory fix** (`packages/jest/src/plugins/plugin.ts`):
- Convert the upfront config-loading `for` loop to
`Promise.all(validConfigFiles.map(async ...))`. Keeps all
`registerTsProject` registrations alive concurrently so refCount goes
`0→1→2→…→N→N-1→…→0` and only one ts-node service is ever created.
- Preserves #35231's hash correctness: preset path and tsconfig extends
chain remain inputs to `calculateHashesForCreateNodes`; `needsDtsInputs`
is still derived from the real jest config + ts-jest transform
inspection.

**pnpm patch** (`patches/@nx__jest@22.7.0-beta.12.patch`):
- Same fix applied to the installed `@nx/jest@22.7.0-beta.12` so the
FreeBSD build (which uses the published package, not source) gets the
fix immediately. Generated via `pnpm patch` from the built source output
— installed `plugin.js` is byte-identical to
`dist/packages/jest/src/plugins/plugin.js`.

**Workflow hardening** (`.github/workflows/publish.yml`):
- `ulimit -c 0` to disable core dumps (prevents 2.3GB files from filling
disk)
- `NODE_OPTIONS='--max-old-space-size=4096'` as a safety net
- Disk usage diagnostics on build failure for future debugging

### Local verification

Cold cache (`npx nx reset` before each run), `NX_PREFER_TS_NODE=true
NX_CACHE_PROJECT_GRAPH=false NX_DAEMON=false`, 96 TS jest configs:

- **Pre-fix (serial for-loop)**: per-iteration heap grows `40 → 60 → 160
→ 756 MB` at iter 1/10/20/30, then OOM at iter ~33 with
`--max-old-space-size=4096`.
- **Post-fix (parallel)**: heap flat at **272 MB from load 1 through
96**. `require.cache` constant at 599 entries. No accumulation.
- Real `nx show projects` end-to-end: 600 MB RSS, 5 s.

### Follow-up (separate PR)

`packages/nx/src/plugins/js/utils/register.js` has a latent leak: when
the transpiler has no real cleanup (ts-node always, swc sometimes),
`registered.delete(registrationKey)` on refCount==0 allows the next
registration with the same key to stack a fresh service. Any Nx plugin
that loads configs serially hits this. Worth gating `registered.delete`
on whether the transpiler is actually disposable, analogous to the
existing `isTsEsmLoaderRegistered` flag. Not in scope for this PR.

## Related Issue(s)

Fixes the FreeBSD build failure in the publish workflow.

---------

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2026-04-16 21:55:42 +00:00
Caleb Ukle 8d5bed18dc docs(nx-cloud): clarify dind launch template image support (#35316)
remove dind images that are not in the allow list and add aside to
mention dind is enterprise only feature atm
2026-04-16 17:49:17 -04:00
Leosvel Pérez Espinosa ea73cf4df8 chore(repo): add diagnose-sandbox-report skill (#35269)
## Current Behavior

No skill for investigating Nx sandbox violations.

## Expected Behavior

The `diagnose-sandbox-report` skill provides a structured workflow for
diagnosing sandbox violations, with a TypeScript script that automates
report parsing, Nx context gathering, violation validation, and file
classification.
2026-04-16 08:12:21 +02:00
Jason Jean fd0535953d fix(core): optimize warm cache performance for task execution (#35172)
## Current Behavior

Running cached tasks in a large workspace takes much longer than the
work actually warrants. The task orchestrator hashes, cache-checks,
schedules, and reports each task individually:

- Per-task JS→Rust→SQLite cache lookups (~N boundary crossings).
- Per-task daemon IPC calls for recording/matching output hashes (~2N
sequential round-trips).
- Per-task filesystem scans for output expansion.
- `TasksSchedule` re-sorts the full schedule array on every insert
(O(n²·log n)).
- The coordinator awaits each worker one at a time via a single-task
dispatch path.

On a 1,110-project benchmark workspace, this accumulates into
multi-second overhead even when every task is a cache hit with nothing
to do.

## Expected Behavior

Warm cache runs should resolve quickly. Every hot-path operation that
can be batched — cache lookups, daemon calls, scheduling, output-hash
tracking, filesystem scans — is batched, and the coordinator dispatches
discrete workers in parallel rather than sequentially.

### Rust native

- **`NxCache.get_batch`** (`cache.rs`) — single `UPDATE … WHERE hash IN
(…) RETURNING` with Rayon-parallel terminal-output reads replaces N
individual round-trips. Uses `rarray` for the `IN` clause, groups the
query / build stages as separate helpers, and collects rows straight
into a `HashMap`.
- **`get_files_for_outputs_batch`** — Rayon-parallel filesystem scanning
for cached-output expansion. Drop the old singular
`get_files_for_outputs` napi export now that every caller goes through
the batch path.

### Daemon output tracking

- Replace the non-batch `recordOutputsHash` / `outputsHashesMatch` chain
(client → server handlers → outputs-tracking helpers) with `*Batch`
equivalents. The single-entry path was dead after the orchestrator
routed everything through the batch methods.
- Short-circuit `outputsHashesMatchBatch` when the daemon has no
recorded hashes — avoids an unnecessary Rayon filesystem scan right
after `nx reset`.
- Skip recording for `local-cache-kept-existing`: the daemon already has
the right hash.

### Task orchestrator

- **Coordinator loop** rewrite: bulk-resolve all cache hits up-front,
batch-hash remaining unhashed tasks before any per-task lifecycle fires,
then dispatch cache-miss workers concurrently up to `parallelism`.
Tracks in-flight workers as a `Set<Promise<void>>` instead of a counter,
and the dispatch is extracted to `dispatchDiscreteWorker` +
`handleDiscreteWorkerFailure` instead of an inline fire-and-forget IIFE.
- **Split cache check from task execution**: `resolveCachedTasksBulk`
reports hits/misses without touching the execution path, so the
coordinator can batch lifecycle calls for the hit set and only dispatch
workers for misses.
- **Route `applyCachedResults` through `DbCache.getBatch`** — one daemon
call per cycle instead of one per task.
- **Group slots**: `closeGroup` can overflow without throwing when all
slots are claimed (parallelism gating is enforced elsewhere), and every
task keeps a single `groupId` through `runDiscreteTasks`.
- **Drop the dead single-entry fallback paths** in the orchestrator
(`shouldCopyOutputsFromCache`, `recordOutputsHash`, and the `processTask
will hash individually` try/catch around `hashTasks`).
- **`getExecutorForTask` takes a `projects` record directly** instead of
re-deriving it from the project graph per call via a module-level
`WeakMap`. Callers compute the record once.

### Task scheduler

- **Parallelism gating + sort stability** — batch scheduling collects
all schedulable roots, pushes them in one pass, and sorts the array once
per cycle instead of after every insert.

### Repo / infra

- `benchmarks/package.json`: run benches through `pnpm exec nx` so
hyperfine sub-shells always hit the workspace-local CLI.
- `fix(core): honor NX_NO_CLOUD / neverConnectToCloud in runner
selection` (`run-command.ts`) — surfaced while unblocking the benchmark
CI: with an ambient `NX_CLOUD_AUTH_TOKEN` on the CI agent,
`getTasksRunnerPath` still routed through the cloud shell even when
`NX_NO_CLOUD=true` was set. The cloud client's light-client require
bridge then loaded the default tasks runner from the parent workspace's
`node_modules/nx` (a published version), creating a cross-version API
mismatch. The guard now short-circuits runner selection to the default
path when cloud is explicitly opted out of.
- Test updates for the new `TasksSchedule(projectGraph, projects,
taskGraph, options)` signature.

## Benchmark Results

Measured locally against the `benchmarks/` workspace (1,110 projects)
with the `bench:*` scripts. Baseline is committed in
`benchmarks/baseline.json`.

| Benchmark | Goal | Baseline | Current | vs Goal | vs Baseline |
  |---|---|---|---|---|---|
  | version | 50ms | 348ms | 333ms | +566% | -4% |
  | show-projects | 100ms | 710ms | 647ms | +547% | -9% |
  | cat-warm | 300ms | 2.44s | 1.17s | +290% | -52% |
  | copy-warm | 1.00s | 6.85s | 1.35s | +35% | -80% |
  | build-warm | 5.00s | 17.75s | 1.44s | -71% | -92% |

## Related Issue(s)

Fixes #31067

No specific issue — performance-focused, driven by benchmark wall time
on large workspaces.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-04-15 17:50:28 -04:00
jase b6e0775633 feat(core): add NX_BAIL environment variable (#34711) 2026-04-15 17:49:14 -04:00
Leosvel Pérez Espinosa 878ec01117 fix(vitest): infer ancestor tsconfig files as test task inputs (#35241)
## Current Behavior

Vite <8 uses esbuild to bundle config files (`vitest.config.mts`).
esbuild walks up from the entry point and reads every `tsconfig.json` in
ancestor directories plus their `extends` chains. These files are not
declared as task inputs, so changes to them don't invalidate the test
cache.

Sandbox violation:
https://staging.nx.app/runs/B5EjkJA6p1/task/angular-rspack-compiler%3Atest?batchId=7f8749c3-4e9a-4a93-b8f4-56efa69f14ab

## Expected Behavior

The `@nx/vite` and `@nx/vitest` plugins walk ancestor directories and
`extends` chains, declaring discovered tsconfig files as selective JSON
inputs that only hash `compilerOptions`. This avoids cache invalidation
from irrelevant tsconfig changes (`include`, `exclude`, `references`,
etc.) while correctly invalidating when compilation-affecting settings
change.

Files already covered elsewhere are excluded:
- Inside the project root (covered by `default`)
- The root tsconfig handled by the native `TsConfiguration` hasher
- Inside `node_modules` (invalidated via lockfile)
- Outside the workspace
2026-04-15 17:48:08 -04:00
Jouke Visser 5686a9e83f chore(core): nx plugin submission @frontenderz/backstage-insights (#32817) 2026-04-15 17:29:01 -04:00
Leosvel Pérez Espinosa bdb53abf25 fix(angular): fall back to addUndefinedDefaults when addUndefinedObjectDefaults is unavailable (#35290) 2026-04-15 17:02:32 -04:00
Jack Hsu eaa7461ae9 chore(misc): add versioned docs snapshot script (#35264)
## Current Behavior

No automated way to create static snapshots of the docs site for
versioned branches (e.g., v22.nx.dev). The existing `release-docs.ts`
force-pushes the full source branch, requiring Netlify to build from
source.

## Expected Behavior

`node ./scripts/create-versioned-docs.mts v22` creates a deployable
orphan branch with the pre-built static site:

- Fetches latest stable git tag for the major version (e.g., `22.6.4`)
- Builds `astro-docs` (v21+) or `nx-dev` with static export (v18-v20)
- Creates orphan branch with pre-built files at `nx-dev/nx-dev/.next/`
- Includes `netlify.toml` that skips `@netlify/plugin-nextjs` for pure
static serving
- Resolves `GITHUB_TOKEN` from 1Password or env var
- Server-side redirects for `/docs` → `/docs/getting-started/intro`
- `--force` flag to overwrite existing branches

Deployed via Netlify branch deploys at `v{major}.nx.dev`.

### Usage

```bash
node ./scripts/create-versioned-docs.mts v22
node ./scripts/create-versioned-docs.mts v21 --force
git push -f origin v22
```

### Tested

- v21 https://v21.nx.dev/docs
- v20 https://v20.nx.dev/docs
- v19 https://v19.nx.dev/docs 

## Related Issue(s)

Fixes DOC-69
2026-04-15 16:39:27 -04:00
Leosvel Pérez Espinosa 0e101c77ef fix(core): don't hang when workspace contains a named pipe (#35289) 2026-04-15 16:16:04 -04:00
Leosvel Pérez Espinosa 45fc97871f fix(js): resolve project tsconfig for inferred tsc run-commands targets in dependency-checks (#35291) 2026-04-15 16:15:36 -04:00
Miroslav Jonaš c05e6e85c7 feat(core): update nx-set-shas usage to v5 (#34934)
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-15 16:11:44 -04:00
Jack Hsu cc3901318b fix(angular): preserve specific file paths in tsconfig when adding secondary entry point (#35254)
## Current Behavior
The secondary entry point generator rewrites all tsconfig
include/exclude entries by stripping the `src/` prefix (e.g.
`src/**/*.ts` → `**/*.ts`). This also strips `src/` from literal file
paths like `src/test-setup.ts`, breaking the exclude rule since the file
still lives at that path.

## Expected Behavior
The generator should add new include/exclude entries scoped to the
secondary entry point directory instead of mutating existing entries.
This is additive — existing entries are left untouched and new
`<name>/src/**/*.ts` patterns are appended for the secondary entry
point.

## Related Issue(s)
Fixes #33051
2026-04-15 15:48:13 -04:00
Miroslav Jonaš 075b627763 docs(nx-cloud): improve the misleading neverConnectToCloud messaging (#35182)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

---------

Co-authored-by: Caleb Ukle <caleb@nrwl.io>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: meeroslav <meeroslav@users.noreply.github.com>
2026-04-15 15:23:38 -04:00
Craigory Coppola 94db4aa6b9 feat(devkit): batch tmp installs in ensurePackage
Add an `ensurePackage(Record<string, string>)` overload that resolves
every missing package in a single tmp project instead of provisioning a
fresh one per call. Exposes `installPackagesToTmp` / `installPackagesToTmpAsync`
from `nx` core for feature-detection, with a graceful fallback to
sequential single-package installs on older cores.

Refactor generators that sequentially install distinct Nx plugins in the
same run (js/library, react/application, react/library, remix/application,
web/application, vue/library add-vite, vue/application add-e2e,
react/application add-e2e, react/application add-vite/setupVitest,
expo/application add-e2e, next/cypress-component-configuration,
nuxt/application add-vitest) to collect their plugin set up front and
ensure it once.
2026-04-15 13:46:37 -04:00
Leosvel Pérez Espinosa 1e7b29ca38 fix(js): avoid full source scan in readTsConfigPaths (#35300)
## Current Behavior

In large monorepos where the root tsconfig lacks `files`/`include`,
`@nx/next:server` (and other executors that rely on
`readTsConfigPaths()` via `withNx`) can hang for minutes and fail with
`ECONNREFUSED` as the Next.js server never gets a chance to start.

## Expected Behavior

`readTsConfigPaths()` returns the configured path mappings quickly
regardless of workspace size, so the Next.js dev server starts normally.

## Technical Details

`readTsConfigPaths()` only needs `compilerOptions.paths`, but
TypeScript's default `ParseConfigHost` enumerates every `.ts` file under
the tsconfig directory when `files`/`include` are absent. Stubbing
`readDirectory` on the host skips the source-file scan while preserving
`extends` resolution.
2026-04-15 15:51:57 +02:00
Leosvel Pérez Espinosa f0a710dda4 fix(core): cap TUI parallel slots by total task count (#35299) 2026-04-15 09:46:10 -04:00
Sai Asish Y cf9c96afcb fix(node): split package-manager exec command for VS Code launch.json (#35295)
## Current Behavior

When generating a `@nx/node:application` from a pnpm workspace, the
generated `launch.json` sets `runtimeExecutable` to the full
`getPackageManagerCommand().exec` string (e.g. `"pnpm exec"`). On
Windows, VS Code rejects this:

```
Can't find Node.js binary "pnpm exec": path does not exist.
Make sure Node.js is installed and in your PATH, or set the
"runtimeExecutable" in your launch.json.
```

The same issue affects npm (`npm exec --`) and yarn (`yarn exec`).

## Expected Behavior

`runtimeExecutable` should be a real binary path (`pnpm`, `npm`,
`yarn`), and the `exec` / `exec --` tokens should live in `runtimeArgs`.

## Fix

Split `getPackageManagerCommand().exec` on whitespace, feed the first
token into `runtimeExecutable`, and prepend the remaining tokens to
`runtimeArgs`. Bun (`bunx`) is unaffected because it has no space.

## Related Issue(s)

Fixes #35276
2026-04-15 11:26:15 +02:00
dan-winters b26087b18e fix(angular-rspack): fixes issues with angular-rspack hmr (#35294)
HMR is freezing on compilation failures but should support recompilation
when updating files after a previous compilation error


## Current Behavior
When running dev server with HMR, compilation errors are freezing the
dev server


## Expected Behavior
HMR should not abort or freeze and should allow recompilation when
saving updated files.

Fixes #35040
2026-04-15 11:25:37 +02:00
Leosvel Pérez Espinosa 04d7df3cc6 fix(testing): declare external tsconfig files as playwright e2e task inputs (#35287)
## Current Behavior

Playwright reads tsconfig files that aren't declared as task inputs:

- The config loader walks the project tsconfig `extends` chain at
compile time.
- The Playwright worker reads the workspace root `tsconfig.json` at
runtime via `isUsingTsSolutionSetup` (called by `nxE2EPreset`).

When any of these files live outside the project root, sandboxed runs
report violations and cached tasks can become stale when those files
change.

## Expected Behavior

The `@nx/playwright` plugin walks the project tsconfig `extends` chain
and also declares the workspace root `tsconfig.json` (when present and
not already handled by the native `TsConfiguration` hasher), exposing
them as selective JSON filesets that hash only `compilerOptions`,
`extends`, `files`, and `include`. This invalidates the cache for
compilation-affecting changes while staying stable when unrelated fields
(e.g. `references`) churn.

Files already covered elsewhere are excluded:
- Inside the project root — covered by `default`
- The native `TsConfiguration` hasher file (`tsconfig.base.json` when it
exists, otherwise `tsconfig.json`)
- Inside `node_modules` — invalidated via the lockfile
- Outside the workspace
2026-04-14 22:24:33 -04:00
Miroslav Jonaš 5ddd24f95e docs(misc): revert conformance doc changes from nx-cloud to nx rename (#35147)
Conformance commands should remain as `nx-cloud conformance` not `nx
conformance`.

<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 18:17:47 +00:00
Nelson Dominguez dcd61cd123 fix(release): surface swallowed publish errors when stdout is not valid JSON (#35283)
## Current Behavior
<!-- This is the behavior we have today -->
When `npm publish` or `pnpm publish` fails, the executor assumes
`err.stdout` (always) contains valid JSON. If a lifecycle script (e.g.
`prepublishOnly`) fails, it writes plaintext to stdout instead. This
causes `JSON.parse` to throw and the actual error to be swallowed by the
outer catch, printing only a generic "something unexpected went wrong"
message.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
Wrap `JSON.parse(err.stdout...)` in a try/catch block. If parsing fails,
fall back to logging raw stderr/stdout directly and return early, so
lifecycle script failures and other non-JSON errors are always visible
to the user.

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

Fixes #34497
2026-04-14 15:07:35 +02:00
Tomas Ptacek b0349877c1 fix(angular-rspack): add fileReplacements to resolve.alias (#34197)
## Current Behavior

The `fileReplacements` option in `@nx/angular-rspack` is passed to the
Angular AOT compiler but not added to rspack's `resolve.alias`
configuration. This means file replacements only work during TypeScript
compilation, not during module resolution/bundling.

## Expected Behavior

File replacements should work consistently, replacing modules both
during compilation and bundling - matching the behavior of `@nx/rspack`.

## Related Issue(s)

https://github.com/nrwl/nx/issues/32647

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2026-04-14 12:11:54 +02:00
Craigory Coppola ff50d97cf3 fix(core): don't cache project graph errors on daemon (#35088)
## Current Behavior
Daemon graph errors are cached until a file change triggers
recomputation

## Expected Behavior
Avoid caching daemon errors, and refresh daemon env on request start

## AI Summary
This pull request introduces several important improvements to the Nx
daemon's client-server communication, focusing on standardizing message
types, improving environment variable handling, and cleaning up imports
and type usage. The main changes include the introduction of a unified
`DaemonMessage` type, a new mechanism for synchronizing environment
variables between client and daemon, and significant import and type
refactoring for clarity and maintainability.

**Key changes:**

### Message Type Standardization

- Introduced a new `DaemonMessage` type in `daemon-message.ts` to serve
as the standard for all messages exchanged between the Nx client and
daemon, replacing the previous generic `Message` type. This includes a
type guard function `isDaemonMessage` for runtime checks.
- Updated all relevant client and server methods, such as `sendMessage`,
`sendToDaemonViaQueue`, and `sendMessageToDaemon`, to use the new
`DaemonMessage` type, ensuring type safety and consistency throughout
the codebase.
[[1]](diffhunk://#diff-dbd790ee3e31e772f1c6d54bf0681b982d9eac6adacc3149463d28e60e11f59dL7-R9)
[[2]](diffhunk://#diff-dbd790ee3e31e772f1c6d54bf0681b982d9eac6adacc3149463d28e60e11f59dL26-R25)
[[3]](diffhunk://#diff-ac77bbed6ea29034032e92619972b1ad989e0accad1b05b5462a276707549da0L1053-R1062)
[[4]](diffhunk://#diff-ac77bbed6ea29034032e92619972b1ad989e0accad1b05b5462a276707549da0R1222-R1232)

### Environment Variable Synchronization

- Implemented a new mechanism to synchronize environment variables
between the client and daemon:
- Added a `getDaemonEnv` function to centralize the construction of the
environment object.
- Modified the client to send environment variables to the daemon with
the first message after startup, and the daemon to update its
`process.env` accordingly.
[[1]](diffhunk://#diff-ac77bbed6ea29034032e92619972b1ad989e0accad1b05b5462a276707549da0R1222-R1232)
[[2]](diffhunk://#diff-ac77bbed6ea29034032e92619972b1ad989e0accad1b05b5462a276707549da0L1323-R1343)
[[3]](diffhunk://#diff-0b91261b5503dc84fcf6ba119ee1c27ae7edff8cf9535a126a6a46439179f1fdR255-R260)

### Import and Type Refactoring

- Refactored imports in both client and server files to remove unused or
redundant imports, group related imports, and improve code organization
and readability.
[[1]](diffhunk://#diff-ac77bbed6ea29034032e92619972b1ad989e0accad1b05b5462a276707549da0R45-R52)
[[2]](diffhunk://#diff-ac77bbed6ea29034032e92619972b1ad989e0accad1b05b5462a276707549da0L86-L92)
[[3]](diffhunk://#diff-ac77bbed6ea29034032e92619972b1ad989e0accad1b05b5462a276707549da0L120-L123)
[[4]](diffhunk://#diff-d5bf3c66e62cac1884a071bf07fd1991320a3e62b07bfc03af3b9557b714c892R11-R17)
[[5]](diffhunk://#diff-d5bf3c66e62cac1884a071bf07fd1991320a3e62b07bfc03af3b9557b714c892R26-R29)
[[6]](diffhunk://#diff-d5bf3c66e62cac1884a071bf07fd1991320a3e62b07bfc03af3b9557b714c892L30-L43)
[[7]](diffhunk://#diff-0b91261b5503dc84fcf6ba119ee1c27ae7edff8cf9535a126a6a46439179f1fdL4-R135)
[[8]](diffhunk://#diff-0b91261b5503dc84fcf6ba119ee1c27ae7edff8cf9535a126a6a46439179f1fdR144-R148)
[[9]](diffhunk://#diff-0b91261b5503dc84fcf6ba119ee1c27ae7edff8cf9535a126a6a46439179f1fdR161-L173)

### Project Graph Error Handling

- Improved error handling in project graph recomputation by ensuring
that if errors are encountered, the cached project graph promise is
cleared, preventing stale or erroneous state from persisting.

These changes collectively make the daemon-client architecture more
robust, maintainable, and extensible, particularly as Nx evolves to
support more complex workflows and integrations.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-14 01:10:19 -04:00
Jason Jean b1b54e9244 fix(core): inline daemon status check, drop subprocess workaround (#35273)
## Current Behavior

`nx daemon` (status, no flags) calls `generateDaemonHelpOutput`, which
`spawnSync`s a helper Node process (`exec-is-server-available.js`) just
to bridge the async `daemonClient.isServerAvailable()` probe into a sync
caller. The only caller — `daemonHandler` in
`packages/nx/src/command-line/daemon/daemon.ts` — is already `async`, so
the sync workaround isn't needed.

That subprocess also has a bug. It is spawned with `cwd: __dirname`,
which points inside `packages/nx/dist/src/daemon/client`. When `nx` is
installed via a pnpm workspace symlink from a nested workspace (e.g. a
`benchmarks` project with `"nx": "workspace:*"`), the child's `cwd`
resolves through the symlink into the parent repo. The child's
workspace-root detection walks up from there and stops at the **outer**
`nx.json`, so the probe queries the wrong workspace's socket.

Reproducer:
```
cd benchmarks
nx daemon --start   # starts benchmarks daemon, succeeds
nx daemon           # reports "Nx Daemon is not running."
```
The daemon is running — the status command is just looking at the parent
repo's socket.

## Expected Behavior

`nx daemon` reports the status of the workspace it was invoked from,
regardless of how `nx` is installed, and without paying for a second
Node process.

This PR inlines the status check directly in `daemonHandler` via `await
daemonClient.isServerAvailable()` and deletes the two helper files
(`generate-help-output.ts`, `exec-is-server-available.ts`).

Behavioral equivalence: socket errors are already resolved to `false`
inside `isServerAvailable()`, so the "running"/"not running" outputs are
byte-identical. The one deliberate change is that `VersionMismatchError`
— which `isServerAvailable()` explicitly `reject`s — now surfaces to the
caller instead of being swallowed as "not running" by the old child's
try/catch.

## Related Issue(s)

N/A — surfaced while benchmarking against a nested workspace that
symlinks `nx` from the host repo.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-13 16:52:47 -04:00
Leosvel Pérez Espinosa 7d2745fd7a chore(core): update native d.ts for json input type changes (#35274)
## Current Behavior

The `index.d.ts` for native bindings had an outdated doc comment for
`inspectInputs` that didn't reflect the `JsonFileSet` resolution added
in #35248.

## Expected Behavior

The doc comment accurately describes `JsonFileSet` resolution behavior.
2026-04-13 16:48:41 -04:00
Craigory Coppola 339328ec3c chore(repo): fix inputs for nx:test-native (#35260)
## Current Behavior
Snapshots are not an input for test:native

## Expected Behavior
Snapshots are an input for test:native
2026-04-10 18:24:50 -04:00
Craigory Coppola 789a734f98 fix(core): replace exec() with spawn() to prevent maxBuffer crash on large command output (#35256)
## Current Behavior

The `run-commands` and `run-script` executors use Node.js
`child_process.exec()` to run shell commands. `exec()` internally
buffers **all** stdout/stderr into memory and compares the total against
a `maxBuffer` limit (set to ~1GB via `LARGE_BUFFER`). When a command
produces output exceeding this limit, Node.js kills the child process
and throws `ERR_CHILD_PROCESS_STDIO_MAXBUFFER`:

```
NX   stdout maxBuffer length exceeded
Pass --verbose to see the stacktrace.
```

This is the **default code path on CI**, because
`PseudoTerminal.isSupported()` checks `process.stdout.isTTY`, which is
`false` when stdout is piped (as it is on all CI runners). So while
local development typically uses the Rust PTY path (which streams output
with no buffer limit), every `run-commands` task on CI goes through the
`exec()` fallback.

The reason this hasn't been hit more often is that the 1GB
`LARGE_BUFFER` is large enough for most commands. But commands that
produce very large output quickly (e.g., deploying a site with thousands
of files) can exceed it.

## Expected Behavior

Commands that produce arbitrarily large output should complete
successfully without crashing Nx. Output should stream through data
events with no internal buffering limit.

This PR replaces `exec()` with `spawn()` + `{ shell: true }` in both the
`run-commands` and `run-script` executors. `spawn()` provides identical
shell-based command execution but uses streaming I/O — there is no
`maxBuffer` at all. Since both executors already consumed output via
stream event listeners (`stdout.on('data')`) rather than the `exec()`
callback, this is a safe swap with no behavioral change.

The PR also includes a test that directly demonstrates the issue: the
same command that crashes `exec()` with a maxBuffer error completes
successfully under `spawn()`.

## Related Issue(s)

N/A — encountered during a deploy task producing large stdout.
2026-04-10 16:55:54 -04:00
Jason Jean 77927e15f6 feat(core): add json input type for selective JSON field hashing (#35248)
## Current Behavior

When configuring task inputs for cache hashing, Nx hashes entire files.
For JSON config files like `tsconfig.json` or `package.json`, changing
any field invalidates the cache — even fields irrelevant to the task
(e.g., changing `description` in package.json invalidates a build task).

The only special case is tsconfig, which has hardcoded selective hashing
in the native hasher.

## Expected Behavior

A new `json` input type allows users and plugins to specify exactly
which fields from a JSON file should be included in the hash. This
enables more granular cache invalidation.

```jsonc
// Only hash the "engines" field from package.json
{ "json": "{projectRoot}/package.json", "fields": ["engines"] }

// Hash all of compilerOptions except paths
{ "json": "{workspaceRoot}/tsconfig.json", "fields": ["compilerOptions"], "excludeFields": ["compilerOptions.paths"] }
```

### Features
- **`{workspaceRoot}` and `{projectRoot}` tokens** — same syntax as
`fileset` inputs
- **Glob support** — e.g. `{projectRoot}/tsconfig*.json`
- **Dot notation** — nested field paths like `compilerOptions.target`
- **Allowlist (`fields`) and denylist (`excludeFields`)** — can be used
together
- **Deterministic hashing** — canonical JSON serialization with sorted
keys

### Files changed
- **TypeScript**: `InputDefinition` type + JSON schemas for IDE support
- **Rust NAPI bridge**: `JsonInput` struct, `Either8` → `Either9`,
`Input::Json` variant
- **Rust hash planning**: `HashInstruction::JsonFileSet`, planner emits
it from `gather_self_inputs`
- **Rust hasher**: new `hash_json.rs` with field filtering, canonical
serialization, and 10 unit tests

## Related Issue(s)

<!-- Link related issues here -->

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-10 16:55:34 -04:00
Caleb Ukle 686b523f32 docs(misc): add troubleshooting guide for Nx in Claude Code sandbox (#35255)
add a kb article explaining using nx w/ claude code sandboxes w/ the
recommended fix (`allowAllUnixSockets: true`) and alternative
workarounds with their tradeoffs.

added some cross-linking to this article so users can discover it in ai
specific pages


Fixes DOC-456

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
2026-04-10 15:18:53 -05:00
Leaf Rogers f9ceff0cc7 docs(core): fix minor typo (#35246)
Just a small typo fix 🎁
2026-04-10 16:14:24 -04:00
FUASHI LOT-BILL 536a30703a chore(core): update dotenv-expand to 12.0.3 (#35232) 2026-04-10 16:12:14 -04:00
Caleb Ukle 3629b377d1 fix(nx-dev): seo improvements for nx.dev/docs (#35244)
The nx.dev/docs site has several SEO issues a few minor a few larger
impacts.

Changes:

- **robots.txt** is served by Next.js with correct `Sitemap:
https://nx.dev/sitemap.xml` and explicit AI crawler policies
- **AI crawlers** (GPTBot, ClaudeBot, Google-Extended, PerplexityBot,
OAI-SearchBot) have explicit Allow rules
- **llms.txt** and **llms-full.txt** are served correctly
(Astro-generated, proxied via Next.js)
- **Sitemap index** has no duplicate entries 
- **Every docs page** has BreadcrumbList + TechArticle JSON-LD schema
markup
- **Logo images** are eager-loaded (`loading="eager"`), improving mobile
LCP
- **Docs sitemap** includes `lastmod` dates (build timestamp)
- **Security headers** (Referrer-Policy, Permissions-Policy) set on
Astro docs
- **Page title** expanded to 47 chars with key terms
- **Twitter card** meta tags explicitly set on all docs pages
- **CSS bundle** no longer scans unused @nx/nx-dev-ui-icons and
@nx/nx-dev-ui-animations packages

## Related Issue(s)

closes DOC-473

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:33:04 +00:00
Jack Hsu a53e6509b4 docs(misc): add back Cloud CNW CTA in the CI tutorial (#35257)
Add the CTA back as an option for users to quickly get a repo up and
running to try the CI tutorial.

Preview:
https://deploy-preview-35257--nx-docs.netlify.app/docs/getting-started/tutorials/self-healing-ci-tutorial
2026-04-10 15:24:01 -04:00
Caleb Ukle 9d50dc0c51 docs(release): add CLI reference links to Nx Release guides (#35245)
## Current Behavior

The Nx Release guide pages (`/docs/features/manage-releases` and
`/docs/guides/nx-release/*`) reference CLI commands like `nx release`,
`nx release version`, `nx release publish`, etc. but don't link to their
CLI reference pages. Developers configuring CI pipelines have to
navigate separately to find the full list of available flags and
options.

## Expected Behavior

Release guide pages now link to the relevant CLI reference pages
(`/docs/reference/nx-commands#nx-release-*`) so developers can quickly
look up available flags and options while reading the guides.

Changes across 8 files:

- **`features/manage-releases.mdoc`** — Added all 5 release subcommand
links to the "References" section
- **`publish-in-ci-cd.mdoc`** — Linked `nx release`, `nx release
publish`, `nx release version`, and `nx release changelog` where
subcommands are introduced
- **`file-based-versioning-version-plans.mdoc`** — Linked `nx release
plan` where the command is introduced
- **`release-projects-independently.mdoc`** — Linked `nx release` CLI
reference near the `--projects` flag discussion
- **`release-groups.mdoc`** — Linked `nx release` CLI reference in the
filters section
- **`release-docker-images.mdoc`** — Linked `nx release` CLI reference
near docker-specific flags
- **`programmatic-api.mdoc`** — Linked `nx release` CLI where the CLI is
mentioned as the counterpart to the programmatic API
- **`automatically-version-with-conventional-commits.mdoc`** — Linked
`nx release version` CLI reference for versioning options

## Related Issue(s)

<!-- Linear issue DOC-472: Add CLI reference links from Nx Release guide
-->


🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
2026-04-10 14:55:36 -04:00
Leosvel Pérez Espinosa 4d207509c9 chore(nx-dev): exclude .next from jest haste-map crawl (#35249)
## Current Behavior

The `nx-dev:test` task reads 124 `.js`/`.ts` files from the `.next/`
build output directory. These reads come from jest-haste-map's
filesystem crawl — it scans all files under the project root matching
`moduleFileExtensions` to build its module index and compute SHA-1
hashes, and `.next/` is not excluded.

## Expected Behavior

Jest should not scan the `.next/` build output directory during its
haste-map crawl, as these files are not needed for test discovery or
execution.

## Fix

Add `modulePathIgnorePatterns: ['<rootDir>/.next']` to the nx-dev jest
config. This tells jest-haste-map to skip the `.next/` directory
entirely during its initial filesystem crawl, eliminating all 124
unexpected file reads.
2026-04-10 14:52:06 -04:00
Jason Jean e6e2f4bfac fix(nextjs): align nx-dev build inputs and update plugin defaults (#35238)
## Current Behavior

- The Next.js plugin infers `default` instead of `production` for build
inputs, meaning test file changes invalidate the build cache
unnecessarily
- The Next.js plugin doesn't infer `.d.ts` dependent task output files,
causing sandbox violations when builds read type declarations from
dependencies
- nx-dev's `project.json` overrides inputs but is missing
`externalDependencies: [next]` and `.d.ts` dependent task outputs that
the plugin would normally provide
- nx-dev's `next:build` doesn't depend on `^build` or `^typecheck`, so
dependency type declarations aren't produced before the build
- `banner.json` (a generated file) was listed as a fileset input instead
of a dependent task output file
- `banner.json` was not excluded from eslint

## Expected Behavior

- Next.js plugin uses `production` for build inputs (matching Vite)
- Next.js plugin infers `dependentTasksOutputFiles: **/*.d.ts` for
builds
- nx-dev build has all necessary inputs and dependsOn to work correctly
with the sandbox
- Generated files are properly handled as dependent task outputs

## Related Issue(s)

N/A - discovered during sandbox violation investigation
2026-04-10 14:44:44 -04:00
Jack Hsu 44ba349fbf fix(js): suppress false swc-node/ts-node warning on Node 22.18+ (#35247)
On Node 22.18+ (which supports native TypeScript execution via type
stripping), Nx incorrectly warns "Unable to locate swc-node or ts-node.
Nx will be unable to run local ts files without transpiling." even
though Node can handle .ts files natively without any transpiler.

The warning should only appear on Node versions that cannot natively
execute TypeScript files. On Node 22.6+ (where
process.features.typescript is truthy), no warning should be emitted
when swc-node and ts-node are absent.

Fixes #32567

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2026-04-10 14:24:11 -04:00
Jason Jean c1cbdbbfaf chore(repo): update workspace-plugin dependencies (#35253)
<!-- 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
<!-- This is the behavior we have today -->

Somehow, these versions got out of sync

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

These versions are in sync with the package.json in the root

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-10 14:02:54 -04:00
Jack Hsu ef8da7bd26 fix(angular-rspack): normalize Windows path separators for i18n (#35252)
## Current Behavior
On Windows, `nx serve project --configuration=some-i18n-configuration`
fails with "cannot find project in graph.nodes" because
`posix.normalize()` does not convert backslashes to forward slashes.
Windows-style paths from `path.relative()` produce backslash-separated
strings that never match the forward-slash keys in the project root map.

## Expected Behavior
i18n configurations should resolve correctly on Windows. The path lookup
in `findProjectForPath` should succeed regardless of whether the input
path uses backslashes (Windows) or forward slashes (POSIX).

## Related Issue(s)
Fixes #32864

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2026-04-10 13:33:10 -04:00
Leosvel Pérez Espinosa 931f86c25a fix(vitest): add dependent task output files as inputs for vitest test targets (#35242)
## Current Behavior

Vitest test targets can resolve workspace dependency imports to build
artifacts (e.g., `dist/*.js`). These build outputs aren't declared as
task inputs, causing sandbox I/O violations (unexpected reads from
dependency `dist/` directories).

## Expected Behavior

The vite and vitest plugins include `dependentTasksOutputFiles` in the
inferred test target inputs. This declares dependency build outputs as
inputs when a test target depends on build tasks via `dependsOn`. The
input is a no-op when there are no build task dependencies. When
`typecheck.enabled` is configured, `.d.ts` files are also included since
`tsc --noEmit` reads type declarations from dependencies.

Also removes redundant explicit `inputs` overrides from `angular-rspack`
and `angular-rspack-compiler` test targets — the plugin-inferred
defaults are now more complete.
2026-04-10 12:30:19 -04:00
Jason Jean 23891a3d0a chore(repo): update nx to 22.7.0-beta.12 (#35250)
Updating Nx from 22.7.0-beta.11 to 22.7.0-beta.12
2026-04-10 16:08:56 +00:00
Jack Hsu a7f170c3aa docs(misc): review remote cache docs and fix powerpack redirect (#35240)
## Current Behavior

- `/powerpack` redirects to the `/enterprise` marketing page, which
doesn't help users who have an expired or missing activation key for
shared cache plugins (`@nx/s3-cache`, `@nx/gcs-cache`, etc.)
- The self-hosted caching guide lists available packages but requires
clicking through to individual reference pages to find install commands
and key setup instructions
- No short, stable URL exists for CLI error messages to link to

## Expected Behavior

- `/powerpack` redirects to the self-hosted caching guide
(`/docs/guides/tasks--caching/self-hosted-caching`), which is the right
landing page for cache plugin users
- `/powerpack/conformance` and `/powerpack/owners` redirect to their
respective enterprise docs pages
- A new `/remote-cache` short URL points to the self-hosted caching
guide for use in CLI error messages (e.g., the `nx-key` hardcoded link
in ocean)
- The self-hosted caching page includes a table with install commands
(`nx add @nx/...`), key setup instructions (`.nx/key/key.ini`, `NX_KEY`
env var, `nx register`), and a section pointing former Powerpack users
to conformance/owners enterprise docs

Preview:
https://deploy-preview-35240--nx-docs.netlify.app/docs/guides/tasks--caching/self-hosted-caching

## Related Issue(s)

Fixes DOC-477

**Follow-up:** The `nx-key` hardcoded link in the ocean repo
(`libs/nx-packages/nx-key/src/consts.rs` L1) should be updated to
`nx.dev/remote-cache` in a separate PR.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-10 11:06:35 -04:00
Leosvel Pérez Espinosa dc479c50a5 fix(js): stop generating baseUrl in tsconfig, use ./ prefix for path mappings (#34965)
## Current Behavior

Nx generators set `compilerOptions.baseUrl: "."` in generated tsconfig
files and write path mappings as bare relative paths (e.g.,
`my-lib/src/index.ts`). `baseUrl` is deprecated in TS 6 and removed in
TS 7.

## Expected Behavior

Nx no longer generates `baseUrl` in any tsconfig. Path mappings use `./`
prefix (e.g., `./my-lib/src/index.ts`), making them relative to the
tsconfig file without needing `baseUrl`. Existing user tsconfigs with
`baseUrl` continue to work correctly.

### Generator and template changes
- Remove `baseUrl` from all templates and generator code
- `addTsConfigPath` normalizes lookup paths with `./` prefix
- Move and remove generators handle `./`-prefixed paths correctly
- Angular secondary entry points and Remix server entry paths use `./`
prefix

### `resolvePathsBaseUrl` helper
New function (in `ts-config.ts`, duplicated in `register.ts`) that walks
the tsconfig `extends` chain to determine the correct directory for
resolving `paths` values. Finds where `paths` is defined, then looks for
the applicable `baseUrl` from that point toward the root — ignoring
child overrides that don't apply to the paths-defining tsconfig. When no
`baseUrl` applies, returns the directory of the tsconfig that defines
`paths`. All path resolver plugins and buildable-libs-utils use this
helper.

### Runtime and bundler fixes for baseUrl-less tsconfigs
- **Rollup**: resolve path mappings to absolute in compiler options
override using `resolvePathsBaseUrl`; use original tsconfig path (not
tmp) for resolution base
- **Module Federation**: add `workspaceRoot` to `resolve.modules` in all
8 MF plugin variants (Angular/React webpack, Angular/React rspack,
webpack SSR, rspack SSR, Angular rspack plugin, rspack plugin) so
workspace-relative expose paths resolve without `baseUrl`
- **Next.js/Jest**: null out SWC `resolvedBaseUrl` in generated jest
configs to prevent SWC from doing incorrect path alias resolution; Nx
jest resolver handles this via `resolvePathsBaseUrl`
- **register.ts**: use `resolvePathsBaseUrl` for correct path alias
registration
- **Path resolver plugins** (webpack, rspack, vite, expo, react-native,
jest, react component testing): use `resolvePathsBaseUrl` for correct
path resolution
- **buildable-libs-utils**: resolve tmp tsconfig paths to absolute so
they work without `baseUrl`
- **eslint-plugin**: handle `./`-prefixed paths in AST utils

## Related Issue(s)

Fixes #32958
2026-04-10 16:33:02 +02:00
Caleb Ukle a0621c8864 fix(nx-dev): improve search ranking for reference pages (#35243)
## Current Behavior

Searching for `nx.json` on nx.dev/docs does not surface the actual
nx.json reference page in the top results. The `.NET Plugin for Nx` and
other technology introduction pages rank higher because they have
`weight: 5` in frontmatter, which inflates their body text scoring via
Pagefind's `data-pagefind-weight` attribute (~25x impact via quadratic
scaling). The same issue affects `project.json`, `inputs`, and other
reference pages.

## Expected Behavior

Reference pages whose title exactly matches the search query should rank
first or near the top. Technology introduction pages should still be
discoverable for their framework name but should not outrank reference
pages for terms they merely mention in body text.

**After this change:**
- `nx.json` → "nx.json Reference" is `#1` (was `#7+`)
- `project.json` → "Project Configuration" is `#1`
- `angular` → "Angular Plugin for Nx" is `#1` (preserved)
- `nest` → "Nest.js Plugin for Nx" is `#1` (preserved)
- `react` → "React Plugin for Nx" is `#2` (React Native `#1` — valid
match)

**Changes:**
- Reduce `weight` on 35 technology introduction pages from `5` → `2` to
reduce body text inflation while keeping a modest boost
- Reduce `weight` on adding-to-monorepo guide from `6.4` → `2`
- Adjust Pagefind ranking params: `termFrequency: 0.75 → 0.65`,
`pageLength: 0.5 → 0.3` to reduce the penalty on long reference pages

## Related Issue(s)

Fixes DOC-475

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:18:17 -05:00
Jason Jean a884f55201 fix(linter): add missing inputs to eslint executor target defaults (#35236)
## Current Behavior

After the custom eslint hasher was removed in d64aeef5df, the
`@nx/eslint:lint` executor target defaults are missing `^default` and
`{workspaceRoot}/tools/eslint-rules/**/*` from their inputs. The old
custom hasher was compensating for this by manually handling dependency
hashing, but now that it's gone, the inputs need to be self-sufficient.

This means:
- Changes in dependencies don't invalidate the lint cache (problematic
for type-aware rules that inspect imported types)
- Changes to custom workspace eslint rules don't trigger re-linting

The inferred/plugin path (`plugin.ts`) already includes these inputs
correctly.

## Expected Behavior

The executor target defaults should include `^default` (dependency file
changes) and `{workspaceRoot}/tools/eslint-rules/**/*` (custom workspace
rules) to match what the eslint plugin already sets for inferred
targets.

## Related Issue(s)

Follows up on d64aeef5df (remove custom eslint hasher).

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-04-10 00:11:15 -04:00
Craigory Coppola c782489023 fix(core): exclude populate-local-registry-storage from sandbox I/O checks (#35239)
## Current Behavior

The `populate-local-registry-storage` target has massive I/O violations
in sandbox reports (~8k unexpected reads, ~7.6k unexpected writes)
because it runs `nx-release --local` which reads all build outputs and
writes version-bumped packages across the entire workspace.

## Expected Behavior

Exclude this target from sandbox I/O validation until it is reworked to
have more focused I/O boundaries. The task is doing too much in a single
step to have meaningful input/output declarations.

## Related Issue(s)

Sandbox violation report:
https://staging.nx.app/runs/ffYkwp6x9i/task/%40nx%2Fnx-source%3Apopulate-local-registry-storage/sandbox-report-raw?sandboxReportId=59a38b85-b0f4-40cc-a914-5383abe98adf&workspaceId=62d013ea0852fe0a2df74438
2026-04-09 18:25:56 -04:00
Miguel 0fb3d8c26e chore(core): skip connect to cloud prompt during migration if neverConnectToCloud is set (#33717) 2026-04-09 18:17:26 -04:00
Craigory Coppola ea644b3e49 feat(core): prompt for setup mode when running nx init in empty git directory (#35226)
## Current Behavior

When running `nx init` in an empty git directory (no `package.json`),
the V2 init handler silently defaults to the `.nx` installation method
without prompting the user. This may not be suitable for users who
intend to create a JavaScript/TypeScript project and would prefer a
`package.json`-based setup.

## Expected Behavior

When running `nx init` in an empty git directory, users are now prompted
to choose between two setup methods:

- **`.nx installation`** — recommended for non-JavaScript projects
(Gradle, .NET, etc.)
- **`package.json installation`** — recommended for
JavaScript/TypeScript projects

The prompt only appears when:
- No `package.json` exists in the directory
- The `--useDotNxInstallation` flag was not explicitly passed
- Running in interactive mode (not AI agent mode)

If the user chooses `package.json`, a minimal `package.json` is created
and the existing npm-repo setup flow takes over. If they choose `.nx`,
the existing dot-nx setup flow is used. In both cases, the workspace is
created in the current directory (not a subfolder).

## Related Issue(s)

Fixes NXC-3983
2026-04-09 17:29:54 -04:00
Craigory Coppola 7edc7b1c44 fix(core): overwrite inferred script target when nx prop defines executor or command (#35227)
## Current Behavior

When a `package.json` has both a script entry and an `nx.targets` entry
for the same target name, and the `nx.targets` entry uses command
shorthand (`command: "tsc"`) or an explicit executor, the two targets
are merged together. This produces an invalid hybrid target that has
both `executor: "nx:run-script"` (from the inferred script target) and
the `command` property (from the nx prop), causing the node to fail to
merge into the project graph.

## Expected Behavior

When the `nx.targets` entry specifies how to run (via `executor` or
`command`), it should completely overwrite the inferred script target
instead of merging with it. Targets without `executor` or `command`
(e.g., just adding `outputs` or `dependsOn`) should continue to merge as
before.

## Related Issue(s)

Fixes NXC-3923

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-09 17:28:16 -04:00
Jack Hsu 2a6ecc4437 fix(misc): bump axios to 1.15.0 for all packages (#35237)
Closes #NXC-4237
2026-04-09 19:48:25 +00:00
Craigory Coppola 069ed82686 fix(core): add run-native-target script input to dotnet build-analyzer (#35221)
## Current Behavior

The `dotnet:build-analyzer` target runs `node
./scripts/run-native-target.js _build-analyzer dotnet` but does not
include the `run-native-target.js` script itself in its `inputs` array.
This means changes to the script won't invalidate the Nx cache,
potentially leading to stale cached results.

## Expected Behavior

The `run-native-target.js` script is included as an input to the
`build-analyzer` target, ensuring cache correctness when the script
changes.

## Related Issue(s)

Fixes NXC-4219
2026-04-09 15:11:17 -04:00
Craigory Coppola 5878f36aea feat(core): add source map annotations to nx show target (#35225)
Large refactor for `nx show target` to increase clarity and fixup a few
issues.

## Custom Hashers

Notes when a custom hasher is used and inputs will not be considered.
See screenshots

<img width="646" height="107" alt="image"
src="https://github.com/user-attachments/assets/a6fecf17-a512-4956-964b-f04557567334"
/>

<img width="646" height="225" alt="image"
src="https://github.com/user-attachments/assets/0d4e0a85-2a8b-4bac-b0ff-4b6ea9e6b0dd"
/>

## Duplicated inputs
- Fixes issue where inputs could show up multiple times and appear
identical. In practice, this was from filesets that had specific
projects arrays that differed.

e.g. `nx show target populate-local-registry-storage` in latest shows

```
Inputs:
  - !{projectRoot}/**/*.stories.@(js|jsx|ts|tsx|mdx)
  - !{projectRoot}/**/*.stories.@(js|jsx|ts|tsx|mdx)
  - !{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)
  - !{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)
  - !{projectRoot}/.eslintrc.json
  - !{projectRoot}/.eslintrc.json
  - !{projectRoot}/.storybook/**/*
  - !{projectRoot}/.storybook/**/*
  - !{projectRoot}/jest.config.[jt]s
  - !{projectRoot}/jest.config.[jt]s
  - !{projectRoot}/src/test-setup.[jt]s
  - !{projectRoot}/src/test-setup.[jt]s
  - !{projectRoot}/tsconfig.spec.json
  - !{projectRoot}/tsconfig.spec.json
  - !{projectRoot}/tsconfig.storybook.json
  - !{projectRoot}/tsconfig.storybook.json
  - default
  - default
  - {projectRoot}/**/*.rs
  - {projectRoot}/**/Cargo.*
  - {workspaceRoot}/scripts/local-registry
  - {"runtime":"node -p '`${process.platform}_${process.arch}`'"}
  - {"runtime":"rustc --version"}
  - {"externalDependencies":["npm:@monodon/rust","npm:@napi-rs/cli"]}
```

After this PR it is
```
Inputs:
  - {projectRoot}/**/*.rs
  - {projectRoot}/**/Cargo.*
  - {workspaceRoot}/.cargo/config.toml
  - {workspaceRoot}/Cargo.lock
  - {workspaceRoot}/Cargo.toml
  - {workspaceRoot}/clippy.toml
  - {workspaceRoot}/scripts/local-registry
  - {"input":"production","projects":["tag:npm:public"]}
  - {"input":"production","projects":["tag:maven:dev.nx.maven"]}
  - {"runtime":"node -p '`${process.platform}_${process.arch}`'"}
  - {"runtime":"rustc --version"}
  - {"externalDependencies":["npm:@monodon/rust","npm:@napi-rs/cli"]}
Outputs:
  - {workspaceRoot}/dist/local-registry/storage
```

## Others

- When running with --verbose, data includes its source location. 
- Changes defaultConfiguration display to `(default)` badge after a
config if it is indeed default, instead of (default: ...) at the end of
the list

Fixes NXC-4077
Fixes NXC-4068
Fixes NXC-4200

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
2026-04-09 15:10:45 -04:00
Leosvel Pérez Espinosa 3ece32d6b9 fix(linter): infer extended tsconfig files as task inputs (#35190)
## Current Behavior

The `@nx/eslint` plugin does not infer extended tsconfig files as inputs
for the inferred lint target. Projects whose `tsconfig.json` extends a
file outside the project root (e.g. `../../tsconfig.base.json`) omit
that upstream file from the lint task's inputs. Tools that walk the
tsconfig chain during linting — the typescript-eslint parser in
type-aware mode, `@nx/enforce-module-boundaries`, Angular template
parsers, and similar — read these files, so sandboxing reports them as
undeclared reads and changes to upstream tsconfigs don't invalidate the
lint cache.

## Expected Behavior

The inferred lint target declares every tsconfig file reached via the
`extends` chain of the project's `tsconfig.json` as an input, when those
files live outside the project root. Files inside the project root are
already covered by `default` (`{projectRoot}/**/*`); shareable configs
resolved from `node_modules` are invalidated via the lockfile; paths
that escape the workspace cannot be declared as `{workspaceRoot}/...`
inputs.

A new lightweight `walkTsconfigExtendsChain` helper is introduced in
`@nx/js/src/internal` so other plugins that need to inspect a tsconfig
extends chain can reuse it. It reads tsconfigs as JSONC without loading
the `typescript` package, walks `extends` arrays in reverse precedence
(matching TypeScript semantics), and accepts a visitor that can
short-circuit for precedence-aware lookups or walk exhaustively for
input collection. The helper is cycle-safe and accepts a caller-supplied
JSON cache to dedupe reads across overlapping chains.
2026-04-09 15:02:36 -04:00
Leosvel Pérez Espinosa 169c1d4a79 fix(testing): add dependent .d.ts inputs for ts-jest without isolatedModules (#35231)
## Current Behavior

When ts-jest runs without `isolatedModules`, it creates a TypeScript
Language Service that reads `.d.ts` files from dependency projects.
Changes to those `.d.ts` files don't invalidate the test cache, leading
to stale test results.

## Expected Behavior

The jest plugin detects ts-jest usage without `isolatedModules` and adds
`dependentTasksOutputFiles: '**/*.d.ts'` as a transitive input. This
ensures dependency type declaration changes correctly invalidate the
test cache.

The plugin:
- Inspects jest config transforms (including presets) for ts-jest
- Walks the tsconfig `extends` chain to resolve the effective
`isolatedModules` value, reusing the lightweight walker from `@nx/js`
(intentionally avoids loading `typescript` for performance)
- Handles `verbatimModuleSyntax` as implying `isolatedModules`
- Respects ts-jest v29 vs v30 semantics for the deprecated
`isolatedModules` transform option
- Mirrors `ts.findConfigFile` upward walk (capped at workspace root)
when no explicit tsconfig is configured
- Tracks external file references (presets, tsconfigs outside project
root) for correct hash computation

## Additional Changes

- **Plugin hash correctness**: config loading moved before hash
computation so external file references (preset files, tsconfig extends
chains) are included in the hash. Previously, changes to files outside
the project root that the plugin reads during inference (e.g., a shared
jest preset or base tsconfig) would not invalidate the cached target
configuration. The lockfile is also now included as a hash input.
- **e2eInputs**: added `dependentTasksOutputFiles` to the `e2eInputs`
named input in `nx.json` since e2e target defaults override
plugin-inferred inputs.
- **Jest preset**: pre-resolve the `@swc-contrib/mut-cjs-exports` SWC
plugin to an absolute path. Tests that `chdir` into temp dirs would fail
SWC plugin resolution since the temp dir has no `node_modules`.
2026-04-09 15:02:00 -04:00
Juri Strumpflohner 5a7e851ce1 docs(nx-dev): blog post on sharing Tailwind styles in a monorepo (#35229)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: juristr <juristr@users.noreply.github.com>
2026-04-09 14:30:06 +00:00
Jack Hsu 1851fe884e fix(js): include npm overrides in generated lockfile (#35192)
## Current Behavior

When using `generateLockfile: true` (e.g. with `@nx/next:build`), the
generated `package-lock.json` is missing overridden packages for two
reasons:

1. `normalizePackageJson()` strips the `overrides` field, so the
generated lockfile lacks overrides both at the top level and in
`packages[""]`.

2. `findTarget()` uses semver satisfaction to match dependency edges,
but npm overrides can force versions outside the declared range (e.g.
`minimatch@^9.0.4` overridden to `10.2.1`). This causes overridden
packages and their transitive deps to be dropped from the pruned graph
entirely.

Running `npm ci` in the output directory fails:
```
npm error Missing: minimatch@10.2.1 from lock file
```

Note: yarn (`resolutions`) and pnpm (`pnpm.overrides`) were already
working correctly.

## Expected Behavior

The generated `package-lock.json` includes `overrides` and all
overridden packages. `npm ci` succeeds.

This is tested in the original issue repro repo, where with the applied
patch `npm ci` works from dist.

<img width="1272" height="362" alt="image"
src="https://github.com/user-attachments/assets/2cdbb266-71f8-45c8-8ee0-cec6dcd12705"
/>

The missing parts are both `overrides` in `package.json`, but also the
lockfile must include the pacakges in the overrides. In this example it
is like this in `package-lock.json`:

```
    "node_modules/minimatch": {
      "version": "10.2.1",
      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.1.tgz",
      "integrity": "sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A==",
      "license": "BlueOak-1.0.0",
      "dependencies": {
        "brace-expansion": "^5.0.2"
      },
      "engines": {
        "node": "20 || >=22"
      },
      "funding": {
        "url": "https://github.com/sponsors/isaacs"
      }
    },
```

## Related Issue(s)

Fixes #34529
2026-04-09 10:11:06 -04:00
Leosvel Pérez Espinosa d64aeef5df fix(linter): remove custom eslint hasher
The custom eslint hasher was an optimization from the Node.js hashing
era that stripped dependency file hashes for non-type-aware lint rules.
With the native Rust hasher this optimization is no longer needed.

Deprecate `hasTypeAwareRules` option (removal in v23).
2026-04-09 09:26:13 -04:00
Craigory Coppola fd0dff1078 fix(core): add missing build inputs for angular-rspack example projects
The example builds read dependent task outputs (devkit, angular-rspack,
angular-rspack-compiler dist JS files) and shared workspace files
(patch-devkit-request-path.js, tsconfig.base.json) that were not
declared as inputs, causing sandbox violations.
2026-04-09 09:23:42 -04:00
Craigory Coppola 3e373612ea fix(angular): add storybook and playwright as implicit dependencies (#35224)
## Current Behavior

The `angular:test` task sandboxing run shows unexpected file reads from
`@nx/storybook` and `@nx/playwright` packages — including `.template`
and `__tmpl__` generator files. These packages are loaded dynamically
via `ensurePackage()` calls (in `generate-storybook-configuration.ts`
and `add-e2e.ts`), so the static dependency analyzer doesn't detect them
as dependencies of the angular project. This means their files are not
included in the test task's input hash, causing sandbox violations.

Relevant run: [staging.nx.app task
run](https://staging.nx.app/runs/B5EjkJA6p1/task/angular%3Atest?batchId=77ad1700-bc33-4663-b344-cbfab899c6c4)

## Expected Behavior

The `storybook` and `playwright` projects are declared as
`implicitDependencies` of the angular project (alongside the existing
`vite` entry which exists for the same reason). This ensures their files
are included in the angular test task's input hash via the `^production`
input qualifier, resolving the sandbox failures.

## Related Issue(s)

Fixes NXC-4216
2026-04-09 08:25:15 +02:00
Craigory Coppola d4c55d806a fix(core): add vale-changed.mjs script to vale target inputs
NXC-4218
2026-04-08 19:39:34 -04:00
Jack Hsu baaa14ea57 fix(misc): stream Framer proxy responses and add edge function timing (#35215)
## Current Behavior

Framer proxy buffers entire HTML response before URL rewriting and
returning to client. No CDN caching on proxied responses. No timing
instrumentation for diagnosing slow page loads.

## Expected Behavior

- **Streaming URL rewrite** via `TransformStream` — reduces TTFB by
sending chunks as they arrive (handles cross-chunk boundary matches)
- **Edge CDN caching** — `Netlify-CDN-Cache-Control` with
`stale-while-revalidate` on Framer/blog proxied responses only (docs
analytics unaffected)
- **Timing instrumentation** — console logs in all edge functions +
`Server-Timing` headers on docs functions for DevTools visibility

## Lighthouse scores

Before: 

<img width="739" height="1056" alt="image"
src="https://github.com/user-attachments/assets/ee5c383c-5ba8-41d1-b568-bcbec9e7cb73"
/>


After:

<img width="703" height="1031" alt="image"
src="https://github.com/user-attachments/assets/67366145-35f8-476c-a333-8a0848c9aee3"
/>
2026-04-08 19:26:07 -04:00
Craigory Coppola fd5d210151 fix(core): add prettier config inputs to astro-docs format target (#35222)
## Current Behavior

The `astro-docs:format` target is cached but has no explicit `inputs`,
so it uses the default named input which only tracks
`{projectRoot}/**/*`. Changes to workspace-root prettier configuration
files (`.prettierrc`, `.prettierignore`) don't invalidate the cache,
potentially returning stale format check results.

## Expected Behavior

The `format` target explicitly lists its inputs: the `.mdoc` files it
formats and the prettier config files that control formatting behavior.
This ensures the cache invalidates correctly when prettier configuration
changes.

## Related Issue(s)

Fixes NXC-4217
2026-04-08 19:10:57 -04:00
Craigory Coppola 8f8fc344e9 fix(core): ensure build tasks use copyReadme named input (#35217)
## Current Behavior

Three packages (`angular-rspack-compiler`, `angular-rspack`, `esbuild`)
have build targets that run `copy-readme.js` but don't correctly declare
all required inputs:

- `angular-rspack-compiler` and `angular-rspack` manually listed partial
inputs (missing `.prettierignore` and using a bare directory path
`{workspaceRoot}/scripts/readme-fragments` that doesn't resolve to
files)
- `esbuild` had no inputs at all for its build target, falling back to
the default `["production", "^production"]`

This means changes to `.prettierignore` or `readme-fragments/*.md` would
not invalidate the build cache for these projects.

## Expected Behavior

All three packages use the `copyReadme` named input (defined in
`nx.json`), consistent with every other package in the repo. This
ensures `.prettierignore`, `readme-fragments/**/*`, `copy-readme.js`,
and project README files are all correctly tracked as build inputs.

## Related Issue(s)

Fixes NXC-4214
2026-04-08 16:03:43 -04:00
Jack Hsu 1526f89612 feat(core): use CNW variant 1 cloud prompt in nx init (#35155)
## Current Behavior

`nx init` uses a different cloud prompt (`code: "enable-ci"`, message:
"Would you like to enable AI-powered Self-Healing CI and Remote
Caching?") with only Yes/Skip choices. There is no way to permanently
opt out of the prompt, and package manager install output is printed
during init.

## Expected Behavior

`nx init` now uses CNW's variant 1 prompt copy:
- **Prompt:** "Enable remote caching to speed up builds with Nx Cloud?"
- **Footer:** "Free for small teams. 2-minute setup with GitHub — cache
locally and in CI"
- **Choices:** Yes / Skip for now / No, don't ask again

Behavior per choice:
| Choice | Action |
|--------|--------|
| **Yes** | Connect to Nx Cloud (set `nxCloudId`) |
| **Skip for now** | Do nothing |
| **No, don't ask again** | Set `neverConnectToCloud: true` in nx.json |

Additional changes:
- Telemetry now tracks the raw choice via `nxCloudArg` field
(yes/skip/never)
- `nx migrate` cloud prompt also supports the "never" choice
- Install stdout suppressed during init (stderr preserved for errors)
<img width="1392" height="978" alt="init"
src="https://github.com/user-attachments/assets/fdacc72b-64ed-4e87-b4c3-01a467051e24"
/>

## Related Issue(s)

Fixes NXC-4189
2026-04-08 14:38:38 -04:00
Craigory Coppola 703e2ee595 fix(core): prevent phantom connections and dead polling in plugin workers (#34823)
The setInterval(async, 10) polling loop used to connect to plugin
workers created overlapping connection attempts because setInterval does
not await its callback. This caused phantom socket connections, event
loop saturation, and cascading worker deaths.

Changes:
- Replace setInterval with recursive setTimeout so only one connection
attempt is ever in flight at a time
- Close the worker's server on first connection to reject phantom
connections that would create duplicate load timeouts
- Detect worker exit during polling and reject immediately instead of
burning through 10,000 attempts against a dead socket
- Clear _connectPromise on failure so ensureAlive() retries instead of
re-awaiting a permanently rejected promise

Fixes: #34388

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-08 14:13:36 -04:00
Craigory Coppola 51cd80af1d chore(repo): issues scraper closures fix (#35195)
## Current Behavior
`closed` issues weren't scraped correctly. If no prior data was present,
we scraped the full repo which caps at 10k issues, when we have 11k now.

## Expected Behavior
Scraping works consistently

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

Fixes #
2026-04-08 14:03:05 -04:00
Jason Jean 1334f75da3 fix(core): add missing inputs and sandbox exclusions for native tasks (#35212)
## Current Behavior

The `native` named input in `nx.json` only includes
`{projectRoot}/**/Cargo.*`, which misses workspace-root files that
Cargo/Clippy read: `Cargo.toml` (workspace manifest), `Cargo.lock`,
`clippy.toml`, and `.cargo/config.toml`. This means changes to these
files don't invalidate the cache for native tasks.

Additionally, Cargo writes intermediate build artifacts to
`dist/target/` which causes sandbox violations in Nx Cloud CI.

## Expected Behavior

Native task cache is correctly invalidated when workspace-root
Cargo/Clippy config files change. Sandbox no longer flags `dist/target/`
reads/writes as violations.

## Related Issue(s)

N/A

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-08 13:44:07 -04:00
Jason Jean 68d357fd45 chore(module-federation): disable webpack-incompatible react e2e suites (#35214)
## Current Behavior

React module federation e2e suites that exercise webpack generation
paths are failing because webpack 5.106.0 removed
`lib/util/create-schema-validation.js`, which
`@module-federation/enhanced@2.3.1` still depends on.

## Expected Behavior

These known-broken suites should be skipped until the upstream module
federation dependency is compatible with webpack 5.106.0+ so they do not
keep failing CI.

## Related Issue(s)

N/A

## Summary

This PR temporarily disables the affected React module federation e2e
suites by switching their top-level test groups to `describe.skip(...)`
and adding a short note about the webpack /
`@module-federation/enhanced` incompatibility.

It covers the webpack-specific suites as well as the mixed Rspack
interoperability/convert flows that still generate webpack-based module
federation apps.

## Validation

- `npx prettier --write` on the modified test files
- `git push -u origin fix/disable-mf-webpack-tests`
- repository pre-push hook passed during push (`nx` prepush checks)

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-04-08 13:38:11 -04:00
Jason Jean 9c76cf199a fix(core): use fresh package manager cache for e2e tests (#35211)
## Current Behavior

When e2e tests publish packages to the local Verdaccio registry with the
same version number (e.g., `23.0.0`), npm and yarn serve stale cached
tarballs from previous test runs instead of fetching the freshly
published packages. This causes e2e tests to run against outdated code.

## Expected Behavior

Each e2e test run uses a fresh package manager cache directory, ensuring
that npm and yarn always fetch the latest packages from the local
registry — even when the version number hasn't changed.

- **npm**: `npm_config_cache` set to a temp directory
- **yarn v1**: `YARN_CACHE_FOLDER` set to a temp directory
- **yarn v2**: `YARN_ENABLE_GLOBAL_CACHE` set to `false`
- **pnpm**: not affected (content-addressed store)
- **bun**: already handled via `--no-cache` flag

## Related Issue(s)

<!-- No specific issue — discovered during local e2e testing -->

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-08 13:37:06 -04:00
Jack Hsu af22e5c289 chore(misc): make expand-deps idempotent and wrap release in try-catch to reset package.json (#35213)
If the publish fails for any reason, the `package.json` files are not
reset, this can leads to `expand-deps` erroring in subsequent runs. Wrap
`resetPackageJsons` in finally block.

Also ensures `expand-deps` can run twice without errors, at least
locally, not in CI.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-08 13:35:57 -04:00
MaxKless 593b8a5d26 fix(core): disable Yarn scripts for temp nx@latest installs (#35210)
## Current Behavior

When Nx pulls `nx@latest` into a temporary directory (for example from
daemon latest resolution or `configure-ai-agents`/`init` handoff), Yarn
Berry can still run lifecycle scripts unless disabled via environment
configuration.

## Expected Behavior

All temporary `nx@latest` installs disable lifecycle scripts
consistently, including Yarn Berry, by always setting
`YARN_ENABLE_SCRIPTS=false` in the install process environment.

## Related Issue(s)

N/A. Follow-up parity change related to
https://github.com/nrwl/nx-console/pull/3108.

Fixes #N/A
2026-04-08 22:49:47 +09:00
Jason Jean 7b6aed81ac chore(repo): update nx to 22.7.0-beta.11 (#35208)
Updating Nx from 22.7.0-beta.10 to 22.7.0-beta.11
2026-04-08 09:47:14 -04:00
FUASHI LOT-BILL e6e2576670 fix(core): support cross-file variable references in .env files (#34956)
## Current Behavior

When Nx loads multiple .env files (such as `apps/nx-22-5/.env`,
`.local.env`, `.env.local`, and `.env`), each file is loaded and has its
variables expanded in sequence. This means referencing works up the
priority list but not down. For example, root `.env` correctly
references variables in project-specific `apps/example/.env`, but not
vice versa.

**Example:**

If root `.env` contains:
```env
WILL_RESOLVE=$FIRST_APP_NAME
GLOBAL_NX_VERSION=22.5.1
```

And `apps/nx-22-5/.env` contains:

```env
WILL_NOT_RESOLVE=$GLOBAL_NX_VERSION
FIRST_APP_NAME=nx-22-5
```

The `WILL_NOT_RESOLVE` variable will not expand correctly to `22.5.1`.
Instead, it becomes an empty string because `GLOBAL_NX_VERSION` is not
available in the environment at the time `apps/nx-22-5/.env` is being
processed. However, `WILL_RESOLVE` correctly resolves to` nx-22-5`.

This is because project-specific .env files are loaded before root .env
files, and variable expansion happens immediately during loading rather
than after all files are loaded.

## Expected Behavior
Variables in one .env file should be able to reference variables from
other .env files that are loaded together, regardless of their loading
priority. Both up-chain and down-chain references should work.

Using the example above:

- `WILL_RESOLVE` should resolve to nx-22-5  (works today)
- `WILL_NOT_RESOLVE` should resolve to 22.5.1  (fixed by this PR)

## Changes Made
Updated `loadAndExpandDotEnvFile` in
`packages/nx/src/tasks-runner/task-env.ts` to accept an array of file
paths instead of a single path. The function now:

1. Loads all .env files first to collect the complete set of variables
2. Performs variable expansion once with all variables available
3. This ensures bi-directional cross-file variable references work
correctly
Also updated `loadRootEnvFiles` in `packages/nx/src/utils/dotenv.ts` to
use the new batched loading approach.

Testing
A reproduction repository demonstrating the issue is available at:
[https://github.com/dullbenz/nx-22-5-env-referencing-example](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)

After this fix, both `WILL_RESOLVE` and `WILL_NOT_RESOLVE` should
correctly expand their variable references.

Related Issue(s)
Fixes #34955

Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
2026-04-08 07:57:43 -04:00
Jason Jean 44136ca74f fix(core): kill discrete tasks and use tree-kill for batch cleanup on SIGINT (#35175)
## Current Behavior

When Nx receives SIGINT (Ctrl+C), `performCleanup()` in the task
orchestrator kills continuous tasks and run-commands tasks, but **not
discrete tasks** (executor-based builds like `@nx/js:tsc`,
`nx:run-script`, etc.). In TUI mode, fork workers run in separate PTY
process groups and don't receive SIGINT directly, so cleanup hangs
waiting for tasks that are never terminated.

Additionally, `BatchProcess.kill()` only sends a signal to the immediate
child process, leaving grandchild processes (e.g. Java JVM, Gradle
daemon, Gradle workers) alive.

The Gradle batch executor also uses `execSync`, which blocks the Node
event loop and prevents the worker from responding to signals.

## Expected Behavior

All task types — discrete, continuous, and run-commands — should be
explicitly killed during SIGINT cleanup. Batch processes should use
`tree-kill` to terminate the entire process tree. The Gradle batch
executor should use async `spawn` instead of blocking `execSync`.

## Related Issue(s)

N/A — found via code inspection and confirmed with tests.
2026-04-07 23:00:49 +00:00
Jason Jean f7725e4e84 chore(maven): bump maven plugin version to 0.0.17 (#35203)
## Current Behavior

The Maven plugin version is `0.0.16`.

## Expected Behavior

The Maven plugin version is bumped to `0.0.17`, with a corresponding
migration for Nx `22.7.0-beta.11` that updates `pom.xml` files in user
workspaces.

## Related Issue(s)

N/A — routine version bump.
2026-04-07 22:50:31 +00:00
Louie Weng 6a9e270f1c fix(gradle): patch 0.1.19 to beta.11 (#35202)
## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Gradle project graph plugin 0.1.19 should be tied to Nx `22.7.0.beta.11`
2026-04-07 18:29:34 -04:00
Jason Jean 53c306a3f4 chore(repo): add pnpm store caching to CI workflow (#35197)
## Current Behavior

The `ci.yml` workflow runs `pnpm install --frozen-lockfile` and `pnpm
playwright install --with-deps` without any caching. Every CI run:
- Downloads all npm packages from the registry from scratch
- Downloads Playwright browser binaries (~hundreds of MB)
- Installs ~100+ system apt packages for Playwright dependencies

This was partially caused by #33772 which migrated from
`actions/setup-node` (which had built-in `cache: 'pnpm'`) to
`mise-action` without adding back equivalent caching.

## Expected Behavior

- **pnpm store** is cached between runs, so `pnpm install` only links
from the local store instead of downloading
- **Playwright browsers** are cached by version, so browser downloads
are skipped on cache hit
- System apt deps still install on cache hit (they're fast), but browser
downloads are skipped

## Related Issue(s)

N/A — performance improvement for CI install times.
2026-04-07 21:40:16 +00:00
Louie Weng 6f62590e6d fix(gradle): hoist shared task computation out of per-class loop in atomized CI target generation (#35199)
## Current Behavior

During atomized CI target generation, `buildTestCiTarget` is called once
per test class discovered in a project. Each invocation independently
recomputes `taskInputs`, `outputs`, and `dependsOn` for the same
`testTask`. Internally, `getInputsForTask` was called with `null` for
`dependsOnTasks`, which forced `getDependsOnTask(task)` — an uncached
call to `task.taskDependencies.getDependencies(task)` — on every
invocation. For a project with 158 test classes backed by the same
Gradle task, this results in 158 redundant dependency tree walks during
project graph discovery.

## Expected Behavior

The shared computation (`getDependsOnTask`, `getInputsForTask`,
`getOutputsForTask`, `getDependsOnForTask`) is performed once per
`testTask` in `processTestFiles` and the pre-computed values are passed
into `buildTestCiTarget`. This eliminates redundant work proportional to
the number of test classes, reducing CPU overhead during project graph
generation — especially on cold Gradle daemon starts.

## Related Issue(s)

Fixes #
2026-04-07 14:22:41 -07:00
Jason Jean 918193acd8 chore(repo): isolate astro-docs build (#35134)
## Current Behavior

The `astro-docs` project is not listed in the isolated build assignment
rules in the dynamic changesets CI workflow. This means it runs
alongside other projects instead of being isolated like `nx-dev`.

## Expected Behavior

The `astro-docs` project is added to the isolated build assignment rules
alongside `nx-dev`, ensuring its build runs in isolation during CI.

## Related Issue(s)

N/A — internal CI configuration improvement.
2026-04-07 19:55:27 +00:00
Jack Hsu 2521f98b6d fix(core): supply chain hardening via transitive dependency pinning (#35159)
## Current Behavior

When users run `pnpm install nx@latest`, transitive dependencies are
resolved at install time by the package manager. An attacker who
compromises a transitive dep (e.g. publishes a malicious patch to a
dep-of-a-dep) can inject code into any `nx@latest` install, even if `nx`
itself is secure. The `nx` package has ~36 direct deps but ~110 total
packages in its dependency tree, leaving ~76 transitive deps with
resolver freedom.

Additionally, `packages/nx/package.json` uses version ranges (`^`, `~`)
and `catalog:` references for some dependencies, giving the resolver
further freedom.

## Expected Behavior

At publish time, the entire transitive dependency tree of `nx` is
flattened into explicit, pinned direct dependencies in `package.json`.
Every package version is predetermined by the Nx team based on what was
tested in CI — zero resolver freedom.

### Changes

**`scripts/expand-deps.ts`** — New script that:
- Parses `pnpm-lock.yaml` to walk the full transitive dep tree for a
given project
- Pins all versions exactly (no ranges, resolves `catalog:` refs)
- Fails on version conflicts with dependency path reporting
- Supports `--dry-run` for preview
- Wired into `nx-release.ts` publish pipeline and
`packages/nx/project.json` as `expand-deps` target

**Inlined `@yarnpkg/parsers`** — Copied the syml parser (~2050 lines,
mostly PEG-generated grammar) into `packages/nx/src/utils/yarn-syml/`,
swapping `js-yaml` for `@zkochan/js-yaml` (already an nx dep). This
eliminates the `argparse@1` vs `argparse@2` transitive conflict.

**Removed `front-matter` dependency** — Last published 6 years ago,
replaced with an inline `parseFrontMatter` function ported from the
original source, using `@zkochan/js-yaml`.

**Replaced `jest-diff` with `@jest/diff-sequences`** — `jest-diff`
pulled in `pretty-format`, `chalk`, `ansi-styles@5`, `@jest/schemas`,
`@sinclair/typebox`, and `react-is`. Replaced with a minimal inline diff
implementation backed by `@jest/diff-sequences` (zero transitive deps).
This eliminates the `ansi-styles@4` vs `@5` conflict.

### Result

`nx run nx:expand-deps -- --dry-run` reports **0 conflicts, 110 total
pinned deps** (34 direct + 76 transitive).

`package.json` now has the pinned dependencies:

```49   "dependencies": {
  50     "@emnapi/core": "1.4.5",
  51     "@emnapi/runtime": "1.4.5",
  52     "@emnapi/wasi-threads": "1.0.4",
  53     "@jest/diff-sequences": "30.0.1",
  54     "@ltd/j-toml": "1.38.0",
  55     "@napi-rs/wasm-runtime": "0.2.4",
  56     "@tybys/wasm-util": "0.9.0",
  57     "@yarnpkg/lockfile": "1.1.0",
  58     "@zkochan/js-yaml": "0.0.7",
  59     "ansi-colors": "4.1.3",
  60     "ansi-regex": "5.0.1",
  61     "ansi-styles": "4.3.0",
  62     "argparse": "2.0.1",
  63     "asynckit": "0.4.0",
  64     "axios": "1.13.5",
  65     "balanced-match": "4.0.3",
  66     "base64-js": "1.5.1",
  67     "bl": "4.1.0",
  68     "brace-expansion": "5.0.2",
  69     "buffer": "5.7.1",
  70     "call-bind-apply-helpers": "1.0.2",
  71     "chalk": "4.1.2",
  72     "cli-cursor": "3.1.0",
  73     "cli-spinners": "2.6.1",
  74     "cliui": "8.0.1",
  75     "clone": "1.0.4",
  76     "color-convert": "2.0.1",
  77     "color-name": "1.1.4",
  78     "combined-stream": "1.0.8",
  79     "defaults": "1.0.4",
  80     "define-lazy-prop": "2.0.0",
  81     "delayed-stream": "1.0.0",
  82     "dotenv": "16.4.7",
  83     "dotenv-expand": "11.0.7",
  84     "dunder-proto": "1.0.1",
  85     "ejs": "5.0.1",
  86     "emoji-regex": "8.0.0",
  87     "end-of-stream": "1.4.5",
  88     "enquirer": "2.3.6",
  89     "es-define-property": "1.0.1",
  90     "es-errors": "1.3.0",
  91     "es-object-atoms": "1.1.1",
  92     "es-set-tostringtag": "2.1.0",
  93     "escalade": "3.2.0",
  94     "escape-string-regexp": "1.0.5",
  95     "figures": "3.2.0",
  96     "flat": "5.0.2",
  97     "follow-redirects": "1.15.11",
  98     "form-data": "4.0.5",
  99     "fs-constants": "1.0.0",
 100     "function-bind": "1.1.2",
 101     "get-caller-file": "2.0.5",
 102     "get-intrinsic": "1.3.0",
 103     "get-proto": "1.0.1",
 104     "gopd": "1.2.0",
 105     "has-flag": "4.0.0",
 106     "has-symbols": "1.1.0",
 107     "has-tostringtag": "1.0.2",
 108     "hasown": "2.0.2",
 109     "ieee754": "1.2.1",
 110     "ignore": "7.0.5",
 111     "inherits": "2.0.4",
 112     "is-docker": "2.2.1",
 113     "is-fullwidth-code-point": "3.0.0",
 114     "is-interactive": "1.0.0",
 115     "is-unicode-supported": "0.1.0",
 116     "is-wsl": "2.2.0",
 117     "json5": "2.2.3",
 118     "jsonc-parser": "3.2.0",
 119     "lines-and-columns": "2.0.3",
 120     "log-symbols": "4.1.0",
 121     "math-intrinsics": "1.1.0",
 122     "mime-db": "1.52.0",
 123     "mime-types": "2.1.35",
 124     "mimic-fn": "2.1.0",
 125     "minimatch": "10.2.4",
 126     "minimist": "1.2.8",
 127     "npm-run-path": "4.0.1",
 128     "once": "1.4.0",
 129     "onetime": "5.1.2",
 130     "open": "8.4.2",
 131     "ora": "5.3.0",
 132     "path-key": "3.1.1",
 133     "picocolors": "1.1.1",
 134     "proxy-from-env": "1.1.0",
 135     "readable-stream": "3.6.2",
 136     "require-directory": "2.1.1",
 137     "resolve.exports": "2.0.3",
 138     "restore-cursor": "3.1.0",
 139     "safe-buffer": "5.2.1",
 140     "semver": "7.7.4",
 141     "signal-exit": "3.0.7",
 142     "string-width": "4.2.3",
 143     "string_decoder": "1.3.0",
 144     "strip-ansi": "6.0.1",
 145     "strip-bom": "3.0.0",
 146     "supports-color": "7.2.0",
 147     "tar-stream": "2.2.0",
 148     "tmp": "0.2.4",
 149     "tree-kill": "1.2.2",
 150     "tsconfig-paths": "4.2.0",
 151     "tslib": "2.8.1",
 152     "util-deprecate": "1.0.2",
 153     "wcwidth": "1.0.1",
 154     "wrap-ansi": "7.0.0",
 155     "wrappy": "1.0.2",
 156     "y18n": "5.0.8",
 157     "yaml": "2.8.0",
 158     "yargs": "17.7.2",
 159     "yargs-parser": "21.1.1"
 160   },
```

## Related Issue(s)

Closes NXC-4197

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2026-04-07 15:47:28 -04:00
Jack Hsu 48a6a86628 docs(misc): update sidebar to expand tutorials and collapse concepts (#35194)
## Current Behavior

- The **Tutorials** sidebar section is collapsed by default with a "New"
badge
- **How Nx Works** (Concepts) and **Platform Features** sections are
expanded by default
- Only ~10% of traffic reaches the CI tutorial, suggesting tutorials are
not discoverable enough

## Expected Behavior

- **Tutorials** section is expanded by default (no badge) to increase
discoverability
- **How Nx Works** and **Platform Features** sections are collapsed by
default to reduce noise and draw attention to tutorials
- This should drive higher engagement with the tutorial flow including
CI setup

<img width="502" height="735" alt="image"
src="https://github.com/user-attachments/assets/76a63a36-ab5d-4459-aab6-dc04282e3779"
/>


## Related Issue(s)

Fixes DOC-474
2026-04-07 14:01:48 -04:00
Louie Weng fe8f120a7e chore(gradle): bump gradle project graph plugin version to 0.1.19 (#35162)
## Current Behavior

The Gradle project graph plugin is at version 0.1.18.

## Expected Behavior

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

## Related Issue(s)

N/A - routine version bump
2026-04-07 10:29:24 -07:00
Louie Weng bebadf607b fix(gradle): infer input extensions on project graph generation (#35160)
## Current Behavior

When output directories are empty (e.g. on a clean build), the plugin
cannot discover file extensions from actual files on disk. This means
`dependentTasksOutputFiles` glob patterns are missing for extensions
like `.class` and `.jar`, leading to incomplete cache inputs.

## Expected Behavior

Add `inferExtensionsFromInputProperties` to supplement file-based
extension discovery using task type checks:
- `Test` tasks → `class` + `jar` (they consume compiled code and library
jars on the test classpath)
- `AbstractCompile` tasks → `class` only (they produce/consume compiled
classes, not jars)
- `AbstractArchiveTask` dependents → their declared archive extension
(jar, war, zip, etc.)

This works at configuration time without requiring files to exist on
disk.

## Related Issue(s)

N/A
2026-04-07 17:20:34 +00:00
Alexandre Ducarne 794e0b42c8 fix(core): replace LGPL-licensed @ltd/j-toml with BSD-3-Clause smol-toml (#35188)
## Current Behavior

`nx` depends on `@ltd/j-toml` which is licensed under **LGPL-3.0**. This
creates licensing concerns for projects that bundle or distribute nx, as
LGPL requires downstream users to allow relinking/modification of the
LGPL component.

A previous attempt
([3446dd2](https://github.com/nrwl/nx/commit/3446dd2f77a1b182f9b64a83586ab68a2f0c063f))
replaced it with `@iarna/toml`, but that library:
- Only supports TOML 1.0.0-rc.1 (not even the final 1.0.0 spec)
- Has been effectively unmaintained since ~2020
- Is significantly slower than alternatives

## Expected Behavior

Use a permissively-licensed, actively maintained, fast TOML parser.

## Solution

Replace `@ltd/j-toml` with
[`smol-toml`](https://github.com/squirrelchat/smol-toml) (BSD-3-Clause):

| | @ltd/j-toml (current) | @iarna/toml (other PR) | **smol-toml (this
PR)** |
|---|---|---|---|
| License | LGPL-3.0 | ISC | **BSD-3-Clause** |
| TOML spec | 1.0.0 | 1.0.0-rc.1 | **1.1.0** |
| Weekly downloads | — | 2.7M | **6.8M** |
| Maintained | Yes | Dormant (~2020) | **Active (2026)** |
| Performance | Baseline | ~same | **2-4x faster** |
| CJS support | Yes | Yes | **Yes** |

### Changes

- Replace `@ltd/j-toml` imports with `smol-toml` in
`set-up-ai-agents.ts` and `test-utils.ts`
- Remove j-toml-specific APIs (`TOML.Section()`, `TOML.inline()`,
`newlineAround` option) in favor of smol-toml's simpler
`parse()`/`stringify()`
- Update inline test snapshots (single quotes → double quotes, minor
formatting differences)

### Note on inline snapshots

Some inline snapshots may need a final update via `--updateSnapshot`
once CI runs the full test suite. The snapshot changes included here
follow the pattern observed from smol-toml's output format
(double-quoted strings, no leading newline before first section).

## Test plan

- [ ] CI passes with updated snapshots
- [ ] `nx configure-ai-agents` generates valid Codex config.toml
- [ ] Release versioning for Rust/Cargo projects still produces correct
Cargo.toml output

---------

Co-authored-by: Alexandre Ducarne <aducarne@ripple.com>
Co-authored-by: FrozenPandaz <jasonjean1993@gmail.com>
2026-04-07 12:35:33 -04:00
Craigory Coppola a5a76e65d6 fix(core): misc tui perf fixes (#35187)
- Add `handles_cursor_movement: Arc<AtomicBool>` field to PtyInstance
- Short-circuit `has_cursor_movement_in_output` on subsequent calls once
  a cursor-movement sequence has been detected, skipping the O(n) UTF-8
  buffer scan on every arrow-key event
- The flag is monotonic (false → true, never reverts) so Relaxed
ordering
  is sufficient; Arc makes it Clone-safe across async resize threads

This pull request refactors the TUI (terminal user interface) codebase
to improve performance, safety, and code clarity. The most significant
changes include switching from debouncing to throttling for PTY resize
operations, updating method signatures to use string slices (`&str`)
instead of owned `String` where possible, and making related adjustments
throughout the codebase. These changes help reduce unnecessary
allocations, improve responsiveness, and clarify intent.

**PTY Resize Handling Improvements:**

* Replaced the `debounce_pty_resize` method with `throttle_pty_resize`,
which limits PTY resize operations to at most one every 200ms
(fire-then-block), reducing excessive work during rapid events like
window resizing. All calls to the old debounce method are updated to use
the new throttle method.
[[1]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL473-R471)
[[2]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL490-R493)
[[3]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL590-R590)
[[4]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL615-R608)
[[5]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL1149-R1131)
[[6]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL1543-R1525)
[[7]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL1852-L1862)
[[8]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL2550-R2541)
[[9]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL2659-R2643)

**API and Type Signature Updates:**

* Changed many method signatures (such as `update_task_status`,
`select_task`, and `select_batch_group`) to accept `&str` instead of
`String`, reducing unnecessary allocations and clarifying ownership. All
corresponding call sites and trait implementations are updated.
[[1]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL220-R220)
[[2]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL417-R426)
[[3]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL534-R527)
[[4]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL590-R590)
[[5]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL1543-R1525)
[[6]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL2550-R2541)
[[7]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL2573-R2558)
[[8]](diffhunk://#diff-c899b0b1f501248ea65ff62c761294b7e6c5f5ece77ed422eae9c3a4849ac85aL218-R224)
[[9]](diffhunk://#diff-c899b0b1f501248ea65ff62c761294b7e6c5f5ece77ed422eae9c3a4849ac85aL709-R709)
[[10]](diffhunk://#diff-c899b0b1f501248ea65ff62c761294b7e6c5f5ece77ed422eae9c3a4849ac85aL833-R847)

**Cloning and Ownership Adjustments:**

* Replaced some `.clone()` and `.to_string()` calls with `.to_vec()` and
`.to_owned()` where more appropriate, further reducing unnecessary
allocations and clarifying intent.
[[1]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL168-R172)
[[2]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL189-R189)
[[3]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL203-R203)
[[4]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL368-R368)
[[5]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL2630-R2614)

**Code Cleanliness and Logic Simplification:**

* Simplified and cleaned up logic in several places, such as input
handling and filter mode transitions, to make the code more readable and
maintainable.
[[1]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL972-R970)
[[2]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL1006-R990)
[[3]](diffhunk://#diff-a7ecbb01dd3a8b83922f97d7040b457813c44325d346172693d1638b2b45a48fL1017)

Overall, these changes improve performance, safety, and maintainability
of the TUI code.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-07 12:04:07 -04:00
MaxKless b063b8475b fix(maven): make install targets noop when maven.install.skip=true (#35009)
When a Maven project sets maven.install.skip=true, the install:install
goal is a no-op at runtime. However, the NxTargetFactory still generated
a full batch executor target with cache:false, causing unnecessary Maven
invocations on every CI agent. This led to flaky failures in DTE when
the batch runner's graph setup failed on some agents.

Now detects maven.install.skip=true and emits an nx:noop target with
cache:true instead. The target still acts as a synchronization point in
the task graph (dependsOn chain is preserved) but avoids spinning up the
batch runner entirely.

<img width="2124" height="842" alt="image"
src="https://github.com/user-attachments/assets/b6c09b3e-c34e-45f8-9c33-2d6ce493bc3d"
/>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:55:46 -04:00
MaxKless 9361a75f7c feat(core): remove polygraph cloud passthrough (#35153) 2026-04-07 22:07:53 +09:00
Craigory Coppola e394165191 fix(repo): update issue-notifier.yml (#35178)
## Current Behavior
issue-notifier.yml uses an outdated syntax that throws

## Expected Behavior
it doesn't throw

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

Fixes #
2026-04-07 08:32:32 -04:00
Jason Jean 828303bb2b feat(repo): add e2e test for nx build process verification (#35119)
## Current Behavior

There is no e2e test that verifies the nx build process works correctly
end-to-end — that the source code compiles, produces expected output
files, and correctly detects source changes on rebuild.

The verdaccio `max_body_size` was set to 20mb, which is too small for
the nx package. The nx `.npmignore` was also missing exclusions for
`.rs` and `.snap` files.

## Expected Behavior

- A new `e2e-nx-build` test project that:
  - Clones the nx repo to a temp directory
- Swaps `@nx/*` and `nx` dependency versions to match what's published
in the local verdaccio registry
  - Installs dependencies from the local registry
  - Builds all `tag:npm:public` packages (same as nx-release)
- Verifies key output files exist (`bin/nx.js`, `src/index.js`,
`src/index.d.ts`)
- Modifies a source file (`bin/nx.ts`), rebuilds, and verifies the
change appears in the output — catching cache misconfiguration (verified
by sabotaging `inputs: []` and confirming the test fails)
- Verdaccio `max_body_size` bumped to 100mb
- `.rs` and `.snap` files excluded from the nx npm package

## Related Issue(s)

N/A — new test infrastructure

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-04-03 21:23:22 -04:00
Victor Savkin 93624a5c24 feat(core): allow generate command to skip project graph creation (#35170)
When `skipProjectGraph` is passed to the `generate()` function, use
`retrieveProjectConfigurationsWithoutPluginInference` instead of
`createProjectGraphAsync`. This loads only default plugins (js,
package-json, project-json) and skips dependency edge computation,
making generation faster while still supporting local plugins.

This is a private API — callers must import the `generate` function
directly and pass `skipProjectGraph: true`.

<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 17:01:58 -04:00
Jason Jean 8d35b8a8f7 fix(maven): prevent batch executor hang from premature worker exit (#35001)
## Current Behavior

When running `nx run-many -t clean --batch` in a multi-module Maven
project, the batch executor hangs indefinitely. Workers use
`taskQueue.poll()` which returns `null` immediately when the queue is
temporarily empty. Workers exit their loop prematurely — even though
other workers are still processing tasks that will produce new root
tasks. Eventually all workers exit and `completionLatch.await()` blocks
forever.

## Expected Behavior

`nx run-many -t clean --batch` completes successfully for Maven projects
of any size. Worker threads now use `taskQueue.take()` which blocks
until a task is available, instead of exiting when the queue is
momentarily empty. When all tasks complete, `executor.shutdownNow()`
interrupts any workers still blocked on `take()`, allowing clean
shutdown.

## Related Issue(s)

Fixes #34757
2026-04-03 13:52:14 -04:00
Leosvel Pérez Espinosa 070b748e73 chore(repo): revert tsgo compiler for nx package (#35167)
## Current Behavior

The `packages/nx` project uses `tsgo` (Go-based TypeScript compiler) via
a dedicated `@nx/js/typescript` plugin entry with `compiler: "tsgo"`.
All other packages use `tsc`.

When a downstream package (e.g., `node:build-base`) runs `tsc --build`
with project references to `nx`, `tsc` detects the `.tsbuildinfo` was
produced by a different compiler version (`7.0.0-dev` vs `5.9.2`) and
recompiles `nx` entirely. This cascades through the reference chain —
every project referencing `nx` is then considered out of date,
triggering rebuilds across devkit, js, workspace, eslint, jest, docker,
and the originating project.

Verified locally with `tsc --build --verbose`:
```
Project '../nx/tsconfig.lib.json' is out of date because output for it
was generated with version '7.0.0-dev.20260327.2' that differs with
current version '5.9.2'
```

## Expected Behavior

All packages use `tsc`, eliminating the compiler version mismatch. `tsc
--build` finds all referenced projects up to date and skips
recompilation.

> **Note:** We'll switch all packages to `tsgo` once they're all
migrated to `nodenext` and prepared for it, so we use a single compiler
across the workspace at a time.
2026-04-03 13:40:45 -04:00
Jason Jean 7439d58b22 chore(repo): add CLI performance benchmarks (#35078)
## Current Behavior

No standardized way to measure Nx CLI performance or detect regressions.

## Expected Behavior

A `benchmarks/` workspace provides reproducible CLI performance
benchmarks using [hyperfine](https://github.com/sharkdp/hyperfine).

### Project Structure

1110 dummy projects in a 3-level fan-out (10 groups → 10 subs → 10
leaves) with implicit dependencies.

### Benchmarks

| Benchmark | Command | Outputs | Dependencies | What it measures |
| --------------- | --------------------- | ------- | ------------ |
----------------------------------------- |
| `version` | `nx --version` | — | — | CLI startup / module loading |
| `show-projects` | `nx show projects` | — | — | Project graph query via
daemon |
| `cat-warm` | `cat lorem.md` × 1110 | No | Flat | Task scheduling +
hashing (no output I/O) |
| `lint-warm` | `cp lorem.md` × 1110 | Yes | Flat | Cached tasks with
output tracking |
| `build-warm` | `cp lorem.md` × 1110 | Yes | Topological | Cached tasks
with deps (disabled) |

### Usage

```bash
# Run all benchmarks
pnpm bench

# Run a single benchmark
pnpm nx bench:cat-warm benchmarks

# Set local baseline for comparison
pnpm bench -- --set-baseline
```

### How it works

- Each `bench:*` target runs hyperfine with `--setup 'nx reset'` (clean
daemon) and `--warmup 1` (warm daemon for measurements)
- `goals.json` (committed) defines target times the team agrees on
- `baseline.json` (gitignored) captures local per-machine numbers for
personal comparison
- First run auto-saves a baseline; subsequent runs compare against it
- The report shows colored deltas against both goals and baseline
- Benchmarks run in CI via `nx affected --targets=bench` on
`linux-large` agents

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-04-03 13:40:06 -04:00
Jason Jean 557c876e96 chore(repo): update nx to 22.7.0-beta.10 (#35166)
Updating Nx from 22.7.0-beta.9 to 22.7.0-beta.10
2026-04-02 19:00:22 -04:00
Jack Hsu 727e8b760e chore(misc): disable failing tests (#35165)
These have been failing for a while, at least a week. Let's disable for
now to unblock PRs, and fix them properly later
2026-04-02 17:41:46 -04:00
Jason Jean a80f24aaa0 fix(gradle): prevent Gradle and Maven daemon accumulation during project graph recalculation (#35143)
## Current Behavior

When file changes trigger rapid project graph recalculations (e.g.,
during development with `nx graph` or a dev server running), each call
to `populateProjectGraph` spawns a new Gradle process via
`execGradleAsync`. If the previous Gradle daemon is still busy
processing the prior request, Gradle spawns a **new daemon**. These
daemons persist for 3 hours by default (Gradle's idle timeout), leading
to dozens of orphaned `java.exe` processes consuming significant memory.

Maven has a similar issue — `runMavenAnalysis` spawns a long-lived
process with no timeout or cancellation support at all.

### Root Cause Analysis

The daemon explosion happens due to three compounding issues:

1. **No cancellation of in-flight processes**: When a newer project
graph request arrives, the previous invocation continues running. Each
concurrent invocation finds the existing daemon busy and spawns a new
one.

2. **Windows process tree issue**: On Windows, `execFile` with `shell:
true` runs `cmd.exe → gradlew.bat → java.exe`. Node's `AbortSignal` only
terminates `cmd.exe` (the immediate child process), leaving `java.exe`
running as an orphan.

3. **No timeout for Maven**: Maven analysis could run indefinitely with
no way to cancel or time out.

### Reproduction

1. Run `nx graph` in a workspace with `@nx/gradle` registered
2. Rapidly modify a `build.gradle.kts` file (e.g., `while true; do echo
"// tick" >> build.gradle.kts; sleep 0.01; done`)
3. Watch `java.exe` processes accumulate: `tasklist | grep java`
(Windows) or `ps aux | grep java` (Unix)
4. Without this fix: **15+ Gradle daemons** within seconds, persisting
for 3 hours each
5. With this fix: **1 Gradle daemon** remains stable under the same
conditions

## Expected Behavior

When rapid file changes trigger multiple project graph recalculations:
- The previous invocation is cancelled before starting a new one
- Cancelled calls that have already spawned a process get their entire
process tree killed (not just the shell wrapper)
- Only 1 daemon remains active at any time, rather than accumulating
dozens
- Both Gradle and Maven have configurable timeouts with clear error
messages

## Changes

### Gradle

#### 1. Self-contained cancellation in `get-project-graph-lines.ts`
Moved the `AbortController` from
`get-project-graph-from-gradle-plugin.ts` into
`get-project-graph-lines.ts`, closer to where processes are spawned.
`getNxProjectGraphLines` now manages its own abort controller —
cancelling any in-flight request before starting a new one. Uses
`abort('cancelled')` reason to distinguish external cancellation from
timeout.

#### 2. Tree-kill on abort (`exec-gradle.ts`)
Instead of passing the `AbortSignal` directly to Node's `execFile`
(which only kills the immediate child process), we intercept the signal
and use `tree-kill` to terminate the entire process tree. This ensures
`java.exe` is killed along with `cmd.exe` and `gradlew.bat` on Windows.

### Maven

#### 3. Timeout and cancellation support for `maven-analyzer.ts`
Added the same abort controller + tree-kill + timeout pattern to Maven
analysis:
- Configurable timeout via `NX_MAVEN_ANALYSIS_TIMEOUT` env var (default:
120s local, 600s CI)
- `cancelPendingMavenAnalysis()` cancels in-flight processes on repeated
calls
- `tree-kill` ensures the entire Maven process tree is killed on abort
- Clear timeout error messages with actionable steps

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-02 15:27:56 -04:00
James Henry 2665550d24 fix(core): update and pin ejs to 5.0.1 (#35157)
<!-- 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
<!-- This is the behavior we have today -->

We are using an old version of `ejs` and it is not pinned.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

We are using the latest version of `ejs` and it is pinned.

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-02 13:50:04 -04:00
Caleb Ukle 097484bda3 docs(nx-cloud): add nx-cloud onboard command reference (#34973)
## Current Behavior

The `nx-cloud onboard` command and its subcommands are not documented in
the Cloud CLI reference page.

## Expected Behavior

The Cloud CLI reference page includes complete documentation for the
`nx-cloud onboard` command, covering:

- Main `onboard` command with interactive and non-interactive modes
- All subcommands: `status`, `connect-workspace`, `connect github`,
`connect github poll`, `orgs list`, `orgs create`, `repos list`,
`templates list`, `vcs status`, and `workspace create`
- Options tables for each subcommand
- Automation notes for AI agent integration

Also changed `--non-interactive` to `--no-interactive` to match the Nx
CLI convention (yargs `--no-` prefix).

## Related Issue(s)

Fixes DOC-451

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 12:27:04 -05:00
Robert Sidzinka aca93cc9bb fix(core): bump axios to 1.13.5 to resolve CVE-2026-25639 (#35148)
## Current Behavior

The `nx`, `create-nx-workspace`, and `nx-dev` packages pin `axios` at
version `1.12.0`, which has a known security vulnerability
([CVE-2026-25639](https://github.com/advisories/GHSA-43fc-jf86-j433)).

## Expected Behavior

Axios is pinned at `1.13.5`, which includes the fix for CVE-2026-25639,
eliminating the security vulnerability.

## Related Issue(s)

Fixes #35145
2026-04-02 13:07:42 -04:00
Steven Nance 54991812e6 docs(misc): add Node 22 and Node 24 agent images to launch templates reference (#35149)
## Current Behavior

The launch templates reference page only lists Node 20-based agent
images (`ubuntu22.04-node20.11-*` and `ubuntu22.04-node20.19-*`).

## Expected Behavior

The launch templates reference page also lists the new Node 22 and Node
24 agent images:

- `ubuntu22.04-node22.22-v1`
- `ubuntu22.04-node24.14-v1`

These images were added to the cloud infrastructure config map via
[CLOUD-4403](https://linear.app/nxdev/issue/CLOUD-4403).

## Related Issue(s)

N/A (documentation update to reflect infrastructure changes from
CLOUD-4403)

---------

Co-authored-by: Caleb Ukle <caleb@nrwl.io>
2026-04-02 19:05:02 +02:00
Jack Hsu af21c0bec8 feat(misc): lock in CNW cloud prompt A/B winner and add new variants (#35154)
## Current Behavior

The CNW cloud prompt A/B test (NXC-4113, shipped in 22.6.3) has three
variants with these results (~2,900 completions across 22.6.3+22.6.4):

| FV | Completions | Yes% | Never% |
| -- | -- | -- | -- |
| 0 ("Connect to Nx Cloud?") | 915 | 7.5% | 27.7% |
| 1 ("Enable remote caching...") | 1,040 | **12.2%** | 18.8% |
| 2 ("Speed up your CI...") | 974 | 10.0% | 19.5% |

FV 1 is the clear winner — 63% relative lift in "yes" over FV 0, nearly
halving the "never" rate.

## Expected Behavior

Lock in FV 1 as the new baseline (FV 0) and introduce two new A/B
variants:

| FV | Code | Prompt | Footer |
| -- | -- | -- | -- |
| 0 (new baseline) | `connect-to-cloud` | "Enable remote caching to
speed up builds with Nx Cloud?" | "Free for small teams. 2-minute setup
with GitHub — cache locally and in CI" |
| 1 | `cloud-ab-never-rebuild` | "Never rebuild the same code twice —
enable Nx Cloud?" | "Free for small teams. Remote caching for local dev
and CI. 2-minute setup" |
| 2 | `cloud-ab-ci-providers-speed` | "Speed up GitHub Actions, GitLab
CI, and more with Nx Cloud?" | "Free remote caching and task
distribution. 2-minute setup" |

Variant 0 (new baseline):
<img width="1392" height="1004" alt="variant_0_baseline"
src="https://github.com/user-attachments/assets/8b05dc5d-64ae-42bb-98cb-942ef1856c96"
/>

Variant 1 (never rebuild same code twice - remote cache in footer):
<img width="1392" height="970" alt="variant_1"
src="https://github.com/user-attachments/assets/eac6bdab-9c7d-41b7-a110-fa73ed188c67"
/>

Variant 2 (speed up CI and mention providers - remote caching in
footer):
<img width="1392" height="1004" alt="variant_2"
src="https://github.com/user-attachments/assets/c962a408-c4b5-4b68-8d79-5cc046841316"
/>

## Related Issue(s)

Fixes NXC-4190
2026-04-02 13:04:36 -04:00
Jason Jean a9cfce55be feat(repo): enforce no-disabled-tests via ESLint with per-project warning caps (#35122)
## Current Behavior

Disabled tests (`.skip()`, `.todo()`, `xit()`, `xdescribe()`, `xtest()`)
can be committed freely with no guardrails. Over time this leads to
tests silently rotting — there are currently ~65 disabled tests across
the workspace.

## Expected Behavior

ESLint warns on any disabled test via `jest/no-disabled-tests`, and
`--max-warnings` caps prevent the count from growing.

### How it works

The setup is like a ratchet — existing disabled tests are grandfathered
at their current counts, but adding new ones fails lint:

- **Global default**: `max-warnings: 5` in `nx.json` target defaults —
covers most projects
- **Per-project overrides** for projects that exceed 5, capped at their
current count:
  - `graph-client`: 15 (react-hooks/exhaustive-deps, unused-vars)
- `e2e-angular`: 9, `e2e-react`: 10, `e2e-next`: 8, `e2e-node`: 6,
`e2e-storybook`: 6
  - `nx-dev-feature-package-schema-viewer`: 7, `nx-dev-ui-markdoc`: 7
- **e2e `.eslintrc.json` files** only un-ignore test files (`*.test.ts`,
`*.spec.ts`) to avoid exposing unrelated lint errors in non-test code

### Changes

- Install `eslint-plugin-jest` and add `jest/no-disabled-tests: warn` to
root `.eslintrc.json` for test file overrides
- Add `.eslintrc.json` to 15 e2e projects
- Set `max-warnings: 5` globally and per-project overrides where needed
- Ignore Maven `target/` build output from linting
2026-04-02 12:58:10 -04:00
Louie Weng ea3450b4b8 chore(gradle): add OpenTelemetry tracing to project graph plugin (#35140)
## Current Behavior

The Gradle project graph plugin (`dev.nx.gradle.project-graph`) has no
observability into where time is spent during project graph generation.
When users report slow `nx show projects` or project graph resolution,
there is no way to identify bottlenecks in the Kotlin plugin code.

## Expected Behavior

The plugin now has opt-in OpenTelemetry distributed tracing. When
`OTEL_EXPORTER_OTLP_ENDPOINT` is set, spans are created for key
operations and exported via OTLP/gRPC to any compatible collector
(Jaeger, Grafana Tempo, etc.). When the env var is not set, tracing is
completely no-op with zero overhead.

Run any Nx command that triggers Gradle project graph generation:
   ```bash
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 pnpm nx show projects
   ```

## Related Issue(s)

N/A — internal observability improvement for debugging Gradle project
graph performance.
2026-04-02 12:43:27 -04:00
Parker Norwood 8b7e277774 fix(js): resolve ENOWORKSPACES test error in setupVerdaccio for @nx/js:library generator (#34755) 2026-04-02 10:53:20 -04:00
Leosvel Pérez Espinosa be8c579b28 chore(repo): remove redundant tsc command from workspace-plugin build (#35146)
## Current Behavior

The `workspace-plugin:build` target explicitly runs `tsc --build
tsconfig.lib.json`, which is the same command the inferred `build-base`
target runs. Since `build` depends on `build-base`, tsc runs twice — the
second time finding nothing to do.

The `nx` package was listed as a dependency but is only referenced in
generator template files, not in compiled source.

## Expected Behavior

- The `build` target is a pure dependency orchestrator with no command.
`build-base` (inferred by `@nx/js/typescript`) handles the actual
compilation.
- The `@nx/dependency-checks` rule is configured with `buildTargets:
["build-base"]` to align with all other packages in the repo.
- The `nx` package is removed from dependencies since it's not imported
in any source file.
2026-04-02 08:47:50 -04:00
Craigory Coppola 51f9d3e4e2 chore(core): adjust error when trying to resolve a migration and hitting a previous version (#35107)
## Current Behavior
If a user has `overrides` set for the `nx` package, we error with
"cannot find the implementation of xxx" if the override pins nx to a
version prior to that migration's inclusion.

## Expected Behavior
We point out the `overrides` field for easier debugging

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-02 07:13:33 -04:00
Jason Jean facec58e57 fix(misc): use workspace root for package manager detection and normalize paths in plugins (#35116)
## Current Behavior

Two issues in plugin code:

1. **Package manager detection at module scope**:
`getPackageManagerCommand()` is called at module level in all 18 plugin
files. This detects the package manager based on the CWD or
`npm_config_user_agent` at import time, rather than using the actual
workspace root. This produces inconsistent `pmc.exec` commands (e.g.
`pnpm exec` vs `npx`) depending on how the process was invoked.

2. **Platform-dependent paths in target configs**: Plugins use
`path.join()` and `path.relative()` to build target configuration values
(outputs, commands, env vars). On Windows this produces backslashes,
making the project graph differ between platforms.

## Expected Behavior

1. Package manager detection uses `context.workspaceRoot` from the
`createNodes` callback, then passes `pmc` down to per-project
target-building functions.
2. All paths in target configs use forward slashes regardless of OS,
using `joinPathFragments` and `normalizePath` from `@nx/devkit`.

## Changes

**Plugin source (20 files):**
- All 18 plugin files: moved `getPackageManagerCommand()` from module
scope into the `createNodes` callback where `context.workspaceRoot` is
available
- `packages/playwright/src/plugins/plugin.ts`: replaced
`path.join`/`posix.join`/`posix.relative` with
`joinPathFragments`/`normalizePath` for target config paths
- `packages/webpack/src/plugins/plugin.ts`,
`packages/vite/src/plugins/plugin.ts`,
`packages/vitest/src/plugins/plugin.ts`,
`packages/nuxt/src/plugins/plugin.ts`: replaced `path.join` with
`joinPathFragments` in `normalizeOutputPath()`, added `normalizePath`
for relative test paths

**Tests (19 files):**
- Added `package-lock.json` to TempFs dirs for deterministic package
manager detection
- Converted next/nuxt root project tests from `workspaceRoot: ''` to
TempFs-based setup
- Fixed all backslash path separators in snapshots and inline snapshots

## Related Issue(s)

<!-- No specific issue — discovered during test debugging -->
2026-04-01 19:07:32 -04:00
Steven Nance 3a2d17ec71 fix(core): display actual error message when plugin loading fails (#35138)
## Current Behavior

When a workspace-local Nx plugin cannot be resolved (e.g., the
`node_modules` symlink for a workspace package is missing), the error
message displays `[object Object]` instead of the underlying module
resolution error:

```
NX   Failed to load 1 Nx plugin(s):

  - @repro/my-plugin/plugin: [object Object]
```

This happens because plugin workers serialize errors as plain objects
via `createSerializableError()`. When these serialized errors are
received back in the parent process, the `instanceof Error` check fails,
and `String(reason)` on a plain object produces `[object Object]`.

## Expected Behavior

The actual error message is displayed:

```
NX   Failed to load 1 Nx plugin(s):

  - @repro/my-plugin/plugin: Cannot find module '@repro/my-plugin/plugin'
```

The fix adds a `reasonToError` helper that checks for an object with a
`message` property (serialized error) before falling back to `String()`
conversion. This properly handles:
- Real `Error` instances (unchanged behavior)
- Serialized error objects from plugin workers (now extracts `message`
and `stack`)
- Other non-error rejection reasons (unchanged `String()` fallback)

## Screenshot of fix
<img width="972" height="244" alt="image"
src="https://github.com/user-attachments/assets/ca87d9a6-43a4-4fd4-a215-71277f6dcc8b"
/>


## Related Issue(s)

Fixes #35137
2026-04-01 22:42:14 +00:00
Leosvel Pérez Espinosa 887fca4ac8 fix(repo): narrow copy-assets outputs to prevent overlap with build-base (#35097)
## Current Behavior

Broad globs in `assets.json` (`**/*.json`, `**/*.js`, `**/*.d.ts`) cause
`copy-assets` targets to claim cache ownership over files also produced
by `build-base` (tsc). Even though a recent change reordered
`copy-assets` to run before `build-base` (reducing the likelihood of the
race condition), the underlying task ownership model is still broken —
both targets claim overlapping files in their output patterns.

## Expected Behavior

Each target exclusively owns its output files. `copy-assets` only claims
non-tsc assets (templates, type declarations, native artifacts), and
`build-base` owns all compiler outputs.

## Changes

**37 `assets.json` files** — replaced broad extension globs with narrow,
destination-safe patterns: template dirs (`**/files/**`), schema type
declarations (`src/**/schema.d.ts`), non-tsc extensions (`.jar`,
`.node`, `.wasm`, `.md`), and explicit file paths for package-specific
assets.

**30 `tsconfig.lib.json` files** — removed `**/*.json` from `include` so
tsc only compiles TypeScript. JSON files are now handled by copy-assets
with explicit entries
(`@(package|executors|generators|migrations).json`,
`src/**/schema.json`).

**Exception:** jest and vite use `import('./schema.json')` which
requires JSON in tsconfig scope with `composite: true`. These keep
`src/**/schema.json` in tsconfig.

**vite** — excludes `test-utils.ts` from lib build (only used by specs)
and includes it in `tsconfig.spec.json`.
2026-04-01 17:56:09 -04:00
Leosvel Pérez Espinosa d2642e13da fix(core): improve migrate error reporting (#34980)
## Current Behavior

`nx migrate` can hide the actual package manager failure behind parent
wrapper noise, and invalid migration metadata can lead to confusing
follow-up failures.

## Expected Behavior

`nx migrate` should surface the underlying fallback install error
clearly, avoid noisy parent-level wrapper failures, and only fail on
invalid migration metadata when the invalid update is actually consumed.
2026-04-01 17:49:19 -04:00
Leosvel Pérez Espinosa 0d0cb3ddc8 fix(core): copy pnpm install configuration to generated package.json (#35016)
## Current Behavior

The generated package.json (used for deployment) only copies
`pnpm.overrides` from the root package.json. Other pnpm fields that
affect `pnpm install` behavior are missing, causing issues like
lifecycle scripts not running (pnpm v10+) or wrong platform-specific
dependencies being installed.

## Expected Behavior

All pnpm configuration fields that affect `pnpm install` in a deployment
context should be copied to the generated package.json:

- `onlyBuiltDependencies` — allowlist for lifecycle scripts (pnpm v10
requirement)
- `neverBuiltDependencies` — denylist for lifecycle scripts
- `allowBuilds` — unified replacement for the above two (pnpm 10.26+)
- `supportedArchitectures` — platform-specific dependency selection
- `ignoredOptionalDependencies` — skip optional dependencies

## Related Issue(s)

Fixes #30240

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: leosvelperez <leosvelperez@users.noreply.github.com>
2026-04-01 17:43:25 -04:00
MaxKless d579fbfb6f fix(core): clean up legacy .gemini/skills during configure-ai-agents (#35117)
## Current Behavior

When `configure-ai-agents` runs for Gemini, it copies skills to the
shared `.agents/skills` directory (used by Codex, Cursor, and Gemini).
However, workspaces that were configured with an older version of Nx
still have a `.gemini/skills` directory containing duplicate Nx-managed
skills. These legacy files are never cleaned up, leaving stale
duplicates in the workspace.

## Expected Behavior

When `configure-ai-agents` runs for Gemini, it should remove any
`.gemini/skills` entries that also exist in `.agents/skills` (indicating
they are Nx-managed skills that have been migrated). User-created custom
skills in `.gemini/skills` that have no counterpart in `.agents/skills`
are preserved.

## Related Issue(s)

N/A — discovered during investigation of template repo AI agent
configurations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-01 17:03:48 -04:00
Jason Jean 0a0d43e6df fix(repo): correct build target outputs for docker and vue packages (#35136)
## Current Behavior

- The `docker` package has its build output path pointing to
`{workspaceRoot}/build/packages/docker/README.md`, but the
`copy-readme.js` script writes to `dist/packages/docker/README.md`. This
means the cache output doesn't match the actual output location.
- The `vue` package has an empty build target (`{}`) with no README copy
step, unlike every other publishable package.

## Expected Behavior

- The `docker` package output path correctly points to
`{workspaceRoot}/dist/packages/docker/README.md`.
- The `vue` package has a proper build target that copies and processes
the README, matching the pattern used by all other packages.

## Related Issue(s)

N/A — found during audit of build target outputs.
2026-04-01 20:36:48 +00:00
Leosvel Pérez Espinosa 37eb4ecde4 fix(bundling): bump esbuild for new projects to a version compatible with vite 8 (#35132)
## Current Behavior

Newly generated JS/esbuild-based projects still default `esbuild` to
`^0.19.2`. That conflicts with Vite 8 which requires `esbuild ^0.27.0`.

## Expected Behavior

Newly generated projects should default to an `esbuild` version
compatible with Vite 8. If a workspace already has `esbuild` installed,
generators should preserve that version instead of blindly bumping it,
and Vite init should fall back to Vite 7 with a warning when the
installed `esbuild` range is incompatible with Vite 8.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-04-01 16:23:42 -04:00
Leosvel Pérez Espinosa cbeedca9e5 chore(repo): add root tsconfig.json to nx-dev-e2e lint inputs (#35130)
## Current Behavior

`nx-dev-e2e` has no `tsconfig.json`. When `eslint .` runs,
`@typescript-eslint/parser` walks up from the project root to the
workspace root `tsconfig.json`. This read is not declared as a lint
input, causing a sandbox violation.

## Expected Behavior

A minimal `tsconfig.json` extending `tsconfig.base.json` exists in the
project, so the parser resolves locally and the sandbox violation is
eliminated.

## Why not fix in the `@nx/eslint/plugin`?

The plugin would need to resolve the ESLint config chain, identify which
parser is in use, and replicate that parser's tsconfig resolution logic
(walking up directories, following `extends` chains). This adds file I/O
and config parsing to `createNodesV2`, which runs on the critical path
during project graph computation — every `nx` command pays the cost. Not
worth it for an edge case that only surfaces when a project has no local
tsconfig.

## Why not an input override?

An input override in `project.json` would duplicate the plugin's
inferred inputs and could drift if the plugin changes what it infers in
the future.
2026-04-01 13:30:53 -04:00
Leosvel Pérez Espinosa 788c8dd2a5 fix(repo): clean Angular CLI restore target before cache copy (#35121)
## Current Behavior

Nightly `e2e-nx-init` runs can fail when the Angular CLI legacy suite
restores a cached workspace into an already-existing temp project
directory. With `NX_E2E_SKIP_CLEANUP=true`, the previous test workspace
is intentionally left on disk, and `fs-extra.copySync` then hits
symlinked `node_modules/.bin` entries and aborts with errors like
`Cannot copy '../which/bin/which.js' to a subdirectory of itself`.

## Expected Behavior

Restoring the cached Angular CLI workspace should be idempotent even
when cleanup is skipped between tests. The restore step should start
from a clean target directory so the suite can reuse the cached baseline
without tripping over stale symlinks from the previous test run.

## Related Issue(s)

No tracked issue. Investigated from nightly GitHub Actions run
`23833817151`.

Validation:
- `pnpm nx typecheck e2e-nx-init`
- Focused local repro on macOS/npm with `NX_E2E_SKIP_CLEANUP=true`
failing before the change and passing after it
2026-04-01 12:40:48 -04:00
Jack Hsu 49a0e3f69e fix(js): use explicit nx/bin/nx path in start-local-registry (#35127)
## Current Behavior

`start-local-registry.ts` uses `require.resolve('nx')` to find the nx
CLI binary for forking a child process. This resolves the package's
`main` entry point, which only incidentally points to the binary. In
pnpm strict mode, this resolution fails when called from within `@nx/js`
because `@nx/js` doesn't declare `nx` as a direct dependency.

## Expected Behavior

Use `require.resolve('nx/bin/nx')` to explicitly resolve the CLI binary
entry point. This is semantically correct (the intent is to fork the nx
CLI) and doesn't rely on the `main` field or pnpm hoisting behavior.
2026-04-01 16:27:27 +00:00
Jack Hsu 7838f73b27 docs(js): use require.resolve('nx/bin/nx') which is more reliable (#35129)
`require.resolve('nx)` can fail for a number of reasons:
- If `./nx` exists, it'll resolve to that first, and fail
- If module resolution is set differently it may resolve to the index
file, or something unexpected
2026-04-01 11:58:16 -04:00
Craigory Coppola b05e9c0909 chore(repo): update preinstall to vary message based on mise status (#35128)
## Current Behavior
pre-install says rust isn't available if mise isn't trusting the dir,
but doesn't mention mise and suggests installing rust. This can trip up
AI agents if they see the output and think rust should be installed

## Expected Behavior
Error message mentions mise

## Notes

This pull request significantly refactors and improves the
`scripts/preinstall.js` dependency check script. The script now performs
more robust version checks for Node, pnpm, and Rust, and adds support
for detecting and guiding users regarding `mise` trust status. The
refactoring also improves maintainability by modularizing checks and
error handling.

**Dependency checks and error handling:**

* Refactored version checks for Node, pnpm, and Rust into separate
functions for better readability and maintainability.
* Improved error messages and guidance, including specific instructions
for updating or installing missing tools, and added checks for minimum
required versions (`Node 20.19.0+`, `pnpm 10.0.0+`, `Rust 1.70.0+`).

**Support for mise integration:**

* Added detection of `mise` installation and trust status, with user
guidance to run `mise trust` when the directory is untrusted and Rust is
missing or outdated.

**Codebase improvements:**

* Consolidated tool version gathering into a single `getToolData`
function and replaced repeated code with a reusable `execOrNull` helper.
* Changed process exit logic to only exit when errors are detected,
improving script robustness. (F43b11f
2026-04-01 11:43:46 -04:00
Leosvel Pérez Espinosa 61dc66d0ea chore(repo): add eslint config chain to lint-pnpm-lock inputs (#35125)
## Current Behavior

The `lint-pnpm-lock` task only declares `pnpm-lock.yaml` as input.
ESLint also reads its config chain (`.eslintrc.json`, `.eslintignore`),
`tsconfig.json`, and the custom rules plugin (`tools/eslint-rules/**`),
causing sandbox violations for 10 undeclared reads.

## Expected Behavior

All files ESLint needs are declared as inputs so sandbox reports no
violations for `@nx/nx-source:lint-pnpm-lock`.
2026-04-01 10:59:05 -04:00
Jason Jean 19bac461a2 fix(core): reduce published nx package size with files allowlist (#35109)
## Current Behavior

The `nx` npm package includes unnecessary files in the published
artifact:
- ~137 Rust source files (`.rs`) from `src/native/`
- Test fixtures, snapshots, and other dev-only files
- Duplicate source directories (`bin/`, `plugins/`, `schemas/`, etc.)
alongside their compiled `dist/` equivalents

The `.npmignore` blocklist approach missed several file types, and the
CI `.node` file cleanup (`find ./dist`) no longer works because the `nx`
package now builds to `packages/nx/dist/` instead of
`dist/packages/nx/`.

## Expected Behavior

- Only `dist/` and essential root JSON files (`migrations.json`,
`executors.json`, `generators.json`) are published
- No Rust source, test fixtures, snapshots, or duplicate source dirs in
the published package
- Native type declarations (`src/native/index.d.ts`) are copied to
`dist/` via `assets.json` so all exports reference `dist/` consistently
- CI correctly removes `.node` files from `packages/nx/dist/` before
publishing to npm

## Related Issue(s)

N/A — discovered during package audit.

---------

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2026-04-01 14:49:17 +00:00
Leosvel Pérez Espinosa 804b5abcb3 chore(misc): add dist to eslint ignorePatterns (#35124)
## Current Behavior

Packages that build to `{projectRoot}/dist` (`maven`, `dotnet`,
`angular-rspack-compiler`) use `!**/*` in their project-level
`.eslintrc.json` `ignorePatterns` to un-ignore dotfiles. This negation
also overrides the root config's `**/dist` ignore pattern, causing
`eslint .` to traverse and read build artifacts in `dist/` during
linting. This produces sandbox violations (46 unexpected reads for
`@nx/maven:lint`).

## Expected Behavior

ESLint skips the `dist/` directory during linting, matching the behavior
already in place for `packages/nx` and `packages/angular-rspack` which
explicitly re-ignore `dist` after the `!**/*` pattern.
2026-04-01 10:18:56 -04:00
Jack Hsu 2426941a88 docs(misc): add tutorial series ToC to all tutorial pages (#35120)
## Current Behavior

Tutorial pages are standalone with no visible series navigation. Path
analysis shows most users drop off after the first tutorial, even though
they generally follow the intended path.

## Expected Behavior

Each of the 8 tutorial pages now shows a "Tutorial Series" aside after
the intro paragraph, listing all tutorials with the current one bolded.
This makes the series feel connected while still allowing users to jump
around or skip as needed.

Additionally, prerequisites are standardized as plain paragraphs (not
asides) across all tutorial pages for a cleaner, less noisy layout.

<img width="971" height="816" alt="image"
src="https://github.com/user-attachments/assets/b5389d98-4809-4400-8f9f-ab9834caba94"
/>


## Related Issue(s)

Closes DOC-466

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2026-04-01 10:11:11 -04:00
Jack Hsu eeee05a72e chore(repo): fix inputs for CNW and CNP (#35123)
They don't specify the right inputs, so you will get the wrong bin file
whenever you build CNW and CNP.

The problem is ordering:

1. `build-base` runs → sees source change → compiles fresh
`bin/create-nx-workspace.js` into `dist/`
2. `build` runs next → checks inputs (`copyReadme`) → cache hit →
restores its cached outputs
3. That cached output includes the old `bin/create-nx-workspace.js`,
which overwrites the fresh one from step 1

So even though the `build-base` is compiling new source with `tsc`, the
`build` task overrides just the bin. This is for both CNW and CNP.
2026-04-01 10:10:27 -04:00
Jason Jean 4e003b7a20 chore(repo): update nx to 22.7.0-beta.9 (#35100)
Updating Nx from 22.7.0-beta.7 to 22.7.0-beta.9
2026-04-01 03:38:14 +00:00
Jason Jean 6962a3d7a1 chore(repo): skip react-router typecheck e2e test due to vite version conflict (#35110)
## Current Behavior

The react-router typecheck e2e test fails in CI because pnpm resolves
both vite 7 and vite 8 in the generated project. `@react-router/dev`
picks up vite 8 plugin types while `defineConfig` uses vite 7 types,
causing a TypeScript incompatibility.

## Expected Behavior

The test is skipped until `@react-router/dev` adds Vite 8 support, at
which point the `useViteV7` workaround and this skip can both be
removed.

## Related Issue(s)

Follow-up to #35101
2026-04-01 01:38:20 +00:00
Craigory Coppola a5523d2c52 fix(core): no-interactive should disable prompts during migrate (#35106)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2026-03-31 19:42:13 -04:00
Jason Jean bd463d055c fix(core): restore metadata table for telemetry session tracking (#35099)
## Current Behavior

Telemetry initialization fails with `no such table: metadata` because
the metadata table was removed during the DB schema refactor that
decoupled DB version from Nx version. The telemetry service depends on
this table to store and retrieve session IDs for analytics tracking.

## Expected Behavior

The metadata table is created as part of DB initialization alongside the
other tables (`task_details`, `running_tasks`, `task_history`).
Telemetry session tracking works without errors. The DB version is
bumped from `1` to `2` so existing databases without the table are
recreated with the correct schema.

### Changes

- Add metadata table creation to `create_all_tables` in `initialize.rs`
- Bump `DB_VERSION` from `1` to `2` to trigger fresh DB creation for
users with v1 databases
- Widen `initialize` module and `initialize_db` visibility to
`pub(crate)` for testability
- Add regression tests in `telemetry/mod.rs` that verify the session
query works against a freshly initialized DB and that session
persist/retrieve round-trips correctly
- Refactor `initialize.rs` tests to use `NxDbConnection` instead of raw
rusqlite `Connection`

## Related Issue(s)

<!-- No open issue for this bug -->
2026-03-31 19:40:51 -04:00
Jason Jean 7c3df37845 fix(repo): re-enable Cypress HMR e2e tests after upstream tapable fix (#35105)
## Current Behavior

Six e2e tests were skipped in #34969 because they were failing with a
Cypress uncaught exception: `[HMR] Hot Module Replacement is disabled`.
The error originated from the webpack `styles.js` bundle during the
`before each` hook due to an upstream tapable issue
(webpack/webpack#20693).

Skipped tests:
- `e2e-nx:e2e-ci--src/workspace-legacy.test.ts`
-
`e2e-react:e2e-ci--src/module-federation/independent-deployability.webpack.test.ts`
-
`e2e-react:e2e-ci--src/module-federation/core-webpack-basic-host-remote-generation.test.ts`
-
`e2e-react:e2e-ci--src/module-federation/misc-rspack-interoperability.test.ts`
-
`e2e-react:e2e-ci--src/module-federation/dynamic-federation.webpack.test.ts`
-
`e2e-react:e2e-ci--src/module-federation/federate-module.webpack.test.ts`

## Expected Behavior

The upstream tapable issue has been resolved (webpack/webpack#20693).
All 6 tests should be re-enabled and passing.

## Related Issue(s)

Upstream fix: webpack/webpack#20693
Reverts the skip from #34969
2026-03-31 19:32:34 -04:00
Louie Weng 2630420dc5 chore(gradle): bump gradle project graph plugin version to 0.1.18 (#35091)
## Current Behavior

The Gradle project graph plugin is at version 0.1.17.

## Expected Behavior

The Gradle project graph plugin is bumped to version 0.1.18 with a
corresponding migration entry at version 22.7.0-beta.9

## Related Issue(s)

N/A - routine version bump
2026-03-31 17:41:38 -04:00
Jack Hsu 9dce32118c chore(repo): skip tests failing due to bad lodash@4.18.0 for now (#35104)
Unblock PRs and re-enable once lodash is patched.
2026-03-31 17:25:33 -04:00
Jason Jean fa7eb3b442 chore(repo): make build-base depend on copy-assets instead of reverse (#35102)
## Current Behavior

`copy-assets` depends on `build-base`, which means it has to wait for
the entire `build-native` → `build-base` chain to finish before it can
start — even though asset copying doesn't need compiled output.

## Expected Behavior

`build-base` depends on `copy-assets` instead. This lets `copy-assets`
start immediately (in parallel with `build-native` and `^build-base`)
rather than waiting for them to complete first.

<img width="767" height="721" alt="image"
src="https://github.com/user-attachments/assets/6a1d8090-8390-4075-850e-bfd309cdc6c9"
/>


### Changes

- Removed `dependsOn: ['build-base']` from the `copy-assets` target
generated by `copy-assets-plugin.ts`
- Added `copy-assets` to `build-base.dependsOn` in `nx.json` and
project-level overrides (`gradle`)
- Removed now-transitive `copy-assets` references from `build.dependsOn`
in `nx.json`, `packages/nx`, `packages/angular`, and `packages/gradle`
- Removed `build-base` from `copy-assets.dependsOn` in `packages/nx` and
`packages/dotnet` project overrides

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-03-31 16:24:14 -04:00
Louie Weng f9e5564781 fix(gradle): detect @Input provider-based dependencies (#35090)
## Current Behavior

When Kotlin compilations are associated (e.g. test -> main), the
`friendPathsSet` `@Input` provider creates implicit dependencies on
producer tasks like `compileKotlin`, `compileJava`, and `jar`. Without
detecting these, Nx excludes them via `--exclude-task`, causing a
provider resolution error at execution time when Gradle tries to resolve
the `friendPathsSet` provider.

The previous implementation only detected lifecycle-based provider
dependencies (Phase 1), missing the `@Input` property-based ones.

## Expected Behavior

`findProviderBasedDependencies` now detects both:
1. **Lifecycle dependencies** — `ProviderInternal` and `TaskProvider`
entries in `lifecycleDependencies` (e.g.
`checkKotlinGradlePluginConfigurationErrors`)
2. **`@Input` property dependencies** — producer tasks discovered by
walking task properties with Gradle's `PropertyWalker` +
`PropertyVisitor`, resolving `taskDependencies` from each `@Input`
`PropertyValue` (e.g. `compileKotlin`, `compileJava`, `jar`)

These tasks are added to `includeDependsOnTasks` so they are not
excluded from Gradle execution.

The function is refactored into two immutable collectors
(`collectLifecycleDependencies` and `collectInputPropertyDependencies`)
merged in the parent, replacing the previous mutable-set-passing
pattern.

## Related Issue(s)

Fixes NXC-4174
2026-03-31 13:09:30 -07:00
Craigory Coppola d063b1a4d5 fix(repo): fixup lock-threads failing with resource inaccessible message (#35005)
## Current Behavior
Every lock threads run is failing

## Expected Behavior
Lock threads at least occasionally passes

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

Fixes #
2026-03-31 15:59:52 -04:00
Jack Hsu 2cfc2898a7 fix(react): force Vite 7 when using React Router in framework mode (#35101)
## Current Behavior

Creating a custom React workspace with React Router for server rendering
(framework mode) fails due to a peer dependency conflict between Vite 8
and React Router. Vite 8 is the current default for new workspaces, but
`@react-router/dev` does not yet support it.

## Expected Behavior

The React application generator uses Vite 7 when React Router is
selected, avoiding the peer dependency conflict until React Router adds
Vite 8 support.

<img width="1270" height="1204" alt="image"
src="https://github.com/user-attachments/assets/87495e85-20df-4086-a1f0-eb3380a78771"
/>


## Related Issue(s)

Fixes NXC-4176
2026-03-31 13:32:14 -04:00
Robert Sidzinka 63a8f27e82 fix(webpack): bump postcss-loader to ^8.2.1 to eliminate transitive yaml@1.x CVE (#35028)
## Current Behavior

`@nx/webpack` depends on `postcss-loader@^6.1.1`, which pulls in
`cosmiconfig@7` → `yaml@1.x`. The `yaml@1.x` package has a known stack
overflow vulnerability
([GHSA-48c2-rrv3-qjmp](https://github.com/advisories/GHSA-48c2-rrv3-qjmp)).

## Expected Behavior

By bumping `postcss-loader` to `^8.2.1`, the transitive dependency chain
is eliminated entirely — `postcss-loader@8` uses `cosmiconfig@9`, which
no longer depends on `yaml` at all. This is a cleaner fix than applying
a `pnpm.overrides` workaround.

The upgrade is safe because:
- `postcss-loader@8` peer deps (`postcss ^7||^8`, `webpack ^5`) are
unchanged
- The `implementation` option and function-based `postcssOptions` API
used by `@nx/webpack` are fully supported in v8
- Nx already requires Node 18+, matching postcss-loader@8's engine
requirement

## Related Issue(s)

Fixes #35025
2026-03-31 11:26:07 -04:00
Jason Jean c59040f340 fix(core): sandbox exclusions, multi-line typeof import detection, global ensurePackage mock (#35056)
## Current Behavior

1. **Sandboxing false positives**: `tsc --build` reads `.tsbuildinfo`
files as an optimization hint, and the `nx-plugin-checks` lint rule
reads `schema.json` from `dist/` directories. Both are flagged as
sandbox violations even though they don't affect caching correctness.

2. **Missing dependencies in project graph**: `typeof import('...')`
inside multi-line generic type parameters (e.g. `ensurePackage<typeof
import('@nx/playwright')>()`) is not detected by the import analyzer.
The newline between `<` and `import()` resets the import type to
Dynamic, so packages like `@nx/playwright` and `@nx/storybook` are
missing from the dependency graph.

3. **ensurePackage mock duplication**: Multiple test files individually
mock `@nx/devkit` just to override `ensurePackage` so it resolves from
source instead of `node_modules`. This is repetitive and easy to miss in
new tests.

## Expected Behavior

1. **Sandboxing**: `.tsbuildinfo` reads are globally excluded.
`dist/**/*.json` reads are excluded for lint targets.

2. **Import analyzer**: `typeof import('...')` inside multi-line
generics is correctly detected as a static import by tracking angle
bracket depth and preserving import type across newlines inside
generics.

3. **ensurePackage mock**: A global `ensurePackage` mock in
`scripts/unit-test-setup.js` replaces per-file mocks, using
`jest.requireActual` to resolve from source code.

## Related Issue(s)

<!-- No directly related open issues found -->

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-31 11:25:16 -04:00
Leosvel Pérez Espinosa 424dabbbd7 fix(core): restore nx package exports compatibility (#35095)
## Current Behavior

The `nx` package's `exports` field uses conditional exports that
restrict subpath access. Consumers relying on deep imports (e.g.,
`nx/src/command-line`, `nx/src/project-graph/plugins`) or importing with
file extensions (e.g., `nx/bin/nx.js`) can't resolve modules or types.
The `typesVersions` field is also incomplete and out of sync with
`exports`, breaking type resolution for consumers using
`moduleResolution: "node"` (node10).

## Expected Behavior

The `nx` package exposes all necessary subpaths through both `exports`
(for modern resolution) and `typesVersions` (for node10 resolution),
keeping them in sync. A new conformance rule prevents future drift
between the two fields.

> **Note:** This restores backwards compatibility to avoid breaking
changes in the current major version. Deep imports into `nx/src/*`
access private/internal APIs that are not part of the public contract —
they are not guaranteed to be stable and may break without notice. In Nx
v23, we plan to constrain the exports to a well-defined public API,
which will be a breaking change.

## Changes

- **Restore `nx` package exports**: expand `exports` and `typesVersions`
to cover all public subpaths including `bin/*`, `plugins/*`,
`src/command-line`, `src/project-graph/plugins`, `release/*`,
`tasks-runners/*`, and their `.js` extension variants
- **Add `types-versions-exports-sync` conformance rule**: enforces that
every `exports` entry with a `types` condition has a corresponding
`typesVersions` entry and vice versa, preventing future drift
2026-03-31 17:11:47 +02:00
Leosvel Pérez Espinosa 77a119a021 fix(core): preserve sibling dependency inputs in native hashing (#35071) 2026-03-31 10:20:24 -04:00
Miroslav Jonaš 43a108e6df docs(nx-dev): replace nx-cloud calls with nx wrapper in docs (#35094)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: meeroslav <meeroslav@users.noreply.github.com>
2026-03-31 15:17:02 +02:00
Miroslav Jonaš 5b8cd7336f fix(core): pin version of axios (#35093)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-31 15:15:43 +02:00
Jason Jean b1d8db3938 fix(js): include tsbuildinfo in narrowed tsc build-base outputs (#35086)
## Current Behavior

PR #35041 narrowed the `build-base` target outputs to only match
tsc-produced file types (e.g. `**/*.{js,d.ts,...}{,.map}`), preventing
cross-OS cache pollution from native binaries. However, `.tsbuildinfo`
files were not included in the narrowed glob, so they are no longer
captured as build outputs. The tsbuildinfo handling was also spread
across multiple conditional branches with duplicated logic.

## Expected Behavior

`.tsbuildinfo` files are always included as a build output since `tsc
--build` implicitly enables `incremental: true` and always produces
them. A new `getTsBuildInfoOutputPath` helper centralizes the logic for
determining the tsbuildinfo file location (respecting `tsBuildInfoFile`,
`outFile`, `outDir`, or the default), and is called once unconditionally
at the end of the output resolution loop.

## Related Issue(s)

Follow-up to #35041
2026-03-31 09:32:34 +02:00
Louie Weng 8a77a08890 fix(gradle): use object notation for exclude tasks (#35085)
<!-- 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 executor's task exclusion logic represents running tasks and
dependency relationships using colon-delimited string IDs (e.g.
"project:target"). Parsing task identity by splitting on : breaks
silently when project or target names contain colons — a common pattern
in Gradle (e.g. :sub:project, compile:java).
## Expected Behavior     

Task identity is represented as a structured ProjectTarget object with
explicit project and target fields, eliminating string-splitting
ambiguity. The getExcludeTasks, getAllDependsOn, and getGradleTaskName
functions now accept and return typed objects, and test fixtures use
object-notation dependsOn entries. A new test case verifies correct
behavior when names contain colons.

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: lourw <lourw@users.noreply.github.com>
2026-03-30 18:17:07 -07:00
Jamie Mason d24aa1a0ce docs(misc): add link to syncpack documentation (#35084)
Hey all,
Thanks a lot for mentioning [syncpack](https://syncpack.dev/) in the
[Managing
Dependencies](https://nx.dev/docs/getting-started/tutorials/managing-dependencies)
tutorial, this PR asks if you would kindly add a link to the official
site 🙏

Thanks a lot,

Jamie
2026-03-30 14:15:02 -04:00
Jack Hsu b86d64119f chore(misc): rename vulnerable packages in test fixture lockfiles (#35072)
This PR removes 62% of dependabot alerts, stemming from unit test
fixtures.

## Current Behavior

Dependabot scans `package.json` files in lock-file test fixtures and
raises vulnerability alerts for packages that are only used as test data
(e.g. `express`, `minimatch`, `postcss`). These are not real
dependencies.

## Expected Behavior

Renaming fixture files from `package.json` to `package.fixture.json`
prevents dependabot from scanning them. The `.fixture.json` extension
still ends in `.json`, so Node's `require()` continues to work without
any test logic changes — only the file paths in the spec files needed
updating.

## Related Issue(s)

Fixes NXC-4169

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2026-03-30 13:47:55 -04:00
Jack Hsu fe5a463c15 feat(misc): update nx init telemetry meta from CSV to JSON format (#35076)
## Current Behavior

`nx init` emits telemetry meta as a CSV string (e.g. "22.6.3,enable-ci")
via `recordStat`, only at the cloud prompt step. There is no start or
error tracking, no AI detection, and no environment context.

## Expected Behavior

`recordStat` now accepts a typed `RecordStatMeta` object and serializes
as JSON, matching the CNW format. Three lifecycle events are recorded:

- **start**: nodeVersion, os, packageManager, aiAgent, isCI
- **complete**: same env info plus pluginsInstalled, useCloud
- **error**: errorCode, errorMessage, aiAgent

The existing cloud prompt `recordStat` calls also now include env info.

## Related Issue(s)

Closes NXC-4168
2026-03-30 12:12:20 -04:00
Jack Hsu d61123be47 fix(core): handle "." and absolute paths as workspace name in CNW (#35083)
## Current Behavior

CNW rejects "." and absolute paths (e.g. `/tmp/acme`) as workspace
names, causing over 1,300 INVALID_WORKSPACE_NAME and DIRECTORY_EXISTS
errors per month. This is the #1 input validation error for both AI
agents and humans.

## Expected Behavior

- "." and "./" in a non-empty directory suggests using `nx init` instead
- "." and "./" in an empty directory resolves to the directory's
basename and creates the workspace in-place
- Absolute paths like `/tmp/acme` extract the basename as the workspace
name and create the workspace at the specified location

The `workingDir` override is threaded through `CreateWorkspaceOptions`
to downstream functions (`createWorkspace`, `createEmptyWorkspace`,
`createPreset`, `cloneTemplate`) without mutating `process.cwd()`.

## Related Issue(s)

Closes NXC-4172
2026-03-30 12:12:11 -04:00
Jack Hsu 203203f238 fix(repo): bump picomatch from 4.0.2 to 4.0.4 (#35081)
## Current Behavior

The pnpm catalog pins picomatch to `4.0.2`, which has two high-severity
vulnerabilities:
-
[GHSA-3v7f-55p6-f55p](https://github.com/advisories/GHSA-3v7f-55p6-f55p)
— Method Injection in POSIX Character Classes causes incorrect glob
matching
-
[GHSA-c2c7-rcm5-vvqj](https://github.com/advisories/GHSA-c2c7-rcm5-vvqj)
— ReDoS via extglob quantifiers

Running `npm audit` on any workspace using `@nx/angular`, `@nx/js`, or
`@nx/workspace` reports these vulnerabilities.

## Expected Behavior

No picomatch-related vulnerabilities reported by `npm audit`. The bump
to `4.0.4` is a patch release that only fixes the security issues with
no API changes.

## Related Issue(s)

Fixes #35068
2026-03-30 12:09:55 -04:00
Jack Hsu 4b8b46b9e4 fix(vite): bump sass version for vue/nuxt presets for Vite 8 compat (#35073)
## Current Behavior

CNW vue-monorepo and nuxt presets pin sass@1.62.1, but Vite 8 requires
sass >= ^1.70.0, causing ERESOLVE failures on npm during workspace
creation.

## Expected Behavior

Workspaces created with vue-monorepo and nuxt presets install
successfully with Vite 8 by using a compatible sass version range.

## Related Issue(s)

Fixes NXC-4171
2026-03-30 11:33:23 -04:00
Jack Hsu a309e3181a fix(core): validate bundler option for Angular presets in create-nx-workspace (#35074)
## Current Behavior

When `--bundler=vite` is passed with an Angular preset
(`angular-monorepo` or `angular-standalone`), yargs accepts it since
`--bundler` is a shared `type: 'string'` option with no per-stack
`choices` constraint. The invalid value flows through to the preset
generator which rejects it after a full pnpm install (~25s), wasting the
user's time.

## Expected Behavior

Validate the bundler early in `determineAngularOptions` before any
install starts. Invalid bundlers throw `CnwError('INVALID_BUNDLER')` so
the error is:
- Properly recorded via `recordStat` for telemetry
- Surfaced as NDJSON for AI agents
- Shown as a clear `output.error()` for interactive users

Valid Angular bundlers: `esbuild`, `rspack`, `webpack`.

## Related Issue(s)

Fixes NXC-4166
2026-03-30 10:30:56 -04:00
Jason Jean 5de23860d3 feat(repo): enable tsgo compiler for nx package (#35047)
## Current Behavior

All packages in the workspace use the standard `tsc` compiler via the
`@nx/js/typescript` plugin.

## Expected Behavior

The `packages/nx` project uses the new Go-based TypeScript compiler
(`tsgo`) for faster builds and typechecks, while all other projects
continue using `tsc`.

### Changes
- Install `@typescript/native-preview` as a dev dependency
- Add a separate `@nx/js/typescript` plugin entry scoped to
`packages/nx` with `compiler: "tsgo"`
- Override `baseUrl: null` in the nx tsconfig to clear the inherited
`baseUrl` (removed in tsgo)
- Set `strict: false` to match existing tsc behavior (tsgo defaults to
strict mode)

## Related Issue(s)

N/A — exploratory adoption of tsgo

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-29 18:56:13 -04:00
Jason Jean 886d78dfb2 chore(repo): update nx to 22.7.0-beta.7 (#35065)
Updating Nx from 22.7.0-beta.6 to 22.7.0-beta.7

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-03-29 00:50:08 +00:00
Jack Hsu c9253fba67 fix(vite): update vitest and plugin-react-swc versions for vite 8 compat (#35062)
## Current Behavior

When creating a workspace with `create-nx-workspace` using presets that
install vitest (react-monorepo with vite bundler, nuxt with vitest, vue,
etc.) and **npm** as the package manager, `npm install` fails with
`ERESOLVE unable to resolve dependency tree`.

**Root cause:** vitest `~4.0.x` depends on `@vitest/mocker@4.0.x` which
has a peer dependency on `vite: "^6.0.0 || ^7.0.0"` — it does **not**
support vite 8. Since Nx now defaults to installing `vite@^8.0.0`, npm
cannot satisfy `@vitest/mocker`'s peer dependency.

Additionally, `@vitejs/plugin-react-swc@^3.5.0` has a peer dependency on
`vite: "^4 || ^5 || ^6 || ^7"` (no vite 8 support), and the SWC compiler
path in `ensure-dependencies.ts` lacks the vite-version detection logic
that the babel path already has.

## Expected Behavior

- Workspaces using vite 8 + vitest install successfully with npm
- `@vitejs/plugin-react-swc` version is selected based on the installed
vite version (v4.3+ for vite 8, v3.x for older vite)

## Changes

1. **Bump `vitestV4Version`** from `~4.0.0`/`~4.0.8` to `~4.1.0` in both
`@nx/vite` and `@nx/vitest` — vitest 4.1.x's dependencies support vite 8
2. **Bump `vitestV4CoverageV8Version` and
`vitestV4CoverageIstanbulVersion`** to `~4.1.0` to match
3. **Update `vitePluginReactSwcVersion`** from `^3.5.0` to `^4.3.0`
(first version with vite 8 peer dep support), add
`vitePluginReactSwcV3Version = '^3.5.0'` for backward compat
4. **Add vite-version detection** to the SWC path in
`ensure-dependencies.ts` (both `@nx/vite` and `@nx/vitest`), mirroring
the existing babel path logic

## Related Issue(s)

Fixes NXC-4164
2026-03-28 12:28:35 -04:00
Jason Jean 87a7c921b1 fix(repo): pass env vars into docker builds in publish workflow (#35060)
## Current Behavior

The `publish.yml` workflow defines `NX_GRADLE_PROJECT_GRAPH_TIMEOUT` and
`NX_VERBOSE_LOGGING` as workflow-level env vars, but the `docker run`
command for Linux native builds only passes `-e PNPM_VERSION`. This
means those env vars are not available inside the Docker containers,
causing Gradle timeouts and missing verbose logs during publish.

## Expected Behavior

`NX_GRADLE_PROJECT_GRAPH_TIMEOUT` and `NX_VERBOSE_LOGGING` are passed
into the Docker containers via `-e` flags so they take effect during
Linux native builds.

## Related Issue(s)

N/A
2026-03-28 16:04:12 +00:00
Jason Jean 439fa7308a chore(repo): fix critical handlebars and underscore vulnerabilities in npm audit (#35063)
## Current Behavior

The npm security audit CI job fails due to two critical vulnerabilities:
- **handlebars** (GHSA-2w6w-674q-4c4q): JavaScript Injection via AST
Type Confusion in versions `>=4.0.0 <=4.7.8`, pulled in transitively via
`verdaccio > @verdaccio/hooks > handlebars@4.7.7`
- **underscore** (GHSA-cf4h-3jhx-xvhq): Arbitrary Code Execution in
versions `<1.13.8`, pulled in via `parse-markdown-links > remarkable >
argparse > underscore`

## Expected Behavior

The npm security audit CI job passes with zero critical vulnerabilities.

## Changes

- Update `verdaccio` from `6.0.5` to `6.3.2` (drops direct handlebars
dependency)
- Remove unused direct `handlebars` devDependency (nothing in the repo
imports it)
- Add `pnpm.overrides` for `handlebars@4.7.9` (needed because
`@verdaccio/hooks` still pins `handlebars@4.7.7` with no stable fix
available) and `underscore@^1.13.8` (needed because
`parse-markdown-links` pins `remarkable@1.7.1` with no fix available)
- Update verdaccio generator version to `^6.3.2` so new workspaces get
the safe version
- Add migration for `22.6.4` to bump verdaccio in existing workspaces

## Related Issue(s)

Fixes the failing [npm-audit CI
job](https://github.com/nrwl/nx/actions/runs/23672915671/job/68970040091)
2026-03-28 14:44:04 +00:00
Jason Jean 9a0ac75974 fix(gradle): increase project graph timeout defaults (#35058)
## Current Behavior

The Gradle plugin's `createNodes` project graph generation has a fixed
60-second timeout. For large Gradle workspaces, this is too short and
causes timeouts — especially in CI environments where builds may be
slower.

## Expected Behavior

- **Local**: Default timeout increased to 3 minutes (180s)
- **CI**: Default timeout increased to 10 minutes (600s)
- The `NX_GRADLE_PROJECT_GRAPH_TIMEOUT` env var still works as an
override
- The publish workflow explicitly sets
`NX_GRADLE_PROJECT_GRAPH_TIMEOUT=600` for extra safety
2026-03-28 03:49:30 +00:00
Jason Jean f39f30417a fix(js): narrow tsc build-base outputs to only tsc-produced file types (#35041)
## Current Behavior

The `@nx/js/typescript` plugin claims the entire `outDir` (e.g.
`{projectRoot}/dist`) as the output for `build-base` targets. When other
tasks like `copy-assets` also write into the same directory (e.g.
`.node` or `.wasm` native binaries), those files get captured in the
`build-base` cache. This causes cross-OS cache pollution — linux native
binaries get cached and restored on macOS (or vice versa).

## Expected Behavior

`build-base` outputs are scoped to only the file types that `tsc`
actually produces:
- `**/*.{js,cjs,mjs,jsx,d.ts,d.cts,d.mts}{,.map}` (default)
- `**/*.{js,cjs,mjs,jsx,json,d.ts,d.cts,d.mts}{,.map}` (when
`resolveJsonModule` is enabled)

Native binaries (`.node`, `.wasm`) and other non-tsc files in the same
output directory are no longer captured by the `build-base` cache,
preventing cross-OS cache corruption.

## Related Issue(s)

N/A — discovered during investigation of cross-OS cache artifacts.
2026-03-27 22:22:40 +00:00
Jason Jean ff351f7294 chore(repo): update nx to 22.7.0-beta.6 (#35031)
Updating Nx from 22.7.0-beta.4 to 22.7.0-beta.6

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-03-27 20:53:58 +00:00
Jason Jean 1d01a675e4 fix(js): recognize tsgo in dependency-checks lint rule (#35048)
## Current Behavior

The `@nx/dependency-checks` lint rule detects `tslib` as a required
dependency by checking if the build command contains `tsc` (via
`/\btsc\b/` regex). When a project uses `tsgo` as its compiler, the
build command is `tsgo --build` which doesn't match — causing a false
positive "tslib is not used" lint error.

## Expected Behavior

The regex also matches `tsgo`, so projects using either `tsc` or `tsgo`
correctly detect `tslib` as needed when `importHelpers: true` is set.

## Related Issue(s)

N/A — discovered while enabling tsgo for the nx package
2026-03-27 20:12:28 +00:00
Jason Jean 691bb11c68 fix(repo): copy-assets plugin and e2e improvements (#35042)
## Current Behavior

- The copy-assets plugin copies `assets.json` into the output directory
(it doesn't exclude itself)
- The copy-assets executor catches errors with `error.message` but
`error` is typed as `unknown`, which can fail at runtime
- No way to skip e2e cleanup when debugging locally

## Expected Behavior

- `assets.json` is excluded from being copied into the output directory
- Error handling properly checks `instanceof Error` before accessing
`.message`
- Setting `NX_E2E_SKIP_CLEANUP=true` preserves the test project
directory for debugging

## Related Issue(s)

Follow-up to #34994 — addresses review comments from that PR.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-27 14:49:01 -04:00
Jack Hsu a8b5d0466d feat(nx-dev): add conditional blog/changelog proxy in edge function (#35043)
## Current Behavior

`/blog` and `/changelog` paths are always served by the Next.js app. The
Netlify edge function excludes these paths (`/blog/*` in `excludedPath`,
`/blog` and `/changelog` in `nextjsPaths`) so they bypass the Framer
proxy and fall through to Next.js.

## Expected Behavior

When the `BLOG_URL` env var is set in Netlify, `/blog/*` and
`/changelog/*` requests are proxied to the standalone blog site (e.g.,
`nrwl-blog.netlify.app`) via the existing Netlify edge function. When
`BLOG_URL` is **not** set, behavior is unchanged — paths fall through to
Next.js as before.

**Changes to `netlify/edge-functions/rewrite-framer-urls.ts`:**

- Read `BLOG_URL` env var
- Conditionally remove `/blog` and `/changelog` from `nextjsPaths` when
`BLOG_URL` is set
- Remove `/blog/*` and `/changelog` from static `excludedPath` so the
edge function can intercept these paths
- Add blog proxy branch: when `BLOG_URL` is set and path matches, proxy
to blog site with URL rewriting (`blogUrl` → `https://nx.dev`) and
security headers (`X-Frame-Options`, `CSP`)
- When `BLOG_URL` is unset, blog/changelog paths fall through to Next.js
via explicit `context.next()` guard

**Asset resolution note:** The edge function only handles `text/html`
requests. Blog site assets (CSS, JS) will need to be served from the
blog site's own CDN (via `build.assetsPrefix` or equivalent in the blog
repo). All existing `/_next/*` assets remain in `excludedPath` and are
unaffected.

## Related Issue(s)

Fixes DOC-455
2026-03-27 14:04:39 -04:00
Jack Hsu 7540eb784e fix(misc): handle non-interactive mode and add template shorthand names for CNW (#35045)
This PR address some common errors seen during CNW around `--template`
and `--preset` during non-interactive flows that are not AI agents. Also
sees that some template names are not qualified with
`nrwl/<name>-template` so we can normal though (which also makes it
shorter in docs).

## Current Behavior

In non-interactive contexts (IDE terminals, scripts, SSH without `-t`),
`determineTemplate()` returns `'custom'` which routes to the preset
flow. Without `--preset` provided, this throws "Preset is required",
which affects ~15 users/day (~145 occurrences Mar 18-27).

Users must also pass full template paths like
`--template=nrwl/angular-template`.

## Expected Behavior

Non-interactive mode defaults to `nrwl/empty-template` (template flow)
instead of `'custom'` (preset flow) when neither `--preset` nor
`--template` is provided.

Shorthand template names are supported:
- `--template=angular` → `nrwl/angular-template`
- `--template=react` → `nrwl/react-template`
- `--template=typescript` → `nrwl/typescript-template`
- `--template=empty` → `nrwl/empty-template`

## Related Issue(s)

Fixes NXC-4153
2026-03-27 13:34:07 -04:00
Jason Jean 6c92d9201f fix(js): add {projectRoot} prefix to d.ts fileset in typescript plugin (#35037)
## Current Behavior

The TypeScript plugin emits a bare `**/*.d.ts` fileset input (without a
`{projectRoot}/` prefix) for dependency file tracking. The Nx hasher
expects all filesets to start with either `{projectRoot}/` or
`{workspaceRoot}/`, so it logs a warning for every project:

```
NX **/*.d.ts does not start with {workspaceRoot}/. This will throw an error in Nx 20.
```

## Expected Behavior

No warning is emitted. The fileset correctly uses
`{projectRoot}/**/*.d.ts` so the hasher knows it's scoped to the
dependency project's root.

## Related Issue(s)

N/A — discovered while debugging e2e test failures.
2026-03-27 15:53:08 +00:00
Jason Jean a040a93791 fix(repo): add copy-assets plugin and migrate all packages from legacy-post-build (#34994)
## Current Behavior

Each package defines a `legacy-post-build` target in `project.json` with
inline asset copy configuration. Inputs are not accurately declared,
leading to sandbox violations in CI. The asset globs, ignores, and
outputs must be manually kept in sync across 37 packages.

## Expected Behavior

A `copy-assets` createNodesV2 plugin reads `assets.json` from each
package and automatically generates the target with:
- Inputs derived from asset globs (positive patterns first, then
negations)
- Outputs derived using the same dest logic as `CopyAssetsHandler`
- `dependentTasksOutputFiles` for gitignored build artifacts (jars,
native binaries)
- Automatic `outDir` exclusion from asset copies

## Changes

**New infrastructure:**
- Add `copy-assets` createNodesV2 plugin in `tools/workspace-plugin`
- Add `copy-assets` executor (simplified from `legacy-post-build` — just
copies assets, no package.json field manipulation)
- Extract `normalizeAssets` and `getAssetOutputPath` into reusable
module in `packages/js`
- Add `copyReadme` namedInput for copy-readme build targets

**Migration (all 37 packages):**
- Create `assets.json` for every package defining what to copy
- Remove all `legacy-post-build` targets from project.json files
- Remove `legacy-post-build` target defaults from nx.json
- Remove redundant `copy-local-native` target (replaced by
`.node`/`.wasm` in asset glob)

**Cleanup:**
- Remove dead config: `creator-files` globs, non-existent template
files, typo'd directory names
- Use root-level `tsconfig*.json` ignore instead of recursive (so
template tsconfigs in `files/` dirs are still copied)
- Replace `!(*.ts)` extglob patterns with explicit globs (extglobs don't
work correctly in Nx inputs)
- Fix gradle lint: add `buildTargets: ["build-base"]` and `tslib`
dependency
- Add jar outputs to maven `_package` target for correct
`dependentTasksOutputFiles` resolution

**Other fixes:**
- Exclude `.swc` directories from sandbox write checks
- Enable typecheck for `angular-rspack` packages (remove
`addTypecheckTarget: false`)
- Pin workspace-plugin deps to explicit versions, add `@nx/plugin` to
root package.json

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-03-27 11:49:24 -04:00
Jack Hsu cc6b5a3046 feat(misc): a/b test cloud prompt copy in create-nx-workspace (#35039)
## Current Behavior

The cloud prompt in CNW is disabled (shouldShowCloudPrompt returns
false). Users see no cloud prompt during workspace creation.

## Expected Behavior

Re-enables the cloud prompt with 3 copy variants tied to the flow
variant (NX_CNW_FLOW_VARIANT), using the existing A/B testing
infrastructure:
- Variant 0 (baseline): "Connect to Nx Cloud?"
- Variant 1 (remote caching): "Enable remote caching to speed up builds
and CI?"
- Variant 2 (CI-first): "Speed up your CI with Nx Cloud?"

Each variant has a unique tracking code for measuring yes/skip/never
rates. New variants emphasize concrete benefits (remote caching, CI
speed), mention CI providers (GitHub, GitLab), and note free tier and
2-minute setup.

Also removes unused shouldShowCloudPrompt() function.

## Screenshots

Variant 0 (current prompts):

<img width="1392" height="935" alt="cnw-variant-0"
src="https://github.com/user-attachments/assets/38187e44-5c8f-41b1-b2d9-bdb0eead3f7d"
/>

Variant 1 (remote cache to speed up builds, free for small teams):

<img width="1392" height="939" alt="image"
src="https://github.com/user-attachments/assets/ba7ab127-c91e-4566-bae6-6f7fe797959e"
/>

Variant 2 (speed up CI, mention CI provides):

<img width="1392" height="935" alt="cnw-variant-2"
src="https://github.com/user-attachments/assets/05bc027a-dcc9-47c4-944c-35ca2fce2007"
/>

## Related Issue(s)

Closes NXC-4113
2026-03-27 11:11:40 -04:00
Jack Hsu a4e8ce9f63 chore(repo): ensure Cypress CT unit tests use Vite 7 since 8 is unsupported (#35038)
Currently, updating to 22.7.0-beta.5 causes Angular and React unit tests
to fail when we are pulling in Vite 8 instead of 7.

Cypress component tests do not support Vite 8 yet, so let's ensure that
the unit tests set up v7 for now.

https://github.com/cypress-io/cypress/issues/33078
2026-03-27 10:27:46 -04:00
James Henry 380aaf1e92 fix(core): add package export for nx/release/changelog-renderer (#35033) 2026-03-27 09:58:47 -04:00
Szymon Wojciechowski a007fce766 chore(repo): use SHAs for GH actions (#35035)
Pin actions versions to SHAs in workflows for improved security.
2026-03-27 14:27:56 +01:00
Juri Strumpflohner fbe33a9cc9 fix(nx-dev): correct YouTube channel URL on courses page (#35034)
## Current Behavior

The courses page YouTube link points to
`https://www.youtube.com/@naborx` which is incorrect.

## Expected Behavior

The link points to `https://www.youtube.com/@nxdevtools`, the actual Nx
YouTube channel.

## Related Issue(s)

N/A
2026-03-27 13:48:22 +01:00
Jason Jean 9747038c90 fix(repo): resolve FreeBSD build disk space issue (#35030)
## Current Behavior

The FreeBSD native build in the publish workflow runs out of disk space
(`No space left on device`). The VM has an 11G disk and the Rust build
fills it completely. The build was already on the edge — the Mar 25 run
succeeded with only 11MB to spare, and the Mar 26 run failed after rustc
1.94.1 slightly increased artifact sizes.

A major contributor is OpenJDK17 and its ~30 X11/font dependencies
(~500MB) being installed solely for the `@nx/gradle` plugin's project
graph step, which is irrelevant to building native Rust bindings.

## Expected Behavior

The FreeBSD build completes successfully with comfortable disk headroom
by disabling the Gradle plugin via `NX_GRADLE_DISABLE=true`, which
eliminates the need for Java and its heavy dependency tree.

## Related Issue(s)

Fixes the FreeBSD build failure:
https://github.com/nrwl/nx/actions/runs/23613960439/job/68776656960
2026-03-26 22:39:50 +00:00
Jack Hsu dd376c2a86 fix(misc): make webinar banner theme-aware with light mode support (#35029)
## Current Behavior

The webinar banner has a hardcoded dark background (`bg-zinc-950`) with
white text in both light and dark mode. This makes the close button
barely visible in light mode since Starlight's global styles override
inherited text colors. The banner design also differs noticeably from
the Framer marketing site, which uses a light background in light mode.

## Expected Behavior

The banner adapts to the current theme:
- **Light mode**: White background, subtle border, dark text, dark CTA
button — matching the Framer marketing site design
- **Dark mode**: Retains the existing dark background with white text
and pink CTA button

All interactive elements (close button, CTA buttons) have proper
contrast in both modes.

Dark:

<img width="759" height="499" alt="image"
src="https://github.com/user-attachments/assets/684113e8-cc48-43df-b17d-431ae8c864fc"
/>

Light: 

<img width="635" height="318" alt="image"
src="https://github.com/user-attachments/assets/9ed514b7-dfe9-45c6-91d7-158434aa6cdc"
/>


## Related Issue(s)

Fixes DOC-457
2026-03-26 16:51:26 -04:00
Jason Jean cf82d78b9c chore(core): bump Rust toolchain to 1.94.0 and fix all warnings (#35021)
## Current Behavior

Rust toolchain is pinned to 1.90.0 (4 versions behind stable). Building
the native code produces 23 compiler warnings (elided lifetimes, unused
imports, dead code).

## Expected Behavior

Rust toolchain is updated to 1.94.0 (latest stable). Native code
compiles with zero warnings.

## Related Issue(s)

N/A — maintenance/hygiene change.

### Changes

- **`rust-toolchain.toml`**: 1.90.0 → 1.94.0
- **Glob parser**: Fixed 19 elided lifetime warnings via `cargo fix`
- **`task_hasher.rs`**: Removed unused `anyhow::anyhow` import
- **`command.rs`**: Removed unnecessary `mut`
- **`hash_plan_inspector.rs`**: Removed unused `project_graph` field and
constructor parameter
- **`hash-plan-inspector.ts`**: Updated TS caller to match new native
constructor signature
- **`index.d.ts`**: Updated generated types to reflect removed parameter

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-26 15:58:04 -04:00
Louie Weng c8ddfedf61 chore(gradle): add project graph timeout (#35018)
## Current Behavior

When the Gradle plugin invokes `gradlew nxProjectGraph` to generate the
project graph, there is no timeout. If Gradle hangs or takes an
unexpectedly long time, the Nx process blocks indefinitely with no
feedback to the user.

## Expected Behavior

The Gradle project graph generation now has a configurable timeout that
defaults to 60 seconds. If the process exceeds this limit:

- The Gradle process is aborted via an `AbortController` signal
- A clear error message is shown with actionable remediation steps:
  - Run `gradlew --stop` and `gradlew clean`
  - Increase the timeout via `NX_GRADLE_PROJECT_GRAPH_TIMEOUT`
  - Disable the plugin entirely via `NX_GRADLE_DISABLE=true`

Users can configure the timeout by setting the
`NX_GRADLE_PROJECT_GRAPH_TIMEOUT` environment variable (in seconds).
Invalid or non-positive values fall back to the 30-second default.

Documentation for the new environment variable has been added to the
environment variables reference page.

## Related Issue(s)

Fixes NXC-4140
2026-03-26 18:57:19 +00:00
Jack Hsu 27c7928519 docs(misc): add consistent next steps and tutorial links across getting started pages (#35024)
## Current Behavior

Getting started pages have inconsistent navigation patterns. Some use
card grids, some use bullet lists, and some have no next steps at all.
The new tutorial series is not linked from most getting started pages.

## Expected Behavior

All getting started pages use consistent bullet-list navigation with
clear next steps. Every page links to the tutorial series so first-time
users can discover it from any entry point.

For example, on the "Add to an existing project" page:

<img width="1011" height="709" alt="image"
src="https://github.com/user-attachments/assets/6534d490-1bdf-4026-9962-0a60506564ce"
/>

### Changes

- **intro.mdoc**: Updated tutorial link from generic "Follow a tutorial"
to "Follow the tutorial series" pointing to the first tutorial
- **installation.mdoc**: Added "Next steps" section linking to new
project, existing project, and tutorial series
- **start-new-project.mdoc**: Added "Next steps" section with tutorial
series, editor setup, and CI setup links
- **start-with-existing-project.mdoc**: Replaced card grid with bullet
list for in-depth guides, added "Keep learning" section with tutorial
series link
- **sidebar.mts**: Fixed label consistency ("Reduce boilerplate" →
"Reducing boilerplate")
2026-03-26 12:06:53 -04:00
Jason Jean b3cb4d8261 fix(core): prevent nx watch infinite loop from overly broad output globs (#34995)
## Current Behavior

Running `nx watch --projects nx -i -- nx build nx` enters an infinite
rebuild loop. Two issues cause this:

1. **Overly broad output globs**: `build-base` declared
`{projectRoot}/src/**/*.d.ts` and `legacy-post-build` declared
`{projectRoot}/**/*.d.ts` as outputs. Cache restore deletes and
recreates committed `.d.ts` files (like `schema.d.ts`,
`perf-hooks.d.ts`) that aren't actual build outputs, triggering the file
watcher.

2. **`declarationDir` in source tree**: With `declarationDir: "."`, tsc
wrote `.d.ts` files into the source tree, making them vulnerable to
cache restore churn.

## Expected Behavior

`nx watch` should not loop when the build produces the same outputs.
Only files actually produced by a build target should be declared as
outputs.

## Changes

- **Move `declarationDir` to `dist`**: Declaration files now go to
`dist/` alongside `.js` output, keeping the source tree clean
- **Remove manual output overrides from `build-base`**: The
`@nx/js/typescript` plugin correctly infers `{projectRoot}/dist`
- **Narrow `legacy-post-build` outputs**: Only declares
`{projectRoot}/dist` since that's the only directory the executor writes
to
- **Fix package.json exports**: Replace invalid `**` subpath patterns
with `*` (Node.js exports only support `*` as wildcard)
- **Add `typesVersions`**: Ensures TypeScript projects using
`moduleResolution: "node"` (which ignores exports maps) can still
resolve `.d.ts` files in `dist/`
- **Remove `@types/minimatch`**: `minimatch@10` ships its own types; the
`@types` package was outdated and conflicted
- **Add verbose watcher logging**: Behind `NX_VERBOSE_LOGGING`, shows
which files were created/updated/deleted by the workspace watcher

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-03-26 04:52:20 +00:00
Leosvel Pérez Espinosa d0ae7045e8 chore(repo): improve nightly failure report with per-error details, start dates, and job links (#34988)
## Current Behavior

The nightly failure report already includes per-error details, but has
several accuracy and completeness issues:

1. **Incorrect per-error start dates** — e.g., `e2e-web`'s
`file-server-legacy.test.ts` reports "failing since 2026-03-24 (1 day)
NEW" when the `edgesOut` error actually started on 2026-03-18 (7 days).
The validation only compared test file names, not error content, so
same-file-different-error changes were missed.

2. **Different combo errors merged** — `e2e-web` fails with different
root causes on different combos (yarn: "could not find a copy of vite to
link", npm: "Cannot read properties of null (reading 'edgesOut')"), but
only one error block is shown with all combos listed together.

3. **Build failures show no useful details** — when tests don't run
because a build step fails (e.g., `gradle:build-base` with TS errors),
the report shows "No test output available" instead of the actual build
errors.

4. **No clickable links to jobs** — the golden projects table is a plain
code block with no links to the specific failed jobs.

5. **Other projects table** wastes vertical space with a full code-block
table.

## Expected Behavior

All issues above are fixed:

**Summary section** — golden projects with clickable job links, compact
other-projects list:
```
🌟 Golden Projects
 Passing: 18 |  Failing: 2

🚨 Failed Golden Projects

e2e-react-native
  · MacOS/npm/20              ← clickable link to job

e2e-web
  · MacOS/npm/20              ← clickable link to job
  · Linux/yarn/20             ← clickable link to job
  · Linux/npm/20              ← clickable link to job

⚠️ Failed Other Projects: e2e-angular (4), e2e-nuxt (4), e2e-nx (10), ...
```

**Failure details** — per-combo errors shown separately with accurate
start dates:
```
e2e-web — 3 combos (npm+yarn)
Project failing since 2026-03-13 | Last fully passing: 2026-03-12

📋 file-server-legacy.test.ts (Linux/yarn/20) — failing since 2026-03-13 (12 days)
    error Invariant Violation: could not find a copy of vite to link ...

📋 file-server-legacy.test.ts (MacOS/npm/20, Linux/npm/20) — failing since 2026-03-18 (7 days) ⚠️ error changed mid-streak
    npm error Cannot read properties of null (reading 'edgesOut') ...
```

**Build failures** — when tests don't run, the report now shows the Nx
failure summary AND the actual failed task output:
```
⚠️ Tests did not run — failed at step: Run e2e tests with pnpm (Linux/Windows)
  NX Running target e2e-local for project e2e-docker and 153 tasks it depends on failed
  Failed tasks: gradle:build-base
   > nx run gradle:build-base
  > tsc --build tsconfig.lib.json
  error TS6307: File '...assert-supported-platform.ts' is not listed within the file list ...
```

## Changes

- **Error signature comparison** — compares normalized error messages
(not just file names) between the current run and first-failing run.
Dynamic parts (temp paths, random IDs, timestamps, versions) are
stripped before comparison. Different errors on different combos are
detected and reported separately.
- **Signature-based binary search** — when the error changed mid-streak,
finds when the current error ACTUALLY started by checking error
signatures in historical runs across all combos.
- **Failed Nx task block capture** — extracts the ` > nx run <task>`
output block with actual build errors, plus a fallback for generic error
patterns when no Nx task markers are found.
- **Clickable job links** — each failing combo in the golden projects
summary links to its specific GitHub Actions job.
- **Compact other-projects** — replaced the code-block table with a
one-liner count summary.
- **Graceful degradation** — if failure details collection fails, the
brief report still posts with a warning.
2026-03-25 23:41:09 -04:00
Jack Hsu a1dee7286f docs(misc): replace monolithic tutorials with focused topic-based tutorials (#34998)
## Current Behavior

The Tutorials section has three large framework-specific tutorials
(React Monorepo, Angular Monorepo, TypeScript Monorepo) that each teach
everything at once. They are 500+ lines, tightly coupled to a specific
tech stack, and don't build knowledge incrementally.

## Expected Behavior

Seven focused, technology-agnostic tutorials that each teach one concept
in ~5 minutes. The design follows progressive disclosure so users learn
one thing well before moving to the next.

Preview:
https://deploy-preview-34998--nx-docs.netlify.app/docs/getting-started/tutorials/crafting-your-workspace

### Design goals

- **Learn the basics in an hour**: A user going through all 7 tutorials
covers workspace structure, dependencies, tasks, running, caching,
debugging, and plugins.
- **AI agent friendly**: Each page has an `llm_copy_prompt` at the top
that an AI agent can use as a tutor prompt. A user can paste this into
Claude Code, Cursor, or any AI tool and be guided through the topic in
their own workspace.
- **No assumed workspace state**: Each tutorial works whether you used
`create-nx-workspace`, ran `nx init` on an existing repo, or jumped to a
specific topic. Pages link back to prerequisites when needed.
- **One concept per page**: Progressive disclosure means plugins aren't
mentioned until tutorial 7, `nx graph` isn't shown until tutorial 6, and
caching configuration doesn't appear until tutorial 5.

### Tutorial sequence

1. **Crafting your workspace** - Nx as a build intelligence layer,
workspace structure, package manager workspaces, TypeScript
solution-style project references, adding projects
2. **Managing dependencies** - Workspace libraries, buildable vs
non-buildable (with `exports` and `customConditions`), `workspace:*`
protocol, single version policy with catalogs
3. **Configuring tasks** - `package.json` scripts vs `project.json`
targets, `dependsOn` with `^` syntax, continuous tasks, named
configurations, target defaults
4. **Running tasks** - `nx run`, shorthand, `run-many` with
`--targets`/`--projects`, task ordering with SVG diagram, parallelism
control, passing arguments
5. **Caching tasks** - Run-twice demo, computation hashing with SVG
diagram, inputs/outputs, named inputs, env vars/runtime inputs,
sandboxing, remote caching with `nx connect`
6. **Understanding your workspace** - `nx graph` as entry point, project
graph with edge screenshots, task graph with screenshots, `nx show
project`/`nx show target`, affected analysis with `--base`/`--head`,
cache debugging
7. **Reducing configuration boilerplate** - `targetDefaults`, Nx
plugins, inferred tasks, `nx add`, configuration cascade, presented as
optional

### Other changes

- **CI tutorial rewritten** to cover remote caching, affected (with
`NX_BASE`/`NX_HEAD`), Nx Agents, and self-healing (was previously
self-healing only)
- **Concept pages** ("How Nx works") link to relevant tutorials via
"Learn by doing" callouts
- **Redirects** from old tutorial URLs to new pages
- **Cross-references** updated across 11 technology/guide pages
- **SVG diagrams** for task dependency ordering and cache hash flow
(same style as sandboxing page)
- **Screenshots** for project graph edge detail and task graph views
- **Sidebar**: Tutorials group has "New" badge, collapsed by default

## Screenshots

Tutorials topics as ordered in sidebar:

<img width="324" height="290" alt="image"
src="https://github.com/user-attachments/assets/87b27e6a-30f6-4c9b-b52d-b371f66e72e8"
/>

AI instructions that can be copied and pasted into Claude Code to act as
a tutor:

<img width="803" height="308" alt="image"
src="https://github.com/user-attachments/assets/2dcf402e-19a6-4cf4-bcac-7005491529bf"
/>

Linking to prev/next tutorials at the bottom of each tutorial topic:

<img width="871" height="457" alt="image"
src="https://github.com/user-attachments/assets/b9a198b5-edc7-4afd-8c13-fd70c10cf858"
/>

For concept pages that are covered by a tutorial, link to the tutorial
in `Next steps`:

<img width="945" height="435" alt="image"
src="https://github.com/user-attachments/assets/a05d1c0b-c95a-42c5-baec-1fb30dff7c64"
/>

## Related Issue(s)

Fixes DOC-452
2026-03-25 20:29:59 -04:00
Robert Sidzinka c6990488d8 fix(vite): add support for Vite 8 (#34850)
## Current Behavior

The `@nx/vite` plugin only supports Vite 5, 6, and 7. Users on Vite 8
get peer dependency errors:

```
peer vite@"^5.0.0 || ^6.0.0 || ^7.0.0" from @nx/vite
```

## Expected Behavior

Full Vite 8 support for new and existing workspaces:

**Nx plugin support:**
- Update peer deps to include `^8.0.0` in `@nx/vite` and `@nx/vitest`
- Default new workspaces to Vite 8 (`viteVersion = '^8.0.0'`)
- Bump `@vitejs/plugin-react` to `^6.0.0` (required for Vite 8, uses Oxc
instead of Babel)
- Add `useViteV7` backward compatibility flag (follows existing
`useViteV5`/`useViteV6` pattern)

**Rolldown migration (Vite 8 replaced Rollup with Rolldown):**
- Handle both `rollupOptions` (Vite <8) and `rolldownOptions` (Vite >=8)
in build executor and plugin detection
- Fix build executor environments API to preserve env-specific
`rolldownOptions` config
- Update e2e tests for Rolldown's different module counts

**Type fixes for Vite 8's ESM-only declarations:**
- Vite 8 ships `.d.mts` type declarations not resolvable under
`moduleResolution: "node"`
- Fix `typeof import('vite')` and `import type` usages across
`@nx/vite`, `@nx/vitest`, `@nx/cypress`, `@nx/react`, `@nx/angular`,
`@nx/remix` with inline casts
- All fixes have `TODO(jack)` comments to remove when switching to
`moduleResolution: "nodenext"`

**Plugin compatibility:**
- `@vitejs/plugin-react@^6.0.0` only supports Vite 8; `^4.2.0` for Vite
<=7
- `ensure-dependencies` detects installed vite version and picks the
correct plugin-react version
- Cypress CT does not support Vite 8 yet — e2e test downgrades to Vite 7

**Angular vitest fix:**
- `@angular/build` depends on `rolldown` which injects
`@oxc-project/runtime` helpers at transform time without declaring it as
a dependency
- Add `@oxc-project/runtime` as an explicit devDependency in the Angular
vitest generator

**Docs:**
- Updated supported versions table to include `^8.0.0`
- Added `rolldownOptions.input` to buildable project detection docs

**E2E coverage:**
- New Vite 8 + React build/test e2e test
- New Vite 7 + React backward compat e2e test (downgrades vite +
plugin-react)
- Updated environments API test for Vite 8 `rolldownOptions`
- Updated incremental build test for Rolldown's module counts
- Cypress CT e2e downgrades to Vite 7 (Cypress doesn't support Vite 8
yet)

## Other notes

We'll do a follow-up PR to include migrations for 22.7.0. This PR's
scope is only to ensure peer deps and our generators work for workspaces
that are already using Vite 8.

## Related Issue(s)

Fixes #34849

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
2026-03-25 15:58:44 -04:00
Jason Jean bc982391aa feat(repo): add nx-labs repo target and use glob pattern for update-all-repos (#34999)
## Current Behavior

The `update-all-repos` target explicitly lists each repo target in its
`dependsOn`. Adding a new repo requires updating this list manually.
There is no target for updating the nx-labs repo.

## Expected Behavior

- New `update-nx-labs-repo` target added for updating the nx-labs
repository
- `update-all-repos` uses a `update-*-repo` glob pattern in `dependsOn`,
so new repo targets are automatically picked up
2026-03-25 14:36:58 -04:00
Jack Hsu 96537f84d6 fix(core): add timeouts to GitHub push flow to prevent CLI hangs (#35011)
## Current Behavior

The `pushToGitHub` flow in create-nx-workspace calls `gh api user` and
`gh repo create --push` with no timeout. When `gh` CLI is wrapped by
1Password SSH agent, credential managers with GUI prompts, SSH keys with
passphrases, or corporate SSO, these calls hang indefinitely — freezing
the CLI after workspace creation with no indication of what's happening.

YTD data shows a **96.3% failure rate** (16,426 failures out of 17,058
push attempts).

## Expected Behavior

- The initial `gh` auth check (`gh api user`) has a **2-second
timeout**. If `gh` is slow to respond (hung on credential prompt), the
push flow is skipped gracefully instead of freezing.
- The `gh repo create --push` command has a **15-second timeout**. If
the push hangs, the process is killed and a helpful message is shown.
- If `gh` CLI is not installed, the push flow is skipped immediately
without attempting any network calls.
- Error messages now include actionable fallback: *"You can push
manually with: git push -u origin main"*.

The error is now captured in `recordStat` as well, so when users see
this we'll also see it in our stats.

<img width="1026" height="334" alt="image"
src="https://github.com/user-attachments/assets/10c0b4a8-9083-4063-9558-88ebb8a5a850"
/>


## Related Issue(s)

Fixes #34482, NXC-4141
2026-03-25 14:29:37 -04:00
Louie Weng f003f56f8e fix(core): prevent batch executor error on prematurely completed tasks (#35015)
## Current Behavior

When a task is prematurely completed (e.g., due to a failure that causes
early termination) before its dependents have been scheduled, calling
`scheduleNextTasks` crashes the batch executor. The crash occurs in
`processTaskForBatches`, which traverses reverse dependencies and
attempts to read `notScheduledTaskGraph.dependencies[task.id]` for a
task that was already removed from `notScheduledTaskGraph` via
`complete()`. This yields `undefined` for the dependencies array,
causing downstream code to throw.

## Expected Behavior

When a task has been prematurely completed before batch scheduling runs,
`processTaskForBatches` should skip that task gracefully rather than
crashing. Tasks that were removed from `notScheduledTaskGraph` early
should be detected and skipped during batch traversal.

## Related Issue(s)

Fixes NXC-4144
2026-03-25 13:41:16 -04:00
Craigory Coppola f81ad0715f fix(js): add input on .d.ts files within dependency projects (#34968)
This pull request makes a targeted improvement to how TypeScript
dependency tracking is handled in the build system. Specifically, it
ensures that all `*.d.ts` files from dependent projects are included as
inputs, improving type safety and correctness in incremental builds.

Dependency tracking improvements:

* Updated the `getInputs` function in `plugin.ts` to add all `*.d.ts`
files from dependencies as tracked inputs, ensuring that changes to type
definition files in dependent projects are properly detected and trigger
rebuilds.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
2026-03-25 16:55:58 +01:00
Jack Hsu 543a8b1dd6 feat(core): auto-open browser for Cloud setup URL during create-nx-workspace (#35014)
## Current Behavior

When a user selects "yes" to connect to Nx Cloud during
`create-nx-workspace`, the Cloud setup URL is only displayed in the
terminal banner. The user must manually click or copy the link to
complete onboarding.

## Expected Behavior

After displaying the banner, the setup URL is automatically opened in
the user's default browser, removing friction at the critical Cloud
conversion moment.

- Skips browser open in CI environments (`CI=true`, GitHub Actions,
etc.)
- Fails gracefully if the browser cannot be opened (e.g., headless/no
display server) — the URL remains visible in the terminal
- Only triggers when user actually connected to Cloud (not for "Maybe
later" / `skipCloudConnect`)

## Related Issue(s)

Fixes NXC-4112
2026-03-25 10:46:37 -04:00
Leosvel Pérez Espinosa 0a381299e7 fix(core): resolve published nx migrate package resolution (#35013)
## Current Behavior

When `nx migrate latest` runs, it installs the target version of `nx`
into a temporary directory and executes that published CLI. During
migration, Nx checks whether `nx` is already installed in the workspace
by resolving `nx/package.json`.

This used to resolve through the workspace-oriented lookup paths, so
migrate correctly detected the workspace-installed `nx` package and
expanded the first-party Nx package group.

That changed recently with `chore(core): build nx to local dist and use
nodenext (#34111)`. As part of that work, the published `nx` package
gained an `exports` map. In Node, a package with `name: "nx"` and
`exports` can self-reference by package name. As a result, when code
running inside the temporary published `nx` package resolves
`nx/package.json`, Node now resolves that request back to the temporary
package itself.

The resolved path points outside the workspace root, so migrate's
existing safety check treats `nx` as not installed in the workspace.
Once that happens, migrate only updates `nx` and never expands the rest
of the first-party Nx package group.

Separately, provenance package-group lookup assumes a
source-layout-relative path to `package.json`, which does not hold for
published artifacts built into local `dist/`.

## Expected Behavior

Published temporary migrate CLIs should still resolve the
workspace-installed `nx` package when migrate determines what is
installed in the workspace. That preserves the existing package-group
migration behavior even after the recent `exports`-based packaging
change.

Provenance package-group lookup should resolve the manifest of the
currently running `nx` package in a way that works for published
artifacts as well as source checkouts.
2026-03-25 10:34:06 -04:00
Leosvel Pérez Espinosa 55f8888dda fix(bundling): disable swc input source map resolution (#35010)
## Current Behavior

When using `compiler: 'swc'` with `useLegacyTypescriptPlugin: false` in
rollup config, builds fail with errors like:

```
ERROR failed to read input source map: failed to find input source map file "index.js.map"
```

SWC defaults `inputSourceMap` to `true`, causing it to look for
`.js.map` files for TypeScript source inputs that obviously don't have
them.

## Expected Behavior

Builds should succeed without source map resolution errors. Rollup
handles source maps via its own output pipeline — the SWC transform step
should not independently try to resolve input source maps.

## Related Issue(s)

Fixes #32671
2026-03-25 09:55:51 -04:00
Jason Jean 3fa06c98d7 chore(repo): update nx to 22.7.0-beta.4 (#35000)
Updating Nx from 22.7.0-beta.3 to 22.7.0-beta.4
2026-03-24 18:57:14 -04:00
Caleb Ukle f6692fc7b6 fix(core): handle owners and conformance project refs on move/remove (#34815)
## Current Behavior

When removing or moving a project in an Nx workspace, the `owners` and
`conformance` sections in `nx.json` are not updated. This leaves stale
project references in:
- `conformance.rules[].projects` (both plain strings and `{ matcher }`
objects)
- `owners.patterns[].projects` (top-level and section-level for GitLab)

## Expected Behavior

- **On project removal**: Strip the removed project from all conformance
rules and owners patterns. Remove entries that become empty after
cleanup (rules with no projects, patterns with no projects).
- **On project move/rename**: Rename all references to the old project
name with the new name in conformance rules and owners patterns
(including section-level patterns for GitLab-style CODEOWNERS).
- **Schema**: Add `owners` configuration schema to `nx-schema.json` for
validation and IDE support, including sections (GitLab CODEOWNERS).

## Related Issue(s)

<!-- No specific issue linked -->

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
2026-03-24 22:06:42 +00:00
Steven Nance 6cc873550a fix(devkit): add startTime and endTime to TaskResult interface (#34996)
## Current Behavior

The `TaskResult` interface exported from the devkit is missing
`startTime` and `endTime` properties. At runtime, these properties are
present on `TaskResult` objects — set by the task orchestrator during
execution and consumed by multiple lifecycle implementations (profiling,
timings, history, store-run-information) — but the public type does not
declare them. This means the [TaskResult reference
docs](https://nx.dev/docs/reference/devkit/TaskResult) don't show these
fields.

## Expected Behavior

The `TaskResult` interface includes optional `startTime` and `endTime`
properties (Unix timestamps) matching what is actually present on
runtime objects. The generated devkit reference docs will now include
these fields.

## Related Issue(s)

N/A
2026-03-24 21:58:16 +00:00
Craigory Coppola 068db9a8ca fix(core): show better log message when isolated plugin shuts down after hook completion (#34922)
## Current Behavior
`shut down after last hook`

## Expected Behavior
`shut down after [hook]`

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

Fixes #
2026-03-24 17:31:58 -04:00
Colum Ferry 36534a4237 fix(angular-rspack): ensure rebuild chunks emitted summary accurate (#34979)
## Current Behavior
Currently, rebuilds produce a summary table that is not accurate.
A key difference in how Rspack sets `chunks.rendered` compared to
Webpack resulted in the logic for determining rebuilt chunks to be
incorrect.

## Expected Behavior
Ensure the summary table for emitted chunks is accurate on rebuild

## Related Issues

It does not _fully_ solve #34936, however it should be a good first step
to finding out if too many chunks are being emitted
2026-03-24 16:49:51 -04:00
Caleb Ukle f368b6a7d6 fix(nx-cloud): remove invalid images (#34997)
<!-- 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
<!-- This is the behavior we have today -->
lists invalid images

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
lists valid images
## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #34970
2026-03-24 16:31:16 -04:00
Leosvel Pérez Espinosa 9cca97fc02 fix(js): pass configName to typecheck command in TS plugin (#34989)
## Current Behavior

The `@nx/js` TypeScript plugin ignores the `configName` option when
constructing the typecheck target command. It always runs `tsc --build
--emitDeclarationOnly` without specifying which tsconfig to use,
defaulting to whatever `tsc` resolves on its own. This means custom
`configName` values (e.g. `tsconfig.lib.json`) have no effect on
typechecking.

## Expected Behavior

The typecheck target should pass `configName` to the `tsc --build`
command, matching how the build target already works: `tsc --build
<configName> --emitDeclarationOnly`.

## Related Issue(s)

Fixes #34274
2026-03-24 15:43:32 -04:00
Louie Weng a52c42ff05 chore(gradle): bump gradle project graph plugin version to 0.1.17 (#34993)
<!-- 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
<!-- This is the behavior we have today -->

Current plugin version is at 0.1.16

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Bump version to 0.1.17

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

Fixes #

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 11:49:44 -07:00
Caleb Ukle 34b8256b97 fix(nx-dev): improve docs search ranking and metrics (#34992)
## Current Behavior

- Searching for a framework (e.g. "nestjs", "vite", "angular") returns
random pages that mention the term instead of the plugin introduction
page.
- The launch templates page is too long impacting word saturation
- Search event tracking uses wrong event

## Expected Behavior

- Technology introduction pages rank first or second when searching for
their framework name.
- Launch templates are split into a focused reference page and a
separate examples page, both cross-linked.
- Use correct search event and track user selected item from query
- enforce usage of pagefind filter names in content collection schemas


Fixes DOC-408
2026-03-24 14:05:19 -04:00
Jason Jean ac2031508c fix(core): suppress postinstall error output when nx is not yet built (#34986)
## Current Behavior

The `postinstall` script in `packages/nx/package.json` runs `node
./dist/bin/post-install` which prints noisy error logs to stderr when
the `dist` directory hasn't been built yet (e.g. during `pnpm install`
in the workspace). The script already exits cleanly via `|| exit 0`, but
the error output is confusing.

## Expected Behavior

The postinstall script silently succeeds when the dist directory doesn't
exist, without printing error logs to the console.

## Related Issue(s)

N/A - minor DX improvement
2026-03-24 13:43:54 -04:00
Jason Jean 7da079877e fix(vitest): resolve addPlugin default in init generator (#34990)
## Current Behavior

Running `nx add @nx/vitest` does not register the `@nx/vitest` plugin in
`nx.json`. The init generator had a wrapper function (`initGenerator`)
that hardcoded `addPlugin: false` before spreading the user-provided
schema. Since `nx add` calls the generator via CLI without passing
`addPlugin`, the value stayed `false` — and the `??=` default logic in
`initGeneratorInternal` never fired because `false` is not nullish.

## Expected Behavior

Running `nx add @nx/vitest` should register the `@nx/vitest` plugin in
`nx.json`, matching the behavior of other plugins like `@nx/jest`,
`@nx/vite`, and `@nx/playwright`.

## Related Issue(s)

<!-- No existing issue tracked for this -->

## Changes

- Merged `initGenerator` and `initGeneratorInternal` into a single
`initGenerator` function that uses the `??=` default logic directly
- Added unit tests for the init generator covering plugin registration
defaults, `NX_ADD_PLUGINS` env var, `addPlugin: true` vs `false`
behavior, package.json handling, and namedInputs
2026-03-24 17:42:48 +00:00
Louie Weng 4a073cd1f3 fix(gradle): ignore test enums when atomizing (#34974)
<!-- 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
When the Gradle plugin's regex-based test parser (used as a fallback
when AST parsing fails) encounters a Kotlin file
containing enum classes, those enum classes are incorrectly included as
test atomization targets. This causes spurious
test entries to appear for enum types like TestStatus or Priority that
are not actual test classes.
## Expected Behavior

Enum classes are excluded from the list of discovered test classes
during atomization, consistent with how abstract
classes and annotation classes are already filtered out. Only real test
classes should be identified as atomization targets.

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

Fixes #
2026-03-24 10:39:48 -07:00
Jason Jean 1ed644799e chore(repo): add mise trust step and nx-labs to update-repos (#34991)
## Current Behavior

The `update-repos` tool clones repositories into `/tmp` and runs `pnpm
install` / `nx migrate` without trusting the repo's mise configuration.
This means the wrong tool versions (node, bun, etc.) may be used.
Additionally, `nrwl/nx-labs` is not included in the update-repos config.

## Expected Behavior

- Run `mise trust` before installing dependencies if the cloned repo has
a `mise.toml` or `.mise.toml`, ensuring correct tool versions are
activated.
- Include `nrwl/nx-labs` in the repos that get updated.

## Related Issue(s)

N/A - internal tooling improvement
2026-03-24 17:36:10 +00:00
Craigory Coppola c96de0be13 fix(core): runtime inputs shouldn't be cached at task_hasher layer and filesets should be in the hash_plans layer (#34971)
This pull request refactors the caching strategy in the task hashing
logic to improve cache isolation and correctness. The main change is to
eliminate shared, long-lived caches in favor of creating fresh caches
for each invocation, preventing stale data from persisting across CLI
commands. Additionally, new caches for project and workspace file set
hashes are introduced, and cache handling is streamlined for better
maintainability.

**Cache management improvements:**

* Removed the `runtime_cache` field from the `TaskHasher` struct and now
create fresh `DashMap` caches for runtime, project file set, and
workspace file set hashes within each invocation of the main hash
function. This ensures no stale cache data persists across CLI commands.
[[1]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bL153)
[[2]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bL184)
[[3]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bL196-R208)
* Updated the `hash_runtime` function and its usage to accept a
reference to a `DashMap` instead of an `Arc<DashMap>`, simplifying
ownership and concurrency concerns.
[[1]](diffhunk://#diff-77cbfff0572545027ac8ad107859d5135e6f78ee7c32babc56b2c9bbf89cfaccL5-R11)
[[2]](diffhunk://#diff-77cbfff0572545027ac8ad107859d5135e6f78ee7c32babc56b2c9bbf89cfaccL54-R61)

**File set hash caching:**

* Introduced the `CachedFileSetHash` struct to store both the hash value
and the list of matched files for project and workspace file set
hashing, enabling more efficient input collection and cache lookups.
* Added per-invocation caches for project and workspace file set hashes,
with logic to check the cache before computing a new hash and to insert
results after computation.
[[1]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bL196-R208)
[[2]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bR353-R385)
[[3]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bR412-R438)
[[4]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bR554-R556)

**Function signature and argument updates:**

* Updated function signatures and argument passing to propagate the new
cache references throughout the hashing logic, including
`HashInstructionArgs` and related functions.
[[1]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bR264-R266)
[[2]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bR341-R343)
[[3]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bR554-R556)

Fixes #30170

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-24 13:18:33 -04:00
Jason Jean d659486402 feat(core): decouple DB version from Nx version and share DB across worktrees (#34942)
## Current Behavior

Nx uses its package version as the DB version. Any Nx version change
**wipes the entire database**, losing all task history and cache
metadata. With multiple worktrees, each worktree maintains its own
separate DB — so switching between them constantly nukes task history,
and worktrees can't benefit from each other's cached results.

## Expected Behavior

1. **Versioned DB filenames**: DB version is decoupled from Nx version.
A new `DB_VERSION` constant is bumped only when the schema changes. The
version is encoded in the filename (`{machine_id}-v{DB_VERSION}.db`), so
multiple schema versions coexist on disk without wiping each other.

2. **Shared DB across worktrees**: When running inside a git worktree,
Nx detects the main repo root and stores the DB in the main repo's
`.nx/workspace-data/` directory. All worktrees share the same task
history, cache metadata, and task details — but **running tasks are
tracked per-worktree** since they are inherently local to each working
copy.

### Changes

- Add `DB_VERSION` constant in `initialize.rs` (bumped only on schema
changes)
- Encode version in DB filename: `{machine_id}-v1.db`
- Remove `nx_version` parameter from `connect_to_nx_db` and
`initialize_db`
- Remove metadata table entirely — schema version is in the filename, so
no runtime version check needed
- Simplify `initialize_db` to use file-existence check instead of
querying metadata
- Add `get_main_worktree_root` napi function in a dedicated `worktree`
module for worktree detection via `git rev-parse --git-common-dir`
- Add `sharedWorkspaceDataDirectory` in TypeScript that resolves to the
main repo's workspace-data dir when in a worktree
- Add `getLocalDbConnection` for per-worktree data (e.g. running tasks)
that should not be shared
- Running tasks use a local DB to avoid false "already running"
conflicts between worktrees
- Daemon stays per-worktree (no changes needed)
- Stale DB files from old schema versions are cleaned up automatically
after 7 days

### What's shared vs local

| Data | Scope | Why |
|------|-------|-----|
| `task_details` | Shared | Keyed by content hash — same code = same
hash regardless of worktree |
| `task_history` | Shared | More data = better time estimates and flaky
detection |
| `cache_outputs` | Shared | Cache lives in one place, tracking should
too |
| `running_tasks` | **Per-worktree** | Each worktree runs tasks
independently — sharing would cause false conflicts |

### Migration

- Old `{machine_id}.db` files are simply ignored (Nx now looks for
`{machine_id}-v1.db`)
- No data migration — fresh DB on first use (same as today on version
bumps)
- Old files cleaned up on `nx reset` and automatically after 7 days of
inactivity

## Related Issue(s)

<!-- N/A - internal improvement -->
2026-03-24 11:51:33 -04:00
Leosvel Pérez Espinosa 95621cd329 fix(core): use upsert to prevent FK constraint violations in task DB (#34977)
## Current Behavior

`INSERT OR REPLACE` is used in `task_details` and `cache_outputs`
tables. The bundled SQLite (`libsqlite3-sys`) is compiled with
`SQLITE_DEFAULT_FOREIGN_KEYS=1`, so FK constraints are enforced by
default. `INSERT OR REPLACE` does a DELETE + INSERT on PK conflict, and
the implicit DELETE on `task_details` fails when child rows exist in
`task_history` or `cache_outputs`:

```
NX   DB transaction error: SqliteFailure(Error { code: ConstraintViolation, extended_code: 787 }, Some("FOREIGN KEY constraint failed"))
```

This happens because `record_task_details` is called multiple times with
the same hash across different code paths (`hashTask`, `hashTasks`,
`hashBatchTasks`), and by the second call, child rows already reference
that hash.

## Expected Behavior

Use `INSERT ... ON CONFLICT DO UPDATE` (upsert) which updates the
existing row in-place without deleting it. No DELETE means no FK
violation, while preserving the same idempotent behavior the code relies
on.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-24 09:42:26 -04:00
Jason Jean cbd3951a12 chore(repo): update nx to 22.7.0-beta.3 (#34958)
Updating Nx from 22.7.0-beta.1 to 22.7.0-beta.3
2026-03-24 13:41:46 +00:00
Jason Jean 96f9ccc824 fix(repo): use @nx/nx-source export condition in jest resolver (#34972)
## Current Behavior

The patched jest resolver handles `nx/*` imports differently for unit
tests and e2e tests:
- **Unit tests**: Manual filesystem-based resolution with regex matching
and `fs.existsSync` checks to find `.ts` source files
- **E2e tests**: Falls through to `options.defaultResolver`, which
follows pnpm `workspace:*` symlinks to `packages/nx/` and resolves via
the package.json exports map — landing on `dist/*.js` files instead of
`.ts` source

This causes ~200 sandbox warnings for undeclared file reads from
`packages/nx/dist/` during e2e task execution, since those files aren't
listed as task inputs.

Additionally, `e2eInputs` in `nx.json` references
`{workspaceRoot}/jest.preset.js` (the root unit test preset) instead of
the actual e2e preset at `{workspaceRoot}/e2e/jest.preset.e2e.js`.

## Expected Behavior

Both unit and e2e tests resolve `nx/*` imports using the `@nx/nx-source`
custom export condition via `options.defaultResolver`. This leverages
the existing exports map in `packages/nx/package.json` to resolve to
`.ts` source files, eliminating:
- The manual filesystem resolution code for `nx/*` (regex matching,
`fs.existsSync` calls)
- The e2e-specific code path that fell through to compiled `.js` files
- Sandbox warnings for undeclared reads from `packages/nx/dist/`

The `e2eInputs` preset reference is corrected to point to the actual e2e
preset file.

## Related Issue(s)

<!-- No specific issue — this was discovered during sandbox warning
investigation -->

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-24 08:54:00 -04:00
Jack Baker 5b2a0a745b cleanup(angular): remove postcss-url dependency (#34976)
Remove the postcss-url from the angular generators as it does not seem
to be used by ng-packagr or tailwind anymore.
https://github.com/ng-packagr/ng-packagr/pull/2736

https://v3.tailwindcss.com/docs/using-with-preprocessors#using-post-css-as-your-preprocessor

## Current Behavior
When generating an angular library postcss-url is automatically added as
dependency.

## Expected Behavior
postcss-url should not be added to be dependencies as it is not used.
2026-03-24 11:49:04 +01:00
Jason Jean d047b81c42 fix(core): add explicit exports entry for nx/src/native directory (#34967)
## Current Behavior

After the nodenext PR (#34111) added an `exports` map to
`packages/nx/package.json`, the nx-cloud light client (ocean) fails to
import `nx/src/native`.

The wildcard exports pattern `"./src/*"` resolves `nx/src/native` to
`./dist/src/native.js` — but the actual file is
`./dist/src/native/index.js` (it's a directory with an index file).
Node's exports map does literal `*` substitution and does **not**
perform CJS-style directory/index resolution.

The cloud client wraps all its nx imports in a single try/catch, so when
the native import fails, `getDbConnection` is never assigned either,
causing `getDbConnection is not a function` errors in CI.

This was not an issue with `nx@22.7.0-beta.1` because that version had
no `exports` map — Node fell back to normal CJS resolution which handles
directory/index lookups.

## Expected Behavior

`require('nx/src/native')` correctly resolves to
`dist/src/native/index.js` via an explicit export entry, and the cloud
client can load the native module and `getDbConnection` without errors.

## Related Issue(s)

N/A — discovered during version bump CI failure investigation.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-23 19:03:28 -04:00
Jason Jean dd8f69ea72 fix(repo): skip flaky Cypress HMR e2e tests (#34969)
## Current Behavior

Six e2e tests are failing on master due to a Cypress uncaught exception:
`[HMR] Hot Module Replacement is disabled`. The error originates from
the webpack `styles.js` bundle during the `before each` hook, causing
Cypress to abort the test suite. This appears to be triggered by an
external dependency update.

Failing tests:
- `e2e-nx:e2e-ci--src/workspace-legacy.test.ts`
-
`e2e-react:e2e-ci--src/module-federation/independent-deployability.webpack.test.ts`
-
`e2e-react:e2e-ci--src/module-federation/core-webpack-basic-host-remote-generation.test.ts`
-
`e2e-react:e2e-ci--src/module-federation/misc-rspack-interoperability.test.ts`
-
`e2e-react:e2e-ci--src/module-federation/dynamic-federation.webpack.test.ts`
-
`e2e-react:e2e-ci--src/module-federation/federate-module.webpack.test.ts`

## Expected Behavior

The flaky tests are skipped so that master CI is green while the root
cause (likely an external dependency update) is investigated separately.

## Related Issue(s)

N/A — CI stabilization fix.
2026-03-23 22:32:25 +00:00
Jason Jean 89cdbb17c2 chore(repo): add update-repos target and restore update-all-repos (#34957)
## Current Behavior

`update-all-repos` only updates ocean and nx-console repositories. There
is no way to update just those two repos separately from the full set.

## Expected Behavior

- `update-all-repos` now includes all four repos: nx, ocean,
nx-examples, and nx-console
- A new `update-repos` target updates only ocean and nx-console (the
most commonly used subset)

## Related Issue(s)

Internal tooling improvement — no external issue.
2026-03-23 15:32:40 -04:00
Jason Jean d9ec2c00fd fix(core): skip workspace context setup when global bin hands off to local (#34953)
## Current Behavior

When the globally installed Nx binary (`bin/nx.ts`) runs, it calls
`setupWorkspaceContext()` **before** determining whether it should hand
off to a local Nx installation. If the global Nx version differs from
the local version (e.g. global `22.7.0-beta.2` vs local
`22.7.0-beta.1`), `isNxVersionMismatch()` returns true,
`daemonClient.enabled()` returns false, and `setupWorkspaceContext()`
creates an in-process `WorkspaceContext` that locks the workspace data
directory.

When the local Nx then tries to start the daemon, it conflicts with this
lock and the daemon fails to start. This means running `nx reset`
followed by any command (e.g. `nx show projects`) results in the daemon
never auto-starting, falling back to in-process graph construction, or
erroring out entirely.

## Expected Behavior

The global bin should not set up a workspace context when it's about to
hand off to a local Nx installation. The local Nx will handle workspace
context setup itself.

`setupWorkspaceContext()` is now only called in the `isLocalInstall` and
`isNxCloudCommand` branches — skipped in the handoff path. This matches
the existing pattern established in #34914 for analytics and DB
connections.

## Related Issue(s)

<!-- No specific issue filed — discovered during development in the nx
repo -->
2026-03-23 15:31:50 -04:00
Jason Jean 7e64e4a3cb fix(core): include command name on all telemetry events (#34949)
## Current Behavior

The command name (e.g., `build`, `test`, `generate`) is only sent as the
`dt` (document title) parameter on `page_view` events. All other
telemetry events like `run_completed` and `project_graph_computed` have
no command context, making it impossible to correlate them with the
command that triggered them in Google Analytics.

## Expected Behavior

All telemetry events include the `dt` parameter with the command name.
The Rust telemetry background thread stores the page title when a
`page_view` is received and automatically injects it into all subsequent
events in the same process.

## Related Issue(s)

N/A — internal analytics improvement

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-03-23 15:31:17 -04:00
Jason Jean fbc4e63a35 fix(core): skip import-equals namespace aliases in native scanner (#34947)
## Current Behavior

The native Rust import scanner mishandles TypeScript's `import X = Y.Z`
namespace alias syntax. When it encounters this pattern, it fails to
recognize it as a non-module statement and continues scanning forward
for string literals, treating the next one it finds as a module
specifier.

On case-insensitive filesystems (macOS default HFS+/APFS), this causes
phantom npm dependencies in the project graph. For example, `import
MyBar = Foo.Bar` followed by `case 'Open':` causes `npm:open` to appear
as a static dependency because `node_modules/Open` resolves to
`node_modules/open`.

This makes `@nx/dependency-checks` impossible to satisfy across
platforms — macOS and Linux disagree on whether the phantom package is
used.

## Expected Behavior

`import X = Y.Z` is a TypeScript namespace alias, not a module import.
The scanner should skip it entirely. Only actual module imports (`import
X = require('module')`, `import ... from 'module'`, etc.) should produce
dependency entries.

After this fix:
- `import X = Y.Z` is correctly identified as a namespace alias and
skipped
- `import X = require('module')` continues to work as a valid CommonJS
import
- String literals in switch/case statements and type aliases are no
longer misidentified as imports

## Related Issue(s)

Fixes #34644
2026-03-23 15:30:54 -04:00
Leosvel Pérez Espinosa d34beae458 chore(repo): fetch and post nightly failure details (#34928)
Example Slack message that would be sent (from a [trimmed-down test
run](https://github.com/nrwl/nx/actions/runs/23434241122)):

>🌟 *Golden Projects*
> Passing: 1
> Failing: 1
>
>🚨 *Failed Golden Projects*
>```
>| Failed project                 |
>|--------------------------------|
>| e2e-web                        |
>```
>
>🔧 *Other Projects*
> Passing: 0
> Failing: 0
>
>
>🔍 *Failure Details*
>
>———————————————————————————
>*e2e-web* — 2 combos (npm+yarn)
>Project failing since 2026-03-13 | Last fully passing: 2026-03-12
>
>📋 `src/file-server-legacy.test.ts` — failing since 2026-03-23 (1 day) 🆕
NEW
>```
> FAIL   e2e-web  src/file-server-legacy.test.ts (142.665 s)
>  ● file-server › should setup and serve static files from app
>
> Command failed: npx nx generate @nx/react:app react-app2511858
--no-interactive --e2eTestRunner=none --verbose
>    npm error Cannot read properties of null (reading edgesOut)
> npm error A complete log of this run can be found in:
/home/runner/.npm/_logs/2026-03-23T11_38_59_333Z-debug-0.log
>
>      426 |     logInfo(`Run Command: ${command}`);
>      427 |     const startTime = performance.now();
>    > 428 |     const logs = execSync(commandToRun, {
>          |                          ^
>      429 |       cwd: opts.cwd || tmpProjPath(),
>      430 |       env: {
>      431 |         CI: true,
>
>      at runCLI (../utils/command-utils.ts:428:26)
>      at Object.<anonymous> (src/file-server-legacy.test.ts:33:11)
>
>[plugin-worker] "nx/core/package-json" (pid: 36960) connected
>[plugin-worker] "nx/js/dependencies-and-lockfile" (pid: 36952) loaded
successfully
>```
>Failing combos: Linux/yarn/20, Linux/npm/20
2026-03-23 14:21:19 +01:00
Jack Baker 0e1f64dce7 fix(angular): update duplicate migration keys (#34961)
Fix duplicate migrations keys as only the last migration was getting
picked up.

## Current Behavior
When running nx migrate only the module federation migration is picked
up and not updating the core angular packages.

## Expected Behavior
Both migrations should be added to migrations.json.
2026-03-23 12:29:41 +00:00
AI-JamesHenry 9e5ba41546 fix(release): fall back to gh user search for author usernames (#34904) 2026-03-23 16:04:52 +04:00
Charlie Croom 79bbe1bdbc fix(core): use scroll-offset-based scrollbar positioning in TUI (#34689)
## Current Behavior

The TUI sidebar scrollbar thumb position is driven by the selected
task's index among tasks (`selected_task_index`). This means the
scrollbar can appear offset from the top even when `scroll_offset=0`
(i.e., the viewport is showing the very beginning of the list), because
the selected task might not be the first one. This makes it look like
there is content above that cannot be scrolled to.

<img width="1165" height="833" alt="Screenshot 2026-03-03 at 8 53 00 PM"
src="https://github.com/user-attachments/assets/43c695ad-c4a8-40c9-85b0-7677a8b83d12"
/>

Here, it looks scrolled down...but actually all the content is in view.

## Expected Behavior

The scrollbar should accurately represent which portion of the entry
list is currently in view. When at the top of the list
(`scroll_offset=0`), the thumb should be at the top. When scrolled to
the bottom, the thumb should be at the bottom.

## Related Issue(s)

N/A (discovered via visual inspection)

## Details

Switch the scrollbar from selection-based metrics to scroll-offset-based
metrics:

- `content_length` = total entries (including spacer rows)
- `viewport_content_length` = viewport height
- `position` = scroll offset

This ensures the scrollbar reflects the actual viewport position rather
than the selected task's position within the task list.

Also adds `total_entries` and `viewport_height` fields to
`ScrollMetrics` to make these values available without additional lock
acquisitions.

Co-authored-by: Amp <amp@ampcode.com>
2026-03-20 22:25:21 -04:00
Leosvel Pérez Espinosa e0b7f1236b fix(core): respect --parallel limit for discrete task concurrency (#34721)
## Current Behavior

`--parallel=N` doesn't cap discrete task concurrency when continuous
tasks exist. `getThreadCount` inflates the thread count to `N +
continuousCount`, and all threads are fungible — any thread picks up any
task. With `--parallel=1` and 2 continuous tasks, 3 threads run,
allowing up to 3 discrete tasks concurrently.

## Expected Behavior

`--parallel=N` caps discrete task concurrency to N. Continuous tasks get
dedicated threads that don't inflate the discrete limit.

### Changes

- **Two-pool thread model**: Split the unified thread pool into discrete
and continuous pools. Each pool runs its own loop and only picks up
matching tasks.
- **`getThreadPoolSize`** (renamed from `getThreadCount`): Returns `{
discrete, continuous, total }`. Discrete pool = `options.parallel`,
continuous pool = number of continuous tasks.
- **`executeDiscreteTaskLoop`**: Handles batches + discrete tasks only.
Uses slot-based groupIds via `closeGroup`/`openGroup`.
- **`executeContinuousTaskLoop`**: Handles continuous tasks only. Uses
counter-based groupIds (`parallel + n++`). Exits once all continuous
tasks have been started.
- **`nextTask(filter?)`** on `TasksSchedule`: Optional filter param to
dequeue only matching tasks. Scheduler stays unaware of pools/limits.

## Related Issue(s)

Fixes #34117
Fixes #31494
2026-03-20 22:23:38 -04:00
Leosvel Pérez Espinosa 5e5184ed69 fix(core): prevent TUI crash when task output arrives after completion (#34785)
## Current Behavior

`nx run-many` with TUI enabled crashes with `TypeError: Cannot read
properties of undefined (reading 'push')` in `tui-summary-life-cycle.ts`
when `appendTaskOutput` is called for a task whose output entry was
already cleaned up by `endTasks`.

## Expected Behavior

Late-arriving task output after `endTasks` has finalized the task is
silently discarded instead of crashing. The output is redundant since it
was already captured when the task completed.

## Related Issue(s)

Fixes #34677
2026-03-20 22:19:23 -04:00
Craigory Coppola 1fc384147b fix(core): split-target should handle projects with colons in name better (#34725)
## Current Behavior
- `splitTarget` causes issues when a project name has more than one
colon
- Project name substitution is triggered when a project depends on the
orginal name of a renamed project, even if the renamed project was
renamed before the dep was registered

That second one is hard to understand. Imagine the real scenario below:

- @nx/gradle was reading settings.gradle.kts and naming the root project
`nx`
- The package.json inference plugin renames it to `@nx/nx-source`
- The package.json inference plugin infers the `nx` project in
`packages/nx`
- The package.json inference plugin reads a config that has `dependsOn:
[nx:build]`
- The substitutors run, and update the dependsOn to
`@nx/nx-source:build`

## Expected Behavior
splitTarget follows the below precedence:

- If splitting a target string thats embedded in a specific project
configuration, targets on that project are preferred
- Targets belonging to the project with the longest name that is valid
from joining segments left to right
- Targets that have the longest name from joining segments are preferred
- Configuration is the remaining segments after picking off the longest
valid project containing a valid target.

Substitutors prefer registering by root if a project with a given name
exists, and only register by name if no project with that root exists
(e.g. if a plugin adds a dependsOn to a project that was inferred by a
later plugin, this would be common if a custom plugin is reading
project.json to get a name or smth).

## AI Summary

> # Branch Analysis: `fix/split-target-fixes` vs `master`
> 
> ## Summary
> 
> | Metric | Lines |
> |--------|------:|
> | **Total raw diff (added+removed, non-test)** | 2,840 + 1,221 = 4,061
|
> | **Lines that were just moved (file split)** | ~960 |
> | **Truly new/changed lines (non-test)** | ~570 |
> | **Test file changes (raw diff)** | 3,109 added / 2,242 removed |
> 
> ## Commits
> 
> | SHA | Message |
> |-----|---------|
> | `57ec87b3c4` | fix(core): split-target should handle projects with
colons in name better |
> | `af1ebc90ab` | fix(core): avoid renaming projects based on former
name if they were rooted when dep is drawn |
> | `b2fffc60c7` | cleanup(core): split project-configuration-utils into
focused modules |
> | `3bae3048d8` | fix(core): fixup name substitution manager |
> 
> ## File Split: `project-configuration-utils.ts` -> 4 modules
> 
> The original `project-configuration-utils.ts` (1,407 lines) was split
into focused modules. **~960 lines were moved as-is** (identical minus
whitespace/formatting) into the new files. The remaining changes are
actual logic modifications.
> 
> | File | Total Lines | Moved from original | Truly new/changed |
> |------|------------:|--------------------:|------------------:|
> | `project-configuration-utils.ts` (remaining) | 444 | ~395 | ~49 |
> | `target-merging.ts` | 494 | ~430 | } |
> | `target-normalization.ts` | 282 | ~250 | } ~111 combined |
> | `project-nodes-manager.ts` | 365 | ~285 | } |
> | **Subtotal** | 1,585 | ~1,360 | ~160 |
> 
> Additionally, ~39 lines were removed from the original and not moved
anywhere (dead code removal or refactored away).
> 
> ## Actual Code Changes (non-test, excluding moved lines)
> 
> ### Major changes
> 
> | File | New | Removed | Net | Description |
> |------|----:|--------:|----:|-------------|
> | `split-target.ts` | ~211 | ~38 | +173 | New logic for handling
projects with colons in names |
> | `name-substitution-manager.ts` | ~152 | ~85 | +67 | Fix: avoid
renaming rooted projects based on former name |
> | Split files (combined, new logic only) | ~111 | — | +111 | New code
introduced during the split refactor |
> | `project-configuration-utils.ts` (new logic only) | ~49 | ~39 | +10
| Residual new code after split |
> 
> ### Minor edits (import path updates, small fixes)
> 
> | File | Added | Removed |
> |------|------:|--------:|
> | `parse-target-string.ts` | 7 | 1 |
> | `command-line/show/target.ts` | 11 | 7 |
> | `devkit-internals.ts` | 3 | 5 |
> | `tasks-runner/utils.ts` | 5 | 3 |
> | `build-project-graph.ts` | 2 | 4 |
> | `error-types.ts` | 2 | 4 |
> | `command-line/run/run-one.ts` | 2 | 1 |
> | `ngcli-adapter.ts` | 1 | 1 |
> | `convert-nx-executor.ts` | 1 | 1 |
> | `project-configuration.ts` (generators) | 1 | 1 |
> | `package-json.ts` | 1 | 1 |
> | `settings.gradle.kts` | 1 | 1 |
> | **Minor edits subtotal** | **37** | **30** |
> 
> ### Other new files
> 
> | File | Lines | Description |
> |------|------:|-------------|
> | `packages/devkit/CLAUDE.md` | 62 | Dev documentation |
> | `__fixtures__/merge-create-nodes-args.json` | 100 | Test fixture
data |
> 
> ## Final Tally: True Non-Test Changes
> 
> | Category | Lines |
> |----------|------:|
> | New logic in `split-target.ts` | ~211 |
> | New logic in `name-substitution-manager.ts` | ~152 |
> | New logic in split module files | ~111 |
> | New logic in remaining `project-configuration-utils.ts` | ~49 |
> | Minor import/path updates across 12 files | ~37 added / ~30 removed
|
> | New non-code files (CLAUDE.md, fixture JSON) | 162 |
> | **Total truly new/changed lines** | **~570 added, ~160 removed** |
> | Moved lines (file split, not real changes) | **~960** |


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

Fixes #

---------

Co-authored-by: FrozenPandaz <jasonjean1993@gmail.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-21 00:37:00 +00:00
Colum Ferry 732a08c77d chore(core): build nx to local dist and use nodenext (#34111)
## Current Behavior

The `nx` package compiles its TypeScript output to
`../../dist/packages/nx/` (relative to the package root), which places
build artifacts outside the package directory at the repo root level
(`dist/packages/nx/`). This makes the package structure harder to reason
about, complicates the build pipeline, and doesn't align with how most
packages organize their output.

The package uses `"module": "commonjs"` with basic module resolution,
which limits future migration paths toward ESM.

## Expected Behavior

The `nx` package now builds to a local `dist/` directory within the
package itself (`packages/nx/dist/`). This is a cleaner, more standard
layout — like having your tools in your own toolbox instead of scattered
across the workshop.

### Key changes:

**Build configuration (`packages/nx/tsconfig.lib.json`):**
- `outDir` changed from `../../dist/packages/nx` to `dist` (local to
package)
- `module` changed to `nodenext` with `moduleResolution: nodenext`
- Updated `include` patterns to explicitly list source directories

**Package entry points (`packages/nx/package.json`):**
- `bin` paths updated: `./bin/nx.js` → `./dist/bin/nx.js`
- Added `"type": "commonjs"` explicitly
- Added comprehensive `exports` map with `@nx/nx-source` condition for
dev/test resolution back to TS source
- Added `postinstall` path update to `./dist/bin/post-install`

**Module resolution fixes:**
- Created `src/utils/handle-import.ts` — a CJS-first import utility that
falls back to ESM `import()` for ESM-only packages, providing a single
migration point for future ESM work
- Converted dynamic `await import()` calls to
`require(require.resolve())` pattern where needed to satisfy `nodenext`
extension requirements
- Plugin worker spawn path now uses correct `.ts`/`.js` extension based
on runtime context (source vs compiled)

**Test infrastructure:**
- Added custom `jest-resolver.js` for the `nx` package that resolves
`nx/...` imports using the `@nx/nx-source` exports condition, so tests
run against TS source
- Updated `jest.preset.js` with SWC transformer configuration
- Added chalk mock for test compatibility

**CI and tooling:**
- Conformance check updated to build `workspace-plugin` first (the Nx
Cloud runner lacks `@swc-node/register` for TS resolution)
- Conformance rule paths in `nx.json` now point to compiled
`dist/workspace-plugin/src/...` output
- Added `dist` to eslint ignore patterns to prevent linting compiled
output
- Added workspace-plugin build target and updated its dependencies

**Other fixes:**
- Various import path fixes across `create-nx-workspace`, gradle, and
other packages to work with `nodenext` resolution
- Updated e2e test paths to reference the new dist location
- Fixed `.gitignore` and `.npmignore` for the new output structure

## Related Issue(s)

Internal infrastructure improvement — no external issue.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Coly010 <Coly010@users.noreply.github.com>
Co-authored-by: FrozenPandaz <jasonjean1993@gmail.com>
2026-03-20 19:30:03 -04:00
Leosvel Pérez Espinosa d5f51d6d33 fix(linter): prepend framework configs before baseConfig in flat config generation (#34898)
## Current Behavior

Framework generators append predefined configs (`flat/react`,
`flat/angular`, etc.) after `baseConfig` in the flat config array. In
flat config, later entries override earlier ones, so framework rules
override user root rules.

Additionally, the parser/plugins config entries in `flat/typescript`,
`flat/javascript`, and `flat/angular` have no `files` restriction,
applying the TypeScript parser to all files globally — including
`.html`, `.json`, and other non-TS/JS files. This was partially fixed in
PR #28381 (which scoped rules/extends) but the parser entries were
missed.

## Expected Behavior

Framework configs are inserted before `baseConfig`, giving user root
config higher priority. Root standalone projects (no `baseConfig`) are
unaffected.

Parser/plugins entries are scoped to their respective file types, so
`.html` files get the correct parser (Angular template parser, or ESLint
default) instead of the TypeScript parser.

## Changes

- Implement `checkBaseConfig` option in `addBlockToFlatConfigExport` to
insert before `...baseConfig` when present
- Framework generators (`@nx/react`, `@nx/angular`, `@nx/next`, etc.)
pass `checkBaseConfig: true`
- Scope parser entries in `flat/typescript` to `**/*.ts, **/*.tsx,
**/*.cts, **/*.mts`
- Scope parser entries in `flat/javascript` to `**/*.js, **/*.jsx,
**/*.cjs, **/*.mjs`
- Scope processor/plugins entry in `flat/angular` to `**/*.ts`
- Refactor `addPredefinedConfigToFlatLintConfig` to use an options
object for optional params
- Fix regex patterns in react-native and expo jest config templates to
use `[.]` instead of `\.` — avoids `no-useless-escape` lint errors and
fixes a latent bug where `\.` in a string literal matched any character
instead of a literal dot

## Related Issue(s)

Fixes #32923
2026-03-20 17:53:24 -04:00
Jason Jean 2c4fb2abc0 fix(module-federation): enable ESM output for Angular rspack MF plugin (#34839)
## Current Behavior

When using Angular + Rspack + Module Federation, the
`NxModuleFederationPlugin` (Angular variant) sets `library: { type:
'module' }` on the Module Federation plugin config, which causes
`remoteEntry.js` to emit ESM `export` statements. However, the
compiler's `experiments.outputModule` and `output.module` flags are not
set, so the MF runtime tries to load the remote entry as a classic
script. This results in:

```
Uncaught SyntaxError: Unexpected token 'export' (at remoteEntry.js:48774:1)
```

This is especially broken during `nx serve` (dev server), because
`@nx/angular-rspack`'s `createConfig` only sets
`experiments.outputModule = true` for production builds, not dev server
builds.

## Expected Behavior

The Angular rspack `NxModuleFederationPlugin` should ensure
`experiments.outputModule = true` and `output.module = true` are set on
the compiler when using `library: { type: 'module' }`, so that Module
Federation works out of the box in both dev and production modes.

This aligns with how the Angular **webpack** MF config already handles
it (in `with-module-federation/angular/with-module-federation.ts`).

## Related Issue(s)

Fixes #34584
Fixes #33992
2026-03-20 14:37:50 -04:00
Jack Hsu 30d64c4ba6 fix(nx-dev): build nx-dev in-place to fix ai package resolution (#34730)
## Current Behavior

The default `@nx/next:build` for nx-dev outputs to `dist/nx-dev/nx-dev`.
At runtime, Node.js can't resolve the `ai` package from that path
because `node_modules` is at the workspace root — causing
`ERR_MODULE_NOT_FOUND` on `/ai-chat`.

Additionally, `ui-video-courses` is missing `@nx/nx-dev-ui-icons` as a
dependency (introduced by #34669), causing a webpack compilation
failure.

## Expected Behavior

Build in-place to `nx-dev/nx-dev` (matching the existing Netlify config)
so `.next` stays close to `node_modules` and package resolution works.
This also simplifies config by removing the Netlify vs Vercel branching
in sitemap scripts and project.json configurations.


## Other Notes

This PR also:
- Redirects `/` to `/blog` since almost everything else, including
homepage, are in Framer.
- Uses `@nx/next/plugin` to infer targets now so we no longer use any
`@nx/next:*` executors.
- Cleans up `nx-dev` project config so it no longer has `serve-docs` and
other weird setup. It is purely just `nx dev nx-dev` or `nx build
nx-dev` or `nx start nx-dev` like a normal Next.js app.
- Removes extra `NETLIFY` env var checks to point outputs in different
places.

## Related Issue(s)

Closes DOC-418

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2026-03-20 14:33:10 -04:00
Jack Hsu 68fbfae286 docs(misc): replace cloud onboarding with CNW in tutorials (#34935)
## Current Behavior

Tutorials direct users to cloud.nx.app CTAs requiring GitHub account +
full cloud onboarding before the tutorial starts. CNW starts dropped to
~1,800/day weekday (target ~2,700). Self-healing CI content buried at
bottom of tutorials where only 15-20% of users scroll.

## Expected Behavior

- Tutorials use npx create-nx-workspace as primary path, cloud link kept
as secondary text link
- llm_only tags added to tell AI agents to use CLI only (they can't
handle the browser OAuth flow)
- Tutorial file trees, app names, and scopes updated to match what CNW
actually generates
- Self-healing CI extracted to standalone "Setting up CI" tutorial
- Nx Cloud page moved from Getting Started to Orchestration & CI
overview (redirect added)
- Sidebar labels converted to sentence case per style guide
- AI integrations moved before Editor setup in sidebar (higher traffic)
- Tutorials expanded by default in sidebar
- Intro page now shows CNW and nx init commands directly

## Notes

A follow-up to break tutorials down into smaller, more focused topics
will be the next step.

<img width="547" height="400" alt="image"
src="https://github.com/user-attachments/assets/b717ee54-0dc6-4c08-b1d3-0d80c9dce1df"
/>


## Related Issue(s)

Closes DOC-448
2026-03-20 13:12:43 -04:00
Jason Jean 7d25d08a6b fix(devkit): prevent double install in generators for TS solution workspaces (#34891)
## Current Behavior

In TS solution workspaces, library generators pass `alwaysRun=true` to
`installPackagesTask` to ensure symlinks are created for new packages.
However, when the init generator already triggered an install (via
`addDependenciesToPackageJson`), the `alwaysRun` flag bypasses the cache
and forces a redundant second install.

## Expected Behavior

Only a single install should run per generator invocation. If install
already ran this cycle, subsequent `ensureInstall` calls should be
skipped since the previous install already picked up all filesystem
changes (including `pnpm-workspace.yaml` updates for symlinks).

## Fix

Renamed `alwaysRun` to `ensureInstall` in `installPackagesTask` and
simplified the install condition:

```typescript
if (packageJsonDiffers || (ensureInstall && !installAlreadyRan))
```

This handles both cases:
- **First library** (deps change): init callback runs install →
`ensureInstall` callback sees install already ran → skips. One install.
- **Second+ library** (no dep changes): init callbacks are no-ops →
`ensureInstall` callback sees no prior install → runs. One install.

## Related Issue(s)

<!-- No existing issue — discovered during investigation -->
2026-03-20 17:02:20 +00:00
Louie Weng 52e737deb2 chore(gradle): bump gradle project graph plugin version to 0.1.16 (#34939)
## Current Behavior

The `dev.nx.gradle.project-graph` plugin is at version `0.1.15`.

## Expected Behavior

The `dev.nx.gradle.project-graph` plugin is bumped to version `0.1.16`,
with a corresponding Nx migration so users are automatically updated
when they migrate to `22.7.0-beta.2`.

## Related Issue(s)

N/A - routine version bump

---

### Changes

- Updated `gradleProjectGraphVersion` in
`packages/gradle/src/utils/versions.ts`
- Updated `version` in `packages/gradle/project-graph/build.gradle.kts`
- Created migration TS and MD files in
`packages/gradle/src/migrations/22-7-0/`
- Added migration entry in `packages/gradle/migrations.json`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 16:50:07 +00:00
Jason Jean ef3a517dcd chore(repo): update nx to 22.7.0-beta.1 (#34932)
## Current Behavior

Workspace uses nx 22.7.0-beta.0 and related @nx/* packages at
22.7.0-beta.0.

## Expected Behavior

Workspace uses nx 22.7.0-beta.1 and related @nx/* packages at
22.7.0-beta.1.

## Related Issue(s)

N/A — routine version bump.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-03-20 11:36:09 -04:00
Juri 56acdf7ed2 docs(nx-cloud): add guide for using bun with Nx Cloud CI 2026-03-20 15:29:15 +01:00
Jason Jean c1a93cb061 fix(core): set windowsHide: true on all child process spawns (#34894)
## Current Behavior

On Windows, the Nx daemon runs as a detached background process with no
console. When child processes are spawned without `windowsHide: true`
(Node.js) or `CREATE_NO_WINDOW` (Rust/Win32), Windows allocates a new
visible console window for each subprocess. This causes command prompt
windows to flash on screen during:

- Project graph creation (daemon spawn, plugin workers)
- Task hashing (runtime hashers)
- NX Console extension detection (`code.cmd --list-extensions`, etc.)
- AI agent configuration checks (`git ls-remote`, npm install)
- Machine ID retrieval, package manager version detection, git
operations, and more

The issue is especially noticeable "after a little bit" following daemon
startup, because background operations like the NX Console status check
and AI agents configuration check kick off after the initial project
graph is computed.

## Expected Behavior

No console windows should flash on Windows. All child process spawns use
`windowsHide: true` (Node.js) or `CREATE_NO_WINDOW` (Rust) to suppress
console windows.

## Root Causes Found

Investigation using a child_process interceptor in the daemon revealed
multiple sources:

1. **Rust native `ide/install.rs`** — `Command::new("code.cmd")` calls
for NX Console extension detection/installation were missing
`CREATE_NO_WINDOW`
2. **Rust native `hash_runtime.rs`** — Had its own `CREATE_NO_WINDOW`
handling but was duplicated
3. **`nx@latest` temp install** — The daemon downloads `nx@latest` to a
temp directory for NX Console and AI agent checks. The install process
(`pnpm add -D nx@latest`) and the downloaded code's `git ls-remote`
calls run without `windowsHide: true`
4. **~120 Node.js `child_process` calls** — Various
`spawn`/`exec`/`execSync` calls across the codebase were missing
`windowsHide: true`

## Changes

### Node.js child_process fixes
- Set `windowsHide: true` on all `spawn`/`exec`/`execSync`/`spawnSync`
calls across the codebase (~120 files)
- Added custom ESLint rule `@nx/workspace/require-windows-hide` that
errors when any spawn/exec call is missing `windowsHide: true`

### Rust native fixes
- **New shared util `native/utils/command.rs`** with `create_command()`
and `create_shell_command()` that set `CREATE_NO_WINDOW` on Windows —
centralizes the pattern so future Rust code gets it right by default
- **`ide/install.rs`** — Use `create_command()` for `code.cmd` calls
(list-extensions, install-extension, version check)
- **`hash_runtime.rs`** — Replaced local `create_command_builder()` with
shared `create_shell_command()`
- **`machine_id/mod.rs`** — Updated to use shared
`create_shell_command()`

### Daemon background operation fixes
- **`handle-configure-ai-agents.ts`** — Now respects `NX_USE_LOCAL` env
var to skip downloading `nx@latest`, avoiding the pnpm install that
opens windows. Once these fixes ship in a release, the downloaded
`nx@latest` will also have the fixes.

### Inlined node-machine-id
- Replaced the `node-machine-id` npm package with an inlined
implementation in `machine-id-cache.ts` that uses `windowsHide: true`
- The original package used `exec`/`execSync` without `windowsHide`

## Related Issue(s)

Supersedes #34455

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-03-20 09:29:44 -04:00
Juri Strumpflohner 2086e4c0b6 fix(testing): gracefully handle broken jest configs in alias migration (#34901)
## Current Behavior

The `replace-removed-matcher-aliases` migration crashes the entire
migration runner when a project has a broken or misconfigured
`jest.config.ts`. This was discovered while upgrading nx-labs from Nx 21
to 22 via `nx migrate --run-migrations`.

The migration uses Jest's `readConfig()` and `Runtime.createContext()`
to resolve jest configs, but has no error handling around these calls.
If any project has issues like:

- A missing file referenced in the config (e.g. `.lib.swcrc` that was
renamed to `.swcrc`)
- A missing transform module (e.g. `@swc/jest` not installed)
- A missing preset file (e.g. `jest.preset.ts` instead of
`jest.preset.js`)

...the entire migration fails with an opaque error:

```
Error: Command failed: /var/folders/.../node_modules/.bin/nx _migrate --run-migrations
    at checkExecSyncError (node:child_process:925:11)
  status: 1,
  stdout: null,
  stderr: null
```

The actual errors are swallowed by the nested `execSync` call, making it
very hard to debug.

## Expected Behavior

The migration should skip projects with broken jest configs and continue
processing the rest of the workspace.

## Fix

Wrapped the `readConfig` / `Runtime.createContext` /
`SearchSource.getTestPaths` block in a try-catch that skips the failing
project. This matches the defensive pattern already used in
`packages/jest/src/plugins/plugin.ts` for similar jest config
resolution.

## Test Plan

- Added 3 tests covering: missing file reference, missing preset, and
verifying valid projects are still processed when a sibling project has
a broken config
- All existing tests continue to pass
2026-03-20 10:20:38 +01:00
Louie Weng 747df3159c fix(gradle): remove annotations from atomizer (#34871)
<!-- 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
<!-- This is the behavior we have today -->
The Gradle plugin's test class atomizer was incorrectly treating Kotlin
annotation class declarations as test targets, generating invalid test
tasks for them. This caused issues when projects defined custom
annotations alongside their test classes—the atomizer would attempt to
run annotation classes as tests.

## Expected Behavior
              
Both the AST-based parser and the regex fallback parser now skip
annotation classes, matching the existing behavior for data classes,
enum classes, sealed classes, and abstract classes. A new test suite
covers all annotation class exclusion scenarios for both parsers,
including files with multiple annotation classes and mixed
annotation/test class files.

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: lourw <lourw@users.noreply.github.com>
2026-03-19 20:16:09 -07:00
Leosvel Pérez Espinosa a4e8fefd5c fix(core): prevent DB corruption from concurrent initialization (#34861)
## Current Behavior

When multiple processes call `connectToNxDb()` concurrently (plugin
workers via `startAnalytics()`, daemon, main CLI), two bugs can corrupt
the workspace database:

**Bug 1: Lock file inode race.** `unlock_file()` deletes the lock file
after unlocking, allowing a subsequent `File::create()` to produce a new
file with a different inode. Two processes can hold "the lock"
simultaneously on different file objects, breaking mutual exclusion.

**Bug 2: Partial file cleanup on version mismatch/connection failure.**
The `reason` arm and `Err` arm in `initialize_db` call
`remove_file(db_path)` which only deletes `.db`, leaving stale `.db-wal`
and `.db-shm` on disk. The recursive `initialize_db` creates a fresh
`.db`, but SQLite detects the stale WAL (different inode salt) and
deletes it — destroying all data that existed only in the WAL.

Both bugs lead to:
```
Database file exists but has no metadata table.
```

## Expected Behavior

1. Lock file persists across lock/unlock cycles — all processes
serialize through the same inode
2. When DB recreation is needed, all auxiliary files (`.db`, `.db-wal`,
`.db-shm`) are cleaned up together via `remove_all_database_files`

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-19 18:51:03 -04:00
Craigory Coppola 91b1414a9e fix(core): pass collectInputs flag through daemon IPC for task hashing (#34915)
When the daemon handles task hashing, the `NativeTaskHasherImpl` checked
`hasTaskInputSubscribers()` in the daemon process where no subscribers
exist, causing the native Rust hasher to skip input collection entirely.
This resulted in empty input arrays in IO tracing signals.

The fix passes collectInputs from the client process (where subscribers
are registered) through the daemon IPC to the hasher, so the daemon uses
the client's subscriber state instead of its own.
2026-03-19 17:02:45 -04:00
Jack Hsu 1081dbdceb fix(core): remove CRA migration logic from nx init (#34912)
## Current Behavior

`nx init` has a special code path for Create React App (CRA) projects
that installs Vite-related dependencies incompatible with `@nx/vite`
when Vite 8 is resolved, causing failures for npm workspaces.

CRA is essentially unused for years so there's no point to keep it
around.

## Expected Behavior

CRA projects are no longer special-cased in `nx init`. They flow through
the normal npm repo path, which detects plugins like `@nx/vite` via the
standard `detectPlugins()` mechanism.

<img width="1279" height="448" alt="Screenshot 2026-03-18 at 2 34 56 PM"
src="https://github.com/user-attachments/assets/17da3c6d-8aef-450f-baaa-6014e03cf41f"
/>

<img width="1280" height="432" alt="Screenshot 2026-03-18 at 2 35 01 PM"
src="https://github.com/user-attachments/assets/e02ccda5-9faf-428f-878d-348e4cc44d74"
/>

<img width="1270" height="821" alt="Screenshot 2026-03-18 at 2 35 15 PM"
src="https://github.com/user-attachments/assets/fdd99af5-db7e-422b-be42-a817c9dcefa2"
/>


## Related Issue(s)

Closes NXC-4107
2026-03-19 16:38:22 -04:00
cylewaitforit ffd2f614e0 docs(core): add Yarn catalog to dependency management (#34874)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
Adds references to [Yarn catalog](https://yarnpkg.com/features/catalogs)
to dependency management documentation.

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

Related #34377

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
2026-03-19 15:14:46 -04:00
Juri ea69d99a9b docs(misc): update self-healing CI video embed 2026-03-19 18:52:34 +01:00
Leosvel Pérez Espinosa b9f251d6fc fix(core): improve error handling in nx migrate registry fetching (#34926)
## Current Behavior

Several issues in `nx migrate` registry fetching cause confusing errors:

- `packageRegistryPack` uses `pnpm pack` for pnpm users, but `pnpm pack`
only packs the local project (unlike `npm pack` which downloads remote
packages). This silently fails for all pnpm users, always falling back
to the slower install path.
- On Windows, `extractFileFromTarball` fails because `join('package',
migrationsFilePath)` produces backslash paths that don't match
forward-slash tarball entries.
- When the install fallback also fails,
`getPackageMigrationsUsingInstall` returns `{}` instead of throwing. The
missing `version` property (`undefined`) propagates through
`packageUpdates` and `collectedVersions`, producing `Fetching
nx@undefined`.
- The install fallback can fail on peer dependency conflicts since
`legacy-peer-deps` was removed as a default (PR #33014), even though the
install only needs files on disk (not a valid dependency tree).
- The `.catch()` in `fetchMigrations` swallows errors without logging,
making it impossible to diagnose registry fetch failures.

## Expected Behavior

- `packageRegistryPack` always uses `npm pack` since it's the only
package manager that supports downloading remote packages
- Tarball entry matching uses `joinPathFragments` to normalize paths
(forward slashes) for cross-platform compatibility
- `getPackageMigrationsUsingInstall` throws on failure with a
descriptive error instead of returning an empty object
- Install fallback sets `npm_config_legacy_peer_deps=true` since it only
needs files on disk, not a valid dependency tree
- Registry fetch errors are logged at verbose level
(`NX_VERBOSE_LOGGING=true`) for debuggability

## Related Issue(s)

Fixes #33135
2026-03-19 17:45:50 +01:00
Leosvel Pérez Espinosa 1db5b32410 fix(core): ensure postTasksExecution fires on SIGINT for continuous tasks (#34876)
## Current Behavior

When pressing Ctrl+C on continuous tasks, `postTasksExecution` never
fires because `process.exit()` in `running-tasks.ts` SIGINT handlers
kills the process before the orchestrator can run async cleanup and
lifecycle hooks.

## Expected Behavior

`postTasksExecution` fires reliably on Ctrl+C with complete task
results, without causing stale `RunningTasksService` DB entries that
block subsequent `nx` invocations with "Waiting for ... in another nx
process" messages.

## Technical Details

Re-applies #34623 (reverted in #34869) with fixes for the issues that
caused CI failures.

**Root cause of the revert**: Removing `process.exit()` from SIGINT
handlers left the nx process alive during async cleanup. The
`running_tasks` DB entry persisted with a still-alive PID, so new nx
processes saw it as a running task and hung.

**Fix 1 — Early DB cleanup**: Synchronously remove all owned DB entries
in the SIGINT handler *before* starting async cleanup. This replicates
the cleanup that `process.exit()` + Rust `Drop` previously provided —
from any external observer's perspective, the tasks are gone
immediately.

**Fix 2 — Always register onExit in startContinuousTask**: The original
PR added a guard that skipped `onExit` registration for initiating
tasks, assuming `executeNextBatchOfTasksUsingTaskSchedule` would handle
it. But `runContinuousTasks()` (used by DTE agents and Playwright) calls
`startContinuousTask` directly without going through `run()`. The
missing handler meant task exit was never processed — no DB cleanup, no
lifecycle hooks. This caused verdaccio (local-registry) to become
unreachable on DTE agents. The fix always registers `onExit` in
`startContinuousTask` and simplifies the
`executeNextBatchOfTasksUsingTaskSchedule` handler to only unblock the
thread.

Changes:
- Remove `process.exit()` from `running-tasks.ts` SIGINT handlers (lets
orchestrator run)
- Replace `cleanupDone` boolean with `cleanupPromise` (fixes
SIGINT/SIGTERM race)
- Set `stopRequested = true` for SIGTERM/SIGHUP (correct task
classification)
- Early synchronous DB cleanup in non-TUI SIGINT handler
- Always register `onExit` handler in `startContinuousTask` for both
initiating and non-initiating tasks
- Simplify initiating task handler in
`executeNextBatchOfTasksUsingTaskSchedule` to only call `res()`
2026-03-19 11:22:13 -04:00
Leosvel Pérez Espinosa e1e4ac8401 fix(core): avoid redundant project graph requests in ngcli adapter (#34907)
## Current Behavior

The Angular devkit adapter (`ngcli-adapter.ts`) calls
`createProjectGraphAsync()` in multiple places, even though callers
(executors, generate command, migrate command) already have the project
graph available. This results in redundant requests to create the graph.

## Expected Behavior

Reuse the project graph from callers when available, falling back to
reading from cache (`readCachedProjectGraph()`) or
`createProjectGraphAsync()` only when necessary.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-19 11:10:54 -04:00
Craigory Coppola 17de526516 docs(core): show supported version range for subcommand (#34889)
## Current Behavior
There's not a great way to attach metadata to CLI commands to influence
rendering the markdown docs for them

## Expected Behavior
There's a metadata system currently used to express minimum support
version for the show target command

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

Fixes #
2026-03-19 11:10:19 -04:00
John Wiegert ba6e036b1c fix(testing): handle undefined options in playwright preset (#34750)
## Current Behavior

When calling `nxE2EPreset(__filename)` without passing the optional
`options` parameter, the function throws a runtime error because
`options.openHtmlReport` accesses a property on `undefined`. Other
property accesses in the function already use optional chaining
(`options?.testDir`, `options?.generateBlobReports`), but this one was
missed.

Additionally, the `openHtmlReport` property documents a default value of
`'on-failure'` via JSDoc, but that default was never actually applied in
the code.

## Expected Behavior

Calling `nxE2EPreset(__filename)` without the `options` argument works
without errors. The `openHtmlReport` option correctly falls back to
`'on-failure'` when not specified, matching the documented `@default` in
the interface.

## Related Issue(s)

N/A - Discovered when upgrading NX and we didn't pass options
2026-03-19 11:02:55 -04:00
Jack Hsu ec8be2deda docs(misc): remove outdated Angular multiple-workspace migration page (#34913)
## Current Behavior
The "Migrating Multiple Angular CLI Workspaces" page is a 26-line stub
with only a YouTube video. It doesn't mention `nx import` and contains
outdated guidance. The single-workspace migration guide (`angular.mdoc`)
also has outdated sections: a list of supported builders, a full CI
setup walkthrough, an irrelevant "From Nx Console" section, and a
reference to `karma.conf.js`.

## Expected Behavior
- The `angular-multiple.mdoc` page is removed with a redirect to the
main Angular migration guide.
- The main migration guide mentions `nx import` for consolidating
multiple Angular CLI projects.
- Outdated sections (Modified folder structure, Set up CI, From Nx
Console) are removed and replaced with concise links.
- The `nx-and-angular.mdoc` guide links to `nx import` docs instead of
the deleted page.

Preview:
https://deploy-preview-34913--nx-docs.netlify.app/docs/technologies/angular/migration/angular-multiple
(redirects to the updated page)


## Related Issue(s)
Closes DOC-419
2026-03-19 10:25:36 -04:00
Leosvel Pérez Espinosa 7054ffaf82 fix(linter): use root config to determine ESLint class in plugin (#34900)
## Current Behavior

The `@nx/eslint/plugin` uses `eslintConfigFiles[0]` to decide between
`FlatESLint` and `LegacyESLint`. Due to glob pattern ordering,
`.eslintrc.*` files sort before `eslint.config.*`, so a stray nested
`.eslintrc.json` (e.g., in `eslint-local-rules/`) causes the plugin to
pick `LegacyESLint` even when the root has a flat config — crashing with
"No ESLint configuration found" during project graph creation.

## Expected Behavior

The ESLint class is determined from the root config, matching ESLint's
own behavior where `find-up` from cwd decides the mode. Nested legacy
config files are irrelevant when a root flat config exists. When both
flat and legacy configs exist at root (mid-migration), flat config is
preferred.

## Related Issue(s)

Fixes #32110
2026-03-19 09:42:38 -04:00
Leosvel Pérez Espinosa f91bc6a665 fix(linter): convert project-level eslint configs and log when skipped (#34899)
## Current Behavior

The `convert-to-flat-config` generator silently skips project-level
`.eslintrc.json` files when `projectConfig.targets` is undefined (e.g.,
package.json-only projects in pnpm workspaces). The `@nx/eslint/plugin`
check is gated behind the targets check and never reached.

## Expected Behavior

Projects with `.eslintrc.json` are converted when `@nx/eslint/plugin` is
registered, even without explicit targets. When a project is skipped
because no ESLint lint target is detected, a warning is logged so users
know which projects were not converted and why.

## Related Issue(s)

Fixes #29458
2026-03-19 09:40:37 -04:00
Leosvel Pérez Espinosa 564d2a5a3e fix(linter): use native nx.configs in convert-to-flat-config for Nx plugins (#34897)
## Current Behavior

The `convert-to-flat-config` generator wraps all plugin extends with
`FlatCompat`, including Nx-specific ones like `plugin:@nx/typescript`.
The output doesn't match what freshly generated projects produce
(`nx.configs['flat/typescript']`). The `@nx` plugin registration uses a
manual `{ plugins: { '@nx': nxEslintPlugin } }` block instead of
`flat/base`.

## Expected Behavior

Nx plugin extends are converted to native `nx.configs['flat/X']`
entries. The `@nx` plugin registration uses `flat/base`. `FlatCompat` is
only used for third-party plugins. The import variable is normalized to
`nx` to match fresh generation.

## Related Issue(s)

Fixes #31736
2026-03-19 09:38:35 -04:00
Leosvel Pérez Espinosa 0f0f99624d fix(linter): detect require() calls in enforce-module-boundaries rule (#34896)
## Current Behavior

The `enforce-module-boundaries` rule only visits ESM AST nodes
(`ImportDeclaration`, `ImportExpression`, `ExportAllDeclaration`,
`ExportNamedDeclaration`). CommonJS `require()` calls bypass all
boundary checks entirely.

## Expected Behavior

`require()` and `require.resolve()` calls are detected and validated
against the same module boundary rules as ESM imports. Auto-fix is
skipped for `require()` nodes since they have no `specifiers`.

## Related Issue(s)

Fixes #34096
2026-03-19 09:37:17 -04:00
Eric Baer 213b1e44dc fix(core): properly quote shell metacharacters in CLI args passed to tasks (#34491)
## Current Behavior

When CLI arguments containing shell metacharacters (like `|`, `&`, `$`,
`;`, `*`, etc.) are passed through Nx to underlying tasks, they are not
properly quoted, causing shell interpretation errors.

For example, running:
```bash
nx test app --grep="@tag1|@tag2"
```

Would fail with `/bin/sh: @smoke: command not found` because the pipe
character `|` was interpreted by the shell as a pipe operator instead of
being passed as a literal string to the underlying command.

Users had to use awkward double-quoting workarounds like
`--grep='"@tag1|@tag2"'` to get the expected behavior.

## Expected Behavior

CLI arguments containing shell metacharacters should be automatically
quoted before being passed to underlying commands, so that:
```bash
nx test app --grep="@tag1|@tag2"
```

Works correctly and passes `--grep="@tag1|@tag2"` to the underlying test
runner without shell interpretation.

## Related Issue(s)

Fixes #32305
Fixes #26682

## Implementation Details

- Created a shared `needsShellQuoting()` utility in
`packages/nx/src/utils/shell-quoting.ts` that detects shell
metacharacters
- Updated `wrapArgIntoQuotesIfNeeded()` in `run-commands.impl.ts` to use
the shared utility
- Updated `stringShouldBeWrappedIntoQuotes()` in
`serialize-overrides-into-command-line.ts` to use the shared utility
- Fixed a bug where `arg.split('=')` would incorrectly split values
containing `=` (e.g., `--define=FOO=bar|baz`)
- Added proper escaping of embedded double quotes when wrapping values
- Added comprehensive test coverage

### Shell metacharacters now handled:
`|` `&` `;` `<` `>` `(` `)` `$` `` ` `` `\` `"` `'` `*` `?` `[` `]` `{`
`}` `~` `#` `!` and whitespace

---------

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2026-03-19 10:33:53 +01:00
Jason Jean 259b8236c3 fix(core): skip analytics and DB connection when global bin hands off to local (#34914)
## Current Behavior

When the globally installed Nx binary (`bin/nx.ts`) runs, it goes
through the following flow before determining whether to hand off to a
local Nx installation:

1. `ensureAnalyticsPreferenceSet()` — prompts user if analytics
preference not set
2. `startAnalytics()` — which calls `getDbConnection()` →
`connectToNxDb(directory, NX_VERSION)` using the **global** Nx version
and native bindings, then calls `initializeTelemetry(dbConnection, ...)`
to initialize telemetry
3. Sets `NX_ANALYTICS_SESSION_ID` env var

Then it checks which execution path to take:
- **`isNxCloudCommand`** — executes commands directly (no handoff)
- **`isLocalInstall`** — the global IS the local, calls `initLocal()`
(no handoff)
- **`localNx` exists** — hands off to the local Nx via
`require(localNx)`

In the handoff case, the local `bin/nx.ts` runs `main()` from scratch,
which calls `startAnalytics()` again. It sees `NX_ANALYTICS_SESSION_ID`
is already set and takes the "reuse session" shortcut — but telemetry
was already initialized with the wrong version's native bindings and DB
connection.

**Problems:**
- The global bin opens a DB connection with the **wrong `NX_VERSION`**
(global version, not local version) and **wrong native bindings**
- Analytics is initialized twice — once from global (incorrect), once
from local (correct but using session reuse path)
- The DB connection opened by the global bin is unnecessary since the
local Nx handles everything

## Expected Behavior

When the global bin is about to hand off to a local Nx installation, it
should **not** initialize analytics or open any DB connections. The
local Nx will handle analytics initialization correctly with its own
version and native bindings.

Analytics and DB connections should only be initialized in the two
branches where the global bin actually executes commands itself:
- `isNxCloudCommand` — needs analytics because it runs commands directly
- `isLocalInstall` — needs analytics because `initLocal()` doesn't
re-enter `bin/nx.ts`

## Related Issue(s)

<!-- Internal discovery during analytics work -->

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-18 23:31:49 -04:00
Jason Jean 724737d0cd chore(repo): correctly pin ktfmt version (#34917)
### Current Behavior

ktfmt... is supposed to be pinned

### Expected Behaior

ktfmt is now actually pinned
2026-03-18 21:03:34 -04:00
Caleb Ukle c03c4ccfcb fix(nx-dev): resolve changelog page 500 error (#34920)
## Current Behavior

Visiting [nx.dev/changelog](https://nx.dev/changelog) returns an HTTP
500 Internal Server Error. The page builds successfully during
deployment (prerendered as SSG), but the Netlify server handler fails at
runtime when serving the page.

## Expected Behavior

The changelog page loads correctly, displaying Nx release history with
version timelines and any manually authored changelog content.

## Related Issue(s)

Fixes #34909

## Changes

- **`next.config.js`**: Add `outputFileTracingIncludes` for
`public/documentation/changelog/**` so the changelog content directory
is included in the Netlify serverless function bundle (Next.js file
tracing can't detect `readdirSync` with string paths)
- **`pages/changelog.tsx`**: Wrap `changeLogApi.getChangelogEntries()`
in try/catch for graceful degradation if the directory is unavailable
during on-demand rendering
- **`rewrite-framer-urls.ts`**: Add `/changelog` to the edge function
`excludedPath` config so the Framer proxy edge function is bypassed
entirely for changelog requests
- **`_redirects`**: Fix malformed redirect on line 55 — destination path
was missing a leading `/`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 20:56:44 -04:00
Leosvel Pérez Espinosa 9e4a9aabb9 fix(js): preserve tsconfig fields in typescript plugin cache (#34908)
## Current Behavior

After certain cache state transitions (e.g., tsconfig parsing cache warm
but targets cache cold), the `@nx/js/typescript` plugin falls back to
the `production` named input instead of deriving precise inputs from
tsconfig `include`/`exclude` paths. This results in broader cache
invalidation than necessary, and in projects with `allowJs` or
`resolveJsonModule`, the wrong file extensions are tracked as inputs.
Output inference is also affected when `emitDeclarationOnly` or
`declarationMap` are set.

Running `nx reset` restores correct behavior, but the issue recurs.

## Expected Behavior

Inferred inputs and outputs are consistent regardless of cache state —
always matching what the tsconfig actually specifies.

The root cause was the tsconfig parsing cache serialization
(`toAbsolutePaths`/`toRelativePaths`) dropping fields the plugin relies
on: `raw.include`, `raw.exclude`, `raw.files`, and `options.allowJs`,
`options.resolveJsonModule`, `options.emitDeclarationOnly`,
`options.declarationMap`. These are now preserved, and
`TSCONFIG_CACHE_VERSION` is bumped to invalidate stale caches.
2026-03-18 14:21:01 -04:00
Leosvel Pérez Espinosa 2962f624b7 fix(js): normalize cwd path separator in typescript plugin targets (#34911)
## Current Behavior

On Windows, the TypeScript plugin produces `cwd` with backslash
separators (e.g., `cwd: "packages\\nx"`) for both the typecheck and
build targets. All paths in Nx targets should use `/` separators.

## Expected Behavior

The `cwd` option uses forward slashes on all platforms (e.g., `cwd:
"packages/nx"`).

## Related Issue(s)

Fixes NXC-4105
2026-03-18 14:15:52 -04:00
MaxKless 100d4f40a4 feat(core): add .nx/self-healing to .gitignore (#34855)
## Summary
- Self-healing auto-apply writes fix context to `.nx/self-healing/`, but
that directory was not in `.gitignore`. This adds it via a migration and
in the CAIA generator, following the same pattern as `.nx/polygraph`.

## Current Behavior

The `.nx/self-healing` directory is not gitignored. Users who run
self-healing auto-apply may accidentally commit generated fix context
files.

## Expected Behavior

`.nx/self-healing` is added to `.gitignore` automatically during `nx
migrate` (via a new migration) and when running the CAIA setup
generator.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-18 17:14:21 +00:00
Jack Hsu 44db03a87b fix(core): wrap CNW normalize args function in error handler (#34905)
This is a follow-up to https://github.com/nrwl/nx/pull/34902, where we
throw `CnwError` for known problems.

We need to wrap `normalizeArgsMiddleware` in a try-catch to invoke the
shared (extracted) error handler, since these errors are not within the
`main` function body but happens prior.

Before this PR:

<img width="1339" height="277" alt="image"
src="https://github.com/user-attachments/assets/911ecd4d-7117-434b-bff7-ff20dddfd84d"
/>


After:

<img width="1258" height="112" alt="image"
src="https://github.com/user-attachments/assets/f9c15bed-2df4-4e78-ac95-11f67cb9d4f5"
/>

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-18 09:56:02 -04:00
Caleb Ukle 58f4bc7b7f fix(nx-dev): add clickjacking protection headers to Netlify configs (#34893)
Add X-Frame-Options and Content-Security-Policy frame-ancestors headers
to prevent clickjacking on nx.dev marketing and docs sites.

Fixes DOC-449

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 08:44:17 -05:00
Craigory Coppola a8c5ca97be chore(core): abortGraphPhase -> notifyPhaseAborted (#34885)
## Current Behavior
#34799 has some method names that could have been better

## Expected Behavior
The methods are named to signify they are notifications, not
instructions

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-18 09:37:14 -04:00
MaxKless 2679029077 fix(core): share .agents skills dir across codex, cursor, gemini (#34882)
## Summary
- The upstream config repo (nx-ai-agents-config) now generates skills
into a shared `.agents/skills/` directory instead of separate per-agent
skills directories for codex, cursor, and gemini.
- Updated the `agentDirs` mapping so `.agents` is copied when any of
codex, cursor, or gemini are enabled, not just codex.
- Widened the `agent` field type from `Agent` to `Agent | Agent[]` to
support mapping a single directory to multiple agents.

## Key decisions
- Used `Agent | Agent[]` union type rather than always-array to minimize
changes to existing single-agent entries. The loop normalizes with
`Array.isArray` before checking.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 22:04:51 +09:00
Jack Hsu 5c0e05c3b3 fix(core): gracefully handle missing package manager and invalid workspace for CNW (#34902)
We want to capture more error and cancel events so that start events
match complete/error/cancel events. This PR ensures that more errors are
properly captured as `CnwError` rather than just `output.error` +
`process.exit(1)`;

- Invalid workpspace name (i.e. starting with a number) now throws
`CnwError` so we record them correctly
- Missing package manager is now captured as `CnwError` correctly
- SIGINT when workpspace is already created now send "cancel" event

Closes NXC-4095
2026-03-18 08:58:46 -04:00
Jason Jean 98ba5ac8ef chore(core): update nx to 22.6.0-rc.2 (#34892)
## Current Behavior

Nx packages are on a previous version.

## Expected Behavior

All Nx packages updated to 22.6.0-rc.2.

## Related Issue(s)

N/A - routine version bump for RC testing.
2026-03-17 20:01:27 -04:00
Jason Jean 6ee7091c55 Revert "feat(js): add deps-sync generator (#34407)" (#34888)
This reverts commit 8d71d5b57b.

## Current Behavior
<!-- This is the behavior we have today -->

This generator causes unnecessary changes

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

The generator is removed for now and will be reintroduced when it is
refined.

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

Fixes #
2026-03-17 17:15:54 -04:00
Caleb Ukle d6f22a2749 fix(nx-dev): cross site link checks working as expected (#34685)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
2026-03-17 15:55:06 -05:00
Caleb Ukle 47857419e6 docs(core): add technology-agnostic batch mode guide (#34813)
## Current Behavior

Batch mode documentation is scattered across individual technology pages
(TypeScript, Gradle, Maven, Jest) with no central guide explaining the
concept, how it works, or which executors support it.

## Expected Behavior

A new guide page at `guides/tasks--caching/batch-mode` provides a
technology-agnostic overview of batch mode, covering:

- What batch mode is and why it's faster
- How to enable it (`NX_BATCH_MODE=true` env var and `--batch` CLI arg)
- Which executors support it (with notes that Gradle/Maven have it on by
default)
- Caching and CI compatibility

Each technology-specific page now links back to the central guide for
the full explanation.

## Related Issue(s)

Fixes #DOC-420

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
2026-03-17 15:54:52 -05:00
Jack Hsu e2a056084a feat(core): bring back cloud prompts and templates in CNW (#34887)
## Current Behavior

CNW flow matches v22.1.3 (restored in #34671): no template prompt is
shown, the cloud prompt uses simplified "Would you like remote caching?"
wording, banner variant is locked to 0, and preset flow connects to
cloud during workspace creation.

## Expected Behavior

Restore the template prompt and cloud prompts that were removed in
#34671:
- **Template prompt**: "Which starter do you want to use?" with 5
choices (Minimal, React, Angular, NPM Packages, Custom)
- **Cloud prompt**: `determineNxCloudV2` ("Connect to Nx Cloud?") for
preset flow when no `--nxCloud` CLI arg; existing CI provider prompt
when `--nxCloud` is explicitly provided
- **Banner**: Variant 2 (box banner) for standard Nx Cloud URLs, variant
0 for enterprise
- **Preset flow**: Deferred cloud connection (`nxCloud: 'skip'`) instead
of connecting during workspace creation
- **Push logic**: Push to GitHub for both `nxCloud === 'github'` and
`nxCloud === 'yes'`
- **Messages**: "Try the full Nx platform?" wording, GitHub repo link in
push messages, "Your remote cache setup is almost complete." title

Preserves all subsequent changes (analytics prompt from #34818,
SANDBOX_FAILED fix, .gitignore updates).

## Related Issue(s)

Fixes NXC-4096
2026-03-17 16:15:04 -04:00
Jason Jean b73cc6939b fix(core): avoid overwhelming DB with connections during analytics init (#34881)
## Current Behavior

Every process that initializes analytics opens its own DB connection to
get/create a session ID. This includes the CLI, the daemon, and **every
plugin worker**. In workspaces with many plugins, dozens of plugin
workers spawn simultaneously, each opening a DB connection and
querying/writing session metadata. This overwhelms the SQLite database
with concurrent connections and causes failures.

## How This Fixes It

The root cause is that plugin workers each independently open a DB
connection just to read the session ID. The fix eliminates this by
having the parent process (CLI or daemon) fetch the session ID once and
pass it to child processes via the `NX_ANALYTICS_SESSION_ID` environment
variable. Plugin workers inherit this env var and initialize telemetry
without touching the DB at all.

| Process | Before | After |
|---------|--------|-------|
| CLI | Opens DB connection | Opens DB connection (1x) |
| Daemon | Opens DB connection | Opens DB connection (1x) |
| Plugin worker (×N) | Each opens DB connection | Reads env var, **no DB
connection** |

In a workspace with 20 plugins, this reduces DB connections from 22 (CLI
+ daemon + 20 workers) down to 2 (CLI + daemon only).

## Two Initialization Paths

- **`initializeTelemetry(dbConnection, ...)`** — Used by CLI and daemon.
Gets/creates the session ID from the DB via a transaction, stores the
connection for persisting session refreshes on flush, and returns the
session ID so the caller can set it as an env var for child processes.
- **`initializeTelemetryWithSessionId(sessionId, ...)`** — Used by
plugin workers. Takes the session ID inherited from the parent process
env var. No DB connection, no DB queries.

## Session Refresh for Long-Lived Processes

The daemon is long-lived and could hold a stale session ID for hours.
The telemetry background thread now tracks activity and generates a new
session ID after 30 minutes of inactivity (matching the existing GA4
session timeout). When a session refreshes, the background thread
notifies the main thread via a channel, which persists the new session
to the DB in a transaction on flush.

## Other Changes

- Extracted `TelemetryOptions` struct to replace the long parameter list
in `TelemetryService::new`
- Moved `SESSION_TIMEOUT_SECS` to `constants.rs` so it can be shared
between modules
- Extracted `init_service` helper to deduplicate between the two init
paths
- Extracted `persist_session_to_db` helper that wraps both metadata
writes in a transaction
- Separated session ID retrieval (`get_or_create_session_id`) from
telemetry service initialization

## Related Issue(s)

Fixes database connection exhaustion when many plugin workers initialize
analytics simultaneously.
2026-03-17 15:34:51 -04:00
Jack Hsu dcdabdda27 docs(core): add telemetry documentation page (#34884)
## Current Behavior

There is no documentation for Nx CLI telemetry, which was added in Nx
22.6.0. Users who are prompted to opt in have no reference page to learn
what data is collected or how to opt out.

## Expected Behavior

A dedicated telemetry reference page at `/reference/telemetry` explains
what is collected, what is not collected, and how to disable telemetry
via `nx.json`. The `nx.json` reference page also documents the
`analytics` property.

Changes:
- New page: `astro-docs/src/content/docs/reference/telemetry.mdoc`
- Sidebar entry added under Reference
- `analytics` property added to nx.json reference (expanded example +
new section)

## Related Issue(s)

Fixes DOC-446
2026-03-17 15:20:40 -04:00
Craigory Coppola cbd64acca6 chore(repo): reduce codeowners to represent team shape a bit better (#34886)
## Current Behavior
The CODEOWNERS setup is getting in the way as core maintainers have
moved around and timezones and such...

## Expected Behavior
Anyone on the CLI reviewers team should be capable of recognizing PRs
they are capable of assessing, this eases the burden of increased PRs
from AI chatbots and timezones.
2026-03-17 15:12:07 -04:00
Jack Hsu c9b261db64 feat(misc): track server page views for AI traffic using Netlify-Agent-Category (#34883)
## Current Behavior

Only the astro-docs (nx-docs) Netlify app tracks server-side page views
via edge functions. AI tool and bot detection relies on fragile
User-Agent regex matching against a hardcoded list of known bot strings.

## Expected Behavior

Both nx-dev and nx-docs page views are tracked server-side via GA4,
using Netlify's built-in `Netlify-Agent-Category` header to distinguish
`ai-agent` from `crawler` traffic.

Tracking edge functions are consolidated into the nx-dev app
(`netlify/edge-functions/`) since all traffic flows through it before
being rewritten to nx-docs. Framer-proxied pages are tracked inline in
`rewrite-framer-urls.ts` because the proxy short-circuits
`context.next()`, preventing downstream edge functions from firing.

**Changes:**
- Moved `track-page-requests.ts` and `track-asset-requests.ts` from
`astro-docs/netlify/edge-functions/` to `netlify/edge-functions/`
- Replaced User-Agent regex with `Netlify-Agent-Category` header checks
in all tracking functions
- Added GA4 tracking to `rewrite-framer-urls.ts` for Framer-proxied
pages

## Related Issue(s)

Fixes DOC-445
2026-03-17 13:58:41 -04:00
Craigory Coppola 631734028f fix(core): ensure workers shutdown after phase cancelled (#34799)
## Current Behavior
New logic in the daemon can cancel an active graph creation, resulting
in worker shutdown not behaving as intended

## Expected Behavior
When the daemon aborts graph construction, the plugins still shut down

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

Fixes #
2026-03-17 13:53:56 -04:00
Caleb Ukle 6482a2c6a9 docs(nx-cloud): update image list for nx agents (#34791)
- define image version list
- document mise step
2026-03-17 18:06:46 +01:00
Jason Jean 1367d2a211 fix(vite): pin vitest v4 to ~4.0.x to fix Yarn Classic resolution failure (#34878)
## Current Behavior

Projects scaffolded with `@nx/vite` or `@nx/vitest` generators use
`^4.0.0` for vitest v4 dependencies. Since vitest 4.1.0 (released Mar
12), its vite peer dep expanded to `^6.0.0 || ^7.0.0 || ^8.0.0-0`. Yarn
Classic's linker fails with `Invariant Violation: could not find a copy
of vite to link` when encountering this expanded OR range.

This breaks all e2e tests running with Yarn Classic (e2e-cypress,
e2e-eslint, e2e-jest, e2e-playwright, e2e-web, e2e-webpack on
Linux/yarn/20 combos).

## Expected Behavior

Scaffolded projects use `~4.0.x` tilde ranges for vitest v4, restricting
to patch updates only. This avoids pulling in vitest 4.1.0+ and the
problematic peer dep range, keeping Yarn Classic compatibility intact.

## Related Issue(s)

Fixes failing CI runs on yarn combos since Mar 12-13.
2026-03-17 11:26:40 -04:00
Craigory Coppola cf79f486f5 fix(core): trim memory usage associated with io-tracing service (#34866)
## Current Behavior
We accumulate `inputs`/`outputs`/`pids` and store them even if no
subscriber is subscribed, and then they hang around to notify late
subscribers that may never come

## Expected Behavior
`inputs`/`outputs`/`pids` are only sent to current subscribers

## AI Summary 

This pull request optimizes how task input notifications are handled in
Nx by ensuring that expensive input collection and storage only occur
when there are active subscribers. This change prevents unnecessary
memory growth in long-lived processes, such as the Nx daemon, and
improves performance by avoiding redundant work.

Notification and input collection optimization:

* Added a `hasTaskInputSubscribers()` method to the `TaskIOService`
class, allowing the hasher to check if any input subscribers are
registered before collecting and notifying task inputs.
* Updated all hashing functions in `hash-task.ts` to only notify task
inputs if there are active subscribers, reducing unnecessary work and
memory usage.
[[1]](diffhunk://#diff-d061dc5551f692abad009b8284c719466cff2f0d3d19bd52e81b7921a9e543d6R57-R63)
[[2]](diffhunk://#diff-d061dc5551f692abad009b8284c719466cff2f0d3d19bd52e81b7921a9e543d6L114-R117)
[[3]](diffhunk://#diff-d061dc5551f692abad009b8284c719466cff2f0d3d19bd52e81b7921a9e543d6R172)
[[4]](diffhunk://#diff-d061dc5551f692abad009b8284c719466cff2f0d3d19bd52e81b7921a9e543d6L185-R188)
[[5]](diffhunk://#diff-d061dc5551f692abad009b8284c719466cff2f0d3d19bd52e81b7921a9e543d6L201-R204)
* Modified the native task hasher implementation
(`native-task-hasher-impl.ts` and Rust code) to conditionally collect
and return input data only when requested, minimizing overhead and
memory allocation.
[[1]](diffhunk://#diff-ddf992f97afbcd8b2206b8d1faab7e7f9571ecfe50e2ab8e3da104001f39f0c3L73-R80)
[[2]](diffhunk://#diff-ddf992f97afbcd8b2206b8d1faab7e7f9571ecfe50e2ab8e3da104001f39f0c3L88-R101)
[[3]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bR194-R200)
[[4]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bL226-R233)
[[5]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bR256)
[[6]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bL262-R273)
[[7]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bL288-R299)
[[8]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bR330-R352)
[[9]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bL348-R383)
[[10]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bL368-R407)
[[11]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bR432)
[[12]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bL417-R475)
[[13]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bL452-R489)
[[14]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bL461-R503)
[[15]](diffhunk://#diff-d81ca7875513ef544822c24671104ce52cd09409a41a796768aba507d87b3c0bR518)

Code cleanup and refactoring:

* Removed unused state and redundant code from `TaskIOService` related
to storing task-to-PID, task-to-input, and task-to-output mappings, as
well as unnecessary graph references and late subscriber emission logic.
[[1]](diffhunk://#diff-fc051b28c1ac25926033d157ec2278cc1cf2fcf7e16626eeedaf876c29fc9d62R42-R66)
[[2]](diffhunk://#diff-fc051b28c1ac25926033d157ec2278cc1cf2fcf7e16626eeedaf876c29fc9d62L91-L95)
[[3]](diffhunk://#diff-fc051b28c1ac25926033d157ec2278cc1cf2fcf7e16626eeedaf876c29fc9d62L104-L111)
* Updated imports and cleaned up constructor logic in
`task-io-service.ts` and `native-task-hasher-impl.ts` for clarity and
maintainability.
[[1]](diffhunk://#diff-ddf992f97afbcd8b2206b8d1faab7e7f9571ecfe50e2ab8e3da104001f39f0c3R16)
[[2]](diffhunk://#diff-fc051b28c1ac25926033d157ec2278cc1cf2fcf7e16626eeedaf876c29fc9d62L1-L2)

These changes collectively make task input tracking more efficient and
robust, especially in scenarios where Nx runs as a daemon or in
environments with no listeners for input notifications.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
2026-03-17 10:35:36 -04:00
MaxKless 61a8e333c6 fix(core): detect npm from package-lock.json before falling back to invoking PM (#34877)
## Current Behavior

When `detectPackageManager()` finds no lock file for bun, yarn, or pnpm,
it falls back to `detectInvokedPackageManager()` which checks
`npm_config_user_agent`. This causes misdetection when a workspace is
created with npm (has `package-lock.json`) but the parent process uses
pnpm — the detection picks up pnpm from the user agent instead of npm
from the lock file.

This has been causing **every nightly E2E run to fail since March 4th**
(when #34691 was merged), particularly in e2e-angular where `ng-add`
tests create npm workspaces but `installPackagesTask` incorrectly
invokes `pnpm install --no-frozen-lockfile`.

## Expected Behavior

`detectPackageManager()` should check for `package-lock.json` (npm's
lock file) before falling back to the invoking package manager
detection. This ensures that workspaces with a `package-lock.json` are
correctly identified as npm workspaces regardless of what package
manager invoked the current process.

## Related Issue(s)

Fixes the nightly E2E matrix failures in e2e-angular (`ng-add.test.ts`,
`plugin.test.ts`), e2e-nx-init, and e2e-workspace-create that have been
consistently failing since #34691 was merged.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 14:26:46 +00:00
Miroslav Jonaš 8d71d5b57b feat(js): add deps-sync generator (#34407)
This PR introduces the `deps-sync` generator which pairs with
`typescript-sync`generator to ensure internal dependencies are correctly
mapped via `devDependencies` of corresponding `package.json`.

## Current Behavior
When dependency to local package is created (via import for example) the
existing typescript-sync generator updates the tsconfig but package.json
is left untouched which might cause issues when referencing transitive
dependencies.

## Expected Behavior
The typescript-sync should be accompanied by deps-sync generator that
would update dependencies in package.json for workspaces.

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

Fixes #

---------

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2026-03-17 10:22:52 -04:00
Craigory Coppola de216f25ec fix(core): show continuous property in nx show target (#34867)
Add the continuous property to the nx show target output. Previously the
command showed cache and parallelism but not whether a target is
continuous.

Fixes NXC-4084

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
2026-03-16 23:16:09 -04:00
Jason Jean 1afb96b7f4 fix(gradle): always check disk cache for gradle project graph reports (#34873)
## Current Behavior

The Gradle plugin uses an in-memory `gradleCurrentConfigHash` variable
to decide whether to skip re-running `./gradlew nxProjectGraph`. Since
plugin workers shut down between graph computations, this variable
resets to `undefined` each time. The `??=` operator on the disk cache
read means it's only read once per worker lifetime, and the
`!gradleCurrentConfigHash` check always evaluates to `true` on fresh
workers — making the in-memory hash comparison dead code.

This means the caching logic works despite itself (via disk cache), but
is fragile and could cause unnecessary Gradle invocations or stale cache
hits if worker lifecycle assumptions change.

There was also another issue with hashing options when calculating the
project graph for nodes and dependencies. Options were not normalized
when hashing which you did not get deterministic hashing when calling
dependencies after createNodes.

## Expected Behavior

Always read the disk cache and compare hashes directly. If the hash
matches, skip running Gradle. If not, run Gradle and update the disk
cache. No in-memory state needed between worker restarts.

Options are normalized before hashing to ensure that regardless of
createNodes or dependencies, we will get a deterministic hash.

## Related Issue(s)

<!-- No specific issue — discovered during code review -->

---------

Co-authored-by: lourw <56288712+lourw@users.noreply.github.com>
2026-03-16 20:51:59 -04:00
nx-cloud[bot] 332671d2e4 chore(core): update nx to 22.6.0-rc.0 (#34872)
## Current Behavior

Nx packages are pinned to 22.6.0-beta.13.

## Expected Behavior

Nx packages updated to the latest pre-release 22.6.0-rc.0.

## Related Issue(s)

N/A - routine version bump

<!-- polygraph-session-start -->
---
[View session information on Nx Cloud
↗](https://staging.nx.app/orgs/62d013d4d26f260059f7765e/agent-sessions/update-00367)

**Related PRs:**
> - https://github.com/nrwl/nx-examples/pull/426
<!-- polygraph-session-end -->

Co-authored-by: FrozenPandaz <jasonjean1993@gmail.com>
2026-03-16 23:43:02 +00:00
Jason Jean 35930fd0d9 fix(core): add .claude/settings.local.json to .gitignore (#34870)
## Current Behavior

When configuring AI agents via `nx polygraph`, a
`.claude/settings.local.json` file is created containing user-specific
settings. This file is not gitignored by Nx, so it can accidentally be
committed to the repository.

## Expected Behavior

`.claude/settings.local.json` should be gitignored by default, similar
to how `.claude/worktrees` is already handled.

## Changes

- Added a migration that adds `.claude/settings.local.json` to existing
workspaces' `.gitignore`
- Updated all three `.gitignore` templates so new workspaces include it
from the start
- Follows the same pattern as the existing
`add-claude-worktrees-to-git-ignore` migration
2026-03-16 17:11:27 -04:00
Jason Jean ded713ffd9 Revert "fix(core): ensure postTasksExecution fires on SIGINT for continuous tasks (#34623)" (#34869)
## Current Behavior

After #34623, when continuous tasks are killed (Ctrl+C), the nx process
stays alive during async cleanup instead of exiting immediately. This
causes the `RunningTasksService` SQLite entry to persist with a
still-alive PID.

When a new `nx` process starts during this cleanup window,
`is_task_running()` finds the stale entry, confirms the PID is still
alive (old process cleaning up), and creates a `SharedRunningTask` —
incorrectly printing:

```
Waiting for @nrwl/ocean:local-registry in another nx process
```

The root cause: #34623 removed `process.exit()` from SIGINT handlers in
`running-tasks.ts`, widening the window where the old process is alive
but the task is no longer actually running.

## Expected Behavior

After killing continuous tasks, a new `nx` invocation should not see
stale "Waiting for ... in another nx process" messages.

This reverts #34623 while a proper fix is designed that achieves both
goals: reliable `postTasksExecution` firing AND prompt DB cleanup.

## Related Issue(s)

Reverts #34623

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-16 16:51:46 -04:00
Victor Savkin e41ba65a94 fix(nx-cloud): download light client to tmp dir when outside nx workspace (#34805)
## Current Behavior
When running nx commands outside of an Nx workspace (no nx.json), the
light client is downloaded to .nx/cache/cloud relative to process.cwd().
This creates an unwanted .nx folder in whatever directory the user
happens to be in.

## Expected Behavior
When outside an Nx workspace, the light client is downloaded to a temp
directory (os.tmpdir()/nx-cloud-client/hash) where hash is derived from
the NX_CLOUD_API URL. This avoids polluting arbitrary directories with
.nx folders while ensuring different cloud instances get separate
directories.

When inside an Nx workspace, behavior is unchanged.
2026-03-16 18:55:18 +00:00
Jason Jean 6b8d5c9e95 chore(maven): bump maven plugin version to 0.0.16 (#34862)
## Current Behavior

The Maven plugin version is at 0.0.15.

## Expected Behavior

The Maven plugin version is bumped to 0.0.16 with a corresponding
migration entry for Nx 22.6.0-beta.14.

## Related Issue(s)

N/A - routine version bump.

### Changes

- Updated all pom.xml files to version 0.0.16
- Updated `mavenPluginVersion` constant in `versions.ts`
- Added migration entry in `migrations.json`
- Created migration file `update-pom-xml-version.ts` for 0.0.16
2026-03-16 09:58:29 -07:00
Leosvel Pérez Espinosa e9781bdd3b fix(js): track tsconfig files from dependency reference chain as inputs (#34848)
## Current Behavior

The `@nx/js/typescript` plugin adds dependency project `tsconfig.json`
files as inputs but doesn't resolve nested `projectReferences` within
those files. When `tsc -b` runs, it follows the full reference chain —
reading `tsconfig.lib.json`, `tsconfig.spec.json`,
`tsconfig.storybook.json`, etc. from dependencies — but these files
aren't declared as inputs, causing potential cache correctness issues.

## Expected Behavior

The plugin now walks the full project reference chain from external
dependencies and collects all distinct tsconfig relative paths (e.g.,
`tsconfig.lib.json`, `tsconfig.spec.json`, `cypress/tsconfig.json`).
These are emitted as `^{projectRoot}/...` input patterns, ensuring that
any tsconfig file read by `tsc -b` through the reference chain is
tracked as an input.

Key changes:
- Renamed `getExternalProjectReferenceConfigFiles` →
`getExternalProjectReferenceTsconfigPatterns` to reflect it now returns
input patterns instead of absolute paths
- Uses a worklist algorithm to traverse the reference chain
(breadth-first, cycle-safe)
- Collects relative paths per dependency project root, deduplicates, and
emits `^{projectRoot}/...` patterns
- For build targets, only tsconfig files reachable from the build
reference chain are included (not all refs from the solution tsconfig)
2026-03-16 12:57:55 -04:00
Miroslav Jonaš 9bebb04410 chore(repo): remove unused flags from ci.yaml (#34847)
These flags were added while we tested changes to the task API and
streaming. They are no longer needed.

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2026-03-16 12:39:53 -04:00
Leosvel Pérez Espinosa 5a799848bf fix(testing): infer task inputs from jest config file references (#34740)
## Current Behavior

The Jest plugin infers `test` target inputs from the preset file path
but ignores other config properties that reference files — transforms,
setup files, module name mappers, reporters, watch plugins, etc. Changes
to those files don't invalidate the test cache.

## Expected Behavior

All Jest config properties that reference files are resolved and
included as task inputs, matching Jest's merge semantics:

- **Replaced** (config wins over preset): `resolver`, `globalSetup`,
`globalTeardown`, `snapshotResolver`, `snapshotSerializers`,
`testResultsProcessor`, `runner`, `reporters`, `watchPlugins`
- **Concatenated** (preset + config): `setupFiles`, `setupFilesAfterEnv`
- **Deep merged** (config keys win): `moduleNameMapper`, `transform`

Also handles `jest-runner-`/`jest-watch-` prefix resolution, `<rootDir>`
in preset values, and Windows path normalization.

Adds a `useJestResolver` option to control whether jest-resolve is used
for input resolution, decoupled from `disableJestRuntime`. By default,
inputs are resolved using path-based classification (fast, no filesystem
calls beyond what's already done). When `useJestResolver` is enabled,
jest-resolve is used instead, which follows symlinks and honors custom
`moduleDirectories`/`modulePaths` — more accurate for workspace-linked
packages but slower due to filesystem probing per resolved path.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-16 11:53:20 -04:00
Leosvel Pérez Espinosa 3e4cfa0ed1 fix(core): ensure postTasksExecution fires on SIGINT for continuous tasks (#34623)
## Current Behavior

When pressing Ctrl+C on continuous tasks (e.g., `nx run app:serve`),
`postTasksExecution` never fires or fires with incomplete task results.
This affects any plugin or custom lifecycle hook relying on
`postTasksExecution` to perform cleanup, reporting, or post-run logic.

The issue manifests in non-TUI mode (`NX_TUI=false`) and in setups where
nx runs as a child of a package manager (pnpm/npm), which sends SIGTERM
shortly after SIGINT.

## Expected Behavior

`postTasksExecution` fires reliably on Ctrl+C with complete task
results, regardless of whether TUI is enabled or how the nx process is
invoked.

## Technical Details

Three independent issues caused the broken behavior:

**1. Initiating continuous task exits before orchestrator cleanup**

When the initiating task is continuous and exits with a signal code
(e.g., 130 from SIGINT), the `onExit` handler called
`process.exit(code)` synchronously — before the orchestrator's SIGINT
handler could run. Cleanup and `postTasksExecution` never executed.

Fixed by replacing `process.exit()` with proper task completion via
`handleContinuousTaskExit`, and ensuring initiating tasks are the sole
`onExit` callback (to avoid floating promises from
`exitCallbacks.forEach` not awaiting async callbacks).

**2. run-commands SIGINT handlers call `process.exit(130)`**

Every `nx:run-commands` task running in the main process registered a
SIGINT handler that called `process.exit(signalToCode('SIGINT'))`,
killing the process before the orchestrator's async cleanup could run.

Fixed by removing `process.exit()` from both SIGINT handlers in
`running-tasks.ts`. The `this.kill('SIGTERM')` call is kept for prompt
child termination. Cache-write safety is already guaranteed by
`postRunSteps` guards (`stopRequested`, `status !== 'stopped'`).

**3. `cleanup()` resolves prematurely on concurrent signals**

When pnpm/npm sends SIGTERM ~30ms after SIGINT, the SIGTERM handler saw
`cleanupDone = true` (set at the start of cleanup, before async work),
returned immediately, and its `.finally()` called `resolveStopPromise()`
before SIGINT's cleanup finished. `run()` returned with incomplete task
results.

Fixed by replacing the `cleanupDone` boolean with a stored promise.
Concurrent callers now await the same in-progress cleanup.

**Additional fixes:**

- SIGTERM/SIGHUP handlers now set `stopRequested = true` so externally
terminated tasks are correctly classified as `'interrupted'` rather than
`'fulfilled'`.
- Extracted shared exit-handling logic into `handleContinuousTaskExit`
to consolidate reason-determination between initiating and
non-initiating continuous tasks.
2026-03-16 11:52:26 -04:00
MaxKless b7732c0646 fix(core): skip analytics prompt for cloud commands (#34789)
## Current Behavior

The analytics prompt (`ensureAnalyticsPreferenceSet()`) and
`startAnalytics()` run for all commands, including cloud commands like
`download-cloud-client`. When a cloud command runs outside an Nx
workspace, `saveAnalyticsPreference()` creates an almost-empty `nx.json`
(`{ "analytics": true }`) in whatever directory you happen to be in.

## Expected Behavior

Cloud commands skip the analytics prompt and `startAnalytics()`
entirely, since they may run without a workspace and there is no
appropriate `nx.json` to write to.

## Related Issue(s)

Fixes the issue where running `nx download-cloud-client` outside a
workspace creates a spurious `nx.json`.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 11:51:04 -04:00
Copilot 23eec78754 chore(repo): remove .nx/workflows/sandboxing-config.yaml (#34860)
Removes the `.nx/workflows/sandboxing-config.yaml` file, which is no
longer needed in the repository.

## Changes

- **Deleted** `.nx/workflows/sandboxing-config.yaml` — no CI pipelines
or workflow files reference this file directly
- The only existing mention is in `astro-docs/.../sandboxing.mdoc`,
which is purely instructional documentation guiding users to create
their own config; no update needed

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> ## Goal
> Remove the workflow configuration file
`.nx/workflows/sandboxing-config.yaml` from the `nrwl/nx` repository.
> 
> ## Context
> - Repository: `nrwl/nx`
> - Base branch: `master`
> - File to remove: `.nx/workflows/sandboxing-config.yaml`
> - Source URL:
https://github.com/nrwl/nx/blob/master/.nx/workflows/sandboxing-config.yaml
> - Commit OID (reference provided by user):
`5dd12046c3d5bc5919abdb176be2d11f16c8f943`
> - Current contents:
>   ```yaml
>   exclude-reads:
>     - '**/node_modules/**'
>     - .nx/**/*
>     - .git/**/*
>     - '**/package.json'
>     - pnpm-workspace.yaml
>   exclude-writes:
>     - nx/**/*
>   ```
> 
> ## Requirements
> 1. Delete `.nx/workflows/sandboxing-config.yaml`.
> 2. Ensure there are no other required references to this file (e.g.,
in CI/workflows) that would break due to removal. If references exist,
update them accordingly.
> 3. Run the full validation suite prior to finalizing (`nx prepush`).
> 4. If validation fails, fix the issues by amending the current commit
(do not create additional commits solely for validation fixes).
> 
> ## Deliverable
> Open a pull request that removes
`.nx/workflows/sandboxing-config.yaml` (and any necessary reference
updates), including a clear description of the change and validation
performed.
> 
> The following is the prior conversation context from the user's chat
exploration (may be truncated):
> 
> User: please open a pr to remove this file
> 
> Assistant: I’m paused waiting for you to accept or reject the pull
request action in the confirmation dialog—once you respond there, I can
continue.
> 
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FrozenPandaz <8104246+FrozenPandaz@users.noreply.github.com>
2026-03-16 11:39:09 -04:00
Jason Jean 9c9cb24248 fix(maven): use mutable lists for Maven session projects (#34834)
## Current Behavior

When using Maven plugins that fork executions (e.g. `maven-pmd-plugin`),
the Nx Maven batch executor crashes with
`java.lang.UnsupportedOperationException`. This happens because Kotlin's
`listOfNotNull()`, `mapNotNull()`, and `filter()` return immutable
lists, but Maven's `MojoExecutor.executeForkedExecutions` calls
`list.set()` on `session.projects`, which requires a mutable list.

## Expected Behavior

Maven plugins that fork executions (PMD, Checkstyle, etc.) should work
correctly with the Nx Maven batch executor. All lists assigned to
`session.projects` and `session.allProjects` are now wrapped with
`toMutableList()` to ensure Maven can mutate them as needed.

The fix is applied to both the Maven 3 and Maven 4 adapters.

## Related Issue(s)

Fixes #34758
2026-03-16 11:37:47 -04:00
Jack Hsu 760004bfc9 docs(nx-dev): document Netlify deployment architecture (#34859)
Document how nx.dev is deployed on Netlify and how requests are routed
between Framer (marketing), Next.js (blog/courses), and Astro (docs).

Includes:
- Request flow diagram and explanation
- Edge function configuration
- _redirects file organization
- Environment variables reference
- Common debugging tasks
- How to add redirects and rewrites

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2026-03-16 11:34:11 -04:00
Jason Jean 6e54e7987b fix(gradle): handle project names containing .json substring (#34832)
## Current Behavior

The `@nx/gradle` plugin fails to parse the project graph when a Gradle
project name contains `.json` as a substring (e.g.
`org.acme.util.jsonutils`). The parsing logic in `processNxProjectGraph`
checks `includes('.json')` to find the JSON file path, but starts from
the task line itself. When the project name contains `.json`, the task
line matches immediately and gets used as a file path, causing an
`ENOENT` error.

## Expected Behavior

The plugin correctly skips the task line and finds the actual JSON file
path on the following line, regardless of whether the project name
contains `.json`.

Two changes:
1. Increment `index` after matching the task line to skip it before
searching for the JSON path
2. Use `endsWith('.json')` instead of `includes('.json')` for a more
precise match

## Related Issue(s)

Fixes #34768
2026-03-16 08:28:07 -07:00
Jason Jean 9466abab97 fix(webpack): bump fork-ts-checker-webpack-plugin to 9.1.0 (#34826)
## Summary
- Bumps `fork-ts-checker-webpack-plugin` from `7.2.13` to `9.1.0` in
root `package.json` and `packages/webpack/package.json`
- v7 depends on `memfs` v3 which uses a deprecated `fs.stat` API,
causing console warnings on Node 22+
- v9 uses updated `memfs` and has no breaking API changes for the
constructor pattern used by Nx

## Test plan
- [ ] Run Angular webpack app and verify no `fstat` deprecation warnings
- [ ] Run Node webpack build and verify no regressions
- [ ] Verify type checking still works via the plugin

Fixes #34404
2026-03-16 11:25:31 -04:00
Jason Jean daf272af4a fix(module-federation): use sslKey instead of sslCert for pathToKey (#34824)
## Summary
- `pathToKey` was incorrectly assigned
`this._options.devServerConfig.sslCert` instead of `sslKey` in all 4
Module Federation dev server plugins (Rspack, Rspack SSR, Angular,
Angular SSR)
- This caused SSL to break when using separate cert and key files

## Files Changed
-
`packages/module-federation/src/plugins/nx-module-federation-plugin/rspack/nx-module-federation-dev-server-plugin.ts`
-
`packages/module-federation/src/plugins/nx-module-federation-plugin/rspack/nx-module-federation-ssr-dev-server-plugin.ts`
-
`packages/module-federation/src/plugins/nx-module-federation-plugin/angular/nx-module-federation-dev-server-plugin.ts`
-
`packages/module-federation/src/plugins/nx-module-federation-plugin/angular/nx-module-federation-ssr-dev-server-plugin.ts`

## Test plan
- [ ] Verify SSL works with separate cert/key files in Module Federation
dev server (Rspack)
- [ ] Verify SSL works with separate cert/key files in Module Federation
dev server (Angular)

Fixes #34811
2026-03-16 15:20:47 +00:00
Jason Jean 410372311c fix(core): add null guards for runningTasksService in WASM fallback (#34825)
## Summary
- When native bindings fail to load (`IS_WASM = true`),
`runningTasksService` is `null`
- Two call sites in `task-orchestrator.ts` accessed it without null
checks, causing `Cannot read properties of null (reading
'addRunningTask')` during `nx serve`
- Added optional chaining (`?.`) at both sites, matching the existing
guard pattern already used elsewhere in the same file

## Test plan
- [ ] Run `nx serve` in an environment where native bindings are
unavailable (e.g. missing `@nx/nx-<platform>`)
- [ ] Verify no crash on `addRunningTask` or `removeRunningTask`

Fixes #34573
2026-03-16 11:19:19 -04:00
Leosvel Pérez Espinosa 5dd12046c3 fix(testing): infer dependency tsconfig files as playwright plugin inputs (#34803)
## Current Behavior

The Playwright plugin does not include `tsconfig*.json` files from
dependency projects as inputs. Playwright resolves these files when
running tests, leading to unexpected file reads that aren't tracked for
caching.

## Expected Behavior

When the `production` named input is used, the Playwright plugin infers
`^{projectRoot}/tsconfig*.json` as an input so dependency tsconfig files
are properly tracked. This is not needed for the `^default` branch since
it already includes all dependency files.
2026-03-16 10:54:53 -04:00
MaxKless 4fc976448b fix(core): add download-cloud-client to cloud command bypass list (#34788)
## Current Behavior

Running `npx nx@next download-cloud-client` outside an Nx workspace
fails with "The current directory isn't part of an Nx workspace" because
`download-cloud-client` is not in the `isNxCloudCommand` list in
`packages/nx/bin/nx.ts`. This means the process exits at the
`handleNoWorkspace` guard before ever reaching the handler fixed in
#34746.

## Expected Behavior

`download-cloud-client` runs successfully outside an Nx workspace, like
`login`, `logout`, `polygraph`, and other cloud commands that don't need
workspace context.

## Related Issue(s)

Follows up on #34728 and #34746 — `download-cloud-client` was added
before the cloud command bypass existed and was missed when the bypass
was introduced.
2026-03-16 23:16:01 +09:00
Caleb Ukle d060c69e56 fix(core): preserve params and options when expanding wildcard dependsOn targets (#34822)
## Summary

- `expandWildcardTargetConfiguration` was explicitly copying only
`projects` and `dependencies` when expanding glob patterns in
`dependsOn` target names, dropping `params` and `options`
- This meant `"params": "forward"` (and `"options": "forward"`) had no
effect when the `dependsOn` target used a wildcard like `"target":
"build*"`
- Fix uses object spread (`...dependencyConfig`) to preserve all
properties from the original dependency config

## Bug

Given this `project.json`:
```json
{
  "targets": {
    "build-all": {
      "executor": "nx:noop",
      "dependsOn": [
        {
          "target": "build*",
          "params": "forward"
        }
      ]
    }
  }
}
```

Running `nx run project:build-all --myParam=value` would correctly
resolve the wildcard to match targets like `build`, `build:test`,
`build:prod`, etc. — but `--myParam=value` was never forwarded to those
targets because `params: "forward"` was dropped during expansion.

## Root Cause

In `expandWildcardTargetConfiguration`
(`packages/nx/src/tasks-runner/utils.ts`), the matched targets were
mapped with only `target`, `projects`, and `dependencies`:

```typescript
return matchingTargets.map((t) => ({
    target: t,
    projects: dependencyConfig.projects,
    dependencies: dependencyConfig.dependencies,
    // params and options were missing!
}));
```

## Fix

Use object spread to carry over all properties:

```typescript
return matchingTargets.map((t) => ({
    ...dependencyConfig,
    target: t,
}));
```

## Test plan

- [x] Added test case verifying `params: "forward"` is preserved after
wildcard expansion
- [x] All 45 existing tests in `utils.spec.ts` continue to pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 08:26:58 -05:00
AI-JamesHenry f0aa006b83 fix(release): deduplicate projects in changelog when using filtered project list (#34851) 2026-03-16 15:36:34 +04:00
Benjamin Cabanes 01840adfcc fix(nx-dev): remove nx-cloud paths from Framer excluded URL rewrites (#34852)
The change removes Nx Cloud routes from the list of excluded URL rewrite
paths in the Framer edge rewrite configuration. This means requests to
those Nx Cloud paths will now be eligible for the rewrite behavior
instead of being skipped.
2026-03-16 06:13:54 -04:00
Miroslav Jonaš 008b0bce55 chore(repo): replace picocolors with native styleText for scripts (#34571)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

---------

Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-16 10:34:13 +01:00
AI-JamesHenry f8c821bd55 fix(release): include dependent projects in release commit message when using --projects filter (#34845) 2026-03-16 13:27:58 +04:00
AI-JamesHenry f40c4a5a17 fix(js): skip npm dist-tag add when no new version was resolved (#34843) 2026-03-15 21:20:57 +04:00
AI-JamesHenry 7fb8a91c14 fix(release): skip indirect patch bump for commit types with semverBump "none" (#34841) 2026-03-15 16:53:57 +04:00
AI-JamesHenry f1735bda36 fix(js): support bun-only environments in release-publish executor (#34835) 2026-03-14 20:38:38 +04:00
Jason Jean 343f95445d feat(core): add task and project count telemetry via performance lifecycle (#34821)
## Current Behavior

Telemetry only reports event duration via the `measureAndTrack` helper,
which uses a `[track] ` prefix convention. No task-level metrics (count,
cache hits, project count) are reported.

## Expected Behavior

- New event dimensions: `taskCount`, `projectCount`, `cachedTaskCount`
available for telemetry events
- `TaskTelemetryLifeCycle` reports task execution metrics (duration,
task count, project count, cached task count) — only runs on the main
CLI process, not on DTE agents
- `performance.measure()` with `detail: { track: true, ... }` replaces
the `measureAndTrack` / `[track] ` prefix pattern
- Perf observer automatically forwards detail entries matching known GA4
dimension keys
- `reportEvent` simplified to a pass-through — callers use
`customDimensions` keys directly
- `customDimensions` and `EventParameters` exported for use by callers
2026-03-13 20:35:35 -04:00
Joel Lefkowitz d6a7e109d7 fix(core): fix TUI help text layout (#34754)
## Current Behavior

The TUI help text format is currently malformed.

<img width="1181" height="191" alt="Screenshot 2026-03-07 at 11 13 40"
src="https://github.com/user-attachments/assets/e66316eb-600d-4456-920e-c9538c10e7e7"
/>

- The links overlap the plaintext
- Some of the plaintext has the link color
- The bullet points are on the same line

## Expected Behavior

Separation of links and plaintext with bullet points on separate lines.

### Changes

The text output of the TUI help section looks like this:

```txt
│                                                                                                                                                                                                                              │
│  Thanks for using Nx! To get the most out of this terminal UI, please check out the docs: https://nx.dev/terminal-uiIf you would prefer to not use the TUI, you can disable it by: - Adding the `--no-tui` flag to your      │
│  command.- Setting NX_TUI=false in your environment.                                                                                                                                                                         │
│  If you are finding Nx useful, please consider giving it a star on GitHub, it means a lot: https://github.com/nrwl/nx                                                                                                        │
│                                                                                                                                                                                                                              │
```

This PR corrects the layout to be more readable:

```txt
│                                                                                                                                                                                                                              │
│  Thanks for using Nx! To get the most out of this terminal UI, please check out the docs: https://nx.dev/terminal-ui                                                                                                         │
│                                                                                                                                                                                                                              │
│  If you would prefer to not use the TUI, you can disable it by:                                                                                                                                                              │
│  - Adding the `--no-tui` flag to your command.                                                                                                                                                                               │
│  - Setting `NX_TUI=false` in your environment.                                                                                                                                                                               │
│                                                                                                                                                                                                                              │
│  If you are finding Nx useful, please consider giving it a star on GitHub, it means a lot: https://github.com/nrwl/nx                                                                                                        │
│                                                                                                                                                                                                                              │
```

### Notes

The help link `https://nx.dev/terminal-ui` doesn't exist at the moment.
2026-03-13 18:41:37 -04:00
Jason Jean 3d1b1ec6b0 feat(core): prompt for analytics preference during workspace creation (#34818)
## Current Behavior

When a user creates a new workspace with `create-nx-workspace`, they are
not asked about analytics. The analytics prompt only appears later on
the first `nx` command run, or via the 22.6.0 migration.

## Expected Behavior

Users are prompted to opt in or out of usage analytics during
`create-nx-workspace`, so the preference is set from the start. The
prompt matches the style of other prompts in the flow (autocomplete with
Yes/No choices).

- **Preset flow**: The `analytics` property is set via the workspace
generator's `createNxJson`, so `nx.json` is properly formatted by
prettier through `formatFiles(tree)`
- **Template flow**: The `analytics` property is written directly to
`nx.json` (matching the pattern used by `setNeverConnectToCloud`)
- Supports `--analytics` CLI flag for non-interactive usage
- Skips the prompt in CI and non-interactive environments (defaults to
`false`)
2026-03-13 19:46:16 +00:00
Jason Jean 9db241cb17 chore(repo): update nx to 22.6.0-beta.13 (#34812)
Updating Nx from 22.6.0-beta.12 to 22.6.0-beta.13
2026-03-13 11:33:02 -04:00
Juri Strumpflohner 7428875252 docs(core): rewrite Nx vs Turborepo comparison page (#34792)
## Current Behavior

The Nx vs Turborepo comparison doc mixed setup complexity with advanced
features without a clear progression. Some sections were missing (code
generation comparison, cross-repo coordination, project graph
visualization). Images were in PNG format.

## Expected Behavior

- Progressive structure: starts with basics (onboarding, running tasks)
and moves to advanced capabilities (CI, AI, cross-repo); beats the
misconception that starting with Nx is more complex or you need to go
full in
- Overview table at top for quick comparison with links to sections (we
could collapse it if it gets too much 🤔)
- New sections: Running tasks (to emphasize how simple it is to run
tasks in an existing repo, again beating the misconceptions that are
around), Cross-repo coordination, CI throughput, Project graph
- Improved sections: Onboarding (incremental adoption story), Caching
(real benchmark configs), Code generation (acknowledges turbo gen)
- All images converted to AVIF
- Migration doc updated: removed beta/Nx 21 language for continuous
tasks

New docs:
- [comparison
doc](https://deploy-preview-34792--nx-docs.netlify.app/docs/guides/adopting-nx/nx-vs-turborepo)
- [migration doc (mostly
untouched)](https://deploy-preview-34792--nx-docs.netlify.app/docs/guides/adopting-nx/from-turborepo)

## Related Issue(s)

N/A - documentation improvement
2026-03-13 16:14:37 +01:00
Jason Jean 0d2d7cb881 fix(core): batch hashing, topological cache walk, and TUI batch fixes (#34798)
## Current Behavior

- `hashBatchTasks` hashes tasks one-by-one via `Promise.all` +
`hashTask` (singular), making N separate native hasher calls.
- Batch cache resolution rebuilds the entire remaining task graph each
wave via `removeTasksFromTaskGraph`, which is O(tasks) per wave and can
crash if `graph.dependencies[id]` is undefined.
- `postRunSteps` for cached batch results is deferred until all cache
resolution completes.
- TUI batch groups appear below "Waiting for task..." placeholders
because their status is based on nested task statuses, which may not
have transitioned yet.

## Expected Behavior

- `hashBatchTasks` uses `hashTasks` (plural) to batch all tasks into a
single native hasher call.
- Batch cache resolution uses a new `walkTaskGraph` util that walks
topologically via in-degree counters — only visits direct dependents per
wave instead of rebuilding the graph.
- `postRunSteps` runs incrementally per wave during cache resolution.
- TUI batch groups are treated as in-progress by existence (since
`start_batch` was called), only moving to completed when all nested
tasks are done.

## Related Issue(s)

Fixes crash: `Cannot read properties of undefined (reading 'filter')` in
`removeIdsFromTaskGraph` during batch cache resolution.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-13 13:26:41 +00:00
Jason Jean a72f0a4447 feat(core): centralize perf tracking and report metrics to telemetry (#34795)
## Current Behavior

- Performance tracking is scattered across multiple files with separate
`PerformanceObserver` instances (daemon server, plugin worker, nx.ts)
- Only `createProjectGraphAsync` duration is reported to analytics via a
dedicated `reportProjectGraphCreationEvent` function
- The Rust telemetry `flush()` has a race condition where closing event
channels before sending the flush request can cause the background
thread to exit before processing the flush
- The `default(timeout)` branch in the background sender does nothing
(`continue`)

## Expected Behavior

- A single centralized `PerformanceObserver` in `perf-logging.ts`
handles all performance measure reporting
- Any `performance.measure()` call prefixed with `[track]` is
automatically reported to telemetry (prefix stripped from display/event
name)
- `reportPerfEvent(name, duration)` is a generic function that works for
any perf measure
- Daemon-aware logging: uses `serverLogger` when running in the daemon,
`console.log` otherwise
- The telemetry flush race condition is fixed by sending the flush
request before closing channels
- The background sender's `default(timeout)` branch properly drains and
sends batches
- Duplicate drain logic is extracted into `enqueue_event`,
`enqueue_page_view`, and `drain_channels` helpers

### Currently tracked measures:
- `createProjectGraphAsync` — full project graph build time
- `{plugin}:createNodes` — per-plugin node creation time
- `{plugin}:createDependencies` — per-plugin dependency creation time

## Related Issue(s)

N/A

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-13 13:24:04 +00:00
Jason Jean e2d79e8dbe fix(nuxt): fix E2E test environment and lint issues (#34808)
## Current Behavior

Nuxt and rspack E2E tests fail due to multiple issues:
1. `NODE_ENV=test` leaking from Jest into build subprocesses, causing
nuxt to skip type-checking
2. ESLint errors on compiled `.vue.js` files containing `__VLS_*`
identifiers
3. Rspack multi-compiler array config tests fail without `NODE_ENV`
4. Remix vite version incompatible with vitest

Nuxt build E2E still fails due to TS6304 (`composite: true` +
`declaration: false` conflict in non-TS-solution workspaces) — that test
is skipped pending a proper fix.

## Expected Behavior

Nuxt lint, rspack, and remix E2E tests pass. Nuxt build test is skipped
with a TODO until the composite tsconfig issue is resolved.

## Related Issue(s)

Fixes CI E2E failures for nuxt, rspack, and remix.

## Changes

### Environment fixes
- **Strip `NODE_ENV` from E2E subprocess env** — Jest sets
`NODE_ENV=test` which leaked into nuxt build, causing it to skip
type-checking. Stripped globally in `getStrippedEnvironmentVariables()`.
- **Strip AI agent env vars** (`CLAUDECODE`, `CURSOR_TRACE_ID`, etc.) —
prevents the test runner's environment from leaking into e2e
subprocesses.
- **Pass `NODE_ENV` explicitly for rspack array config tests** — rspack
multi-compiler builds need `NODE_ENV` to determine build mode; pass it
via `runCLI` env option.

### Nuxt fixes
- **Add `**/*.vue.js` to ESLint flat config ignores** — compiled Vue
files contain `__VLS_*` identifiers that trigger lint errors.
- **Skip nuxt build e2e test** — pending fix for TS6304
composite/declaration conflict in non-TS-solution workspaces.

### Remix fix
- **Bump vite from `^5.0.0` to `^6.0.0`** — vitest dropped vite 5
support.

### E2E infra
- **Always print E2E workspace directory** — removed `isVerbose()` gate
so the path is always logged.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-13 08:30:23 -04:00
Steven Nance 6b59e74586 docs(nx-cloud): add DPE information exchange section to Okta SAML docs (#34794)
## Current Behavior

The Okta SAML doc ends with a vague "Contact your developer productivity
engineer" message. It doesn't specify what information needs to be
exchanged between the customer and DPE to enable SAML and SCIM. This
section was present in the old combined `auth-saml.md` but was lost
during the migration to separate Okta/Azure docs in astro-docs.

## Expected Behavior

The doc now has a clear "Information to exchange with your DPE" section
that outlines:
- **From your DPE** (provided up front): Nx Cloud App URL, JWT token,
and Organization ID for SCIM setup
- **Send back to your DPE**: SAML certificate and SAML entry point URL

This matches the pattern already used in the Azure SAML doc and assumes
SCIM will be configured.

## Related Issue(s)

N/A

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: llwt <llwt@users.noreply.github.com>
2026-03-12 22:28:49 +01:00
Jason Jean 926c603ec3 Revert "fix(core): gate tui-logger init behind NX_TUI env var (#34426)" (#34797)
## Current Behavior

The TUI debug pane (F12) opens but shows no log output. This is because
PR #34426 gated `tui_logger::init_logger()` behind `NX_TUI=true` in
`initialize_logger()`. However, `enable_logger()` uses `Once::call_once`
and is called from many places (WorkspaceContext, PseudoTerminal, etc.)
before yargs sets `process.env.NX_TUI = 'true'`. Since the first call
wins, the tui-logger layer is never registered and the debug pane stays
empty.

## Expected Behavior

The TUI debug pane (F12) displays log output when the TUI is active,
regardless of which code path calls `enable_logger()` first.

## Changes

- Always register `TuiTracingSubscriberLayer` in the global tracing
subscriber — it just buffers events with no thread overhead
- Defer `tui_logger::init_logger()` (which spawns the mover thread) to
the TUI lifecycle `__init`, where we know the TUI is actually in use
- Non-TUI contexts still avoid the background thread cost
2026-03-12 14:26:58 -04:00
Louie Weng 0bff3bc20e chore(gradle): ensure that version catalogue changes invalidate gradle hash (#34804)
<!-- 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
<!-- This is the behavior we have today -->

We do not track changes to `libs.versions.toml` files

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Include `libs.versions.toml` files in the list of files that we track
when we hash. This ensures that changes to that file will trigger a
regeneration of the gradle project graph.

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

Fixes #
2026-03-12 14:26:44 -04:00
Caleb Ukle b43e693c3d fix(nx-dev): adding missing legacy route redirects (#34772)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 12:53:36 -04:00
Miroslav Jonaš 0e77802bd5 docs(nx-dev): add self-healing to manual DTE docs (#34802)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2026-03-12 14:50:54 +00:00
Jason Jean 08a2b164e4 chore(repo): update nx to 22.6.0-beta.12 (#34760)
Updating Nx from 22.6.0-beta.10 to 22.6.0-beta.12
2026-03-11 20:53:56 -04:00
Juri 4dee3d3646 docs(nx-dev): add auto-apply suggestions video to self-healing CI page 2026-03-11 20:54:27 +01:00
Leosvel Pérez Espinosa e206a0dc66 chore(repo): do not ignore relevant native files (#34793)
- Remove relevant native files entries from `.nxignore`, causing them to
be missing inputs.
- Remove stale entry from `.nxignore` used to workaround an issue that
was already solved
2026-03-11 18:21:36 +01:00
Caleb Ukle 592ea0602e docs(nx-cloud): add actions read permission to gh permission list (#34786) 2026-03-11 10:52:20 -05:00
MaxKless 003722dd1a chore(repo): switch to new polygraph plugin (#34790)
the mcp & skills have moved.
2026-03-12 00:42:00 +09:00
Jason Jean 4b1f420695 fix(nuxt): bump nuxt to 3.21.1 to resolve critical audit vulnerability (#34783)
## Current Behavior

The npm audit CI job fails with a critical vulnerability
(GHSA-r275-fr43-pm7q) in `simple-git < 3.29.0`, pulled in transitively
via `nuxt@3.17.6` → `@nuxt/devtools@2.6.2` → `simple-git@3.28.0`.

## Expected Behavior

The audit passes. Bumping `nuxt` from `^3.10.0` to `^3.21.1` pulls in
`@nuxt/devtools@3.2.3` → `simple-git@3.33.0`, which includes the fix.

## Related Issue(s)

Fixes the failing audit job:
https://github.com/nrwl/nx/actions/runs/22930179319/job/66549735267
2026-03-11 11:13:41 -04:00
Jason Jean ac400a12db chore(maven): bump maven plugin version to 0.0.15 (#34782)
## Current Behavior

The Maven plugin is at a previous version and needs to be updated.

## Expected Behavior

The Maven plugin version is bumped to `0.0.15`, with a corresponding
migration for users upgrading to Nx `22.6.0-beta.12`.

## Related Issue(s)

N/A
2026-03-11 10:35:33 -04:00
Jason Jean 444ddb5953 feat(maven): report external Maven dependencies in project graph (#34368)
## Current Behavior

The Maven plugin only reports dependencies between workspace projects.
External dependencies (Spring, JUnit, etc.) from Maven Central are
invisible — `nx graph` doesn't show the full dependency picture, and Nx
can't invalidate cache when an external dependency changes.

## Expected Behavior

External Maven dependencies now appear as full-fidelity external nodes
in the Nx project graph, with dependency edges between them, hashes for
cache correctness, and `externalDependencies` inputs on targets.

### External Nodes

External nodes use the naming convention `maven:groupId:artifactId`
(e.g., `maven:org.springframework:spring-core`) with:
- Type `"maven"`
- `groupId` and `artifactId` as separate fields
- Declared version (or `"managed"` if inherited from a parent POM)
- SHA-1 hash read from Maven's `.sha1` sidecar files in
`~/.m2/repository`

### External-to-External Edges

Edges between external nodes are derived by parsing POMs from the local
Maven repository. For example, `spring-boot-starter-web` → `spring-web`
→ `spring-core`. This gives `nx graph` a complete picture of the
transitive dependency tree.

### Cache Invalidation via externalDependencies Inputs

Every cacheable target now includes `{"externalDependencies":
["maven:groupId:artifactId", ...]}` in its inputs. This means Nx
invalidates cache when a resolved artifact changes — important for
SNAPSHOTs and version ranges where the dependency can change without
`pom.xml` changing.

### Changes

**Kotlin (maven-plugin)**
- `NxProjectAnalyzerMojo.kt`: Changed ResolutionScope to COMPILE for
full transitive resolution. Added `generateExternalNodes()` with
deduplication and SHA-1 hash reading. Added `generateExternalEdges()`
via POM parsing from ~/.m2. Embedded external nodes in createNodesResult
tuples, added project-to-external and external-to-external dependency
edges.
- `NxProjectAnalyzer.kt`: Uses `project.artifacts` (transitive) instead
of `project.dependencies` (direct only) for external deps. Added
`artifactFile` field for hash lookup. Collects external dep names and
passes them to target factory.
- `NxTargetFactory.kt`: Accepts externalDependencies list, threads it
through all target creation methods, and adds `{"externalDependencies":
[...]}` to every cacheable target's inputs.

**TypeScript**
- `dependencies.ts`: External sources/targets with `maven:` prefix pass
through as-is instead of rootToProjectMap lookup.
- `types.ts`: Added `externalNodes` field to `MavenAnalysisData`.

## Related Issue(s)

<!-- Feature parity with Gradle plugin for external dependency support
-->
2026-03-11 10:33:48 -04:00
Craigory Coppola 690466a869 fix(core): show json by default for agentic ai (#34780)
<!-- 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
`nx show *` doesn't default to JSON

## Expected Behavior
For agents, it defaults to JSON

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

Fixes #
2026-03-11 10:23:55 -04:00
Leosvel Pérez Espinosa a358b19c15 fix(js): always infer dependentTasksOutputFiles for tsc build targets (#34784)
## Current Behavior

The `@nx/js/typescript` plugin only infers `dependentTasksOutputFiles`
for `tsc --build` targets when external project references are detected.
Otherwise it falls back to `^production`, which tracks dependency source
files.

This is semantically incorrect — `tsc --build` resolves dependencies
through build artifacts (`.d.ts` and `.tsbuildinfo`), never source
files, regardless of reference type (external refs, internal refs, or
ad-hoc task dependencies).

## Expected Behavior

`dependentTasksOutputFiles` is always inferred for `tsc --build` targets
since that's what tsc actually reads. The `^production` fallback is
removed as it was a proxy that's no longer needed.
2026-03-11 10:01:05 -04:00
Jason Jean dcba2bfc6a fix(core): ensure batch tasks always have hash for DTE (#34764)
## Current Behavior

After #34446, batch tasks with `depsOutputs` inputs had their hashing
deferred until after execution. This meant the streaming `endTasks`
callback fired with `task.hash = undefined`, which Cloud/DTE rejects.

## Expected Behavior

All batch tasks always have a valid hash when `endTasks` is called.
Tasks with `depsOutputs` get a preliminary hash upfront (based on
whatever outputs are on disk), then are re-hashed after execution with
fresh outputs for correct cache storage.

### How it works

1. **Phase 1** now hashes ALL root tasks at each level (not just
cache-eligible ones). Ineligible tasks get a preliminary hash so the
streaming callback always has something valid to send.
2. **Phase 2** runs the batch, then clears and re-hashes all tasks that
ran — outputs are fresh on disk, so depsOutputs tasks get correct final
hashes.
3. The re-hash logic is consolidated into a single block after both code
paths (cache-enabled and cache-skipped).

## Related Issue(s)

Fixes the undefined hash regression from #34446

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-03-11 18:51:55 +09:00
Jason Jean 9e5ba5a2cf fix(webpack): cap less version to <4.6.0 to avoid ESM incompatibility (#34781)
## Current Behavior

`@nx/webpack` specifies `"less": "^4.1.3"` as a dependency, which allows
`less@4.6.0` to be installed. However, `less@4.6.0` switched to ESM
(`"type": "module"`), and `less-loader@11.x` uses `require()` to load
it. This causes a runtime error:

```
class WebpackFileManager extends implementation.FileManager {
                                                ^
TypeError: Class extends value undefined is not a constructor or null
```

This breaks any React/webpack project that uses Less stylesheets (e.g.
the "should support global and css modules" e2e test).

## Expected Behavior

The `less` version range is capped to `>=4.1.3 <4.6.0`, preventing the
incompatible ESM-only version from being installed. Less stylesheets
compile correctly with webpack and less-loader.

## Related Issue(s)

N/A - discovered via e2e test failure
2026-03-10 22:10:26 -04:00
Louie Weng 4f67a056e9 chore(gradle): bump gradle project graph plugin version to 0.1.15 (#34779)
## Current Behavior

The gradle project graph plugin version is 0.1.14.

## Expected Behavior

The gradle project graph plugin version is bumped to 0.1.15 with a
corresponding migration.

## Related Issue(s)

N/A - Routine version bump.

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-10 16:56:02 -04:00
Louie Weng 6326b9c38c feat(gradle): add properties and wrappers to inputs (#34778)
<!-- 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
Gradle task inputs in Nx do not includ configuration files like
gradle.properties, gradle/wrapper/gradle-wrapper.jar, and
gradle/wrapper/gradle-wrapper.properties. When these files change, Nx's
cache does not invalidate, potentially causing builds to use stale
cached results despite configuration changes that affect build behavior.

## Expected Behavior
Gradle wrapper and properties files are now automatically included as
inputs for all Gradle tasks when they exist in the workspace. This
ensures that changes to Gradle version (via wrapper files) or build
configuration (via gradle.properties) properly invalidate Nx's task
cache, guaranteeing accurate incremental builds and cache hits.

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: lourw <lourw@users.noreply.github.com>
2026-03-10 13:02:35 -07:00
Louie Weng dcd269fb2f fix(gradle): ensure that ci test target depends on take overrides into account (#34777)
<!-- 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

When generating atomized CI test targets for Gradle projects, the
dependsOn entries do not respect targetNameOverrides or targetNamePrefix
configuration. This means that if a test task depends on other tasks
(like compileTestKotlin or classes), and those tasks have been renamed
via overrides or prefixed (e.g., gradle-compileTestKotlin), the
generated CI test targets reference the original, non-transformed task
names. This creates broken dependencies in the project graph.

## Expected Behavior

Atomized CI test targets now correctly apply both targetNameOverrides
and targetNamePrefix to their dependsOn entries. When a test task
depends on other tasks, the generated CI targets will reference the
properly transformed target names, ensuring dependency integrity
throughout the project graph. The fix passes these configuration
parameters through the entire CI target generation pipeline in
CiTargetsUtils.kt.

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: lourw <lourw@users.noreply.github.com>
2026-03-10 15:48:47 -04:00
MaxKless 3945a740f8 fix(core): improve nx wrapper error message for malformed nx.json (#34736)
## Current Behavior

When `nx.json` exists but contains a syntax error (e.g. invalid JSON),
the nx wrapper shows:

```
[NX]: The "nx.json" file is required when running the nx wrapper.
```

This is misleading because the file exists — it's just malformed.

## Expected Behavior

The nx wrapper now distinguishes between a missing `nx.json` and a
malformed one:

- **Missing file**: `[NX]: The "nx.json" file is required when running
the nx wrapper.`
- **Parse error**: `[NX]: Failed to parse "nx.json": <actual error>. See
...`

The existence check is done upfront before attempting to parse, so the
`catch` block only handles parse errors.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 15:44:05 -04:00
Leosvel Pérez Espinosa f9cfd195d6 fix(js): add external project reference config files as inputs for tsc tasks (#34770)
## Current Behavior

The `@nx/js/typescript` plugin's `getInputs()` doesn't include tsconfig
files from external project references as task inputs. When `tsc
--build` follows a project reference to another Nx project (e.g.,
`../ui-common/tsconfig.lib.json`), it reads that tsconfig file, but the
dependency isn't declared. This means changes to an external reference's
tsconfig won't invalidate the dependent task's cache.

## Expected Behavior

External project reference config files (and their extended configs) are
declared as inputs for correct cache invalidation.

## Changes

- Replace `hasExternalProjectReferences` boolean check with
`getExternalProjectReferenceConfigFiles` that collects external ref
config file paths in a single traversal
- Add collected paths as inputs alongside `dependentTasksOutputFiles`
- Remove now-unused `hasExternalProjectReferences` (one traversal
instead of two when external refs exist)
2026-03-10 15:29:33 -04:00
Leosvel Pérez Espinosa 0589e67b7d fix(js): include transitive dep outputs in typecheck inputs (#34773)
## Current Behavior

The `@nx/js/typescript` plugin infers `dependentTasksOutputFiles:
'**/*.{d.ts,tsbuildinfo}'` as inputs for typecheck tasks, but only
tracks `.d.ts` outputs from **direct** dependencies. TypeScript project
references transitively read `.d.ts` files from the full dependency
chain, so when a project typechecks, it reads `.d.ts` outputs from
transitive deps too. These undeclared inputs can cause incorrect cache
hits.

## Expected Behavior

The inferred inputs for typecheck tasks include `.d.ts` and
`.tsbuildinfo` outputs from the entire transitive dependency graph by
setting `transitive: true` on the `dependentTasksOutputFiles` input.
2026-03-10 15:27:33 -04:00
Jason Jean 4593af3ea5 feat(core): persist analytics session ID across CLI invocations (#34763)
## Current Behavior

Each `nx` CLI invocation generates a new random session ID for GA4
analytics. This means GA4 cannot correlate multiple commands from the
same user working session, making active user tracking inaccurate.

## Expected Behavior

Session IDs are persisted in the SQLite metadata table with a 30-minute
timeout. Consecutive `nx` commands within that window share the same
session ID, enabling accurate GA4 active user tracking. After 30 minutes
of inactivity, a new session is automatically created.

## Related Issue(s)

N/A — internal analytics improvement
2026-03-10 09:34:57 -04:00
Chau Tran e7092db540 fix(core): misc graph changes with nx/graph 1.0.5 (#34761) 2026-03-10 18:57:46 +07:00
Jason Jean 556ff2d171 fix(webpack): update e2e snapshot for vitest reportsDirectory change (#34766)
## Current Behavior

The webpack legacy e2e test
(`e2e-webpack:e2e-ci--src/webpack.legacy.test.ts`) fails with a snapshot
mismatch because the `reportsDirectory` value changed from
`../coverage/app3224373` to `coverage/app3224373`.

## Expected Behavior

The snapshot should match the new `reportsDirectory` path format
introduced by #34720.

## Related Issue(s)

Fixes the e2e test breakage introduced by #34720 (`fix(vitest)!: resolve
reportsDirectory against workspace root`).
2026-03-09 22:21:04 +00:00
Colum Ferry 4bb7c76d45 feat(core): add analytics (#34144)
## Current Behavior

Nx CLI has no mechanism for collecting usage analytics, and users are
not prompted about their analytics preferences. There is no way for the
Nx team to understand which commands, generators, and features are most
used.

## Expected Behavior

This PR adds opt-in analytics collection to the Nx CLI with two main
components:

### 1. Analytics Prompt

Users are prompted for their analytics preference on first interactive
CLI run when `analytics` is not yet configured in `nx.json`:

- Only appears when `analytics` is undefined in `nx.json`
- Skipped in CI environments
- Skipped in non-interactive terminals (piped input/output)
- Stores the user's choice as a boolean (`true`/`false`) in the
`analytics` field of `nx.json`
- Defaults to `false` if the user cancels (Ctrl+C)
- Includes a migration (`update-22-6-0/enable-analytics-prompt`) for
existing workspaces

### 2. Analytics Collector

When analytics is enabled, the CLI collects usage data via a Rust-based
telemetry service and sends it to GA4. Data collected includes:

- **Commands run** (e.g. `build`, `test`, `generate`, `add`) — tracked
as page views
- **Command arguments** — with aggressive sanitization of sensitive
values (project names, file paths, URLs, credentials, free-form text are
all redacted; only boolean flags and safe enum values are preserved)
- **Generator and package names** for `nx add` and `nx generate` (as
custom dimensions)
- **Project graph creation duration**
- **Environment metadata**: Nx version, Node version, package manager,
OS, architecture, CI detection

### Workspace Identification

Each workspace is identified by a deterministic ID (used as the GA4
client ID) with the following priority:

1. **`nxCloudId`** (or `nxCloudAccessToken`) from `nx.json` — used
directly, most stable
2. **Git remote URL** (`git remote get-url origin`) — SHA-256 hashed for
privacy
3. **First commit SHA** (`git rev-list --max-parents=0 HEAD`) — used
directly as a fallback

Each user/machine is identified separately via `node-machine-id`.

### Privacy & Safety

- No project names, file paths, or other PII is collected
- Sensitive CLI arguments are redacted (see `SENSITIVE_ARGS_KEYS` list)
- Analytics is strictly opt-in (must be `true` in `nx.json`)
- Telemetry failures are silently ignored — never blocks or crashes the
CLI
- WASM builds are excluded (no native telemetry module available)
- The native telemetry functions are loaded with optional chaining to
prevent crashes when running against published Nx binaries that don't
include them yet

### Key Files

- `packages/nx/src/utils/analytics-prompt.ts` — Prompt logic and
workspace ID generation
- `packages/nx/src/analytics/analytics.ts` — Analytics collector, event
tracking, argument sanitization
- `packages/nx/src/native/telemetry/` — Rust telemetry service
(constants, service, mod)
- `packages/nx/src/utils/machine-id-cache.ts` — Machine ID for user
identification
- `packages/nx/src/migrations/update-22-6-0/enable-analytics-prompt.ts`
— Migration for existing workspaces

## Related Issue(s)

Closes NXC-3731
Closes NXC-3732
Closes NXC-3733
Closes NXC-3734

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Coly010 <Coly010@users.noreply.github.com>
Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
2026-03-09 11:33:52 -04:00
Jason Jean b3d1b1a0db chore(gradle): bump gradle project graph plugin version to 0.1.14 (#34752)
https://claude.ai/code/session_01BMRoUBzqhTQL6WrQFiBxnr

<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-09 11:27:54 -04:00
Steven Nance 654118adca fix(vitest)!: resolve reportsDirectory against workspace root (#34720)
## Current Behavior

When `reportsDirectory` is configured with `{workspaceRoot}` token in
`nx.json` targetDefaults:

```json
"@nx/vitest:test": {
  "options": {
    "reportsDirectory": "{workspaceRoot}/coverage/{projectRoot}"
  }
}
```

Coverage output lands in the wrong location. For example, with a project
at `apps/my-app`, coverage goes to `apps/my-app/coverage/apps/my-app/`
instead of the intended `coverage/apps/my-app/`.

## Expected Behavior

Coverage output should be written to
`<workspaceRoot>/coverage/apps/my-app/`.

## Root Cause

Nx's `resolveNxTokensInOptions` strips `{workspaceRoot}/` from option
values and replaces `{projectRoot}`, producing a workspace-root-relative
path (e.g. `coverage/apps/my-app`). The vitest executor then passed this
directly to vitest, which resolved it relative to the **project root** —
not the workspace root.

## Fix

Resolve non-absolute `reportsDirectory` paths against the workspace root
before passing them to vitest, so vitest writes coverage to the correct
location.

## Test Plan

- Added unit tests for the new `resolveReportsDirectory` helper
- Verified with a reproduction workspace that coverage now lands at the
correct path
2026-03-09 15:18:31 +00:00
Leosvel Pérez Espinosa 92335c4241 fix(gradle): exclude non-JS gradle sub-projects from eslint plugin (#34735)
## Current Behavior

The `@nx/eslint/plugin` infers a `lint` target for
`gradle-project-graph` because it contains a single `.ts` file
(`publish-maven.ts`), even though it's a Kotlin/Gradle project.
Similarly, the parent `gradle` project's `eslint .` scans into non-JS
sub-project directories unnecessarily.

## Expected Behavior

Non-JS Gradle sub-projects (`project-graph`, `batch-runner`) should not
have lint targets inferred by the ESLint plugin, and the parent `gradle`
project's lint should not scan into those directories.

## Changes

- Add `project-graph` and `batch-runner` to ESLint `ignorePatterns` in
`packages/gradle/.eslintrc.json`

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: leosvelperez <leosvelperez@users.noreply.github.com>
2026-03-09 10:32:38 +00:00
Jason Jean 6f9bfbd7ea fix(gradle): use object format for dependsOn instead of shorthand strings (#34715)
## Current Behavior

The Gradle plugin generates `dependsOn` entries using the shorthand
string format (e.g., `"projectName:taskName"`). This doesn't leverage
the full object syntax that Nx supports.

## Expected Behavior

`dependsOn` entries now use the object format:
- Same-project dependencies: `{ "target": "taskName" }`
- Cross-project dependencies: `{ "target": "taskName", "projects":
["proj1", "proj2"] }` with projects grouped by target name

This is more explicit, consistent with the CI targets code (which
already used object format), and enables the `projects` array for
grouping multiple project dependencies under a single target.

## Related Issue(s)

N/A - internal improvement

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-03-06 22:36:56 +00:00
Leosvel Pérez Espinosa 8f44377d98 fix(js): include tsbuildinfo in dependentTasksOutputFiles for tsc tasks (#34733)
## Current Behavior

The `@nx/js/typescript` plugin sets `dependentTasksOutputFiles:
'**/*.d.ts'` for tsc tasks with external project references. This misses
`.tsbuildinfo` files that `tsc --build` reads from referenced projects
for incremental compilation, which can lead to incorrect cache hits.

## Expected Behavior

`dependentTasksOutputFiles` uses the glob `**/*.{d.ts,tsbuildinfo}`,
ensuring all files read by `tsc --build` from dependencies are tracked
as inputs for correct cache invalidation.
2026-03-06 17:30:36 -05:00
Leosvel Pérez Espinosa 997d6d8953 fix(linter): add catalog: references when fixing missing dependencies (#34734)
## Current Behavior

When the `dependency-checks` ESLint rule auto-fixes missing dependencies
in a project's `package.json`, it resolves the version from the root
`package.json` or falls back to the installed version from the project
graph. This inserts explicit version strings even when the workspace
uses catalogs, breaking same-version policy.

## Expected Behavior

The fixer now checks catalogs before falling back to installed versions.
When exactly one catalog entry for a missing dependency satisfies the
installed version, the fixer inserts `catalog:` (default catalog) or
`catalog:<name>` (named catalog) instead of an explicit version.

Fallback chain: root `package.json` → catalog lookup → installed
version.

Edge cases handled:
- Package in multiple catalogs but only one satisfies → uses that one
- Package in multiple catalogs and multiple satisfy → falls back to
installed version
- `file:` and other protocol-based versions → exact string comparison
instead of semver
- No catalog manager or no catalog definitions → falls back to installed
version

Also caches the catalog manager instance and catalog definitions per
lint run instead of re-creating them per function call.
2026-03-06 17:30:09 -05:00
Jason Jean 043aaee475 fix(core): batch-safe hashing for maven and gradle (#34446)
## Current Behavior

In batch mode (Maven/Gradle), all task hashes are computed upfront in
`processScheduledBatch` before the batch executor runs any tasks. Tasks
with `dependentTasksOutputFiles` (aka `depsOutputs`) get hashed using
whatever dependency outputs happen to be on disk from a previous run.
This leads to:

- **False cache hits**: If a dependency's sources changed but its old
outputs are still on disk, the dependent task's hash matches a stale
cache entry and wrong results are served.
- **False cache misses**: On cold runs with no outputs on disk, the hash
is computed without dependency output content and never matches any
stored cache entry.

Non-batch mode doesn't have this problem because it uses lazy hashing —
tasks with `depsOutputs` are only hashed after their dependencies
complete and fresh outputs exist on disk.

## Expected Behavior

Batch mode hashes tasks topologically — each task is hashed only after
its dependencies have run and their outputs are on disk. This means
hashes are always computed against fresh outputs, eliminating both false
cache hits and false cache misses.

### How it works

`applyFromCacheOrRunBatch` now has two phases:

1. **Topological cache resolution** — Walk the **entire** batch task
graph level by level. At each level, partition root tasks into
cache-eligible vs ineligible. A task is **ineligible** for cache if it
has `depsOutputs` inputs AND any of its dependencies were not cached
(their outputs aren't on disk, so the hash would be wrong). Hash and
check cache for eligible tasks, then remove **all** roots from the graph
to expose the next level — even when some tasks are cache misses. This
ensures the walk continues past cache misses to find deeper cache hits.

2. **Run remaining tasks, then hash** — Rebuild a run graph from all
non-cached task IDs and run them through the batch executor. After the
batch completes, hash all tasks that ran. Since all outputs (including
from sibling batch tasks) are now fresh on disk, tasks with
`depsOutputs` get correct hashes on the first pass — no re-hash needed.

### Task history lifecycle fix

The batch streaming callback calls `endTasks` as tasks finish mid-batch,
but tasks haven't been hashed yet at that point (hash is deferred to
post-execution). Previously, `TaskHistoryLifeCycle` and
`LegacyTaskHistoryLifeCycle` eagerly snapshotted `task.hash` in
`endTasks`, which sent `undefined` to the native Rust layer causing a
"Missing field `hash`" crash.

**Fix:** Both lifecycles now store `TaskResult` references in `endTasks`
and defer building `TaskRun` objects until `endCommand`, when
`task.hash` is guaranteed to be set by the post-batch re-hash. The
streaming callback and `runBatch` return value also now use the original
task object reference (instead of spread copies) so that the hash
mutation from `hashBatchTasks` flows through to all stored references.

### Example: 3 tasks over 3 runs

Consider a batch with three tasks in a linear chain: **A → B → C**

- **Task A** — `lib:compile`. Inputs: source files only. No
`depsOutputs`.
- **Task B** — `app:compile`. Depends on A. Inputs: only `depsOutputs`
from Task A (e.g., `target/classes/**`). No source file inputs.
- **Task C** — `app:checkstyle`. Depends on B. Not cacheable.

Hash notation: `H(inputs…)` means the hash is a function of those
inputs.

---

#### Run 1 — Fresh (no outputs on disk, empty cache)

| Step | What happens |
|------|-------------|
| **Phase 1** | Roots = `[A]` (B depends on A, C depends on B). Hash A →
**H_A** |
| | Check cache: A = miss. A is added to `nonCachedTaskIds`. Remove all
roots. |
| **Phase 1, iter 2** | Roots = `[B]`. B has `depsOutputs` and A is
non-cached → B is **ineligible**. Added to `nonCachedTaskIds`. Remove
all roots. |
| **Phase 1, iter 3** | Roots = `[C]`. C has no `depsOutputs` →
eligible. Hash C → **H_C**. Cache miss. Added to `nonCachedTaskIds`.
Remove all roots. |
| **Phase 2** | Rebuild run graph from `nonCachedTaskIds` = {A, B, C}.
Run batch: all 3 tasks execute. A produces `target/classes/`. |
| | Hash all tasks post-execution: A → **H_A**, B → `H(A_outputs)` =
**H_B**, C → **H_C** |
| **Cache** | Store A as **H_A**, store B as **H_B**. C is not cached. |

> **Key:** B is hashed *after* the batch, when A's outputs already exist
on disk. The hash is correct on the first pass. C was still checked
against cache even though A and B were misses.

---

#### Run 2 — Warm (nothing changed, cache populated from Run 1)

| Step | What happens |
|------|-------------|
| **Phase 1, iter 1** | Roots = `[A]`. Hash A → **H_A** |
| | Check cache: A = **HIT**  → restore `target/classes/` to disk. |
| **Phase 1, iter 2** | Roots = `[B]`. B has `depsOutputs` but A is
cached (not in `nonCachedTaskIds`) → B is **eligible**. Hash B →
`H(A_outputs)` = **H_B** (A's outputs just restored!) |
| | Check cache: B = **HIT**  → restore B's outputs. |
| **Phase 1, iter 3** | Roots = `[C]`. Hash C → **H_C**. Not cacheable →
no hit. Added to `nonCachedTaskIds`. |
| **Phase 2** | Rebuild run graph from `nonCachedTaskIds` = {C}. Run
batch with just C. Hash C post-execution. |

> **Key:** Phase 1 restored A's outputs from cache *before* hashing B.
So B's hash matches Run 1's value → cache hit. The topological walk
peels the chain one level at a time: A → B → C.

---

#### Run 3 — Source changed (A's source modified, stale outputs from Run
2 still on disk)

| Step | What happens |
|------|-------------|
| **Phase 1, iter 1** | Roots = `[A]`. Hash A → `H(A_src')` = **H_A'**
(new hash!) |
| | Check cache: A = **miss** (H_A' not in cache). A added to
`nonCachedTaskIds`. |
| **Phase 1, iter 2** | Roots = `[B]`. B has `depsOutputs` and A is
non-cached → B is **ineligible**. Added to `nonCachedTaskIds`. |
| **Phase 1, iter 3** | Roots = `[C]`. C has no `depsOutputs` →
eligible. Hash C → **H_C**. Cache miss. Added to `nonCachedTaskIds`. |
| **Phase 2** | Run batch: all 3 tasks execute. A produces *new*
outputs. |
| | Hash all tasks post-execution: A → **H_A'**, B → `H(A_new_outputs)`
= **H_B'**, C → **H_C** |
| **Cache** | Store A as **H_A'**, store B as **H_B'**. C is not cached.
|

> **Key:** Because hashing happens after execution, B is always hashed
against A's *fresh* outputs. No stale hash, no re-hash needed. And C is
still checked against cache at every level, even when upstream tasks
miss.

---

#### Summary of hashes across runs

| Task | Run 1 (fresh) | Run 2 (warm) | Run 3 (src changed) |
|------|--------------|-------------|-------------------|
| **A** | miss → cache **H_A** | hit **H_A**  | miss → cache **H_A'** |
| **B** | miss → post-exec hash & cache **H_B** | hit **H_B**  | miss →
post-exec hash & cache **H_B'** |
| **C** | not cacheable → runs | not cacheable → runs | not cacheable →
runs |

### Maven plugin fixes

Several fixes to the Maven plugin to ensure correct batch behavior:

- **Propagate batch runner exit code failures**: Batch runner process
exit codes are now correctly propagated so task failures are reported
properly.
- **Use glob patterns for gitignored dependent task outputs**:
`depsOutputs` patterns like `target/classes` are now resolved using glob
patterns, fixing issues with `.gitignore`d output directories.
- **Fix inputs for `maven:test`**: Test task inputs now correctly
include test source files so hash changes when tests are modified.
- **Include test sources in `testCompile` task hash**: The `testCompile`
target now includes `src/test/java` in its inputs.

## Related Issue(s)

Related to #30949
2026-03-06 17:28:37 -05:00
Jack Hsu e50cc74212 docs(misc): add Vale as automated editor and a Claude skill to ensure style guide is followed (#34744)
This PR makes it much easier for everyone to contribute to our docs.

1. [Vale](https://vale.sh/) is installed via `mise` - This is our
automated editor.
2. Claude skill to invoke Vale and also follow
`astro-docs/STYLE_GUIDE.md` for things that Vale cannot pick up.
3. `CLAUDE.md` instruction to invoke the skill (2) whenever someone is
updating docs.

Demo: https://www.loom.com/share/415a9da056d3483da297fda61f7e7382
2026-03-06 15:39:33 -05:00
Victor Savkin d267145a82 fix(nx-cloud): allow download-cloud-client to work outside nx workspaces (#34746)
Remove the isNxCloudUsed guard that prevented the command from running
without an nx.json. Now gracefully falls back to default cloud URL when
not in an Nx workspace.

<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:18:41 -05:00
Jason Jean 9097d9204a chore(repo): update nx to 22.6.0-beta.10 (#34748)
Updating Nx from 22.6.0-beta.9 to 22.6.0-beta.10
2026-03-06 15:00:56 -05:00
Philip Fulcher 18e47b3db9 docs(nx-dev): add siriusxm success story (#34745) 2026-03-06 14:15:40 -05:00
Rares Matei d6359d496c chore(repo): remove explicit tracing directory setting (#34749)
Remove NX_CLOUD_IO_TRACING_DIRECTORY environment variable.

<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2026-03-06 19:02:20 +00:00
Leosvel Pérez Espinosa 60c72ced4f fix(core): add missing @nx/angular-rspack packages to nx packageGroup (#34743)
## Current Behavior

Running `nx migrate latest` updates all `@nx/*` packages except
`@nx/angular-rspack` and `@nx/angular-rspack-compiler`.

## Expected Behavior

`nx migrate latest` updates `@nx/angular-rspack` and
`@nx/angular-rspack-compiler` along with all other `@nx/*` packages.

## Related Issue(s)

Fixes #32772
2026-03-06 12:53:16 -05:00
Steven Nance 5359ac2792 fix(js): derive tsbuildinfo filename from iterated tsconfig, not outer config (#34738)
## Current Behavior

The `getOutputs()` function in the `@nx/js/typescript` plugin derives
`.tsbuildinfo` filenames from `config.basenameNoExt` (the outer
`ConfigContext`, which always corresponds to `tsconfig.json`) instead of
the currently iterated internal project reference. This causes all
internal references to produce `dist/tsconfig.tsbuildinfo` as the output
path instead of the correct filenames like
`dist/tsconfig.lib.tsbuildinfo` and `dist/tsconfig.spec.tsbuildinfo`.

This leads to:
- Cache misses because Nx looks for `dist/tsconfig.tsbuildinfo` which
doesn't exist
- Missing actual `.tsbuildinfo` files from cache outputs
- Potential race conditions in parallel `tsc --build` invocations

## Expected Behavior

The `.tsbuildinfo` filename should be derived from each individual
tsconfig's file path. For a project with:
- `tsconfig.lib.json` → `dist/tsconfig.lib.tsbuildinfo`
- `tsconfig.spec.json` → `dist/tsconfig.spec.tsbuildinfo`
- `cypress/tsconfig.json` → `cypress/dist/tsconfig.tsbuildinfo`

The fix changes the loop in `getOutputs()` to iterate over entries (path
+ data pairs) so the basename can be correctly derived from each
tsconfig's file path. Also fixes the `outFile` and no-outDir branches
which had similar issues using the outer config parameter instead of the
loop variable.

## Related Issue(s)

Fixes #34737
2026-03-06 17:39:18 +00:00
Victor Savkin 2cd3d58632 chore(repo): remove enterprise nx plugin (#34729)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: vsavkin <vsavkin@users.noreply.github.com>
2026-03-06 10:32:54 -05:00
Juri 23192694d2 docs(repo): refresh repository README
Rewrite README to reflect Nx's current capabilities: zero-config caching,
polyglot plugin system, CI distribution, AI-native tooling, and self-healing CI.
Remove stale badges (Gitter, Semantic Release). Point courses banner to nx.dev/courses.
2026-03-06 16:27:29 +01:00
Leosvel Pérez Espinosa fb8884e967 fix(vitest): handle zoneless Angular apps in vitest configuration generator (#34700)
## Current Behavior

When running `@nx/vitest:configuration` on an Angular project, the
generator always generates `import
'@analogjs/vitest-angular/setup-zone'` regardless of whether the app is
zoneless. Additionally, the setup file generation logic for Angular 21+
(which uses `setupTestBed()`) only exists in
`packages/angular/src/generators/utils/add-vitest.ts`
(`createAnalogSetupFile`), making the vitest generator not
self-contained.

## Expected Behavior

The vitest configuration generator should:
- Auto-detect whether an Angular project is zoneless (by checking
polyfills for apps, or zone.js dependency for libraries)
- Generate `setup-snapshots` instead of `setup-zone` for zoneless
projects
- Handle Angular 21+ `setupTestBed()` setup directly, without requiring
a separate function in the angular package
- Accept an explicit `zoneless` option to override auto-detection

## Related Issue(s)

Fixes #33983
2026-03-06 12:37:39 +01:00
Leosvel Pérez Espinosa 42f623e2c1 fix(vite): skip root-relative paths in nxViteTsPaths resolveId (#34694)
## Current Behavior

The `resolveId` hook in `nxViteTsPaths` processes all import paths,
including Vite root-relative paths (e.g. `/src/test-setup.ts`). In Vite,
`/foo` means "relative to project root," but `nxViteTsPaths` resolves it
via tsconfig's `baseUrl` (workspace root), producing wrong paths.

In an Angular standalone workspace with Vitest + Analog, generating a
library and running `nx test test-lib` fails with `Error: Need to call
TestBed.initTestEnvironment() first` because the library's
`src/test-setup.ts` resolves to the root app's file instead. The Analog
Angular compiler never compiled that file, so the transform returns
empty content and `setupTestBed()` never runs.

## Expected Behavior

`nxViteTsPaths` should skip `/`-prefixed paths and let Vite's built-in
resolver handle them. These are filesystem paths (absolute or
root-relative), not TypeScript import specifiers. Library tests should
work correctly with their own `test-setup.ts`.

## Related Issue(s)

Fixes #34300
2026-03-06 12:37:23 +01:00
Leosvel Pérez Espinosa 8bc7234dd5 feat(js): support configurable typecheck config name (#34675)
## Current Behavior

The TypeScript plugin's typecheck target inference was tied to
`tsconfig.json`, so users could not configure a different tsconfig file
name for typecheck inference.

## Expected Behavior

The plugin supports configuring `typecheck.configName`, which defaults
to `tsconfig.json`.
2026-03-06 11:46:51 +01:00
Victor Savkin 035e061ea2 fix(core): allow nx cloud commands to run outside of a workspace (#34728)
## Current Behavior

Running Nx Cloud commands (login, logout, polygraph, etc.) from outside
an Nx workspace fails with 'The current directory is not part of an Nx
workspace' because handleNoWorkspace exits before reaching the cloud
command handler. Additionally, polygraph was not in the isNxCloudCommand
list.

## Expected Behavior

Nx Cloud commands work regardless of whether you are inside an Nx
workspace, since they only delegate to the cloud client.

## Related Issue(s)

N/A

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 03:18:38 +00:00
Craigory Coppola 7b3598532c feat(core): add safe plugin cache write utilities with LRU eviction (#34503)
## Current Behavior

Plugin cache writes (`writeJsonFile`, `writeFileSync`) across the
codebase have inconsistent error handling:
- Some throw on failure, aborting project graph calculation entirely
- Some silently swallow errors, leaving corrupted cache files on disk
- No mechanism exists to recover from oversized or corrupted caches
- `nx-deps-cache.ts` retries 5 times then throws, crashing the graph

## Expected Behavior

- Plugin cache write failures **never** abort graph calculation — they
warn and continue
- A centralized `safeWritePluginCache` utility handles all hash-map
plugin caches with a 3-step strategy:
1. Attempt full write
2. On failure: evict oldest 50% of entries (LRU) and retry
3. On second failure: wipe cache file, log warning, return without
throwing
- `PluginCache<T>` class wraps cache data with a Proxy that
transparently tracks access order, enabling true LRU
eviction (not just insertion order)
- Access order is stored as a simple `string[]` array — front is oldest,
back is most recent
- Backward-compatible with 3 on-disk formats: legacy plain `Record`,
timestamp-based `{ entries, accessedAt }`, and
current `{ entries, accessOrder }`
- All plugin cache consumers migrated: package-json, js/lockfile,
dotnet, cypress, playwright, gradle, maven
- `nx-deps-cache.ts` changed from throw-after-retries to warn + cleanup
- New utilities exported via `@nx/devkit` internals for plugin authors

## Related Issue(s)

Fixes NXC-3833"

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
2026-03-05 20:56:21 -05:00
Jack Hsu cb6452ce93 fix(misc): address security CVE cluster (copy-webpack-plugin, koa, minimatch) (#34708)
## Current Behavior

Several security-related issues reported:

1. **copy-webpack-plugin** (#34632): `@nx/webpack` and `@nx/next` pin
`copy-webpack-plugin@^10.2.4` which transitively depends on
`serialize-javascript@^6.0.1` (vulnerable) and `fast-glob` (supply-chain
risk).

2. **koa** (#34621): `@nx/module-federation` transitively pulls
`koa@3.0.3` via `@module-federation/dts-plugin`, which is vulnerable to
CVE-2026-27959 (Host Header Injection, fixed in koa 3.1.2).

3. **css-minimizer-webpack-plugin**: `@nx/webpack` pins `^5.0.0` which
also depends on vulnerable `serialize-javascript@^6.0.1`.

4. **@module-federation/enhanced**: Versions `<2.1.0` transitively
install vulnerable `koa` via `dts-plugin`.

5. **Next.js**: Versions `16.0.x` are vulnerable to GHSA-9g9p-9gw9-jx7f
(Image Optimizer DoS) and GHSA-5f7q-jpqc-wp7h (PPR Resume memory
consumption).

6. **minimatch** (#34701): User reports minimatch vulnerability, but the
Nx pnpm catalog already pins the patched version `10.2.4`. No code
change needed — users should delete their lockfile and reinstall.

## Expected Behavior

1. **copy-webpack-plugin** bumped to `^14.0.0` which uses
`serialize-javascript@^7.0.3` (patched). Added `noErrorOnMissing: true`
to all 3 copy-webpack-plugin usage sites to handle the v14 breaking
change where missing glob patterns now throw errors by default.

2. **css-minimizer-webpack-plugin** bumped to `^8.0.0` which uses
`serialize-javascript@^7.0.3` (patched).

3. **koa** bumped to `^3.1.2` in `@nx/node` versions.ts.
`@module-federation/dts-plugin@2.1.0` completely removes koa dependency.

4. **@module-federation/enhanced**, **runtime**, **sdk** bumped to
`^2.1.0` across all packages (`@nx/module-federation`, `@nx/react`,
`@nx/angular`, `@nx/rspack`). Added `noErrorOnMissing` fix for
`@module-federation/enhanced` 2.x `runtime-library-control.plugin.ts`
compatibility.

5. **Next.js** bumped to `~16.1.6` and `eslint-config-next` to
`^16.1.6`.

6. **minimatch** — no change needed, already resolved.

### Migrations added (22.6.0-beta.10)
- `@nx/module-federation`: Bump MF packages to `^2.1.0`
- `@nx/react`: Bump `@module-federation/enhanced` to `^2.1.0`
- `@nx/angular`: Bump `@module-federation/enhanced` to `^2.1.0`
- `@nx/node`: Bump `koa` to `^3.1.2`
- `@nx/next`: Bump `next` to `~16.1.6`

### Skipped
- **esbuild** (`<=0.24.2`, moderate severity, dev server only): Fix
requires breaking change jump from `^0.19.2` to `0.25+`. Will address
separately.

## Testing

Created a fresh Nx workspace with all affected plugins to verify `npm
audit` is clean after changes:

- `@nx/next` (nextapp)
- `@nx/webpack` (webpackapp)
- `@nx/rspack` (shell, remote1, remote2 via Module Federation)
- `@nx/module-federation` (shell + remotes with MF config)
- `@nx/react` (MF host/remotes)
- `@nx/node` + koa (api)

```
├── apps
│   ├── api                  # @nx/node (koa)
│   ├── nextapp              # @nx/next
│   ├── remote1              # @nx/react + rspack + MF
│   ├── remote2              # @nx/react + rspack + MF
│   ├── shell                # @nx/react + rspack + MF (host)
│   └── webpackapp           # @nx/webpack
```

Post-change audit result — only remaining issue is esbuild (moderate,
skipped intentionally):

```
# npm audit report

esbuild  <=0.24.2
Severity: moderate
esbuild enables any website to send any requests to the development server
and read the response - https://github.com/advisories/GHSA-67mh-4wv8-2f99
fix available via `npm audit fix --force`
Will install esbuild@0.27.3, which is a breaking change

1 moderate severity vulnerability
```

## Related Issue(s)

Fixes #34632
Fixes #34621
Fixes #34701
2026-03-05 17:56:19 -05:00
Jack Hsu 9b4e9ff16e chore(misc): add .netlify to gitignore instead of nxignore (#34727)
This addresses feedback on PR #34726 - .netlify directories are build
artifacts and should be in .gitignore rather than .nxignore. This also
generalizes the pattern from `astro-docs/.netlify` to `.netlify` to
cover the root-level `.netlify/static/documentation` directory that was
causing duplicate project detection.

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-05 17:43:56 -05:00
Victor Savkin e31ac44e77 feat(core): add polygraph command to initiaze cross-repo sessions (#34722)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2026-03-05 22:24:42 +00:00
Jack Hsu b316ec1ff9 fix(core): surface clearer error when CNW hits SANDBOX_FAILED (#34724)
This PR surfaces install errors instead of silently failing without
anything useful printed. It also records `needs_input` in the AX flow as
`cancelled` so we account for cases where AI agents exit without
recording either success, complete, or cancelled.

BEFORE:

<img width="1288" height="381" alt="image"
src="https://github.com/user-attachments/assets/44fe9642-764e-452b-90be-f30c4a230be5"
/>

AFTER:

<img width="1279" height="850" alt="Screenshot 2026-03-05 at 12 30
25 PM"
src="https://github.com/user-attachments/assets/24c96584-2790-4dcb-8404-7e221c50876c"
/>

## Notes

1. **Remove `--silent` from all PM install commands** — since
`execAndWait` uses `exec()` (captures output in memory, never shown to
terminal), `--silent` just suppressed error info for no benefit
2. **Increase `maxBuffer`** from default 1MB to 10MB to prevent process
being killed when PMs emit verbose output
3. **Fallback error message** when both stderr and stdout are empty —
includes exit code and log file path
4. **Structured sandbox error** with exit code, log file, and actionable
hint
5. **Record telemetry stat** for AI agent `needs_input` flow (was
previously missing)
6. **Migrate from deprecated `CreateNxWorkspaceError`** to `CnwError` in
`execAndWait`

## Related Issue(s)

Fixes NXC-4035
2026-03-05 13:42:12 -05:00
Juri Strumpflohner a3c5f2716b feat(nx-dev): add YouTube channel callout to courses page (#34669)
## Current Behavior

[The courses
page](https://deploy-preview-34669--nx-dev.netlify.app/courses) has a
hero section with title and subtitle but no mention of the YouTube
channel for one-off educational videos.

## Expected Behavior

A subtle callout link with a YouTube icon appears below the hero
subtitle, directing users to the Nx YouTube channel for one-off
educational videos.

## Related Issue(s)

N/A
2026-03-05 16:31:46 +00:00
MaxKless 67ecf04773 docs(misc): add blog post on making Nx agent-ready (#34678)
## Current Behavior

No blog post covering the AX principles behind recent Nx CLI
improvements.

## Expected Behavior

New draft blog post (`docs/blog/2026-03-05-making-nx-agent-ready.md`)
covering:
- Why agentic experience (AX) matters for developer tools
- AX principles: context management, structured feedback, idempotency,
informative output
- The open question of human vs agent experience divergence
- A forward look at `nx connect` going agentic

The post is set to `draft: true` and scheduled for Thursday March 5th.

## Related Issue(s)

N/A — new content

---

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Juri <juri.strumpflohner@gmail.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: MaxKless <MaxKless@users.noreply.github.com>
2026-03-05 16:43:02 +01:00
Juri Strumpflohner bc45b92037 fix(core): add .claude/worktrees to gitignore (#34693)
## Current Behavior

When Claude Code creates worktrees under `.claude/worktrees/`, Nx picks
them up as workspace projects. This causes duplicate project errors that
break the project graph.

## Expected Behavior

`.claude/worktrees` is gitignored so worktree copies of the repo don't
interfere with Nx's project detection.
2026-03-05 15:08:17 +00:00
Leosvel Pérez Espinosa a5555d6f77 fix(core): prevent TUI panic when Nx Console is connected (#34718)
## Current Behavior

After the napi v2→v3 migration, running tasks with TUI enabled while Nx
Console is connected causes a panic: `there is no reactor running, must
be called from the context of a Tokio 1.x runtime`. This happens because
`end_command` is a sync NAPI callback that calls `end_running_tasks()`
which uses `tokio::spawn`, but napi v3 no longer wraps sync callbacks
with Tokio runtime context by default.

## Expected Behavior

Tasks complete without panic when Nx Console is connected and TUI is
enabled.
2026-03-05 07:44:57 -05:00
Jason Jean ce559a1714 chore(repo): update nx to 22.6.0-beta.9 (#34712)
Updating Nx from 22.6.0-beta.8 to 22.6.0-beta.9
2026-03-05 09:00:27 +01:00
Louie Weng a9678b2180 chore(repo): bump version to 22.6.0-beta.8 (#34706)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Bump Nx version to 22.6.0-beta.8

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

Fixes #
2026-03-04 20:47:16 +00:00
Leosvel Pérez Espinosa 320bfe5216 fix(js): normalize paths to posix format in typescript plugin (#34702)
## Current Behavior

On Windows, the `@nx/js` TypeScript plugin fails during project graph
creation with a path mismatch assertion error. The plugin uses
`path.join()` and `path.relative()` from Node's `path` module, which
produce backslash-separated paths on Windows. These are passed to
TypeScript's `readConfigFile` API, which has an internal inconsistency:
its parser normalizes paths to forward slashes for diagnostics but
retains the original (backslash) path on the source file, causing an
assertion failure when parse diagnostics are present.

Additionally, `posix.normalize()` was incorrectly relied upon to convert
backslashes to forward slashes — it only normalizes paths already in
POSIX format.

## Expected Behavior

The TypeScript plugin normalizes paths to POSIX format (forward slashes)
for TypeScript API compatibility and cache key consistency, working
correctly on both Windows and Unix systems.

## Related Issue(s)

Fixes #31232
2026-03-04 15:12:50 -05:00
Jack Hsu e11be5d0b0 docs(misc): clean up outdated version references (#34707)
## Current Behavior

Documentation contains version-conditional content and version
qualifiers referencing Nx versions older than 20 (e.g. "Nx 18+" / "Nx <
18" tabs, "Starting from Nx 11", "Since Nx 16", "Prior to Nx 18"). These
are no longer useful since the current version is 22.

## Expected Behavior

Remove conditional content gated on versions < 20. Keep only the modern
code path as the default. Also apply style guide fixes to all touched
pages (fix typos, remove self-referential language, replace
non-descriptive link text, remove AI-style phrases).

### Changes across 11 files:

**Version-conditional tabs removed:**
-
[`react-native/introduction`](https://deploy-preview-34707--nx-docs.netlify.app/docs/technologies/react/react-native/introduction)
— Removed "Nx < 18" tab, kept `nx add` as default
-
[`cypress/introduction`](https://deploy-preview-34707--nx-docs.netlify.app/docs/technologies/test-tools/cypress/introduction)
— Same

**Outdated version qualifiers removed:**
-
[`next-config-setup`](https://deploy-preview-34707--nx-docs.netlify.app/docs/technologies/react/next/guides/next-config-setup)
— Removed "Nx 15 and prior" section, dropped "Nx 16" qualifier
-
[`deploy-nextjs-to-vercel`](https://deploy-preview-34707--nx-docs.netlify.app/docs/technologies/react/guides/deploy-nextjs-to-vercel)
— Removed "Starting from Nx 11"
-
[`faster-builds-with-module-federation`](https://deploy-preview-34707--nx-docs.netlify.app/docs/technologies/module-federation/concepts/faster-builds-with-module-federation)
— Removed "Starting in Nx 14"
-
[`webpack-plugins`](https://deploy-preview-34707--nx-docs.netlify.app/docs/technologies/build-tools/webpack/guides/webpack-plugins)
— Removed "Prior to Nx 18" references
-
[`webpack-config-setup`](https://deploy-preview-34707--nx-docs.netlify.app/docs/technologies/build-tools/webpack/guides/webpack-config-setup)
— Removed "introduced in Nx 18"
-
[`use-environment-variables-in-react`](https://deploy-preview-34707--nx-docs.netlify.app/docs/technologies/react/guides/use-environment-variables-in-react)
— Removed "with the release of Nx 19"
-
[`environment-variables`](https://deploy-preview-34707--nx-docs.netlify.app/docs/reference/environment-variables)
— Removed "Workspaces created before Nx 18"
-
[`configure-inputs`](https://deploy-preview-34707--nx-docs.netlify.app/docs/guides/tasks--caching/configure-inputs)
— Removed "As of Nx 18"
-
[`configure-outputs`](https://deploy-preview-34707--nx-docs.netlify.app/docs/guides/tasks--caching/configure-outputs)
— Removed "As of Nx 18"

**Style guide fixes:** Fixed typos, removed self-referential language,
replaced non-descriptive link text ("here", "this page"), removed
AI-style phrases ("seamless", "comprehensive", "It's important to
note"), added missing Oxford comma.

## Related Issue(s)

Fixes DOC-437
2026-03-04 14:58:05 -05:00
Leosvel Pérez Espinosa f60f1c6b85 fix(angular): preserve skipLibCheck in tsconfig.json for standalone projects (#34695)
## Current Behavior

When creating a new Angular standalone project with Vitest
(`create-nx-workspace` → Angular → Standalone), running tests fails
with:

```
✘ [ERROR] TS2304: Cannot find name 'Disposable'. [plugin angular-compiler]

    node_modules/@vitest/spy/dist/index.d.ts:158:80:
      158 │ ...tends Procedure | Constructable = Procedure> extends Disposable {
```

For standalone (root) projects, `getRootTsConfigFileName` returns
`tsconfig.json` — the same file as the project tsconfig.
`getNeededCompilerOptionOverrides` compares the file against itself,
sees `skipLibCheck: true` already matches, and strips it. The result:
`skipLibCheck` disappears from the final `tsconfig.json`.

## Expected Behavior

Standalone Angular projects should have `skipLibCheck: true` in their
`tsconfig.json` (matching what Angular CLI generates), preventing type
errors from third-party `.d.ts` files like `@vitest/spy`.

## Related Issue(s)

Fixes #34164
2026-03-04 13:41:05 -05:00
Leosvel Pérez Espinosa feb8bd4b19 fix(js): strip catalogs from pruned pnpm lockfile (#34697)
## Current Behavior

When using `generatePackageJson: true`, Nx generates a pruned
`pnpm-lock.yaml` that includes the `catalogs:` section from the root
lockfile. Since the dist folder doesn't include `pnpm-workspace.yaml`,
pnpm 10.24.0+ throws `ERR_PNPM_LOCKFILE_CONFIG_MISMATCH` during `pnpm
install --frozen-lockfile`.

## Expected Behavior

The pruned lockfile strips the `catalogs` section since the dist folder
has no `pnpm-workspace.yaml` to define them.

## Related Issue(s)

Fixes #34337

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-04 13:40:10 -05:00
Rares Matei b05c565331 chore(repo): use absolute path for sandboxing signal files (#34704)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2026-03-04 13:38:06 -05:00
Copilot 32319ed11b fix(core): support tuple validation when schema items is an array (JSON Schema draft 07) (#34636)
`validateProperty` in `params.ts` did not handle the case where `items`
is an array — the JSON Schema draft 07 tuple validation form. This
caused false validation failures for schemas like Angular's
`@angular/build:unit-test`, which uses tuple `items` to type reporter
configurations:

```json
{
  "type": "array",
  "minItems": 1,
  "maxItems": 2,
  "items": [
    { "anyOf": [{ "type": "string" }, { "enum": ["junit", "html", ...] }] },
    { "type": "object" }
  ]
}
```

Options like `"reporters": [["junit", {"suiteName": "MyApp"}]]` would
incorrectly fail validation with _"Property 'reporters' does not match
the schema"_.

## Changes

- **`validateProperty`**: when `schema.items` is an array, validates
each element against its positional schema instead of passing the whole
array as a schema
- **`minItems`/`maxItems` enforcement**: array length is now validated
against `minItems` and `maxItems` constraints when present
- **`additionalItems` support**: rejects extra items when
`additionalItems: false`; validates against the `additionalItems` schema
when present; otherwise allows additional items (spec-compliant default)
- **`PropertyDescription` type**: added `minItems`, `maxItems`,
`additionalItems` fields; narrowed `items` from `any` to
`PropertyDescription | PropertyDescription[]`
- **Type guards**: added guards in `coerceType` and
`getPromptsForSchema` where `items.enum` was accessed without accounting
for the array form

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>Schema validation fails when `items` is a
list.</issue_title>
> <issue_description>### Current Behavior
> 
> In JSON Schema draft 07 (2018), the `"items"` property can be a list
and must be validated using tuple validation.
> 
> The `validateProperty` util in `packages/nx/src/utils/params.ts`
currently does not support this, causing validation to fail with the
error that the property does not match the schema (but it does).
> 
> ### Expected Behavior
> 
> A schema using JSON Schema draft 07 like
https://github.com/angular/angular-cli/blob/15794dc101fffd49818545c4ab015a3bf238b14a/packages/angular/build/src/builders/unit-test/schema.json
must be successfully parsed by the NX parser.
> 
> OR
> 
> The parser must give a clear error message that it does not support
the given schema.
> 
> ### GitHub Repo
> 
> https://github.com/Ionaru/schema7fail
> 
> ### Steps to Reproduce
> 
> In https://github.com/Ionaru/schema7fail:
> 
> 1. Run `npm install`
> 2. Run `nx test my-app`
> 
> ---
> 
> Clean repro:
>  
> 1. Create an NX project with an Angular application
> 2. In `project.json` add:
> ```json
>     "test": {
>       "executor": "@angular/build:unit-test",
>       "options": {
>         "reporters": [["junit", {"suiteName": "MyApp"}]]
>       }
>     }
> ```
> 3. Run `nx test <app_name>`
> 
> ### Nx Report
> 
> ```shell
> Node           : 24.14.0
> OS             : win32-x64
> Native Target  : x86_64-windows
> npm            : 11.11.0
> 
> nx                     : 22.3.3
> @nx/js                 : 22.3.3
> @nx/eslint             : 22.3.3
> @nx/workspace          : 22.3.3
> @nx/angular            : 22.3.3
> @nx/devkit             : 22.3.3
> @nx/eslint-plugin      : 22.3.3
> @nx/module-federation  : 22.3.3
> @nx/playwright         : 22.3.3
> @nx/plugin             : 22.3.3
> @nx/rspack             : 22.3.3
> @nx/vite               : 22.3.3
> @nx/vitest             : 22.3.3
> @nx/web                : 22.3.3
> @nx/webpack            : 22.3.3
> typescript             : 5.9.3
> ```
> 
> ### Failure Logs
> 
> ```shell
> NX   Property 'reporters' does not match the schema.
> {
>   "oneOf": [
>     {
>       "anyOf": [
>         {
>           "type": "string"
>         },
>         {
>           "enum": [
>             "default",
>             "verbose",
>             "dots",
>             "json",
>             "junit",
>             "tap",
>             "tap-flat",
>             "html"
>           ]
>         }
>       ]
>     },
>     {
>       "type": "array",
>       "minItems": 1,
>       "maxItems": 2,
>       "items": [
>         {
>           "anyOf": [
>             {
>               "type": "string"
>             },
>             {
>               "enum": [
>                 "default",
>                 "verbose",
>                 "dots",
>                 "json",
>                 "junit",
>                 "tap",
>                 "tap-flat",
>                 "html"
>               ]
>             }
>           ]
>         },
>         {
>           "type": "object"
>         }
>       ]
>     }
>   ]
> }'
> ```
> 
> ### Package Manager Version
> 
> _No response_
> 
> ### Operating System
> 
> - [x] macOS
> - [x] Linux
> - [x] Windows
> - [ ] Other (Please specify)
> 
> ### Additional Information
> 
> Linked to
https://github.com/angular/angular-cli/issues/32618</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes nrwl/nx#34631

<!-- START COPILOT CODING AGENT TIPS -->
---

 Let Copilot coding agent [set things up for
you](https://github.com/nrwl/nx/issues/new?title=+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: AgentEnder <6933928+AgentEnder@users.noreply.github.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Copilot <Copilot@users.noreply.github.com>
2026-03-04 13:37:32 -05:00
Jason Jean db97a6897d fix(core): enable output prefixing for direct nx:run-commands path (#34670)
## Current Behavior

When `NX_PREFIX_OUTPUT=true` (e.g. `--output-style=stream`),
`nx:run-commands` tasks are forced out of the fast direct execution path
and into a slower forked process, because the direct path had no
mechanism to prefix output with project names.

## Expected Behavior

`nx:run-commands` tasks stay on the direct execution path even when
output prefixing is needed. The PTY's `quiet` mode suppresses direct
stdout writes, and the orchestrator intercepts output via `onOutput`
callbacks to prefix each line with the colored project name before
writing to stdout.

### Changes

- Allow `nx:run-commands` to use the direct execution path regardless of
prefix output setting
- When prefixing is enabled, suppress direct stream output and intercept
it via `onOutput` to add colored project-name prefixes
- Extract a shared `writePrefixedLines` utility used by both the direct
path and the existing `addPrefixTransformer` stream — eliminates
duplicated split/filter/prefix logic
- Use `os.EOL` instead of manual platform newline detection
- Hoist formatted prefix string outside the per-line callback for
efficiency
- Simplify boolean expressions (`streamOutput && !shouldPrefix` instead
of ternary, remove redundant guard)

## Related Issue(s)

N/A — performance improvement for streaming output mode.
2026-03-04 13:35:02 -05:00
Jack Hsu d61170c98d fix(misc): exclude .netlify paths from Framer proxy edge function (#34703)
## Current Behavior
Requests to `/.netlify/images?url=...` are intercepted by the Framer
proxy edge function and forwarded to Framer, returning broken images on
docs pages (e.g. sandboxing page).

## Expected Behavior
`/.netlify/*` requests pass through to Next.js, which rewrites them to
the astro-docs site where the actual images are hosted.

## Related Issue(s)
Fixes DOC-436
2026-03-04 12:57:17 -05:00
Jack Hsu bdfef86fb7 docs(core): add task sandboxing documentation (#34686)
This PR adds a new feature page for sandboxing.

- What task sandboxing is (hermetic task execution with IO tracing)
- Why hermeticity matters for caching correctness, with concrete Vite
examples
- How to investigate sandbox violations in the Nx Cloud UI (with
annotated screenshots)
- How to inspect declared inputs/outputs with `nx show target` and `nx
show project`
- How to enable sandboxing (`NX_CLOUD_IO_TRACING_DIRECTORY`) and
configure path exclusions

The page is listed under Orchestration & CI in the sidebar.

Preview:
https://deploy-preview-34686--nx-docs.netlify.app/docs/features/ci-features/sandboxing

<img width="396" height="658" alt="image"
src="https://github.com/user-attachments/assets/96dc802a-eb1a-4b4a-9df4-bde846ed2775"
/>


## Related Issue(s)

Closes DOC-429

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-03-04 16:28:26 +00:00
Jason Jean 4ce62bdc29 chore(repo): add sandbox exclusions for writes and reads (#34699)
## Current Behavior

The sandboxing config only excludes reads for `node_modules`, `.nx`,
`.git`, and `package.json` paths. No write exclusions are configured,
and `pnpm-workspace.yaml` is not excluded from reads.

## Expected Behavior

- The `nx/**/*` directory is excluded from write sandboxing, allowing
write operations to the nx directory during CI workflows.
- `pnpm-workspace.yaml` is excluded from read sandboxing, similar to
other workspace config files.

## Related Issue(s)

N/A
2026-03-04 10:20:30 -05:00
Jack Hsu dd1c729208 fix(core): restore CNW user flow to match v22.1.3 (#34671)
This PR brings our CNW experience back to previous state.

## Current Behavior

The CNW prompt flow diverges from v22.1.3 in several ways:
- Shows "Which starter do you want to use?" template prompt
- Cloud prompt says "Try the full Nx platform?" instead of caching
question
- Preset flow uses simplified cloud prompt instead of CI provider →
caching fallback
- Completion message shows box banner with `accessToken=undefined`
manual URL
- Setup message includes `github.com/new` link not present in v22.1.3

## Expected Behavior

Human-visible CNW flow identical to v22.1.3 while preserving:
- NDJSON AI output (agentic experience)
- `--template` flag (works via CLI, not surfaced in prompts)
- Telemetry, error handling, AI agent detection

Changes:
- Skip template prompt, go straight to preset/stack flow
- Restore "Would you like remote caching?" with v22.1.3 wording
- Restore CI provider → caching fallback prompt chain for preset flow
- Pass actual nxCloud to createEmptyWorkspace so cloud token is real
- Restore v22.1.3 completion message ("Your remote cache is almost
complete.")
- Restore v22.1.3 getNxCloudInfo signature with rawNxCloud URL
visibility
- Restore "Nx Cloud has been set up successfully" spinner text
- Remove github.com/new link from push message

## Related Issue(s)

Closes NXC-4020
2026-03-04 09:44:52 -05:00
Leosvel Pérez Espinosa 556fd83fe4 cleanup(core): remove stale tui snapshot (#34696)
Removes stale test snapshot diff for the TUI.
2026-03-04 14:13:02 +00:00
MaxKless 4377c8b00d fix(core): fall back to invoking PM in detection (#34691)
## Current Behavior
when you run things like `pnpm nx@latest init`, there might not be a
pnpm lockfile yet. So nx commands will detect the PM as `npm` by
default... even though the fact that the user is invoking the command
via `pnpm` is a strong signal that that's the PM they want to use.

## Expected Behavior
We fall back to detecting the invoking PM via env var if no lockfile
exists.
2026-03-04 19:29:13 +09:00
MaxKless 4b4da78800 feat(core): add Codex subagent support to configure-ai-agents (#34553)
## Summary
- Read generated `config.toml` from `nx-ai-agents-config` repo as single
source of truth for Codex config format
- Deep-merge into user's existing `.codex/config.toml` using
`@ltd/j-toml` (already in monorepo)
- Adjust MCP args dynamically for Nx version (`["nx", "mcp"]` for ≥22,
`["nx-mcp"]` for <22), preserving extra user args
- Respect `multi_agent = false` if explicitly set by user
- Copy `.codex/agents/` subagent TOML files alongside existing
`.agents/skills/`
- Add unit tests (7) and e2e tests (4) for the new functionality

## Test plan
- [ ] Unit tests: `nx test nx -- --testPathPatterns set-up-ai-agents`
- [ ] E2e tests: `nx e2e e2e-nx -- --testPathPatterns
configure-ai-agents` (codex agent describe block)
- [ ] Verify codex config merges correctly with existing user config
- [ ] Verify `multi_agent = false` is not overwritten on re-run

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 11:01:01 +01:00
Jason Jean a23eaa690e fix(testing): remove stale ci.yml from extras.test snapshot (#34690)
## Current Behavior

The `extras.test.ts` e2e test is flaking on master because the snapshot
file expects `.github/workflows/ci.yml` in the "general" task inputs,
but `create-nx-workspace --no-interactive` no longer generates it.

PR #34332 accidentally updated the snapshot to include this file — the
author likely ran tests against a cached workspace from before PR #34616
fixed the CI workflow generation bug.

## Expected Behavior

The snapshot should not include `.github/workflows/ci.yml` since
`create-nx-workspace` correctly skips CI workflow generation in
non-interactive mode (fixed in PR #34616).

## Related Issue(s)

Fixes the `e2e-nx:e2e-ci--src/extras.test.ts` CI flakiness on master.
2026-03-04 00:15:41 -05:00
Craigory Coppola f77897a54a chore(repo): add a few more excluded reads to sandboxing (#34687)
Excludes a few more dirs for sb
2026-03-03 20:28:07 -05:00
Craigory Coppola 92fb88787f fix(core): stabilizes project references in dependsOn and inputs when later plugins rename a project (#34332)
## Current Behavior
There's a bug currently where is a plugin returns a dependsOn dependency
or input that directly references another project by name, and a later
plugin renames that project, the dependsOn or input entry is left stale
and pointing at a now non-existent project.

## Expected Behavior
The old refs are kept up to date as the nodes get merged together

## AI Summary
This pull request introduces a new mechanism to handle project name
substitutions in the Nx project graph, ensuring that references to
project names in `inputs` and `dependsOn` blocks remain accurate even if
a plugin changes a project's name during graph construction. The main
addition is the `ProjectNameInNodePropsManager`, which tracks and
updates references when project names change. Several related
refactorings and improvements were made to integrate this manager into
the project configuration merging process.

**Project name substitution and consistency:**

* Added a new `ProjectNameInNodePropsManager` class to manage and apply
project name substitutions when project names change, ensuring that all
references in `inputs` and `dependsOn` blocks remain consistent.
* Integrated the `ProjectNameInNodePropsManager` into the
`mergeCreateNodesResults` function, registering substitutors for node
results, marking roots as dirty when names change, and applying
substitutions after merging.
[[1]](diffhunk://#diff-774ce1a4fd8ec0c898c989fb75e2d8c87a0055549bca680945bce50f717db117R518)
[[2]](diffhunk://#diff-774ce1a4fd8ec0c898c989fb75e2d8c87a0055549bca680945bce50f717db117L521-R551)
[[3]](diffhunk://#diff-774ce1a4fd8ec0c898c989fb75e2d8c87a0055549bca680945bce50f717db117R563-R571)

**API and function changes:**

* Modified `mergeProjectConfigurationIntoRootMap` to return an object
indicating whether a project name was changed, instead of just returning
void.
[[1]](diffhunk://#diff-774ce1a4fd8ec0c898c989fb75e2d8c87a0055549bca680945bce50f717db117L59-R62)
[[2]](diffhunk://#diff-774ce1a4fd8ec0c898c989fb75e2d8c87a0055549bca680945bce50f717db117R238-R244)

**Code organization and import cleanup:**

* Refactored imports in `project-configuration-utils.ts` for better
organization and to accommodate the new manager.
[[1]](diffhunk://#diff-774ce1a4fd8ec0c898c989fb75e2d8c87a0055549bca680945bce50f717db117L9-R25)
[[2]](diffhunk://#diff-774ce1a4fd8ec0c898c989fb75e2d8c87a0055549bca680945bce50f717db117R43-L43)

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
2026-03-03 17:22:29 -05:00
Jack Hsu ffa6959844 docs(misc): add /docs redirect (#34684)
The clean-up PR inverted the reverse proxy logic such that only the
defined paths are passed to Next.js. The default is to return Framer
pages. Since we also remove the Nextjs redirect, we lose the `/docs` one
that was missing from `_redirects` file.

https://github.com/nrwl/nx/pull/34672

This PR adds the redirect to fix it again.
2026-03-03 16:45:02 -05:00
Copilot c89dd93e45 fix(core): resolve false positive loop detection when running with Bun (#34640)
Bun includes extra consecutive async frames for async functions in call
stacks, causing `preventRecursionInGraphConstruction` to falsely detect
a recursive loop during normal project graph construction.

## Root Cause

`preventRecursionInGraphConstruction` uses `getCallSites().slice(2)` to
skip the top 2 frames (itself +
`buildProjectGraphAndSourceMapsWithoutDaemon`), then checks if
`buildProjectGraphAndSourceMapsWithoutDaemon` appears again in the
remaining frames.

In Bun, `buildProjectGraphAndSourceMapsWithoutDaemon` appears **twice
consecutively** due to async frame duplication — leaving one occurrence
after the slice, which incorrectly triggers the loop error.

**Node call stack (after `slice(2)`):**
```
#0 createProjectGraphAndSourceMapsAsync  ← clean
#1 createProjectGraphAsync
#2 runOne
```

**Bun call stack (after `slice(2)`):**
```
#0 buildProjectGraphAndSourceMapsWithoutDaemon  ← false positive!
#1 createProjectGraphAndSourceMapsAsync
#2 createProjectGraphAndSourceMapsAsync         ← Bun duplicates async frames
#3 createProjectGraphAsync
```

## Fix

Since the call stack recursion check does not work reliably under Bun,
`preventRecursionInGraphConstruction` now returns early when running
under Bun, detected via `'Bun' in globalThis` — consistent with the
existing Bun runtime detection pattern used elsewhere in the codebase
(e.g., `isolated-plugin.ts`). The original `slice(2)` logic is preserved
unchanged for Node.js and other runtimes.

```ts
export function preventRecursionInGraphConstruction() {
  // Bun's async stack traces include extra frames that cause false positives in the
  // recursion check below, so we skip the check when running under Bun.
  if ('Bun' in globalThis) {
    return;
  }
  // ... existing Node.js check ...
}
```

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>


----

*This section details on the original issue you should resolve*

<issue_title>getCallSites output differs between Node and Bun triggering
loop detection</issue_title>
<issue_description>### Current Behavior

Hey team,

I am trying to use Bun (1.3.5) instead of Node (v22.17.0) for running Nx
(v22.1.3) and bumped into the following error:

Command:
```bash
bunx --bun nx run api:build
```

Error:
```
 NX   Project graph construction cannot be performed due to a loop detected in the call stack. This can happen if 'createProjectGraphAsync' is called directly or indirectly during project graph construction.

To avoid this, you can add a check against "global.NX_GRAPH_CREATION" before calling "createProjectGraphAsync".
Call stack:
buildProjectGraphAndSourceMapsWithoutDaemon (/app/node_modules/.pnpm/nx@22.1.3_@swc-node+register@1.10.9_@swc+core@1.11.1_@swc+helpers@0.5.15__@swc+types@0.1.18_t_twtgkxomntuzxcyp4ewkmtxn2q/node_modules/nx/src/project-graph/project-graph.js:81:62)
createProjectGraphAndSourceMapsAsync (/app/node_modules/.pnpm/nx@22.1.3_@swc-node+register@1.10.9_@swc+core@1.11.1_@swc+helpers@0.5.15__@swc+types@0.1.18_t_twtgkxomntuzxcyp4ewkmtxn2q/node_modules/nx/src/project-graph/project-graph.js:274:31)
createProjectGraphAndSourceMapsAsync (/app/node_modules/.pnpm/nx@22.1.3_@swc-node+register@1.10.9_@swc+core@1.11.1_@swc+helpers@0.5.15__@swc+types@0.1.18_t_twtgkxomntuzxcyp4ewkmtxn2q/node_modules/nx/src/project-graph/project-graph.js:225:53)
createProjectGraphAsync (/app/node_modules/.pnpm/nx@22.1.3_@swc-node+register@1.10.9_@swc+core@1.11.1_@swc+helpers@0.5.15__@swc+types@0.1.18_t_twtgkxomntuzxcyp4ewkmtxn2q/node_modules/nx/src/project-graph/project-graph.js:222:45)
createProjectGraphAsync (/app/node_modules/.pnpm/nx@22.1.3_@swc-node+register@1.10.9_@swc+core@1.11.1_@swc+helpers@0.5.15__@swc+types@0.1.18_t_twtgkxomntuzxcyp4ewkmtxn2q/node_modules/nx/src/project-graph/project-graph.js:205:40)
runOne (/app/node_modules/.pnpm/nx@22.1.3_@swc-node+register@1.10.9_@swc+core@1.11.1_@swc+helpers@0.5.15__@swc+types@0.1.18_t_twtgkxomntuzxcyp4ewkmtxn2q/node_modules/nx/src/command-line/run/run-one.js:23:52)
runOne (/app/node_modules/.pnpm/nx@22.1.3_@swc-node+register@1.10.9_@swc+core@1.11.1_@swc+helpers@0.5.15__@swc+types@0.1.18_t_twtgkxomntuzxcyp4ewkmtxn2q/node_modules/nx/src/command-line/run/run-one.js:16:23)
Pass --verbose to see the stacktrace.
```

After some digging I found that the stack trace produced by
https://github.com/nrwl/nx/blob/691bb320ce1e9cc2872e1a1b364d3fdeb9e1ad0e/packages/nx/src/utils/call-sites.ts
differs between Node and Bun. When
https://github.com/nrwl/nx/blob/691bb320ce1e9cc2872e1a1b364d3fdeb9e1ad0e/packages/nx/src/project-graph/project-graph.ts#L422
is run, the produced function call tracing is:

Node (v22.17.0):
```
nrwl/nx#0 createProjectGraphAndSourceMapsAsync
nrwl/nx#1 createProjectGraphAsync
nrwl/nx#2 runOne
nrwl/nx#3 <anonymous>
nrwl/nx#4 <anonymous>
nrwl/nx#5 handleErrors
nrwl/nx#6 handler
```

Bun (1.3.5):
```
nrwl/nx#0 buildProjectGraphAndSourceMapsWithoutDaemon <- This entry causes Nx to detect a loop
nrwl/nx#1 createProjectGraphAndSourceMapsAsync
nrwl/nx#2 createProjectGraphAndSourceMapsAsync
nrwl/nx#3 createProjectGraphAsync
nrwl/nx#4 createProjectGraphAsync
nrwl/nx#5 runOne
nrwl/nx#6 runOne
```

This is not a Nx bug per-se, but wondering if this falls into the
efforts of supporting Bun into Nx (i.e.
https://nx.dev/blog/nx-19-5-adds-stackblitz-new-features-and-more#bun-and-pnpm-v9-support)?

I will cross post the above into the Bun repo too for input.

### Expected Behavior

Able to execute Nx commands with Bun

### GitHub Repo

_No response_

### Steps to Reproduce

1. Run bunx --bun nx run api:build


### Nx Report

```shell
NX_DAEMON=true bunx --bun nx --disableNxCache --disableRemoteCache --outputStyle dynamic-legacy report                       1 ✘  16:18:00 

 NX   Report complete - copy this into the issue template

Node           : 24.3.0
OS             : darwin-arm64
Native Target  : aarch64-macos
pnpm           : 9.6.0

nx                     : 22.1.3
@nx/js                 : 22.1.3
@nx/jest               : 22.1.3
@nx/eslint             : 22.1.3
@nx/workspace          : 22.1.3
@nx/cypress            : 22.1.3
@nx/devkit             : 22.1.3
@nx/esbuild            : 22.1.3
@nx/eslint-plugin      : 22.1.3
@nx/module-federation  : 22.1.3
@nx/nest               : 22.1.3
@nx/next               : 22.1.3
@nx/node               : 22.1.3
@nx/playwright         : 22.1.3
@nx/plugin             : 22.1.3
@nx/react              : 22.1.3
@nx/rollup             : 22.1.3
@nx/storybook          : 22.1.3
@nx/vite               : 22.1.3
@nx/vitest             : 22.1.3
@nx/web                : 22.1.3
@nx/webpack            : 22.1.3
@nx/docker             : 22.1.3
nx-cloud               : 19.1.0
@nrwl/nx-cloud         : 19.1.0
typescript             : 5.7.3
---------------------------------------
Registered Plugins:
@nxlv/python
---------------------------------------
Community plu...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes nrwl/nx#33997

<!-- START COPILOT CODING AGENT TIPS -->
---

 Let Copilot coding agent [set things up for you](https://github.com/nrwl/nx/issues/new?title=+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot) — coding agent works faster and does higher quality work when set up for your repo.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: AgentEnder <6933928+AgentEnder@users.noreply.github.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Copilot <Copilot@users.noreply.github.com>
2026-03-03 16:13:45 -05:00
Craigory Coppola e4f2d399ad fix(core): skip writing deps cache if already up-to-date (#34582)
## Current Behavior
Frequent write cache calls during tasks hashing results in delays

## Expected Behavior
Cache is validated but only written when changed

## AI Summary
This pull request introduces an optimization to the project graph cache
writing logic, reducing unnecessary disk writes when serving repeated
requests with unchanged graphs. The main change is the addition of a
mechanism to track the cache file's modification time and only write to
disk if the file has been externally modified or not written yet by the
current process.

Optimizations to cache writing:

* Added `writeCacheIfStale` function in `nx-deps-cache.ts` to prevent
redundant cache writes by checking the cache file's modification time
before writing. This function is now used in the daemon's graph
recomputation logic, replacing the previous unconditional write.
[[1]](diffhunk://#diff-82bd1a5a7b7320ffc3233470f191782c054bf69a696dc16001d2c4b1d0b04963R285-R312)
[[2]](diffhunk://#diff-d5bf3c66e62cac1884a071bf07fd1991320a3e62b07bfc03af3b9557b714c892L17-R17)
[[3]](diffhunk://#diff-d5bf3c66e62cac1884a071bf07fd1991320a3e62b07bfc03af3b9557b714c892L136-R149)
* Introduced `lastWrittenCacheMtimeMs` variable to track the last
successful write's modification time, updated after each cache write.
[[1]](diffhunk://#diff-82bd1a5a7b7320ffc3233470f191782c054bf69a696dc16001d2c4b1d0b04963R202-R208)
[[2]](diffhunk://#diff-82bd1a5a7b7320ffc3233470f191782c054bf69a696dc16001d2c4b1d0b04963R256-R261)

Codebase updates:

* Updated imports in `nx-deps-cache.ts` to include `statSync` for file
modification time checks.

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

Fixes #
2026-03-03 16:08:06 -05:00
Copilot 42f73a5221 fix(core): interpolate {projectRoot} and {projectName} in {workspaceRoot} input patterns in native hasher (#34637)
`{projectRoot}` and `{projectName}` tokens inside `{workspaceRoot}/...`
input patterns were silently never substituted in the native Rust
hasher, causing the glob to match zero files and those inputs to be
entirely excluded from the cache hash — a silent cache correctness bug.

## Root Cause

In `gather_self_inputs` (`hash_planner.rs`), workspace filesets (those
starting with `{workspaceRoot}/`) were forwarded as-is to
`HashInstruction::WorkspaceFileSet`. When `globs_from_workspace_globs`
later stripped `{workspaceRoot}/`, the remaining `{projectRoot}/**/*.go`
was matched literally — which never exists on disk.

## Changes

- **`hash_planner.rs`**: Before storing workspace filesets in
`HashInstruction::WorkspaceFileSet`, replace `{projectRoot}` and
`{projectName}` with their actual values from the project graph node.
- **`planner.spec.ts`**: Added a test verifying that a pattern like
`{workspaceRoot}/{projectRoot}/**/*.go` correctly resolves to
`{workspaceRoot}/libs/parent/**/*.go` in the hash plan.

```json
// nx.json — this pattern now works correctly
"namedInputs": {
  "goSource": ["{workspaceRoot}/{projectRoot}/**/*.go"]
}
```

This pattern is documented as valid per the [Nx inputs
reference](https://nx.dev/docs/reference/inputs): `{projectRoot}` and
`{projectName}` can appear anywhere after the leading `{workspaceRoot}`.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `repo.gradle.org`
> - Triggering command: `/usr/lib/jvm/temurin-17-jdk-amd64/bin/java
/usr/lib/jvm/temurin-17-jdk-amd64/bin/java
--add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED
--add-opens=java.base/java.util=ALL-UNNAMED
--add-opens=java.prefs/java.util.prefs=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
--add-opens=java.base/java.util=ALL-UNNAMED
--add-opens=java.prefs/java.util.prefs=ALL-UNNAMED
--add-opens=java.base/java.nio.charset=ALL-UNNAMED
--add-opens=java.base/java.net=ALL-UNNAMED
--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED
--add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED
-XX:MaxMetaspaceSize=384m -XX:&#43;HeapDumpOnOutOfMemoryError -Xms256m
-Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en` (dns
block)
> - `staging.nx.app`
> - Triggering command:
`/home/REDACTED/work/_temp/ghcca-node/node/bin/node node
./bin/post-install` (dns block)
> - Triggering command: `/opt/hostedtoolcache/node/24.13.1/x64/bin/node
/opt/hostedtoolcache/node/24.13.1/x64/bin/node
/home/REDACTED/work/nx/nx/node_modules/.pnpm/nx@22.6.0-beta.5_@swc-node&#43;register@1.11.1_@swc&#43;core@1.15.10_@swc&#43;helpers@0.5.18__@swc&#43;_a827ebc424be037fc154d90301143d4e/node_modules/nx/src/project-graph/plugins/isolation/plugin-worker
/tmp/plugin4368-16-420.890618.sock @nx/enterprise-cloud` (dns block)
> - Triggering command: `/opt/hostedtoolcache/node/24.13.1/x64/bin/node
/opt/hostedtoolcache/node/24.13.1/x64/bin/node
/home/REDACTED/work/nx/nx/node_modules/.pnpm/nx@22.6.0-beta.5_@swc-node&#43;register@1.11.1_@swc&#43;core@1.15.10_@swc&#43;helpers@0.5.18__@swc&#43;_a827ebc424be037fc154d90301143d4e/node_modules/nx/src/project-graph/plugins/isolation/plugin-worker
/tmp/plugin5770-16-420.874901.sock @nx/enterprise-cloud` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/nrwl/nx/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>{projectRoot} not interpolated inside {workspaceRoot}
input patterns in native hasher</issue_title>
> <issue_description>## Current Behavior
> 
> When using a `{workspaceRoot}/{projectRoot}/**/*.go` pattern in target
inputs, the `{projectRoot}` token is **not interpolated** by the native
Rust hash planner. The pattern silently matches zero files, causing the
cache hash to exclude those files entirely.
> 
> ```json
> // nx.json
> "namedInputs": {
>   "gosourceUnfiltered": ["{workspaceRoot}/{projectRoot}/**/*.go"]
> }
> ```
> 
> ```json
> // target config
> "format": {
>   "inputs": ["gosourceUnfiltered", { "externalDependencies": [] }]
> }
> ```
> 
> The hash plan for this target contains **zero `.go` file inputs**:
> 
> ```
> Task: my-project:format:write
>   Inputs:
>     my-project:ProjectConfiguration
>     my-project:TsConfig
>     env:NX_CLOUD_ENCRYPTION_KEY
>     file:nx.json
>     file:.gitignore
>     // no .go files!
> ```
> 
> ## Root Cause
> 
> In the Rust hash planner (`hash_planner.rs`), fileset inputs are
partitioned based on their prefix:
> 
> ```rust
> .partition(|file_set| {
> file_set.starts_with("{projectRoot}/") ||
file_set.starts_with("!{projectRoot}/")
> });
> ```
> 
> A pattern starting with `{workspaceRoot}/` is classified as a
**workspace fileset**. It then flows to `hash_workspace_files.rs` where
`{workspaceRoot}/` is stripped via `strip_prefix("{workspaceRoot}/")`,
leaving `{projectRoot}/**/*.go`. But `{projectRoot}` is **never
substituted** with the actual project root, so the glob literally tries
to match paths starting with `{projectRoot}/` — which don't exist.
> 
> ## Expected Behavior
> 
> Per the [Nx docs on inputs](https://nx.dev/docs/reference/inputs):
> 
> > `{workspaceRoot}` should only appear in the beginning of an input
but **`{projectRoot}` and `{projectName}` can be specified later in the
input to interpolate the root or name of the project** into the input
location.
> 
> The native hasher should interpolate `{projectRoot}` (and
`{projectName}`) within `{workspaceRoot}` patterns before glob matching.
After stripping `{workspaceRoot}/` and interpolating `{projectRoot}`,
the pattern should become e.g. `packages/shared/go/middleware/**/*.go`
and correctly match files.
> 
> ## Impact
> 
> This is a **silent cache correctness issue**: targets using this
pattern appear to work but their cache hash doesn't include the matched
files. Changes to those files won't invalidate the cache. There's no
warning or error emitted.
> 
> ## Workaround
> 
> Use the literal path instead of `{projectRoot}` inside workspace-level
patterns:
> 
> ```js
> // In a createNodes plugin, instead of:
> inputs: ["{workspaceRoot}/{projectRoot}/**/*.go"]
> // Use:
> inputs: [`{workspaceRoot}/${actualProjectRoot}/**/*.go`]
> ```
> 
> ## Related
> 
> - nrwl/nx#34225 — Nested Project Files Excluded from Parent Project
Inputs (the reason `{workspaceRoot}/{projectRoot}` patterns are used in
the first place: to bypass project file filtering and include files from
nested sub-projects)
> 
> ## Environment
> 
> - **Nx version**: 22.6.0-beta.3
> - **OS**: macOS (Darwin 24.6.0)
> - **Package manager**: pnpm</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes nrwl/nx#34595

<!-- START COPILOT CODING AGENT TIPS -->
---

🔒 GitHub Advanced Security automatically protects Copilot coding agent
pull requests. You can protect all pull requests by enabling Advanced
Security for your repositories. [Learn more about Advanced
Security.](https://gh.io/cca-advanced-security)

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: AgentEnder <6933928+AgentEnder@users.noreply.github.com>
Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Copilot <Copilot@users.noreply.github.com>
2026-03-03 16:04:33 -05:00
Copilot 3fc52ead00 fix(core): resolve input files for targets with defaultConfiguration (#34638)
`nx show target inputs` returns empty results for any target with
`defaultConfiguration` set because
`HashPlanInspector.inspectTaskInputs()` keys results as
`project:target:config` (e.g. `my-app:build:local`), but the lookup was
using `project:target` — a guaranteed miss.

## Changes

- **`packages/nx/src/command-line/show/target.ts`**: In
`resolveInputFiles`, construct the plan lookup key using the explicitly
passed `configuration` first, then fall back to the target's
`defaultConfiguration`:

```ts
const targetConfig = graph.nodes[projectName]?.data?.targets?.[targetName];
const effectiveConfig = configuration ?? targetConfig?.defaultConfiguration;
const taskId = effectiveConfig
  ? `${projectName}:${targetName}:${effectiveConfig}`
  : `${projectName}:${targetName}`;
```

If the computed `taskId` is not found in the hash plan, an error is
thrown instead of silently returning empty results.

- **`showTargetInputsHandler`**: Now extracts the configuration from the
target string (`project:target:config`) or the `-c`/`--configuration`
flag and forwards it to `resolveInputFiles`.

- **`ShowTargetInputsOptions`** (`command-object.ts`): Added
`configuration?: string` so the type correctly reflects the prop.

- **`packages/nx/src/command-line/show/target.spec.ts`**: Added tests
covering:
  - Resolving input files when `defaultConfiguration` is set
  - Preferring an explicit `configuration` over `defaultConfiguration`
  - Throwing when the task ID is not found in the hash plan

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>nx show target inputs returns empty when target has
defaultConfiguration</issue_title>
> <issue_description>## Current Behavior
> 
> `nx show target inputs <project>:<target> --json` returns no files for
any target that has a `defaultConfiguration` set (directly or via
`targetDefaults`).
> 
> ```bash
> $ nx show target inputs card-api-lambda:build --json
> {
>   "project": "card-api-lambda",
>   "target": "build"
> }
> # Expected: files array with resolved input files
> ```
> 
> The `--check` flag also reports files as not being inputs when they
should be:
> 
> ```bash
> $ nx show target inputs card-api-lambda:build --check
packages/card/api/lambda/main.go
> ✗ packages/card/api/lambda/main.go is not an input for
card-api-lambda:build
> ```
> 
> Targets **without** `defaultConfiguration` on the same project resolve
correctly:
> 
> ```bash
> $ nx show target inputs card-api-lambda:generate-docs --json
> {
>   "project": "card-api-lambda",
>   "target": "generate-docs",
> "files": [ ".gitignore", "nx.json",
"packages/card/api/lambda/main.go", ... ]
> }
> ```
> 
> ## Root Cause
> 
> In `packages/nx/src/command-line/show/target.ts`, the
`resolveInputFiles` function constructs the lookup key as:
> 
> ```js
> const taskId = `${projectName}:${targetName}`;
> ```
> 
> But the native `HashPlanInspector.inspectTaskInputs()` returns results
keyed by the **full task ID including the default configuration**, e.g.
`card-api-lambda:build:local`.
> 
> When a target has `defaultConfiguration: "local"`, the plan result is
keyed as `project:target:local`, but the lookup searches for
`project:target` — which doesn't exist — so it falls through to the
empty default `{ files: [], ... }`.
> 
> Verified by calling `inspectTaskInputs` directly:
> 
> ```
> === build ===
> Task IDs in result: card-api-lambda:generate-docs,
card-api-lambda:build:local
> # lookup for "card-api-lambda:build" → miss → empty
> 
> === generate-docs ===
> Task IDs in result: card-api-lambda:generate-docs
> # lookup for "card-api-lambda:generate-docs" → hit → 142 files
> ```
> 
> ## Suggested Fix
> 
> The lookup key should account for the default configuration:
> 
> ```js
> const defaultConfig =
graph.nodes[projectName]?.data?.targets?.[targetName]?.defaultConfiguration;
> const taskId = defaultConfig
>   ? `${projectName}:${targetName}:${defaultConfig}`
>   : `${projectName}:${targetName}`;
> ```
> 
> ## Expected Behavior
> 
> `nx show target inputs` should resolve and display input files
regardless of whether the target has a `defaultConfiguration`.
> 
> ## Environment
> 
> - **Nx version**: 22.6.0-beta.3
> - **OS**: macOS (Darwin 24.6.0)
> - **Node**: v22
> - **Package manager**: pnpm</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes nrwl/nx#34594

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: AgentEnder <6933928+AgentEnder@users.noreply.github.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Copilot <Copilot@users.noreply.github.com>
2026-03-03 16:00:07 -05:00
Jason Jean c5876ed0b1 feat(core): migrate napi-rs v2 to v3 (#34619)
## Current Behavior

napi-derive v2 has a bug where the type definition temp file doesn't get
cleaned between builds with different profiles (release vs dev), causing
duplicate class declarations in `index.d.ts`.

## Expected Behavior

With napi-rs v3, the temp file handling is fixed — each crate gets its
own folder, preventing duplicate declarations across build profiles.

## Related Issue(s)

N/A — internal build tooling improvement.

## Changes

### Dependency upgrades
- **Cargo.toml**: `napi` 2.x → 3.8.3, `napi-derive` 2.x → 3.5.2,
`napi-build` 1.x → 2.3.1
- **package.json**: `@napi-rs/cli` → 3.5.1 (was 3.0.0-alpha.56)

### External data sharing (Arc pattern)
- Replaced raw-pointer `StoredExternal<T>` wrapper with napi-recommended
`Arc<T>` pattern for shared ownership
- Read-only data: `External::new(Arc::new(data))` at creation, `Arc<T>`
in struct fields
- Mutable data (DB): `External::new(Arc::new(Mutex::new(data)))`,
`Arc<Mutex<T>>` in struct fields
- Constructors take `&External<Arc<T>>`, clone the Arc;
`#[napi(ts_arg_type)]` preserves TS types
- Deleted `types/external_compat.rs` (86 lines of unsafe code removed)

### API migrations
- `ThreadsafeFunction`: Accept directly as napi parameters instead of
building from `Function<'_>`
- Return-only structs: Use `#[napi(object, object_from_js = false)]` for
structs with `External<T>` fields
- `env.create_object()` → `Object::new(&env)`, `JsObject` → `PromiseRaw`
for async returns

### Watcher fix
- Deferred `Watchexec::default()` creation from constructor to `watch()`
inside napi's `spawn()` block
- `Watchexec::default()` internally calls `tokio::spawn()` which
requires a Tokio runtime in TLS — the `#[napi(constructor)]` runs on the
JS main thread with no runtime context
- Changed `napi::tokio::spawn(...)` to `spawn(...)` (napi's
`bindgen_prelude::spawn` which uses a static runtime, works from any
thread)
- Store `watch_exec` as `Arc<Mutex<Option<Arc<Watchexec>>>>` for lazy
initialization

### TUI fix
- Same Tokio runtime issue: `tokio::spawn(async {})` placeholder in
`Tui::new()` panicked on JS main thread
- Changed `task` field from `JoinHandle<()>` to
`Option<JoinHandle<()>>`, initialized as `None`
- Moved `tui.start()` (which calls `tokio::spawn`) inside napi's
`spawn()` async block
- Changed `napi::tokio::spawn(...)` to `spawn(...)` in lifecycle.rs

### Platform-specific watcher improvements
- Gated non-macOS watcher functions with `#[cfg(not(target_os =
"macos"))]`
- Added `rlib` to `crate-type` in Cargo.toml for cargo test
compatibility

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-03-03 15:17:24 -05:00
Leosvel Pérez Espinosa ff621875b3 cleanup(core): reduce misc allocations (#34647)
## Current Behavior

Several Rust native modules and one TS utility have unnecessary
allocations:
- `hash_planner.rs`: visited set uses `HashSet<String>` with
`to_string()` per insert; unnecessary `.collect::<Vec<_>>()` creating
temp vecs; no pre-allocation for dependency inputs
- `context.rs`: `update_files` allocates a String per map entry inside
retain loop
- `hash_workspace_files.rs`: `.clone()` before `.as_bytes()` — 2
needless heap allocs per file
- `find_matching_projects.rs`: collects HashMap keys into Vec + linear
search instead of O(1) lookup
- `validate_outputs.rs`: compiles regex on every call
- `project-configuration-utils.ts`: uses `JSON.parse(JSON.stringify())`
for deep cloning

## Expected Behavior

All unnecessary allocations removed:
- Borrow `&str` from project graph instead of cloning Strings into
visited set
- Use `Path::new()` once outside retain closure (also more correct —
component-boundary-aware matching)
- Call `.as_bytes()` directly without clone
- Use `HashMap::get_key_value()` for O(1) lookup
- Cache compiled regex with `LazyLock<Regex>`
- Use `structuredClone` (Node 18+) instead of JSON round-trip

See individual commits for detailed rationale per change.
2026-03-03 15:10:56 -05:00
Leosvel Pérez Espinosa 1a973bafad fix(angular-rspack): use relative path for postcss-cli-resources output (#34681)
## Current Behavior

When using `@nx/angular-rspack` with SCSS imports that reference
external assets (e.g., `flag-icon-css`), the `postcss-cli-resources`
plugin generates absolute filesystem paths in CSS `url()` values:

```css
.flag-icon-us{background-image:url(/some/project/path/dist/bug-demo/browser/media/us.2d0a1dd6.svg)}
```

This happens because `normalizeOutputPath()` makes `outputPath.media`
absolute, and this absolute path is passed directly as
`resourcesOutputPath` to `postcss-cli-resources`.

## Expected Behavior

CSS `url()` values contain relative paths:

```css
.flag-icon-us{background-image:url(media/us.2d0a1dd6.svg)}
```

## Related Issue(s)

Fixes #34092
2026-03-03 11:08:36 -05:00
Leosvel Pérez Espinosa e81f187768 fix(misc): use pathToFileURL for cross-platform path handling in postcss-cli-resources (#34676)
## Current Behavior

CSS `url()` references to fonts and assets fail to resolve on Windows
with webpack, rspack, and angular-rspack builds. The
`postcss-cli-resources` plugin passes Windows absolute paths (e.g.
`E:\dev\project\font.woff2`) to `new URL(path, 'file:///')`, which
misinterprets the drive letter (`E:`) as a URL protocol, stripping it
from `pathname` and producing unresolvable paths like
`\dev\project\font.woff2`.

## Expected Behavior

CSS `url()` references to fonts, images, and other assets resolve
correctly on all platforms.

## Related Issue(s)

Fixes #33052
2026-03-03 11:08:07 -05:00
Jack Hsu e01b5de8f4 docs(nx-dev): invert Framer proxy to default-proxy, keep only Next.js paths (#34672)
## Current Behavior

The Netlify edge function reads `NEXT_PUBLIC_FRAMER_REWRITES` env var to
determine which paths to proxy to Framer. As more pages move to Framer,
this growing allowlist becomes cumbersome to maintain.

## Expected Behavior

The edge function now proxies all requests to Framer by default. Only
paths explicitly listed in `nextjsPaths` and `excludedPath` are served
by Next.js. This removes the need for the `NEXT_PUBLIC_FRAMER_REWRITES`
env var (should be removed from Netlify dashboard manually).

Deleted 25 page files (pages router + app router) that are now served by
Framer: homepage, 404, enterprise/*, contact/*, solutions/*, community,
company, customers, nx-cloud, partners, brands, careers, java, react,
remote-cache, resources, webinar.

**Next.js paths kept:** `/blog/*`, `/courses/*`, `/pricing`, `/podcast`,
`/ai-chat`, `/changelog`, `/resources-library`, `/whitepaper-fast-ci`,
`/500`, `/api/*`, `/docs/*`

**Manual follow-up:** Remove `NEXT_PUBLIC_FRAMER_REWRITES` env var from
Netlify dashboard.

## Related Issue(s)

Closes DOC-431
2026-03-03 11:07:19 -05:00
Jack Hsu f42be4e9c5 fix(misc): fix broken nx.dev redirects and remove legacy redirect-rules files (#34673)
## Current Behavior

10 `nx.dev` URLs return 404 — broken links in CLI output, graph UI, and
cloud UI. Additionally:
- ~20 wildcard redirect rules silently broken because `:slug*` was never
converted to Netlify's `*`/`:splat` syntax
- Specific `/getting-started/` rules ordered after the wildcard
catch-all, sending users to the generic intro page instead of the
correct page (e.g., `/getting-started/editor-setup`)
- Redirect chain breaks where intermediate targets (e.g.,
`/nx-api/powerpack-*-cache` → `/nx-api/*-cache`) had no rule

## Expected Behavior

All documented `nx.dev` URLs resolve correctly. `_redirects` is the sole
source of truth — no more JS generator pipeline.

### Changes

1. **Fixed `_redirects`**:
   - Converted all `:slug*` to `*`/`:splat` (Netlify syntax)
- Reordered specific `/getting-started/` rules before the wildcard
catch-all
   - Added 13 new redirect rules for broken 404 URLs

2. **Fixed `astro-docs/netlify.toml`**:
   - Added 3 redirects for `/docs/` path typos (trailing-s, wrong path)

3. **Deleted legacy files** (-2,248 lines):
   - `redirect-rules.js`
   - `redirect-rules-docs-to-astro.js`
   - `redirect-rules.spec.js`
   - `scripts/generate-netlify-redirects.mjs`

## Related Issue(s)

Fixes DOC-428
2026-03-03 09:35:34 -05:00
Jason Jean 923fc45136 fix(gradle): tee batch runner output to stderr for terminal display (#34630)
## Current Behavior

When running Gradle batch tasks (e.g. `nx build my-gradle-project
--no-tui`), the terminal shows no task output. The Gradle build output
is captured into `ByteArrayOutputStream` for JSON results but never
forwarded to the terminal. Users can only see the output in Nx Cloud
task results.

## Expected Behavior

Gradle batch task output (build logs, test results, etc.) should be
visible in the terminal in real-time as the batch executes.

## Changes

- **`TeeOutputStream.kt`** (new): An `OutputStream` that writes to two
destinations simultaneously — captures output for JSON results while
also forwarding to `System.err` for terminal display.
- **`GradleRunner.kt`**: Wrap `setStandardOutput` and `setStandardError`
with `TeeOutputStream` to tee into `System.err` in both
`runBuildLauncher` and `runTestLauncher`.
- **`gradle-batch.impl.ts`**: Replace `PseudoTerminal` (which swallowed
all output with `quiet: true`) with `execSync` using `stdio: ['pipe',
'pipe', 'inherit']` so stderr flows directly to the terminal.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-03-02 13:10:39 -05:00
Jonathan Cammisuli 216f5cabed chore(core): enable polygraph ai tools for claude (#34667) 2026-03-02 11:51:50 -05:00
Jason Jean f48bf319bf fix(repo): remove redundant inputs override for build-base target (#34649)
## Current Behavior

The `build-base` target in `nx.json` has a manual `inputs` override of
`["production", "^production"]` which shadows the more accurate inputs
inferred by the `@nx/js/typescript` plugin.

## Expected Behavior

Let the `@nx/js/typescript` plugin infer the correct inputs for
`build-base` tasks, providing more accurate cache invalidation based on
the actual tsconfig project references.

## Lint Rule Changes

Removing the broad `inputs` override causes the `@nx/dependency-checks`
lint rule to flag a few dependencies as "unused" across three packages.
This happens because the rule uses the build target's inputs to
determine which files to scan for imports, and the narrower tsc-inferred
inputs don't cover certain files:

- **`packages/nx`**: `@napi-rs/wasm-runtime` — used in
`nx.wasi-browser.js`, a `.js` file outside tsconfig scope
- **`packages/angular`**: `@angular-devkit/core` — only referenced as a
string (for `ensurePackage()`, migrations config) and is a
`peerDependency`, not directly imported at runtime
- **`packages/angular-rspack-compiler`**: `semver` — used in
`patch/patch-angular-build.js`, a `.js` patch file outside tsconfig
scope

These are all legitimate dependencies. Adding the `.js` files to
tsconfig would require `allowJs` and pull non-TS scripts into the build
pipeline unnecessarily. Adding them to `ignoredDependencies` in each
package's `.eslintrc.json` is the correct fix.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-03-02 11:41:31 -05:00
Leosvel Pérez Espinosa 2c802ba486 fix(vitest): respect reporters from target options in vitest executor (#34663)
## Current Behavior

The vitest executor ignores `reporter`/`reporters` set in target options
(project.json). Both forms leak through as passthrough CLI args, causing
vitest's `resolveConfig` to override the `reporters` array (which
includes NxReporter), making the executor hang indefinitely.

Additionally, when the vite config uses `reporter` (singular), the
config value always overrides the `reporters` array passed as inline
options — again removing NxReporter.

## Expected Behavior

Target-level `reporter`/`reporters` options take priority over
config-file values. NxReporter is always preserved in the final
reporters array regardless of configuration source.

Priority chain: target `reporter` (singular) > target `reporters`
(plural) > config `reporter` (singular) > config `reporters` (plural).

## Related Issue(s)

Fixes #34495
2026-03-02 15:31:48 +00:00
MaxKless aa4f47e6be feat(core): add .nx/polygraph to gitignore in migration and caia (#34659) 2026-03-03 00:15:46 +09:00
James Henry 72eb1e0808 fix(core): update minimatch to 10.2.4 (#34660) 2026-03-02 16:34:42 +04:00
Jack Hsu 0975384d24 docs(js): expand TS solution migration guide with validated steps and edge cases (#34646)
This PR updates the guide for integrated -> TS solution setup with
additional information. It also adds `% llm_copy_prompt %}` and `{%
llm_only %}` components to provide instructions to the AI agent to
perform the migration.

Preview:
https://deploy-preview-34646--nx-docs.netlify.app/docs/technologies/typescript/guides/switch-to-workspaces-project-references

## Current Behavior

The migration guide covers basic steps but is missing several nuances
discovered in the ocean repo's convert-ts-solution generator and through
end-to-end validation against a real workspace.

## Expected Behavior

The guide covers all steps needed for a successful migration, including:
- .gitignore updates for out-tsc/dist/test-output artifacts
- Order of operations (install before removing paths)
- Root tsconfig cleanup (remove paths entirely, baseUrl, rootDir)
- Package.json self-export and nested path alias strategies
- Update build targets (remove @nx/js:tsc for non-buildable libs)
- Import path updates after package renaming
- Bundler config updates (webpack auto-detect, Jest resolver,
Vite/Vitest)
- Edge cases: circular deps, e2e projects, non-standard locations,
  tsconfig include/exclude patterns

Validated end-to-end against a test workspace with 5 libs and 2 React
apps (webpack+jest, vite+vitest) across 2 clean iterations.

## Screenshots

<img width="810" height="458" alt="Screenshot 2026-02-27 at 7 31 16 AM"
src="https://github.com/user-attachments/assets/80ad87db-6ebe-4f54-9995-65f2ee2c46f1"
/>
<img width="784" height="735" alt="Screenshot 2026-02-27 at 7 31 20 AM"
src="https://github.com/user-attachments/assets/a0a7fe26-7d7d-4225-94bb-f82e5fc49178"
/>

<img width="897" height="161" alt="Screenshot 2026-02-27 at 7 31 39 AM"
src="https://github.com/user-attachments/assets/3b410092-5fb4-420d-9909-ee83c34ff0d6"
/>

## Related Issue(s)

NXC-2950

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2026-02-27 19:24:07 -05:00
Caleb Ukle 7370195070 fix(misc): boost CLI command reference search ranking (#34625)
## Current Behavior

Searching for CLI commands like `nx watch` on the docs site does not
surface the [Nx Commands reference
page](https://nx.dev/docs/reference/nx-commands) on the first page of
results, even when filtering by "References."

Root causes:
- **Term saturation**: "nx" appears 150+ times on the CLI reference page
(in every heading, usage block, and example), causing it to saturate and
contribute almost nothing to ranking differentiation.
- **Page length penalty**: The current `pageLength: 0.5` setting
actively penalizes long pages—the CLI reference is one of the longest on
the site.
- **No weight boost**: The CLI page had no `weight` set, while
generators/executors pages already get `weight: 2.0`.

## Expected Behavior

Searching for `nx watch`, `nx run-many`, or other CLI commands should
surface the Nx Commands reference page prominently in results.

This PR applies two quick-win tuning changes:
1. **`weight: 4`** on the CLI commands page entry — gives body text ~16×
impact (quadratic scaling), making it competitive with shorter pages
that mention commands incidentally. include the command name in the sub
headers for more improvement in relevancy search without impacting other
pages
2. **`termSaturation: 1.2`** (down from default 1.4) — makes highly
repeated terms like "nx" saturate faster so that the differentiating
term (e.g. "watch") carries more relative weight.

## Related Issue(s)

Addresses
[DOC-401](https://linear.app/nxdev/issue/DOC-401/investigate-boosting-cli-command-reference-pages-in-search)
2026-02-27 15:33:31 -06:00
Jason Jean 6309b63853 chore(repo): update nx to 22.6.0-beta.7 (#34651)
Updating Nx from 22.6.0-beta.6 to 22.6.0-beta.7
2026-02-27 16:11:55 -05:00
Caleb Ukle 3978674caa docs(nx-cloud): add ent release notes for 2026.01 (#34652) 2026-02-27 14:48:46 -06:00
Jason Jean eb498861c5 fix(repo): reset package.json files after local release (#34648)
## Current Behavior

When running `pnpm nx-release --local false`, the `nx release version`
step modifies `package.json` files for `angular-rspack`,
`angular-rspack-compiler`, `dotnet`, and `maven` (bumping versions and
resolving `workspace:*` protocols). The local release path (`--local
false`, non-CI) exits early before reaching the reset logic that the CI
path uses, leaving unstaged changes behind.

## Expected Behavior

After the release script completes (or is interrupted), the source
`package.json` files should be restored to their original state. The
version bumps are only needed in `dist/` for publishing — the source
files should stay at `0.0.1` with `workspace:*` protocols.

This PR:
- Extracts a shared `resetPackageJsons()` function used by both the
local and CI code paths
- Wraps the local release steps in `try/finally` so files are restored
even on errors
- Adds a `SIGINT` handler so files are restored on ctrl+C
2026-02-27 18:11:00 +00:00
Rares Matei 3c3d70339f chore(misc): add sandboxing config for Nx Cloud workflows (#34643)
Add sandboxing-config.yaml to exclude node_modules from reads in Nx
Cloud workflow sandboxing.

## Current Behavior
No sandboxing configuration exists for Nx Cloud workflows.

## Expected Behavior
Nx Cloud workflows use sandboxing config that excludes `node_modules/**`
from reads.

## Related Issue(s)
N/A

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2026-02-27 17:57:20 +00:00
Jack Hsu 352bebae07 docs(misc): fix redirects for /blog (#34650)
Fix bad redirect.
2026-02-27 12:22:23 -05:00
Omer 94cc841a40 cleanup(linter): reuse ESLint instance across child projects in plugin (#34645)
## Current Behavior

In `internalCreateNodesV2`, the ESLint plugin creates a **new `ESLint`
instance per child project root** to check whether the project has
non-ignored lintable files via `isPathIgnored`:

```ts
const eslint = new ESLint({
  cwd: join(context.workspaceRoot, projectRoot),
});
for (const file of lintableFilesPerProjectRoot.get(projectRoot) ?? []) {
  if (!(await eslint.isPathIgnored(...))) { ... }
}
```

In large monorepos, this means hundreds or thousands of ESLint
instantiations during graph calculation. Each instantiation involves
loading and resolving the ESLint configuration, which is the dominant
cost in the plugin.

## Expected Behavior

A single ESLint instance should be shared across all child projects
under the same ESLint config directory. Since `isPathIgnored` receives
**absolute paths**, the instance's `cwd` does not affect the result — it
only needs to resolve the correct config, which is the same for all
children of a given config root.

## Changes

* In `internalCreateNodesV2`: create one lazily-initialized shared
ESLint instance per config directory (the `configDir`), reused across
all child project roots
* Projects that have their own `.eslintignore` file fall back to a
per-project ESLint instance, preserving correct behavior for ESLint v8
(which resolves `.eslintignore` relative to `cwd`)

## Benchmark

Measured on a real monorepo with **1,609 projects** and a single root
ESLint config.

| | Before | After | Change |
|---|---|---|---|
| Cold run (avg of 3) | **~18,700ms** | **~7,300ms** | **-61%** |
| ESLint instances created | 1,457 | 8 | **-99.5%** |

### Breakdown

| Version | Run 1 | Run 2 | Run 3 |
|---|---|---|---|
| Baseline (upstream) | 23,482ms | 16,238ms | 16,389ms |
| With shared instance | 7,473ms | 7,012ms | 7,515ms |

### Methodology

* `NX_DAEMON=false` to prevent daemon caching
* ESLint plugin hash cache cleared between each cold run
* `performance.now()` instrumentation around `internalCreateNodesV2`
* Each measurement repeated 3 times
* **Verified same number of lint targets** (1,473) before and after — no
behavior change

### Why `configDir === '.'` is not excluded

The earlier revision excluded root-level ESLint configs (`configDir ===
'.'`) from the optimization as a conservative safety measure. However,
benchmarking showed this **completely disables the optimization** for
the most common monorepo setup (single root ESLint config), dropping
1,456 of 1,457 instances back to per-project instantiation with zero
measurable improvement.

The per-project `.eslintignore` check already handles the ESLint v8
concern: projects with their own `.eslintignore` still get dedicated
instances, while all others share one instance whose `cwd` correctly
resolves the root config and root `.eslintignore`.

## Related

This is the `createNodesV2` (Nx plugin) code path. The change does not
affect ESLint execution itself — only the graph calculation phase.
2026-02-27 18:08:57 +01:00
MaxKless c43671906b fix(core): update sourceRespository description of nx import (#34606)
we can also import local repos
2026-02-27 13:56:57 +00:00
Jason Jean 3a2c1a2876 chore(repo): update nx to 22.6.0-beta.6 (#34633)
Updating Nx from 22.6.0-beta.5 to 22.6.0-beta.6
2026-02-27 08:42:56 -05:00
Leosvel Pérez Espinosa 65d0f554f8 chore(repo): preserve x-prompt and requires in angular migrations upgrade script (#34641)
When latest >= next, the build-migrations script now preserves the
existing x-prompt and requires fields from the pre-release entry, rather
than skipping them, and adjusts the requires upper bound to the stable
version.
2026-02-27 08:41:11 -05:00
MaxKless 53c0123bef fix(maven): synchronize batch runner invoke() to prevent concurrent access (#34600)
## Current Behavior

The Maven batch runner uses a parallel thread pool to execute tasks.
When multiple tasks are independent roots in the task graph, they get
picked up by separate threads simultaneously. Both threads call
`invoke()` on the same shared `CachingResidentMavenInvoker` (Maven 4) or
`CachingMaven3Invoker` (Maven 3) instance concurrently.

Maven 4's `LookupInvoker.invoke()` is not thread-safe — it
snapshots/restores `System.getProperties()` and the thread context
classloader in a `finally` block, and all concurrent invocations share
the same resident `MavenContext`. This can cause deadlocks in Maven's
internal session machinery.

## Expected Behavior

Maven executions through the shared invoker are serialized via
`@Synchronized`, preventing concurrent access to non-thread-safe Maven
internals. The parallel thread pool still handles task graph management,
build state recording, and result emission concurrently.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 08:30:37 -05:00
Nelson Dominguez 8255c2867c fix(core): support canonical SSH URLs when extracting GitHub user/repo slug during nx release (#31684)
## Current Behavior

When running `nx release` with Git remotes configured as **canonical SSH
URLs**, the repository slug is extracted incorrectly.

Examples of affected remotes include:

- `ssh://git@ssh.github.com:443/org/repo.git`
- `ssh://git@gitlab.company.com:2222/group/subgroup/repo.git`

In these cases, the existing regex-based logic misinterprets the port
number as part of the repository path (for example: `443/org`). This
causes the release creation request to be built with an invalid
repository slug and results in `404 Not Found` errors from the GitHub or
GitLab APIs.

## Expected Behavior

`nx release` should correctly extract the repository slug from all valid
Git remote URL formats, regardless of whether the remote uses HTTPS,
SCP-style SSH, or fully qualified SSH URLs with explicit ports.

Valid examples should resolve to the correct slug:

- `ssh://git@ssh.github.com:443/org/repo.git` => `org/repo`
- `ssh://git@gitlab.company.com:2222/group/subgroup/repo.git`=>
`group/subgroup/repo`

Users should not need to modify their Git remote configuration in order
for `nx release` to work correctly.

## What’s Changed

- Introduced a shared utility
([`extractRepoSlug`](https://github.com/nrwl/nx/pull/31684/changes#diff-799188c178b8a084e86dbe9063ec88a7c324212a8ef79729777f56e4bf7f455cR29-R60))
to consistently extract repository slugs from Git remote URLs.
- Replaced provider-specific, regex-based parsing in:
  - `GithubRemoteReleaseClient`
  - `GitLabRemoteReleaseClient`
- Added support for:
  - HTTPS remotes
  - SCP-style SSH remotes (`git@host:org/repo.git`)
  - Fully qualified SSH URLs with custom ports
  - Arbitrarily nested GitLab group and subgroup paths
  - Self-hosted GitHub and GitLab instances via hostname matching
- Added comprehensive unit tests covering valid and invalid URL formats
for both providers.

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

Fixes #31682
2026-02-27 08:10:16 -05:00
Leosvel Pérez Espinosa af07e75d58 feat(core): use jemalloc with tuned decay timers for native module (#34444)
## Current Behavior

The Nx native module (Rust cdylib loaded by Node.js) uses the system
allocator. The daemon process retains a large RSS footprint after the
initial project graph build, even though most of that memory is no
longer in use. On macOS and Linux, the system allocator doesn't
aggressively return freed pages to the OS.

## Expected Behavior

The daemon's steady-state RSS drops significantly after graph build by
using jemalloc with tuned page purge timers. Peak RSS and wall time are
unaffected.

## Changes

Adds [tikv-jemallocator](https://github.com/tikv/jemallocator) as the
global allocator on Linux and macOS, with two compile-time settings:

- **`dirty_decay_ms:1000`** — returns freed pages to the OS after 1s
instead of the default 10s. Tuned to Nx's phase-separated workload
(graph build → idle → task execution), where transitions happen every
~30-60s. Benchmarked against 5s and 10s — both too slow to purge between
phases.
- **`muzzy_decay_ms:0`** — skips the lazy purge phase (`MADV_FREE`) and
goes straight to `MADV_DONTNEED`. Required on macOS and Linux ≥ 4.5
where `MADV_FREE` doesn't actually reduce RSS.

Windows and WASI continue using the system allocator. Windows is
excluded because `tikv-jemalloc-sys` fails to build with MSVC (spaces in
`cl.exe` path break the autoconf configure script). Tracked upstream in
[tikv/jemallocator#99](https://github.com/tikv/jemallocator/pull/99).

### Other Settings Considered

Tested narenas reduction, tcache_max, extent fit tuning, background
threads, and decay timer values. Only the decay timer configuration
improved steady-state RSS without wall time regression.
2026-02-26 23:47:47 -05:00
Jesse Zomer ac2ef1aaef fix(linter): allow for wildcards paths in enforce-module-boundaries rule (#34066)
closed #32190

## Current Behavior

eslint crashes when tsconfig.base.json path includes a * and you have an
import going to that project
## Expected Behavior
The plugin shouldn't crash and it should auto fix to a working import

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->
https://github.com/nrwl/nx/issues/32190

Fixes #32190
2026-02-26 16:21:10 -05:00
Jason Jean 191054d876 chore(repo): update nx to 22.6.0-beta.5 (#34618)
Updating Nx from 22.6.0-beta.3 to 22.6.0-beta.5

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-02-26 15:40:35 -05:00
Eric Baer b8b6ed8b85 fix(testing): use surgical text replacement in Jest matcher alias migration (#34350)
## Current Behavior

The `replace-removed-matcher-aliases` migration uses `tsquery.replace()`
which reprints the entire AST through TypeScript's Printer. This causes
two problems:

1. **Syntax corruption**: Valid TypeScript files are mangled:
   - Destructuring patterns: `{ result }` becomes `{result}:`
   - Arrow functions: missing opening braces
   - Nested callbacks: collapsed/merged code blocks

2. **Unnecessary file changes**: Every test file is written back to disk
even when no matchers are replaced. This triggers `formatFiles()` to
reformat unchanged files, creating large whitespace-only diffs. In large
codebases, this can result in hundreds or thousands of files being
modified unnecessarily, making the migration PR difficult to review.

**Why I care a Lot**

I was running this on a multi-million-LOC monorepo and ran into two
issues:

* I got ~10k modified files with whitespace-only changes from the
removal of newlines. These changes couldn't be fixed with Prettier
because it didn't care about the number of newlines, so the diff was
unmergeable.
* I got ~8 files with malformed Typescript, causing commit hooks, CI,
etc. to fail without manual intervention.

## Expected Behavior

The migration should:
1. Only replace the deprecated matcher names (e.g., `toBeCalled` →
`toHaveBeenCalled`)
2. Preserve all surrounding code exactly as written
5. Only touch files that actually contain deprecated matchers

## Solution

Replace AST-reprinting with surgical text replacement:
- Use `tsquery.query()` to find matching AST nodes
- Collect text positions (start/end) for each node to replace
- Apply replacements in reverse order using string slicing
- Only write files that actually changed

This pattern is already used successfully in other Nx migrations (e.g.,
`rename-cy-exec-code-property.ts` in the Cypress package).

**Additional improvements:**
- Single AST parse with regex selector vs. 11 separate passes
- Quick string check skips parsing files without deprecated matchers
- New regression test covers complex patterns that triggered corruption

## Related Issue(s)

Fixes #32062

---------

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
2026-02-26 15:20:15 -05:00
Jason Jean bdc61b5ad5 chore(repo): improve e2e test timeout handling and bump cache bust (#34383)
## Current Behavior

E2E tests may timeout without clear error messages, making it difficult
to diagnose test failures.

## Expected Behavior

E2E test utilities should provide better timeout handling and logging to
help diagnose test failures.

## Changes

- Add timeout handling to e2e test utilities (`runCLI` and
`runLernaCLI`)
- Add command logging to track execution time
- Improve timeout error messages with process output
- Bump cache bust value

## Related Issue(s)

CI stability and debugging improvements
2026-02-26 13:13:34 -05:00
Jason Weinzierl 31dad4109b fix(linter): support eslint v10 (#34534)
<!-- 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

`@nx/eslint` relies on ESLint internals that changed in ESLint v10
(`use-at-your-own-risk`), which causes failures.

It looks like https://github.com/nrwl/nx/pull/24632 originally attempted
to use `loadESLint()` which would've been forward compatible with v10,
but it was later removed in https://github.com/nrwl/nx/pull/27404 in
favor of the `use-at-your-own-risk` import.

## Expected Behavior

`@nx/eslint` supports ESLint v10.

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

Fixes #34415
2026-02-26 12:35:59 -05:00
omasakun c3643126ef fix(core): make watch command work with all and initialRun specified (#32282)
<!-- 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
<!-- This is the behavior we have today -->

If you specify both the `all` and `initialRun` options when running `nx
watch`, `initialRun` have no effect.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

The command should be called once at the beginning even if there are no
file changes.

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

Fixes #32281
2026-02-26 11:45:51 -05:00
Anurag Agarwal dcfc2134d4 fix(maven): fix set the pom file without changing base directory (#34182)
## Current Behavior
nx-maven-plugin 0.0.12 is also changing the base directory along with
the pom file when the plugins like flatten-maven-plugin /
maven-shade-plugin produces pomFile in different directory other than
the base directory

## Expected Behavior
plugin should only update the pom file and not the base directory
location

## Related Issue(s)

Fixes #34181

https://github.com/mojohaus/flatten-maven-plugin/issues/50

Co-authored-by: anurag.ag <anuragagarwal561994@users.noreply.github.com>
2026-02-26 11:20:42 -05:00
Jack Hsu 77100fac5d docs(misc): add Requirements sections to all technology intro pages (#34613)
## Current Behavior

Technology introduction pages have inconsistent or missing version
requirements information. Some pages have no Requirements section,
others use ad-hoc formats (asides, bullet lists under Prerequisites),
and page titles follow different naming conventions ("Overview of the Nx
X Plugin", "Nx X Plugin Overview", "Introduction - X", etc.).

## Expected Behavior

Every technology introduction page now has a standardized Requirements
section with:
- A version support table using consistent semver range format
- Code-formatted package names in the `Package` column
- An intro sentence identifying the Nx plugin (e.g. "The `@nx/react`
plugin supports the following package versions.")
- A note linking to [code generation docs](/docs/features/generate-code)
for auto-installed packages
- Consistent **"X Plugin for Nx"** page title pattern across all intro
pages

Additional changes:
- Deleted the standalone Node.js/TypeScript compatibility page, inlining
its content into the respective plugin intro pages
- Created a proper introduction page for Angular Rsbuild (previously
linked directly to `createConfig` API reference)
- Added Requirements tables to Java, Gradle, and Maven pages with system
dependency versions
- Updated sidebar links and redirects for removed/moved pages
- Applied style guide fixes across all edited pages (removed "allows you
to", "easily", product possessives, etc.)

## Related Issue(s)

Fixes DOC-423
2026-02-26 10:42:51 -05:00
Leosvel Pérez Espinosa b1614d7504 feat(angular): add support for Angular v21.2 (#34592)
## Current Behavior

Nx doesn't support Angular v21.2.

## Expected Behavior

Nx should support Angular v21.2.
2026-02-26 10:23:53 -05:00
Caleb Ukle 0ae45cd445 docs(nx-plugin): document special schema options (#34615)
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
2026-02-26 17:56:54 +09:00
Jason Jean fcf4660389 fix(core): preserve nxCloud=skip in non-interactive CNW mode (#34616)
## Current Behavior

After #34580, `determineNxCloudV2()` returns `'skip'` in non-interactive
mode, but the caller remaps it to `nxCloud = 'yes'` with
`skipCloudConnect = true`. This causes `setupCI()` to run and generate
`.github/workflows/ci.yml` in new workspaces — which didn't happen
before.

This breaks the `extras.test.ts` e2e snapshot test because
`.github/workflows/ci.yml` now appears in the expanded default task
inputs.

## Expected Behavior

Keep `nxCloud = 'skip'` when the cloud choice is `'skip'`, which
prevents CI file generation in non-interactive mode. This restores the
behavior prior to #34580.

## Related Issue(s)

Fixes the `extras.test.ts` e2e snapshot failure introduced by #34580.
2026-02-25 23:02:58 -05:00
Louie Weng 221ea40462 chore(gradle): bump version to 0.1.13 (#34614)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Bump project graph plugin version.

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

Fixes #

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:50:07 +00:00
Leosvel Pérez Espinosa 12812dc994 cleanup(core): cache compiled glob sets to avoid redundant recompilation (#34602)
## Current Behavior

`build_glob_set` recompiles identical glob pattern sets on every call,
even when the same set of patterns has been compiled before.

## Expected Behavior

Compiled `NxGlobSet` instances are cached in a static `DashMap` keyed by
sorted glob strings. Repeated calls with the same patterns return a
shared `Arc<NxGlobSet>` instead of recompiling. Profiling `nx run-many
-t build lint test --parallel 8` in the Nx repo measured 95.6% cache hit
rate (9,758 of 10,202 calls) with only 444 unique pattern sets, reducing
hashing-phase CPU by ~40%.
2026-02-25 15:52:30 -05:00
Jack Hsu 4c3812f731 fix(nx-dev): move redirects from Next.js config to Netlify _redirects (#34612)
## Current Behavior

All 1,200+ redirect rules are processed by the Next.js serverless
function via the `redirects()` config in `next.config.js`. Every
redirect request requires a cold start of the serverless function, which
contributed to the 10-minute outage reported in DOC-415.

## Expected Behavior

Redirects are handled at the Netlify CDN edge via a plain `_redirects`
file, which is faster and doesn't depend on the Next.js serverless
function being healthy.

- Converted all redirect rules from `redirect-rules.js` and
`redirect-rules-docs-to-astro.js` into Netlify `_redirects` format
(1,231 rules)
- Expanded Next.js regex group patterns (e.g. `/(l|latest)/...`) into
individual Netlify rules since Netlify doesn't support regex
- Converted `:path*` wildcards to Netlify `*`/`:splat` syntax
- Rewrites (Astro docs proxy) remain in `next.config.js` as they require
server-side processing
- Original JS redirect files kept for reference (can be removed in
follow-up)

## Related Issue(s)

Fixes DOC-415
2026-02-25 15:49:44 -05:00
Leosvel Pérez Espinosa 098a830e5d fix(core): use scoped cache key for unresolved npm imports in TargetProjectLocator (#34605)
## Current Behavior

`TargetProjectLocator.findProjectFromImport` stores `null` for
unresolved imports using a bare `importExpr` key, but
`findNpmProjectFromImport` looks up cache entries using
`${packageName}__${dirPath}`. The key mismatch means repeated lookups
for the same import+directory re-run the full resolution waterfall
(typescript + require.resolve) instead of returning the cached `null`.

## Expected Behavior

Store `null` for unresolved imports using the same
`${packageName}__${dirPath}` key that `findNpmProjectFromImport` uses
for lookups. Repeated lookups for already-failed imports skip the
expensive resolution steps.

Also removes an unused cache write for builtin module imports as a minor
cleanup.
2026-02-25 15:47:54 -05:00
Jason Jean f31e7a75be fix(core): handle FORCE_COLOR=0 with picocolors (#34520)
## Current Behavior

After migrating from chalk to picocolors (#34305), `FORCE_COLOR=0` no
longer disables colors. picocolors checks `!!env.FORCE_COLOR`, and since
`!!"0"` is `true` in JavaScript, it treats `FORCE_COLOR=0` as "enable
colors."

This breaks CI environments and tools like Homebrew that set
`FORCE_COLOR=0` to get plain text output.

## Expected Behavior

`FORCE_COLOR=0` should disable ANSI color output, matching the previous
chalk behavior and the [FORCE_COLOR spec](https://force-color.org/).

## Related Issue(s)

Fixes #34387

Upstream issue filed:
https://github.com/alexeyraspopov/picocolors/issues/100
2026-02-25 15:47:24 -05:00
Louie Weng 09c44a637a fix(gradle): use globs for dependent task output files (#34590)
## Current Behavior

When processing Gradle tasks, Nx tracks dependent task output files by
recording individual file paths for each output. This can lead to
incorrect cache invalidation behavior since we are prefixing the paths
unnecessarily. We will therefore never match.

## Expected Behavior

Nx now consolidates dependent task output files using glob patterns
based on file extensions (e.g., **/*.jar, **/*.class). This focuses on
the types of files produced rather than their specific paths. The
approach groups all output files by extension and generates a single
glob pattern per extension, reducing the complexity of input tracking
while maintaining correctness.

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

Fixes #Q-247
2026-02-25 15:02:34 -05:00
Louie Weng dc81b8bbd6 fix(gradle): ensure that atomized task targets have dependsOn (#34611)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

The dependsOn of atomized tasks should match the base non-atomized task.

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

Fixes Q-174
2026-02-25 19:03:42 +00:00
Jack Hsu f7e46e33e9 feat(core): add explicit cloud opt-out to CNW (#34580)
## Current Behavior

The CNW cloud prompt is locked to auto-select deferred connection
(CLOUD-4255), always generating a short URL but never writing nxCloudId
to nx.json. Users have no explicit choice.


## Expected Behavior

The cloud prompt now offers three explicit choices:
- Yes: connect now, generate nxCloudId in nx.json, show strong
completion message
- Skip for now: deferred connection (no nxCloudId), still show short URL
and update README
- No: full opt-out, set neverConnectToCloud: true in nx.json, no URL, no
README update, no cloud messaging

**CLI args:** `--nxCloud=skip`, `--nxCloud=never` (new),
`--nxCloud=yes`. Non-interactive defaults to skip.

Closes CLOUD-4242
2026-02-25 13:56:03 -05:00
Jason Jean 5d64f726d6 chore(core): add tests for large directory file watching (#34601)
## Current Behavior

PR #34523 fixed the macOS file watcher issue (#34522) but did not
include comprehensive test coverage.

## Expected Behavior

Tests should verify that the fix works correctly and catch any future
regressions.

## Related Issue(s)

Adds test coverage for #34523 and #34522

---

## Changes

**TypeScript integration test**
(`packages/nx/src/native/tests/watcher.spec.ts`):

Added **"should detect file changes in large directory structures"** - a
comprehensive integration test that:
1. Creates 10,000+ directories simulating a monorepo-scale workspace
2. Starts a real `Watcher` instance
3. Creates and modifies files deep in the directory tree
4. Verifies that file change events are actually delivered

This test validates the actual behavior users care about - that file
watching works reliably in large repos - rather than testing
implementation details. It would catch any regression where events fail
to be delivered at scale.

## Testing

TypeScript integration test validates the actual bug fix - that file
events are delivered reliably in large directory structures with 10,000+
directories.
2026-02-25 13:36:48 -05:00
Nikola Kalinov 1e1a8a7a40 fix(vite): isPreview=true for Vite Preview server (#34597)
<!-- 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
Given the following Vite config:
```ts
import { defineConfig } from 'vite';

export default defineConfig((config) => {
  console.log(config);
  return {};
});
```

`npx nx preview` logs:
```ts
{
  mode: 'development',
  command: 'build',
  isSsrBuild: false,
  isPreview: false
}
```

## Expected Behavior
`npx nx preview` should log:
```ts
{
  mode: 'development',
  command: 'build',
  isSsrBuild: false,
  isPreview: true
}
```

## Related Issue(s)
https://github.com/vitejs/vite/issues/15694

Fixes #
2026-02-25 13:27:05 -05:00
Leosvel Pérez Espinosa 872b9c9045 fix(core): remove unused getTerminalOutput from BatchProcess (#34604)
## Current Behavior

`BatchProcess` accumulates all stdout/stderr output in
`terminalOutputChunks` and exposes it via `getTerminalOutput()`, but
nothing ever calls `getTerminalOutput()`. The accumulated strings are
unique allocations (created via `chunk.toString()`), not shared with the
output callbacks or `process.stdout.write`.

For verbose batched tasks (e.g., Maven/Gradle with hundreds of tasks),
this can hold tens to hundreds of MB for the entire batch duration.

## Expected Behavior

Remove the dead accumulation code. stdout/stderr chunks are still
forwarded to `process.stdout`/`process.stderr` and output callbacks as
before — only the unused storage is removed.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-02-25 12:39:17 -05:00
Jack Hsu 1e3f8e00f7 fix(js): remove redundant vite.config.ts generation for vitest projects (#34603)
## Current Behavior

When generating a library with vitest as the test runner and a non-vite
bundler (e.g. `tsc`), the js library generator creates two config files:
- `vitest.config.mts` (from the vitest `configurationGenerator`) with
`root: __dirname`
- `vite.config.ts` (from a second `createOrEditViteConfig` call) with
`root: import.meta.dirname`

The redundant `vite.config.ts` uses ESM-only `import.meta.dirname`
syntax, which causes TS1470 when the project targets CommonJS output:

```
vite.config.ts:5:9 - error TS1470: The 'import.meta' meta-property is not allowed in files which will build into CommonJS output.

5   root: import.meta.dirname,
          ~~~~~~~~~~~
```

## Expected Behavior

Only `vitest.config.mts` should be generated. The vitest
`configurationGenerator` already handles creating the correct config
file with `root: __dirname`. The second `createOrEditViteConfig` call
from `@nx/vite` was redundant and produced the conflicting file.

## Related Issue(s)

Fixes #34399
2026-02-25 12:27:22 -05:00
Philip Fulcher 919907cf0f docs(nx-dev): add foundations article (#34599) 2026-02-25 11:23:22 -06:00
Charlie Croom d5cd6a1a56 fix(core): use recursive FSEvents on macOS instead of non-recursive kqueue (#34523)
## Current Behavior

Since Nx 22.5.0, the daemon's native file watcher silently drops all
file change events on macOS in large monorepos (~5,250+ watched
directories). `nx watch`, `nx serve`, and any daemon-dependent file
watching is broken.

The root cause is that #34329 switched all watched paths to
`WatchedPath::non_recursive()`. On macOS, the `notify` crate uses
**kqueue** for non-recursive watches instead of **FSEvents**. kqueue
silently fails at scale due to vnode table pressure (`kern.num_vnodes ==
kern.maxvnodes`), causing the daemon to never detect file changes.

This is a **scale-dependent** bug: it works fine in small workspaces
(~30 directories) but breaks silently in large ones.

| | **Nx 22.4.5** | **Nx 22.5.0+** |
|---|---|---|
| **Small repo (~30 dirs)** | Works (FSEvents) | Works (~30 kqueue
watches) |
| **Large repo (~5,250+ dirs)** | Works (FSEvents) | **Broken** (kqueue
silently drops all events) |

## Expected Behavior

The macOS file watcher should detect file creates, modifications, and
deletions at any scale, matching the behavior of Nx 22.4.x.

## Fix

Use platform-conditional watch modes:
- **macOS:** Single recursive watch on the workspace root (uses FSEvents
natively)
- **Linux/Windows:** Non-recursive per-directory watches (preserves the
#33781 inotify fix)

On macOS, FSEvents handles recursive watching from a single root path,
so directory enumeration and dynamic registration are skipped entirely.
This also improves daemon startup time on macOS from ~10 minutes to <1
second in a 354-project monorepo.

### What changed in `watcher.rs`

1. **Initial pathset:** On macOS, watch only the root directory
recursively via FSEvents instead of enumerating all directories for
non-recursive kqueue watches.
2. **Dynamic directory registration (`on_action`):** Wrapped in
`#[cfg(not(target_os = "macos"))]` since FSEvents already watches the
full tree.

Linux/Windows behavior is completely unchanged.

### Why the event filter is fine as-is

We verified that with recursive FSEvents watches, macOS emits specific
`FileEventKind` variants (`Create(File)`, `Modify(Data(Content))`,
`Remove(File)`, `Modify(Name(Any))`) that the current
`watch_filterer.rs` already handles correctly. Zero events were rejected
by the catch-all. The `Modify(Any)` / `Create(Any)` variants are kqueue
artifacts that are not needed with FSEvents.

### Why kqueue fails silently

Apple's [File System Events Programming
Guide](https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/FSEvents_ProgGuide/KernelQueues/KernelQueues.html)
explicitly recommends FSEvents over kqueue for large hierarchies: *"If
you are monitoring a large hierarchy of content, you should use file
system events instead."* kqueue requires `open(path, O_EVTONLY)` per
watched directory. Under vnode table pressure, the kernel recycles
vnodes with kqueue watches attached without notifying the watcher. There
is no error, no partial delivery, and no diagnostic signal.

## Tested on

- macOS 26.3 (Tahoe), Apple Silicon (arm64), APFS
- 354-project pnpm monorepo (~19,865 non-ignored directories)
- Verified: file modifications, file creates, and file deletes all
detected
- Daemon init time: ~10 min (with enumeration) -> <1s (with root-only
FSEvents watch)

## Related Issue(s)

Fixes #34522

Co-authored-by: Amp <amp@ampcode.com>
2026-02-25 09:45:31 -05:00
Caleb Ukle 700c98fcaf fix(nx-dev): correct interpolate sub command for cli reference (#34585)
also adding e2e for command hierarchy

<img width="823" height="362" alt="image"
src="https://github.com/user-attachments/assets/3db98945-4221-4bf3-8b92-9d5b25eb2444"
/>

<img width="778" height="349" alt="image"
src="https://github.com/user-attachments/assets/432ebd61-c34e-40f5-b95a-f8d73c682da4"
/>


![wm_2026-02-24T14-11-07@2x](https://github.com/user-attachments/assets/a3d635a3-b928-4ff2-a147-28f0873d26c2)
2026-02-25 14:30:34 +00:00
Colum Ferry df9eb0bf10 fix(release): add null-safe fallback for version in createGitTagValues (#34598)
## Current Behavior

When nx release runs with docker-configured projects (either via
explicit config or
@nx/docker plugin inference), git tags are created with the literal
string {version}
instead of the actual version number (e.g., v{version} instead of
v1.0.6, or
  app-3@{version} instead of app-3@1.0.0).

  This happens because:

1. If ANY project in a release group has docker config,
preferDockerVersion is auto-set to
  true for the ENTIRE group
2. createGitTagValues() then blindly selects
projectVersionData.dockerVersion, which is
  null for non-docker projects (or projects with no changes)
3. The interpolate() function receives null for {version} and returns
the literal
  placeholder unchanged

Commit messages are unaffected because createCommitMessageValues() only
uses newVersion and
already guards against null. The changelog code (changelog.ts:1117-1121)
also already has
  the correct null-safe pattern.

 ## Expected Behavior

When preferDockerVersion is true but dockerVersion is null, git tags
should fall back to
using newVersion instead of producing literal {version} placeholders.
When both versions
  are null, no tag should be created.

For mixed release groups (some projects have docker config, some don't),
the auto-enable
logic should use 'both' mode instead of true, which already has proper
null-safe checks for
   each version type.

 ## Changes

- shared.ts: Added null-safe fallback (??) in createGitTagValues() for
both independent and
fixed group code paths, plus a guard to skip tag creation when both
versions are null
- config.ts: Refined auto-enable logic to check whether ALL or only SOME
projects have
  docker config — mixed groups now get 'both' mode instead of true
- shared.spec.ts: Added 5 test cases covering null version fallback
scenarios for fixed
groups, independent groups, both-null, reverse fallback, and mixed
groups

 ## Related Issue(s)

  Fixes #34382
  Fixes #33890
  Fixes #34391
2026-02-25 09:10:01 -05:00
MaxKless 4e55f9aa32 docs(misc): update nx download stats (#34596)
## Current Behavior
The "7. Thriving Community" section on
`nx.dev/docs/guides/adopting-nx/from-turborepo` displayed an outdated Nx
download statistic (~5 million downloads per week).

## Expected Behavior
The "7. Thriving Community" section on
`nx.dev/docs/guides/adopting-nx/from-turborepo` now reflects the latest
Nx download statistic (~9 million downloads per week).

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: MaxKless <MaxKless@users.noreply.github.com>
2026-02-25 08:26:01 -05:00
Jack Hsu 127255aa96 fix(bundling): fix regression on process.env usage for webpack (#34583)
When we optimized the `process.env` values to not embed the full object
unnecessarily, we also regressed in cases where users do use
`process.env` instead of `process.env["NX_PUBLIC_FOO"]`.

## Current behavior

Users cannot use `process.env` and must access each key individuall.
Although the serializing the full object can bloat bundle sizes, we also
don't want to break existing apps unnecessarily.

## Expected behavior

Existing apps should continue to work as usual.

## Related issues

Fixes #34279
2026-02-25 08:16:05 -05:00
Kai Gritun b46de60cd9 fix(js): guard against undefined closest node in rehoistNodes (#34347)
## Current Behavior

When running `@nx/js:prune-lockfile` on a monorepo with transitive
dependencies that have multiple versions where neither version is
reachable from a direct dependency in package.json, the executor throws:

```
NX   An error occurred while creating pruned lockfile

Original error: Cannot read properties of undefined (reading 'name')

TypeError: Cannot read properties of undefined (reading 'name')
    at switchNodeToHoisted (node_modules/nx/src/plugins/js/lock-file/project-graph-pruning.js:165:31)
```

## Expected Behavior

The lockfile pruning should complete without crashing, even when some
transitive dependencies cannot be traced back to a direct dependency.

## Root Cause

In `rehoistNodes()`, when there are multiple nested nodes for a package,
the code finds the "closest" node by computing `pathLengthToIncoming()`
for each. However, when none of the nested nodes have a path to any
direct dependency in package.json, `pathLengthToIncoming()` returns
`undefined` for all of them. Since `undefined < Infinity` is `false` in
JavaScript, `closest` remains `undefined`, and then
`switchNodeToHoisted(undefined, ...)` crashes.

## Fix

Add a guard to only call `switchNodeToHoisted()` when a closest node was
actually found:

```typescript
if (closest) {
  switchNodeToHoisted(closest, builder, invBuilder);
}
```

This allows the pruning to continue - the nested nodes simply won't be
rehoisted if no closest node can be determined.

## Related Issue

Fixes #34322

## Test Added

Added a unit test that verifies `rehoistNodes()` doesn't crash when
nested nodes have no path to package.json dependencies.
2026-02-25 13:28:19 +01:00
Tomas Ptacek 736551590a fix(angular-rspack): exclude .json files from JS/TS regex patterns (#34195)
## Current Behavior

When importing a `package.json` file in an Angular application built
with `@nx/angular-rspack`, the build fails with a Babel syntax error if
the `package.json` contains `@angular/*` dependencies:

```
SyntaxError: /path/to/package.json: Missing semicolon. (2:10)

  1 | {
> 2 |     "name": "@org/app",
    |           ^
  3 |     "version": "4.0.2",
  4 |     "dependencies": {
  5 |         "@angular/platform-browser": "20.3.7",
```

This happens because the `JS_ALL_EXT_REGEX` pattern
`/\.[cm]?(js)[^x]?\??/` incorrectly matches `.json` files. When the JSON
file content contains `@angular` strings, the
`angular-partial-transform-loader` attempts to process it through Babel,
which fails because JSON is not valid JavaScript.

**Root cause:** The regex `[^x]?` (optional character that is NOT 'x')
allows `.json` to match because 'o' is not 'x'.

## Expected Behavior
- `.json` files should NOT match `JS_ALL_EXT_REGEX` or
`TS_ALL_EXT_REGEX`
- Importing `package.json` in Angular applications should work correctly
- All existing matches for `.js`, `.jsx`, `.mjs`, `.cjs` (and TypeScript
equivalents) should continue to work

## Related Issue(s)
https://github.com/nrwl/nx/issues/32649
2026-02-25 09:55:15 +00:00
MaxKless e031d024ef chore(repo): update @nx/graph to 1.0.4 (#34558) 2026-02-25 18:27:42 +09:00
Jason Jean d042483a3f chore(gradle): clean up project.json configurations (#34587)
## Current Behavior

The Gradle projects have redundant and inconsistent project.json
configurations:
- `batch-runner` has its own project.json with duplicate targets
- `project-graph` has duplicate test/lint/format targets
- Implicit dependency syntax is inconsistent between projects
- e2e project has unnecessary implicitDependencies

## Expected Behavior

Cleaner, more maintainable project structure:
- Consolidated batch-runner configuration into parent project
- Removed duplicate targets from project-graph
- Consistent implicit dependency syntax using project name format
(`:project-name`)
- Streamlined e2e project configuration

## Related Issue(s)

N/A - Internal cleanup
Closes Q-173

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
Co-authored-by: Louie Weng <56288712+lourw@users.noreply.github.com>
2026-02-24 22:50:08 -05:00
Berend de Boer 39f252df97 docs(misc): add link to new nx-knip plugin (#34011)
This allows you to run knip against your typescript and javascript
projects.

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
2026-02-24 22:31:27 -05:00
Aude Planchamp 3f70561586 docs(misc): incorrect tsconfig inheritance described in TypeScript project references documentation (#34124)
## Current Behavior

Documentation bugfix on

https://nx.dev/docs/concepts/typescript-project-linking#set-up-typescript-project-references

In the section about setting up TypeScript project references, the
documentation currently states:

"Each project's tsconfig.lib.json file extends the project's
tsconfig.json file and adds references to the tsconfig.lib.json files of
project dependencies."

## Expected Behavior

In a standard Nx workspace configuration, tsconfig.lib.json extends the
workspace-level tsconfig.base.json, not the project-level tsconfig.json
(and the example provided just after is correct).

Suggested correction:

"Each project's tsconfig.lib.json file extends the workspace
tsconfig.base.json file and adds references to the tsconfig.lib.json
files of project dependencies."

## Related Issue(s)

Fixes  #34118

---------

Co-authored-by: Aude Planchamp <aude.planchamp@ekino.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
2026-02-24 22:31:13 -05:00
Miguel b72a203ed7 fix(release): allow null values in schema of dockerVersion (#34171)
<!-- 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
<!-- This is the behavior we have today -->

TS file documents `projectVersionData.dockerVersion` as having type
`string | undefined`. However, code behaves differently. For instance,
[here](https://github.com/nrwl/nx/blob/e57848cea748b85f17e5fc704b901975a8424c4d/packages/nx/src/command-line/release/version/release-group-processor.ts#L128)
and
[here](https://github.com/nrwl/nx/blob/e57848cea748b85f17e5fc704b901975a8424c4d/packages/nx/src/command-line/release/utils/shared.ts#L294)
it is setting as and comparing against `null`.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Schema has value that code sets (`null`)

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

Fixes https://github.com/nrwl/nx/issues/34172
2026-02-24 22:30:24 -05:00
Craigory Coppola 1ecf0fb6a7 fix(core): reject pending promises directly when plugin worker exits unexpectedly (#34588)
When a plugin worker process exits unexpectedly, the exit handler
previously sent synthetic `loadResult` messages to all pending response
handlers. If any handler was waiting for a different result type (e.g.
`createNodesResult`), the type validation would reject with a confusing
"Expected createNodesResult, got loadResult" error instead of surfacing
the actual cause.

Split response handlers into `onMessage` / `onError` callbacks so the
exit handler can reject each pending promise directly with a clear
"Plugin worker exited unexpectedly" error.

Also use unique transaction IDs for `load` messages (via `generateTxId`)
to avoid potential handler overwrites during worker restarts.

Fixes #34564
2026-02-24 17:44:40 -05:00
Jason Jean c743313078 chore(repo): update nx to 22.6.0-beta.3 (#34579)
Updating Nx from 22.6.0-beta.2 to 22.6.0-beta.3
2026-02-24 17:36:31 -05:00
Jason Jean 1bbe936513 chore(repo): disable CI continuous assignment (#34578)
## Summary

Testing CI behavior with continuous assignment disabled and cache bust
set to 4.

This is part of investigating flakiness potentially related to
continuous assignment in CI.

## Test plan

- Monitor CI execution behavior
- Compare with other test branches (bust=2, bust=3)
2026-02-24 17:34:24 -05:00
Jack Hsu c966e20746 docs(misc): dedupe and clean up getting started pages (#34521)
## Current Behavior

Documentation pages across Getting Started, How Nx Works, and Platform
Features sections contain:

1. Duplicated content — mental-model.mdoc has a ~70-line caching section
and a ~20-line DTE section that are near-verbatim
copies of how-caching-works.mdoc and distribute-task-execution.mdoc
respectively. remote-cache.mdoc re-explains local caching
 in its intro instead of linking to the canonical page.
2. Missing cross-reference links — Key concepts like "affected command",
"remote cache", "project graph", and "task pipeline
configuration" are mentioned without linking to their dedicated pages.
3. Style guide violations — Trust-undermining words ("simply", "just",
"straightforward"), anti-AI phrases ("Let's take",
"Whether you're..."), product possessives ("Nx's"), customer perspective
issues ("allows you to"), and em dashes appear
across Getting Started and How Nx Works pages.

## Expected Behavior

1. Content consolidation — mental-model.mdoc is trimmed by ~85 lines,
keeping the concept + images and linking to dedicated
pages for details. remote-cache.mdoc intro references the canonical
caching page. publish-conformance-rules-to-nx-cloud.mdoc
deduplicates its intro. maintain-typescript-monorepos.mdoc shortens its
inferred tasks re-explanation.
2. Cross-reference links added — First-mention links for affected,
remote cache, computation caching, task pipeline
configuration (in mental-model) and project graph (in self-healing-ci).
3. Style guide compliance — 18 fixes across 10 Getting Started and How
Nx Works pages, removing banned phrases and aligning
with the new STYLE_GUIDE.md.
4. Sidebar improvements — Cache Task Results added after Run Tasks in
Platform Features; Maintain TypeScript Monorepos moved
to first in KB > TypeScript.

## Pages changed
```
┌─────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────┐
│     Section     │                                              Pages                                              │
├─────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Getting Started │ intro, index, nx-cloud, ai-setup, start-with-existing-project                                   │
├─────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────┤
│ How Nx Works    │ mental-model, how-caching-works, task-pipeline-configuration, nx-plugins, nx-daemon             │
├─────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Features        │ remote-cache, self-healing-ci, maintain-typescript-monorepos, cache-task-results (sidebar only) │
├─────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Enterprise      │ publish-conformance-rules-to-nx-cloud                                                           │
└─────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────┘
```
2026-02-24 16:42:31 -05:00
Miroslav Jonaš f42976f852 fix(repo): remove chalk from e2e tests (#34570)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2026-02-24 15:39:27 -05:00
Leosvel Pérez Espinosa 6d90572257 fix(core): show the correct status for stopped continuous tasks (#34226)
## Current Behavior

### 1. Continuous tasks missing from `postTasksExecution` hook

When running continuous tasks (e.g., `nx serve app`) and stopping them
with Ctrl+C, the `postTasksExecution` lifecycle hook does not include
them in `taskResults`. This breaks plugins that rely on post-run
statistics (e.g., uploading task stats to DataDog).

### 2. Confusing TUI status when sibling continuous task exits

When multiple continuous tasks run together and one exits unexpectedly,
its sibling is marked as "failed" even though it was intentionally
terminated/stopped by the task orchestrator.

## Expected Behavior

1. All tasks, including continuous ones, are included in `taskResults`
for the `postTasksExecution` hook
2. Continuous tasks that are intentionally stopped (because dependent
tasks completed or during graceful shutdown) report as `success` with
`Stopped` display status
3. Continuous tasks that exit unexpectedly (crash) report as `failure`
4. TUI summary shows correct status: success when all tasks completed
successfully, square icon for stopped tasks

## Related Issue(s)

Fixes https://github.com/nrwl/nx/issues/33561

Supersedes:

- https://github.com/nrwl/nx/pull/33562
- https://github.com/nrwl/nx/pull/34132
2026-02-24 13:48:52 -05:00
Rares Matei f84ec34cbd chore(repo): enable signal file writing (#34572)
Add NX_CLOUD_IO_TRACING_DIRECTORY environment variable.

<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes Q-245
2026-02-24 17:34:51 +00:00
Juri 566a370375 docs(core): move synthetic monorepos back to "How Nx Works" sidebar section 2026-02-24 18:02:29 +01:00
Juri Strumpflohner 4c1dd1e5ed docs(core): add synthetic monorepos page (#34565)
## Current Behavior

No documentation exists explaining the concept of synthetic monorepos —
how they bridge polyrepo and monorepo setups by connecting separate
repositories into a unified dependency graph.


https://deploy-preview-34565--nx-docs.netlify.app/docs/concepts/synthetic-monorepos

## Expected Behavior

New concept page under "How Nx Works" that explains:
- What synthetic monorepos are (unified graph across separate repos
without moving code)
- Why they matter for humans (visibility, cross-repo coordination) and
AI agents (seeing beyond repo boundaries)
- What they provide (cross-repo graph, actionable tooling, AI agent
enablement)
- How they serve as a gradual entry point toward deeper monorepo
adoption

## Related Issue(s)

N/A — new documentation page based on existing content from webinars and
internal knowledge.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: juristr <juristr@users.noreply.github.com>
2026-02-24 16:51:20 +01:00
Loëck Vézien 8f64e844c9 feat(core): add yarn berry catalog support (#34552)
## Current Behavior

The Nx catalog system (`catalog:` protocol) only supports pnpm
workspaces. Yarn Berry (v4+) introduced [catalog
support](https://yarnpkg.com/features/catalogs) in `.yarnrc.yml`, but Nx
does not recognize `catalog:` references in Yarn workspaces. This means
Yarn Berry users cannot benefit from Nx's catalog-aware dependency
resolution, validation, or version updating.

## Expected Behavior

Nx should support Yarn Berry's `catalog:` protocol, just like it does
for pnpm. With this PR:

- `catalog:` and `catalog:<name>` references in `package.json`
dependencies are correctly resolved against `.yarnrc.yml` definitions
for Yarn Berry workspaces
- Validation provides helpful error messages with suggestions (missing
catalog, missing package, duplicate default definitions)
- Catalog versions can be updated programmatically via
`updateCatalogVersions`
- The `CatalogManager` interface is generalized with
`getCatalogDefinitionFilePaths()` and `CatalogDefinitions` to support
multiple package managers cleanly

### Changes

- **`YarnCatalogManager`** — New manager that reads `catalog:` /
`catalogs:` from `.yarnrc.yml`, mirroring the pnpm implementation with
Yarn-specific config paths and error messages
- **`yarn-workspace.ts`** — Type definitions for Yarn's `.yarnrc.yml`
catalog structure (`YarnWorkspaceYaml`, `YarnCatalogEntry`)
- **`manager-factory.ts`** — Registers `YarnCatalogManager` for `yarn`
package manager
- **`manager.ts`** — Adds `getCatalogDefinitionFilePaths()` to the
`CatalogManager` interface; moves `formatCatalogError` here from
`types.ts` (runtime function doesn't belong with type-only exports)
- **`types.ts`** — Adds generic `CatalogDefinitions` interface so
consumers don't need to depend on package-manager-specific types
- **`pnpm-manager.ts`** — Implements the new
`getCatalogDefinitionFilePaths()` method; import cleanup
- **592-line test suite** covering parsing, resolution, validation
(named catalogs, default catalog, dual-definition errors, missing
catalogs/packages with suggestions), and `updateCatalogVersions`

### Context

I'm currently applying a patch on the compiled `@nx/devkit` package in
my Yarn Berry project to get catalog support while waiting for upstream
support:

<details>
<summary>Current workaround patch on <code>@nx/devkit</code></summary>

```diff
diff --git a/src/utils/catalog/manager-factory.js b/src/utils/catalog/manager-factory.js
index 6216749..d46e242 100644
--- a/src/utils/catalog/manager-factory.js
+++ b/src/utils/catalog/manager-factory.js
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
 exports.getCatalogManager = getCatalogManager;
 const devkit_exports_1 = require("nx/src/devkit-exports");
 const pnpm_manager_1 = require("./pnpm-manager");
+const yarn_manager_1 = require("./yarn-manager");
 /**
  * Factory function to get the appropriate catalog manager based on the package manager
  */
@@ -11,6 +12,8 @@ function getCatalogManager(workspaceRoot) {
     switch (packageManager) {
         case 'pnpm':
             return new pnpm_manager_1.PnpmCatalogManager();
+        case 'yarn':
+            return new yarn_manager_1.YarnCatalogManager();
         default:
             return null;
     }
diff --git a/src/utils/catalog/yarn-manager.js b/src/utils/catalog/yarn-manager.js
new file mode 100644
index 0000000..048fdec
--- /dev/null
+++ b/src/utils/catalog/yarn-manager.js
@@ -0,0 +1,102 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.YarnCatalogManager = void 0;
+const node_fs_1 = require("node:fs");
+const node_path_1 = require("node:path");
+const devkit_exports_1 = require("nx/src/devkit-exports");
+const devkit_internals_1 = require("nx/src/devkit-internals");
+class YarnCatalogManager {
+    constructor() {
+        this.name = 'yarn';
+        this.catalogProtocol = 'catalog:';
+    }
+    isCatalogReference(version) {
+        return version.startsWith(this.catalogProtocol);
+    }
+    parseCatalogReference(version) {
+        if (!this.isCatalogReference(version)) { return null; }
+        return { catalogName: undefined, isDefaultCatalog: true };
+    }
+    getCatalogDefinitions(treeOrRoot) {
+        if (typeof treeOrRoot === 'string') {
+            const p = (0, node_path_1.join)(treeOrRoot, '.yarnrc.yml');
+            if (!(0, node_fs_1.existsSync)(p)) { return null; }
+            return readYamlFileFromFs(p);
+        } else {
+            if (!treeOrRoot.exists('.yarnrc.yml')) { return null; }
+            return readYamlFileFromTree(treeOrRoot, '.yarnrc.yml');
+        }
+    }
+    resolveCatalogReference(treeOrRoot, packageName, version) {
+        if (!this.parseCatalogReference(version)) { return null; }
+        const config = this.getCatalogDefinitions(treeOrRoot);
+        if (!config || !config.catalog) { return null; }
+        return config.catalog[packageName] || null;
+    }
+    validateCatalogReference(treeOrRoot, packageName, version) {
+        if (!this.parseCatalogReference(version)) {
+            throw new Error(`Invalid catalog reference: "${version}"`);
+        }
+        const config = this.getCatalogDefinitions(treeOrRoot);
+        if (!config) { throw new Error('No .yarnrc.yml found'); }
+        if (!config.catalog) { throw new Error('No catalog in .yarnrc.yml'); }
+        if (!config.catalog[packageName]) {
+            throw new Error(`"${packageName}" not in .yarnrc.yml catalog`);
+        }
+    }
+    updateCatalogVersions() {}
+}
+exports.YarnCatalogManager = YarnCatalogManager;
+function readYamlFileFromFs(path) {
+    try { return (0, devkit_internals_1.readYamlFile)(path); }
+    catch (e) {
+        devkit_exports_1.output.warn({ title: 'Unable to parse .yarnrc.yml', bodyLines: [e.toString()] });
+        return null;
+    }
+}
+function readYamlFileFromTree(tree, path) {
+    const content = tree.read(path, 'utf-8');
+    const { load } = require('@zkochan/js-yaml');
+    try { return load(content, { filename: path }); }
+    catch (e) {
+        devkit_exports_1.output.warn({ title: 'Unable to parse .yarnrc.yml', bodyLines: [e.toString()] });
+        return null;
+    }
+}
```

</details>

This PR replaces that workaround with a proper TypeScript implementation
including full test coverage, named catalog support, helpful error
messages, and `updateCatalogVersions` support.

## Related Issue(s)

<!-- No existing issue found for Yarn Berry catalog support — this PR
introduces the feature -->
2026-02-24 10:34:40 -05:00
Jack Hsu 7f7bba633d fix(bundling): add docs link to generatePackageJson error message (#34562)
## Current Behavior

When users hit the `generatePackageJson: true` error with TS Solution
Setup, the error tells them to "unset the option" but gives no guidance
on the replacement workflow.

## Expected Behavior

The error message now includes a link to the pruning guide at
https://nx.dev/docs/technologies/node/guides/deploying-node-projects so
users can immediately find the migration steps.

## Related Issue(s)

Related #30146
2026-02-24 08:31:57 -05:00
Colum Ferry 1a15ea183a fix(js): use per-invocation cache in TS plugin to fix NX_ISOLATE_PLUGINS=false (#34566)
When plugin isolation is off, concurrent createNodesV2 invocations share
the same module instance. The module-level mutable `cache` variable
caused
invocation A's `finally` block to null it out while invocation B was
still
reading from it, resulting in "Cannot read properties of null (reading
'configContexts')".

Replace the shared mutable `cache` with a Symbol-keyed Map so each
invocation gets its own isolated cache. The tsconfig disk cache is
shared
across invocations with an idempotent initialization guard.

CLOSES NXC-3971
2026-02-24 12:51:54 +00:00
Juri Strumpflohner 8c0600225a docs(nx-dev): add 'A Monorepo Is NOT a Monolith' blog post (#34567)
## Summary
- Updated version of the classic "Misconceptions about Monorepos"
article
- New sections on AI compatibility, scaling strategies (affected,
caching, distribution, atomization), and `@nx/owners`
- Custom SVG diagrams for project graph illustrations (replacing old
Medium images)
- Authors: Victor Savkin, Juri Strumpflohner

## Test plan
- [ ] Verify blog post renders correctly on preview
- [ ] Check all images load (SVGs + avif)
- [ ] Verify internal doc links resolve
- [ ] Check TOC renders properly

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: juristr <juristr@users.noreply.github.com>
2026-02-24 13:46:52 +01:00
MaxKless 832355081b feat(core): add passthrough for nx-cloud apply-locally command (#34557)
## Current Behavior
folks had to type in `nx-cloud apply-locally`

## Expected Behavior
now `nx apply-locally` works

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-02-24 19:42:41 +09:00
MaxKless 1081c320ab feat(core): add --json flag for better AX to nx list (#34551)
### Current Behavior

nx list <plugin> shows generator/executor names and descriptions in text
format only. It does not show where the plugin or its
generators/executors are located on disk, and there is no
machine-readable output option.

  ### Expected Behavior

- nx list --json outputs all local and installed plugins with their
paths and capability types
- nx list <plugin> --json outputs detailed structured JSON including
resolved paths to each generator/executor implementation and schema
  - nx list <plugin> (text mode) now also shows the plugin's root path
2026-02-24 10:34:41 +01:00
Samuel Briole bdeeb036fb fix(bundling): skip unnecessary type-check in TS Solution Setup when skipTypeCheck is true (#34493)
## Current Behavior

In TS Solution Setup, the esbuild executor forces `runTypeCheck` even
when `skipTypeCheck: true` and `declaration: false`, due to the `||
options.isTsSolutionSetup` condition in `esbuild.impl.ts` (lines 139-140
and 195).

When `declaration: false`, this type check runs in `noEmit` mode with
`ignoreDiagnostics: true` — making it **completely pointless** (no
declarations emitted, no diagnostics reported). Its only observable
effect is writing a poisoned 19-byte tsbuildinfo file that causes race
conditions with `tsc --build`.

## Expected Behavior

When `skipTypeCheck: true` and `declaration: false`, the esbuild
executor should not run type checking at all. The `isTsSolutionSetup`
override should only force type checking when declarations actually need
to be generated.

## Fix

### Primary: Skip unnecessary type check (`esbuild.impl.ts`)

```diff
  // Non-watch mode (line 195)
- if (!options.skipTypeCheck || options.isTsSolutionSetup) {
+ if (!options.skipTypeCheck || (options.isTsSolutionSetup && options.declaration)) {

  // Watch mode (lines 139-140)
- options.isTsSolutionSetup
+ (options.isTsSolutionSetup && options.declaration)
```

Only force type checking in TS Solution Setup when declarations need to
be generated. This eliminates the pointless type check entirely.

### Defense-in-depth: Prevent tsbuildinfo in `noEmit` mode
(`run-type-check.ts`)

```diff
- : { noEmit: true };
+ : { noEmit: true, composite: false };
```

Setting `composite: false` alongside `noEmit: true` prevents TypeScript
from writing tsbuildinfo files, protecting against this class of bug
from any caller of `runTypeCheck`.

## Why This is Safe

| Scenario | Before | After |
|----------|--------|-------|
| `skipTypeCheck: false`, `declaration: false`, `isTsSolutionSetup:
true` | Runs type check (noEmit) | Still runs (`!false \|\| ...` = true)
|
| `skipTypeCheck: false`, `declaration: true`, `isTsSolutionSetup: true`
| Runs type check (emitDeclarationOnly) | Still runs |
| `skipTypeCheck: true`, `declaration: true`, `isTsSolutionSetup: true`
| normalize.ts overrides skipTypeCheck to false; runs type check | Still
runs (same normalization) |
| **`skipTypeCheck: true`, `declaration: false`, `isTsSolutionSetup:
true`** | **Runs pointless type check (noEmit + ignoreDiagnostics),
writes poisoned tsbuildinfo** | **Skipped entirely** |

The only behavior change is in the last row — the case where the type
check was doing nothing useful but causing harm.

## Related Issue(s)

Fixes #34492

---------

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
2026-02-23 22:32:01 -05:00
Jack Hsu 4b1bf5f7ba docs(node): add pruning guide for Docker deployments (#34560)
## Current Behavior

Users migrating to Nx 20's TS Solution Setup lose `generatePackageJson`
support and have no documentation on the replacement prune workflow
(`prune-lockfile`, `copy-workspace-modules`). The error message tells
them to "unset the option" but doesn't explain what to do instead.

## Expected Behavior

A dedicated guide at
`/docs/technologies/node/guides/deploying-node-projects` covers the full
prune workflow: when to use pruning vs bundling, target configuration,
Dockerfile setup, and step-by-step migration from `generatePackageJson`.

Also updated the existing bundling guide to match the same structure
(intro table, cross-links, style guide compliance). The two articles are
sister guides covering the two ways to deploy Node.js apps: bundle
everything into a single file, or prune dependencies for a
`node_modules`-based install.

Cross-links added from the bundling guide and ci-deployment guide.

## Related Issue(s)

Closes #30146

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2026-02-23 16:00:46 -05:00
Jack Hsu f935d9a7bf docs(release): document checkAllBranchesWhen type and behavior (#34515)
## Current Behavior
The `checkAllBranchesWhen` option is documented as type `string` with a
minimal description, which does not match the actual implementation.

## Expected Behavior
Document the correct type (`boolean | string[]`) and explain the default
branch resolution behavior, the three value modes (true, false,
string[]), and when this option is useful.

## Related Issue(s)
Closes DOC-414

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2026-02-23 15:47:41 -05:00
Jason Jean dd325d790a fix(core): retry entire SQLite transaction on DatabaseBusy (#34533)
## Current Behavior

When multiple Nx processes (task hasher, daemon, workers) access the
SQLite database concurrently, the `NxDbConnection::transaction()` method
only retries the BEGIN step using the `retry_db_operation_when_busy!`
macro. Operations executed inside the transaction and the COMMIT are not
retried, so if the database is busy during those steps, the task crashes
with:

```
Error: DB transaction operation error: SqliteFailure(Error { code: DatabaseBusy, extended_code: 5 }, Some("database is locked"))
```

This is particularly common during parallel task hashing with continuous
tasks, where `TaskDetails.recordTaskDetails()` and `RunningTasksService`
compete for write access.

## Expected Behavior

The entire transaction (begin, execute, commit) is retried as a single
unit when any step encounters a `DatabaseBusy` error. If the database is
busy during the operation or commit, the transaction is automatically
rolled back (via drop) and retried with the same exponential backoff
used everywhere else.

## Related Issue(s)

<!-- No public issue linked -->
2026-02-23 12:28:58 -05:00
Jason Jean ed786fb12c chore(repo): upgrade fast-xml-parser to 5.3.7 to fix CVE-2026-25896 (#34555)
## Current Behavior

The NPM audit CI job is failing due to a critical XSS vulnerability
(CVE-2026-25896) in `fast-xml-parser` version 4.5.3.

## Expected Behavior

The NPM audit should pass with no critical vulnerabilities.

## Related Issue(s)

Fixes the failing NPM audit CI run:
https://github.com/nrwl/nx/actions/runs/22288455713

---

This PR upgrades `fast-xml-parser` from `^4.2.7` to `^5.3.7` to address
GHSA-m7jm-9gc2-mpf2, a critical XSS vulnerability that allows entity
encoding bypass via regex injection in DOCTYPE entity names.

The package is only used in
`scripts/documentation/internal-link-checker.ts` for parsing XML
sitemaps, so the risk of this upgrade is low.
2026-02-23 12:22:36 -05:00
Jason Jean cc5eeefde9 feat(core): add preferBatch executor option (#34293)
## Current Behavior

Batch mode is binary:
- `--batch` flag → batch ALL executors that support it
- No flag → batch NOTHING

This means users of gradle/maven must always remember to pass `--batch`
to get the performance benefits.

## Expected Behavior

Plugin authors can now set `preferBatch: true` in their executor config
to indicate batch mode should be used by default. Users can still
opt-out with `--no-batch`.

Three states:
- `--batch` → batch everything
- `--no-batch` → batch nothing  
- (not specified) → use each executor's `preferBatch` preference

| `--batch` flag | `preferBatch` | Result |
|----------------|---------------|--------|
| `true`         | any           | Batch  |
| `false`        | any           | No batch |
| not set        | `true`        | Batch  |
| not set        | `false`/undefined | No batch |

## Changes

- Added `preferBatch?: boolean` to `ExecutorJsonEntryConfig` and
`ExecutorConfig` interfaces
- Updated `--batch` default from `false` to `undefined` to allow
`preferBatch` to decide
- Modified batch scheduling logic to respect `preferBatch`
- Enabled `preferBatch: true` for gradle and maven executors
- Added 5 unit tests covering all `preferBatch` scenarios

## Related Issue(s)

<!-- Link any related issues here -->
2026-02-23 12:19:15 -05:00
Jason Jean cf53d15ae5 chore(repo): update nx to 22.6.0-beta.2 (#34556)
Updating Nx from 22.6.0-beta.1 to 22.6.0-beta.2

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-02-23 11:50:54 -05:00
Mathias Schopmans 7351e21150 fix(webpack): ensure safe process.env fallback replacement (#34464)
PR #30826 introduced a fallback definition for `process.env`:

```ts
{ 'process.env': '{}' }
```

Since `DefinePlugin` performs raw textual replacement, this can generate
invalid JavaScript when user code accesses environment variables via dot
notation:

```ts
process.env.SOME_KEY
```

becomes:

```js
{}.SOME_KEY
```

`{}` is parsed as a block statement (not an object literal), resulting
in:


> Unexpected token: punc (.)

This PR updates the fallback to a parenthesized object literal:

```ts
{ 'process.env': '({})' }
```

which produces valid output:

```js
({}).SOME_KEY
```

This preserves the intended bundle-size optimization while ensuring
syntactically correct output for standard `process.env.X` access
patterns.


## Related Issue(s)
Refs #30826
Fixes #34460 

//CC @Coly010 @coolassassin
2026-02-23 16:23:21 +00:00
MaxKless c5ab66152a feat(core): add AI agent mode to nx import (#34498)
## Current Behavior

`nx import` relies on interactive prompts (enquirer) and spinners (ora)
for user interaction. AI agents cannot parse this output or respond to
prompts, making `nx import` unusable in agent workflows.

## Expected Behavior

When `isAiAgent()` is true, `nx import` now:
- Skips all interactive prompts and spinners
- Emits NDJSON progress to stdout (`starting`, `cloning`, `filtering`,
`merging`, `detecting-plugins`, `complete`)
- Returns structured `needs_input` when required args are missing (all
at once to minimize round-trips)
- Returns structured `needs_input` for plugin selection when `--plugins`
flag is not provided
- Returns structured success/error results with hints and next steps
- Supports new `--plugins` flag (`skip`/`all`/comma-separated list)

Shared AI output types extracted from `init` into
`packages/nx/src/command-line/ai/ai-output.ts` for reuse across
commands.
2026-02-23 16:51:10 +01:00
MaxKless 1805301941 fix(misc): update maven & gradle icons to java duke icon (#34508)
duke is an official and open-source icon so we'll use it
<img width="1601" height="644" alt="image"
src="https://github.com/user-attachments/assets/3e95d94e-76d6-482a-ac09-bbe17a9f076a"
/>
<img width="1191" height="516" alt="image"
src="https://github.com/user-attachments/assets/151982fa-b497-4569-bf17-26f0d064d414"
/>

---------

Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-02-23 09:33:39 -05:00
MaxKless e8633e0299 fix(core): preserve existing source properties in claude plugin config (#34499)
## Current Behavior

Running `configure-ai-agents` overwrites the entire `source` object in
`extraKnownMarketplaces['nx-claude-plugins']`, removing any user-added
properties like `ref`.

## Expected Behavior

User-added source properties (e.g. `ref`) are preserved, while `source`
and `repo` are always set to the correct values.
2026-02-23 21:45:51 +09:00
Colum Ferry 6bcaa46864 fix(angular): use SASS indented syntax in nx-welcome component when style is sass (#34510)
The nx-welcome component inline styles were always using CSS/SCSS syntax
(with braces and semicolons) regardless of the selected style option.
When --style=sass is chosen, the component now correctly uses SASS
indented syntax (no braces or semicolons) matching the expected
behavior for the .sass file format.

Fixes #33489
2026-02-23 11:50:43 +00:00
MaxKless d545472da8 feat(core): improve AX of configure-ai-agents with auto-detection (#34496)
## Current Behavior

When `configure-ai-agents` is invoked from within an AI agent (e.g.
Claude Code), it either shows an interactive multi-select prompt (which
the agent can't interact with) or requires `--agents` and
`--no-interactive` flags to work correctly. This makes the experience
awkward when AI agents call the command as part of workspace setup.

## Expected Behavior

When an AI agent is detected (via environment variables like
`CLAUDECODE`), the command now:

1. **Auto-configures the detected agent** if it's not yet configured,
partially configured, or outdated — no prompts needed
2. **Auto-updates any other outdated agents** alongside the detected one
3. **Reports non-configured agents** with a suggested `nx
configure-ai-agents --agents ...` command
4. **Reports up-to-date status** if the detected agent is already fully
configured

When `--agents` is explicitly passed, detection is ignored entirely
(existing behavior preserved). `--check` mode also works with detection
— it checks the detected agent plus all other configured agents.

Additionally:
- Strips AI agent detection env vars (`CLAUDECODE`, `CLAUDE_CODE`,
`OPENCODE`, `GEMINI_CLI`, etc.) from e2e subprocess environments to
prevent the test runner's environment from leaking into tests
- Fixes e2e tests to use `AGENTS.md` (not `GEMINI.md`) for gemini
assertions, matching what the gemini generator actually creates for
fresh installations

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-02-23 20:45:35 +09:00
Leosvel Pérez Espinosa 025db33a75 cleanup(repo): avoid unnecessary project graph recomputations (#34423)
## Current Behavior

- Cypress `start-dev-server.ts` file creates a port lock file next to
the source code
- Native temp DB files created by tests are not properly ignored
- Astro config timestamp file is not ignored

These all trigger watch file change events, which cause the project
graph to be recomputed unnecessarily.

## Expected Behavior

Output files should not trigger watch file change events. The project
graph should not be recomputed unnecessarily.
2026-02-23 10:08:05 +00:00
Leosvel Pérez Espinosa 731db47fd7 fix(misc): bump minimatch to 10.2.1 to address CVE-2026-26996 (#34509)
## Current Behavior

Several Nx packages directly depend on a minimatch version with a
high-severity vulnerability
(https://github.com/advisories/GHSA-3ppc-4f35-3m26).

## Expected Behavior

Several Nx packages should depend directly on a minimatch version that
does not include the reported high-severity vulnerability.

Note: unsafe `minimatch` versions can still be pulled in transitively.
Upstream deps need to be updated, and then we need to update the Nx
packages to newer versions.

## Related Issue(s)

Fixes #34507

---------

Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
2026-02-23 09:42:07 +00:00
Copilot 4b6aea9f5e docs(core): clarify trailing slash requirement for inputs directory paths (#33664)
## Current Behavior

Users specifying directory paths in `inputs` without a trailing slash or
glob pattern find that files are not matched. For example,
`{projectRoot}/src` does not match any files, while `outputs` allows
naked directory paths without issue.

## Expected Behavior

Documentation clearly explains that directory paths in `inputs` require
a trailing slash or glob pattern:

```jsonc
{
  "inputs": [
    "{projectRoot}/src/",       // ✓ Works (trailing slash)
    "{projectRoot}/src/**/*",   // ✓ Works (glob pattern)
    "{projectRoot}/src"         // ✗ Does NOT work
  ]
}
```

### Changes

- **Reference doc** (`reference/inputs.mdoc`): Added "Directory Paths"
section explaining the requirement with examples
- **Guide** (`configure-inputs.mdoc`): Added callout warning at top
alerting users to this behavior
- Both docs note the difference from `outputs`, which do support naked
directory paths

## Related Issue(s)

Fixes
https://linear.app/nxdev/issue/NXC-2102/clarify-trailing-slash-requirement-for-inputs-in-directory-paths

Co-authored-by: Steven Nance <steven@nrwl.io>
2026-02-23 18:35:55 +09:00
Altan Stalker 0568059fb8 chore(repo): force nx-dev:prebuild-banner onto linux-extra-large (#34535)
Temp fix while scheduling is fixed for real

---------

Co-authored-by: FrozenPandaz <jasonjean1993@gmail.com>
2026-02-20 18:24:33 -05:00
Craigory Coppola 3e5df300ab feat(core): add commands for debugging cache inputs / outputs (#34414)
## Current Behavior
There's not a great way to troubleshoot or test inputs and outputs
configurations on tasks.

## Expected Behavior
Adds `nx show target` to enable users to debug inputs and outputs. It
has flags `--inputs`, `--check-input`, `--outputs`, and `--check-output`
to list or test specific file patterns.

<img width="1077" height="198" alt="image"
src="https://github.com/user-attachments/assets/7ffd4502-1542-40e6-867c-37f70440a421"
/>

<img width="1077" height="105" alt="image"
src="https://github.com/user-attachments/assets/eb5b09e1-23fb-4710-9fb0-84f0c8e80c14"
/>

<img width="1077" height="538" alt="image"
src="https://github.com/user-attachments/assets/74c60668-285c-4195-ba77-6693a66e4897"
/>

<img width="1077" height="318" alt="image"
src="https://github.com/user-attachments/assets/ee228c43-98c2-441d-8b9d-277b38213e4d"
/>

<img width="1077" height="92" alt="image"
src="https://github.com/user-attachments/assets/8cca6553-4362-4662-b948-723abcc75671"
/>

<img width="1077" height="74" alt="image"
src="https://github.com/user-attachments/assets/6dc2188e-5dc5-4b5f-afd4-2a492a896e1d"
/>

---

<img width="492" height="430" alt="image"
src="https://github.com/user-attachments/assets/ae22bb2e-92c2-4c75-ad6f-b9cccda3def4"
/>

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <jasonjean1993@gmail.com>
2026-02-20 17:35:50 -05:00
Jack Hsu 221ed882fa fix(misc): prevent nxCloudId from being generated for new workspaces (#34532)
## Current Behavior

When creating a new workspace using `create-nx-workspace` with the
"custom" preset flow, an `nxCloudId` is generated and added to
`nx.json`. This happens even though the onboarding flow is supposed to
handle Cloud setup separately via a short URL.

## Expected Behavior

New workspaces created via `create-nx-workspace` should not have
`nxCloudId` set in `nx.json`. Instead, a short URL is provided for users
to finish Cloud onboarding on their own. The `nxCloud: 'skip'` option is
now passed for the custom flow to prevent the ID from being generated.

E2E tests are updated to verify that `nxCloudId` is undefined in the
generated `nx.json` across all workspace presets.

## Related Issue(s)

N/A - internal fix for workspace creation behavior.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-02-20 19:56:58 +00:00
Craigory Coppola df8a2c43f4 fix(core): commands shouldn't hang when passing --help (#34506)
## Current Behavior
`--help` on commands that hit yargs help are hanging

## Expected Behavior
It doesn't hang. This contains a quick fix in adding the process.exit
call, but also adds the unref needed to maintain previous working
behavior. We'll need to investigate long term if additional areas keep
commands alive, but adding this unref theoretically allows removing the
process.exit calls from `nx show`

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

Fixes #

---------

Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
2026-02-20 13:49:21 -05:00
Jason Jean 391d23c65e chore(repo): re-enable e2e tests disabled by api-extractor issue (#34519)
## Current Behavior

14 e2e test suites were disabled (`xdescribe`) due to an ESM import
issue in `@microsoft/api-extractor@7.57.0` (see
https://github.com/qmhc/unplugin-dts/issues/461).

## Expected Behavior

With the upstream issue resolved, all 14 e2e test suites are re-enabled
(`describe`) and should pass normally.

## Related Issue(s)

Reverts #34516
2026-02-20 12:17:20 -05:00
Jason Jean 092cea6073 chore(repo): update nx to 22.6.0-beta.1 (#34527)
Updating Nx from 22.5.0-beta.5 to 22.6.0-beta.1
2026-02-20 11:21:34 -05:00
Jack Hsu de2dc7ca13 fix(nextjs): reset daemon client after project graph creation in withNx (#34518)
## Current Behavior

Running `nx test` for Next.js projects causes Jest to hang with:
```
Jest did not exit one second after the test run has completed.
```

This happens because `next/jest` loads `next.config.js`, which calls
`withNx` → `createProjectGraphAsync()`. The daemon client socket
connection is left open, keeping the Node.js event loop alive and
preventing Jest from exiting. Non-Next.js projects are unaffected since
they don't trigger this code path.

## Expected Behavior

Jest exits cleanly after tests complete for Next.js projects, without
needing `forceExit: true`.

## Fix

Pass `resetDaemonClient: true` to `createProjectGraphAsync()` in
`packages/next/plugins/with-nx.ts`. This tells the project graph
function to call `daemonClient.reset()` after fetching the graph, which
closes the socket and allows Jest to exit.

### Verification

| Scenario | Before | After |
|----------|--------|-------|
| `nx test next-app` | Hangs | Exits cleanly |
| `NX_DAEMON=false nx test next-app` | Exits cleanly | Exits cleanly |
| Direct `npx jest` | Exits cleanly | Exits cleanly |
| Non-Next.js `nx test react-lib` | Exits cleanly | Exits cleanly |

## Related Issue(s)

Fixes #32880
2026-02-20 11:08:50 -05:00
Jason Jean 5236e02308 chore(maven): bump maven plugin version to 0.0.14 (#34505)
## Current Behavior

The Maven plugin is on version `0.0.13`.

## Expected Behavior

The Maven plugin is bumped to version `0.0.14`, with a migration
generated for Nx `22.6.0-beta.1`.
2026-02-19 18:27:14 -05:00
Altan Stalker 8e1d873edc chore(core): enable nx cloud verbose logging (#34524)
## Current Behavior
Agents are silent and hard to diagnose

## Expected Behavior
Agents should print debug logs without making all of Nx print debug logs
2026-02-19 22:41:35 +00:00
Jason Jean 4ca3ee97c3 chore(repo): disable e2e tests broken by @microsoft/api-extractor@7.57.0 (#34516)
## Current Behavior

14 e2e tests are failing across master with "Failed to process project
graph" errors. The root cause is `@microsoft/api-extractor@7.57.0` which
has a broken ESM export (`ConsoleMessageId`). When `@nx/vite/plugin` or
`@nx/vitest` plugins load `vite.config.mts` files, they transitively
import api-extractor which crashes.

## Expected Behavior

Broken e2e tests are disabled via `xdescribe` so they no longer block
CI. Tests should be re-enabled once the upstream api-extractor ESM issue
is fixed.

## Disabled Tests

| Project | Test File |
|---------|-----------|
| e2e-vite | `vite.test.ts`, `vite-legacy.test.ts`,
`vite-ts-solution.test.ts` |
| e2e-vue | `vue.test.ts`, `vue-legacy.test.ts`,
`vue-ts-solution.test.ts` |
| e2e-js | `js-ts-solution.test.ts` |
| e2e-web | `web-vite.test.ts` |
| e2e-react | `react-vite.test.ts`, `react-ts-solution.test.ts` |
| e2e-next | `next-ts-solutions.test.ts` |
| e2e-release | `release-publishable-libraries.test.ts`,
`release-publishable-libraries-ts-solution.test.ts` |
| e2e-storybook | `storybook-nested.test.ts` |

## Related Issue(s)

Upstream: https://github.com/qmhc/unplugin-dts/issues/461
2026-02-19 19:16:57 +00:00
Jason Jean e6ad74afed chore(maven): upgrade maven-shade-plugin to 3.6.0 (#34514)
## Current Behavior

The `maven-shade-plugin` at version 3.5.0 intermittently fails on CI
with:

```
Could not replace original artifact with shaded artifact!
```

This is a file-locking race condition where the plugin fails to
atomically replace the original JAR with the shaded JAR.

## Expected Behavior

Upgrading to 3.6.0 resolves the intermittent CI failures by using
improved file-handling logic with better retry behavior during the
artifact replacement step.

## Related Issue(s)

N/A - fixes intermittent CI flakiness in `maven-batch-runner` builds.
2026-02-19 10:28:14 -08:00
Ondrej Kelle 79f41e54af feat(core): use static_vcruntime to avoid msvcrt dependency (#19781)
Closes #19779

<!-- 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` -->

## Current Behavior
When targeting Windows the resulting binary (nx.dll) dynamically links
against Microsoft Visual C++ runtime (msvcrt140.dll). This means nx
won't be able to run on Windows systems without this runtime installed.

## Expected Behavior
I'd like to avoid this dependency by linking the runtime statically into
the nx binary. (This is also how e.g. cargo.exe for Windows is built.)

## Related Issue(s)

Fixes #19779

---------

Co-authored-by: Craigory Coppola <craigorycoppola@gmail.com>
2026-02-19 09:07:17 -05:00
Leosvel Pérez Espinosa 4f9be499b4 fix(core): reduce terminal output duplication and allocations in task runner (#34427)
## Current Behavior

Terminal output in the task runner is accumulated via repeated string
concatenation (`terminalOutput += chunk`). Each `+=` on a growing string
causes V8 to allocate a new, larger string and copy the old contents,
resulting in O(n²) allocation behavior for tasks with large output.
Additionally, `PseudoTtyProcess.onExit` didn't pass `terminalOutput` to
its callbacks, forcing callers like `TaskOrchestrator` to duplicate
output accumulation logic with a separate `onOutput` listener.

## Expected Behavior

- Terminal output is collected in `string[]` arrays and joined once at
the end, reducing intermediate allocations from O(n²) to O(n)
- `PseudoTtyProcess.onExit` now passes `terminalOutput` as a second
argument, matching the signature of other `RunningTask` implementations
- `TaskOrchestrator` no longer needs a special code path for
`PseudoTtyProcess` — unified `onExit` handling for all task types
- `tui-summary-life-cycle` accumulates output in chunks during execution
and stores the finalized string on task completion, allowing chunk
arrays to be GC'd
- `SeriallyRunningTasks` and `RunningNodeProcess` similarly switched to
chunk-based accumulation
- `BatchProcess` and `NodeChildProcessWithNonDirectOutput` lazily join
and cache their terminal output
2026-02-18 19:05:41 -05:00
Caleb Ukle 42b534366d docs(nx-dev): tech intro page structure improvements (#34450)
Work on making a tech intro pages more consistent with each other and
focus on "answering the 80%" for the given technology.

Focusing on 
- Angular
- Maven/Gradle
- react
- TS
- Vite
- Vitest/Jest

The changes are based around answering the following, where each
"category" of page might have a different set of depth for the answer.

1. Why do I want to use this plugin?
- Plugins are considered fully optional and are aimed at providing
better DX for a technology, such as inferred setup, generators,
migrations.
- some plugins (like TSC) might have special call outs in some of this,
but generally the same for all plugins.
2. How do I use this plugin in my workspace?
  - also pretty commonly the "same" for all plugins in terms of "setup"
- where they differ is mostly for frameworks, e.g. Angular, React.
You're looking at setting up a project to use these tools
- For Build/Test tools you're looking at adding to an existing project,
or converting from one to another.
- Build/Test tools are "means to an end", so should callout if the goal
is tool + framework in a "new" context point to the framework based
plugin page. Otherwise, show adding to an existing project like React
project.
3. What do I need to know about using this plugin?
- understanding finer details of a plugin options, e.g. buildable &
publishable
  - extra generators for the plugin. e.g. "convert-to-swc"
- generally I like the idea of having a "CI considerations" where we
talk about CI setups that can help, e.g. options or batch mode etc.


closes DOC-407

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2026-02-18 22:25:23 +00:00
Caleb Ukle 7528cc51fa fix(nx-dev): update breadcrumb links to match sidebar (#34500)
navigation of the breadcrumbs could lead to confusing state since they
were based around the folder structure.

Breadcrumbs are now based around the sidebar structure so they match the
hierarchy of content.

Note: I left the existing index file based route pages in place in case
there are any links people have booked marked/linked to in other
locations. these will get cleaned up when we finally rewrite all the
URLs to their new content locations
2026-02-18 22:23:00 +00:00
Caleb Ukle bbb1baa631 fix(nx-dev): widen search dialog (#34504) 2026-02-18 22:02:18 +00:00
Leosvel Pérez Espinosa 91b350efa8 fix(core): skip stale recomputations and prevent lost file changes in daemon (#34424)
## Current Behavior

When file changes arrive rapidly, the daemon triggers multiple
concurrent project graph recomputations that all run to completion —
wasting CPU/memory on redundant work and returning stale results.

Additionally, after processing file changes, the daemon clears all
tracked files indiscriminately. Files that changed mid-recomputation are
silently lost and never reflected in the project graph until another
unrelated file change arrives.

## Expected Behavior

Stale recomputations detect when a newer one has started and exit early,
chaining to the newer promise so callers always get the freshest result.

File change tracking now uses versioned maps. Each batch of file watcher
events gets a unique version, and only files matching the snapshotted
version are cleared after processing. Files that changed
mid-recomputation are preserved and picked up by the next cycle.
2026-02-18 16:18:43 -05:00
Jason Jean 50ca951540 fix(repo): fix e2e CI failures from Node 22.12 incompatibility (#34501)
## Current Behavior

Two categories of e2e CI failures were observed in run
https://github.com/nrwl/nx/actions/runs/22127884259:

1. **`e2e-nx-init` and `e2e-js` fail on Node 22.12.0** with:
   ```
error eslint-visitor-keys@5.0.0: The engine "node" is incompatible with
this module.
   Expected version "^20.19.0 || ^22.13.0 || >=24". Got "22.12.0"
   ```
Node 22.12.0 is one minor version short of the `^22.13.0` range required
by `eslint-visitor-keys@5.0.0`.

2. **`e2e-nx` tests fail because `[isolated-plugin]` / `[plugin-worker]`
verbose messages leak into captured stdout**, causing:
- `JSON.parse(runCLI('show project --json'))` to throw `SyntaxError:
Unexpected token 'i', "[isolated-p"...`
- `expect(runCLI('show projects')).toEqual('')` to fail with worker
spawn noise
- The `@nx/workspace:infer-targets` test to unexpectedly find
`@nx/remix` in output (from a worker spawn message)

Root cause: in `isolated-plugin.ts`, the plugin worker's stdout was
piped directly to `process.stdout`, so `[plugin-worker]` verbose
messages written by the worker ended up in the stdout captured by
`runCLI` in e2e tests.

## Expected Behavior

1. The CI matrix uses a Node 22.x version that satisfies `^22.13.0`.

2. Plugin worker verbose/diagnostic messages go to `process.stderr` (not
`process.stdout`), so they don't contaminate output captured by `runCLI`
in e2e tests. Both worker stdout and stderr now pipe to
`process.stderr`, and the max listener bump is consolidated to `+2` on
stderr.

## Related Issue(s)

N/A — identified from CI run
https://github.com/nrwl/nx/actions/runs/22127884259
2026-02-18 15:48:03 -05:00
MaxKless 18bfb0bc4a fix(maven): write output after each task in batch mode to ensure correct files are cached (#34400)
## Current Behavior
When running in maven 4 batch mode, the build state is recorded only
after the full batch is done.
This means that nx caching records the state of a task before build
state is recorded to disk.
When running another maven task that depends on this partially recorded
cache, the build state file is missing and we get errors.

## Expected Behavior
build state should be recorded after every task is done and before nx
caching can kick in. This way we can ensure that nx cache is correct.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 11:22:18 -05:00
Eric Baer 3b0fb81570 feat(devkit): add NX_SKIP_FORMAT environment variable to skip Prettier formatting (#34336)
## Current Behavior

When running generators or migrations, Nx automatically skips Prettier
formatting if no root Prettier config is detected (added in #30426).
However, there's no way to explicitly skip Prettier formatting when a
config IS present but the user wants to bypass it for specific
operations.

This can be needed when:
- When running something like Oxfmt that may treat prettier slightly
differently, even with the same config (this is the main thing I ran
into)
- Running migrations where Prettier reformatting causes unintended side
effects (e.g., breaking `eslint-disable` comments)
- Temporarily disabling formatting for debugging purposes
- Using a formatter that coexists with Prettier in the workspace but
should take precedence for certain files

## Expected Behavior

Users can set `NX_SKIP_FORMAT=true` to explicitly skip Prettier
formatting in generators and migrations, regardless of whether Prettier
is configured. TSConfig path sorting (controlled by
`sortRootTsconfigPaths` or `NX_FORMAT_SORT_TSCONFIG_PATHS`) continues to
work independently.

```bash
NX_SKIP_FORMAT=true nx migrate --run-migrations
NX_SKIP_FORMAT=true nx g @nx/react:app my-app
```

## Related Issue(s)

Related to #30403 and #30426. This enhancement adds explicit user
control for cases where auto-detection of Prettier configuration isn't
sufficient.
2026-02-18 09:56:43 -05:00
Craigory Coppola bdbc14902e feat(core): add --otp to top-level nx release command and detect EOTP errors (#34473)
## Current Behavior
When publish fails due to missing OTP code, its not clear as a user who
is using the top level command what to do next.

## Expected Behavior
Add the --otp flag to the top-level `nx release` command so users can
provide a one-time password for 2FA-enabled registries when running the
full release orchestration (version + changelog + publish).

When publish fails due to an expired or missing OTP (EOTP error),
display a helpful warning listing affected projects and the exact
command to re-run the publish step in isolation with a new OTP.

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

Fixes #
2026-02-18 08:05:40 -05:00
MaxKless dc6716828b feat(core): improve codex support for configure-ai-agents (#34488)
Codex has only basic MCP/AGENTS.md support right now. Also, because it
used to have only global-level config files, we had some extra logic
around configuring that.

We want Codex to get the latest skills too (they don't support custom
subagents yet, though) and use project-level config files that they now
support.
2026-02-18 20:14:27 +09:00
MaxKless 8de74d0984 feat(core): implement configure-ai-agents outdated message after tasks (#34463)
After running nx build (or any task), the daemon now shows a hint if
your AI agent configuration is outdated: "Your AI agent configuration is
outdated. Run nx configure-ai-agents to update."

The daemon computes and caches the full agent configuration status
(fully configured, outdated, partially configured, non-configured) using
latest Nx from npm, so the check is always against the newest available
configuration. Running nx configure-ai-agents resets the daemon's cache
so the message disappears on the next build.

  Key changes

- Daemon agent status endpoint: New GET_CONFIGURE_AI_AGENTS_STATUS /
RESET_CONFIGURE_AI_AGENTS_STATUS message types. The handler fires off
computation in the background and returns immediately (never blocks the
request). Results are cached for the daemon's lifetime.
- Shared latest-nx module: Extracted the "install nx@latest to tmp"
logic from nx-console-operations into daemon/server/latest-nx.ts so both
Nx Console and AI agents handlers share a single cached installation.
Includes a race-condition guard (in-flight promise deduplication).
- Post-task outdated hint: run-command.ts queries the daemon after task
execution and prints a single dim line if agents are outdated.
- Daemon reset from configure-ai-agents: The CLI sets NX_DAEMON=false
for configure-ai-agents, so we bypass daemonClient.enabled() and use
isServerAvailable() directly to reach an already-running daemon. The
socket is closed in a finally block so the process exits cleanly.
- Async editor detection (Rust): Made isEditorInstalled,
canInstallNxConsoleForEditor, installNxConsole, and related napi
functions async so they run on the libuv thread pool instead of blocking
Node's event loop. This prevents the daemon from stalling for ~3.5s when
checking editor extensions.
- output.logRawLine: New helper that prints a single line without the NX
prefix.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-02-18 18:53:41 +09:00
MaxKless b89c3084e7 feat(core): automatically set up ai agents in cnw/init when run from within an ai agent (#34469)
We want to minimize prompts for people and agents. But we also want to
help them by setting up nx config for them so their agents can work
optimally.
If they're executing `nx init` or `create-nx-workspace` from within an
agent, it's a reasonable assumption that they'll want the best AI config
for that specific agent - so we set it up for them.
2026-02-18 18:10:13 +09:00
Simon Heather bdf6d257b7 docs(core): add cacheKeyPrefix option to s3 remote cache options (#34157)
This pull request updates the documentation for the S3 cache plugin to
add the missing `cacheKeyPrefix` setting.

Text taken from https://github.com/nrwl/nx/pull/31395

Fixes #34147

---------

Co-authored-by: Caleb Ukle <caleb@nrwl.io>
Co-authored-by: Caleb Ukle <caleb.ukle+github@pm.me>
Co-authored-by: Simon Heather <simon.heather@yulife.com>
2026-02-17 22:24:35 -05:00
Leosvel Pérez Espinosa 678cd321f5 fix(core): replace buggy ignore-files trie with correct path-component gitignore matching (#34447)
## Current Behavior

The `nx watch` file watcher uses the `ignore-files` and
`watchexec-filterer-ignore` crates to handle `.gitignore` matching.
These crates use a trie-based approach that has a bug with
path-component matching — certain gitignore patterns (e.g., prefix
patterns) don't match correctly, causing files that should be ignored to
trigger unnecessary watch events.

## Expected Behavior

Gitignore patterns are matched correctly using per-directory `Gitignore`
instances from the `ignore` crate — the same crate already used by the
file walker. Each `.gitignore` file is scoped to its directory, and
matching is done deepest-first so that nested gitignores take priority —
matching standard git behavior.

### What changed

- Replaced `ignore-files` + `watchexec-filterer-ignore` with direct use
of `ignore::gitignore::{Gitignore, GitignoreBuilder}`, aligning the
watcher with the approach already used by the file walker
- Each `.gitignore` is now compiled as a standalone instance tied to its
parent directory
- Gitignore evaluation walks deepest-first; first match wins
- `.nxignore` matching now uses `matched_path_or_any_parents` for
correct ancestor checking
- `create_filter` is now synchronous (no longer `async`) since the new
approach doesn't need async I/O
- Removed 2 crate dependencies (`ignore-files`,
`watchexec-filterer-ignore`)
2026-02-17 18:30:22 -05:00
Jay Bell a0e34557f9 fix(core): use workspace root for path resolution when baseUrl is not set (#34453)
## Current Behavior
                                                            
When a project-level `tsconfig.json` (e.g., `apps/aurora/tsconfig.json`)
inherits `paths` via `extends` from `tsconfig.base.json` at the
workspace root and no explicit `baseUrl` is set, Nx incorrectly resolves
`./`-prefixed path mappings relative to the project tsconfig directory
instead of the workspace root where the paths were defined.
This causes errors when loading TypeScript config files (e.g.,
`rspack.config.ts`) that import workspace libraries using path aliases:
  NX   Cannot find module './libs/plugins/rspack/src'

`@swc-node/register`'s `readDefaultTsConfig` auto-sets `baseUrl` to
`dirname(tsConfigPath)` (the project directory) when not explicitly
configured, causing SWC to rewrite imports to incorrect relative paths
during transpilation.

  ## Expected Behavior

Path aliases defined in `tsconfig.base.json` (e.g.,
`"@trellis/plugins/rspack": ["./libs/plugins/rspack/src/index.ts"]`)
should resolve relative to the workspace root when no `baseUrl` is
configured.

This is needed so that when using `tsgo` and needing to prefix all paths
with `./` (no more `baseUrl` allowed) the paths are still resolved from
the right spot.

I tested this fix against our codebase on the branch I was trying to
switch to tsgo on and it seemed to work.

  ## Related Issue(s)

Fixes
https://discord.com/channels/1143497901675401286/1471627045694865581
2026-02-17 18:22:07 -05:00
Altan Stalker 5c7c9dd5fa chore(core): enable continuous assignment (#34471)
## Current Behavior
Continuous assignment is not enabled

## Expected Behavior
Continuous assignment is enabled
2026-02-17 18:17:15 -05:00
Juri Strumpflohner 4f31277f4f docs(repo): update CONTRIBUTING.md with Discord link (#34461)
## Current Behavior

CONTRIBUTING.md contains an outdated "How to Get Started Video" section
and references Stack Overflow for general questions.

## Expected Behavior

Remove outdated video section and point users to the Discord community
instead of Stack Overflow for general questions.

## Related Issue(s)

N/A
2026-02-17 18:15:38 -05:00
Colum Ferry c16377af25 feat(misc): use caret range for swc dependencies in pnpm catalog (#34487)
Use a range for the swc dependencies

Fixes #34472
2026-02-17 18:14:17 -05:00
Craigory Coppola 130cec466f fix(core): avoid blocking event loop during TUI PTY resize (#34385)
When switching from inline mode to full-screen TUI (or during window
resize), the PTY resize operation reparsed ALL raw terminal output
through a new vt100 parser synchronously on the event loop. For tasks
with large output, this caused a noticeable hang.

Add `resize_async()` which moves the expensive reparse to a background
thread using a snapshot-and-replay pattern:
1. Quick snapshot of raw output (brief read lock)
2. Expensive reparse on background thread (no locks held)
3. Quick swap with replay of any new output (brief write lock)

A generation counter prevents stale resizes from overwriting newer ones.

Also combine two separate O(n) scrollback processing calls in inline
mode into a single pass.
2026-02-17 18:07:43 -05:00
Copilot 65b94a1293 chore(repo): update copyright year to 2026 and refresh README description (#34437)
## Current Behavior

Copyright year shows 2017-2025 and README uses older tagline.

## Expected Behavior

Copyright reflects current year 2026 and README uses updated repository
description.

## Changes

- **LICENSE**: Updated copyright year from `2017-2025` to `2017-2026`
- **README.md**: Replaced heading and description
- New heading: "The Monorepo Platform that amplifies both developers and
AI agents. Nx optimizes your builds, scales your CI, and fixes failed
PRs automatically. Ship in half the time."
  - Removed redundant description line below heading

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> ## Update License and README
> 
> Please make the following changes:
> 
> 1. **Update LICENSE file**: Change the copyright year from `2017-2025`
to `2017-2026`
>    - File: `LICENSE`
> - Line 3: Update `Copyright (c) 2017-2025 Narwhal Technologies Inc.`
to `Copyright (c) 2017-2026 Narwhal Technologies Inc.`
> 
> 2. **Update README.md description**: Replace the current description
with the repository's official description
>    - File: `README.md`
> - Line 22: Change the heading from `# Smart Monorepos · Fast Builds`
to `# The Monorepo Platform that amplifies both developers and AI
agents. Nx optimizes your builds, scales your CI, and fixes failed PRs
automatically. Ship in half the time.`
> - Line 24: Remove the current description line: `Get to green PRs in
half the time. Nx optimizes your builds, scales your CI, and fixes
failed PRs. Built for developers and AI agents.`
> 
> The new README should have the repository description as the main
heading, followed immediately by the "Create a new Nx workspace with"
section.


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FrozenPandaz <8104246+FrozenPandaz@users.noreply.github.com>
Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
2026-02-17 16:45:38 -05:00
Leosvel Pérez Espinosa 896a3f31ad fix(core): gate tui-logger init behind NX_TUI env var (#34426)
## Current Behavior

`tui_logger::init_logger()` and `TuiTracingSubscriberLayer` are
initialized unconditionally in `initialize_logger()`. This spawns a
background thread, causing unnecessary allocation churn and increased
processing.

## Expected Behavior

`tui_logger` is only initialized when `NX_TUI=true`, avoiding the
background thread and allocation overhead for all non-TUI contexts.
2026-02-17 16:40:48 -05:00
Caleb Ukle ea81b52442 chore(nx-dev): condense redirect rules (#34452)
## Current Behavior

We have ~1,657 redirect rules across `redirect-rules.js` and
`redirect-rules-docs-to-astro.js`, getting close to Netlify's limit and
we need room for more as the Astro migration continues.

## Expected Behavior

Reduced to **1,139 rules** (~31% reduction) by:

- Resolving duplicate/conflicting source paths across sections
- Flattening multi-hop redirect chains to point directly to final
destinations
- Consolidating groups of individual rules into wildcard patterns
(tutorials, CLI, helm, concepts, recipes, etc.)
- Removing old 2022-era sections (`schemaUrls`, `overviewUrls`,
`packagesIndexes`, `packagesDocuments`) whose destinations chain 3-5
hops deep and are long superseded by newer redirects
- made sure old links in nx code base still have redirects (will update
in future PR)

Build, tests, and internal link check all pass with no issues.

## Related Issue(s)

Fixes DOC-403

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
2026-02-17 11:21:33 -06:00
Caleb Ukle edc9cc5af8 fix(nx-dev): use shared preview url for netlify deploy (#34467)
nextjs and astro should route to same preview deployments now


![wm_2026-02-16T19-40-04](https://github.com/user-attachments/assets/593c011a-ff78-4412-9bf0-ad186157f5d4)
2026-02-17 11:21:24 -06:00
Jack Hsu 2fa93afe2b feat(core): add agentic mode to nx init (#34418)
## Current Behavior

When AI agents (Claude Code, Cursor, Windsurf, etc.) run `nx init`, the
command works but:
- Uses interactive prompts that AI agents can't handle
- Outputs human-readable text that AI agents must parse
- Doesn't provide structured progress or error information

## Expected Behavior

When `nx init` detects an AI agent (via environment variables like
`CLAUDE_CODE=1`), it should:
- Skip interactive prompts and use sensible defaults
- Output structured NDJSON for progress updates, success, and errors
- Include detailed context for AI agents to understand and fix issues

## Changes

This PR adds agentic mode to `nx init`:

### `nx init` Changes
- Detect AI agents via `isAiAgent()` native function
- Auto-defaults: `interactive=false`, `nxCloud=false`, auto-detect `.nx`
installation
- NDJSON output with `type: progress|success|error`
- Error logs written to `.nx/ai-errors/` with full context
- Cursor restoration escape sequence skipped for AI agents (prevents
NDJSON corruption)

### Output Format
```jsonl
{"type":"progress","step":"starting","message":"Initializing Nx..."}
{"type":"success","nxVersion":"22.5.0","projectsDetected":1,"pluginsInstalled":["@nx/vite"]}
```

Or on error:
```jsonl
{"type":"error","message":"Failed to install","code":"INSTALL_ERROR","errorLogPath":".nx/ai-errors/nx-init-error-2025-01-15T10-30-00.log"}
```
2026-02-18 01:54:04 +09:00
MaxKless ee22084d1a fix(core): only pull configure-ai-agents from latest if local version is not latest (#34484)
## Current Behavior
we pull from latest all the time even if the current version is already
latest

## Expected Behavior
we can skip this extra work sometimes
2026-02-17 16:30:34 +00:00
Jack Hsu ca2fc0fa85 fix(misc): rewrite Framer URLs to nx.dev in HTML responses (#34445)
## Current Behavior

Pages proxied from Framer contain canonical URLs pointing to the Framer
domain (`ready-knowledge-238309.framer.app`), causing duplicate indexing
issues in search engines.

## Expected Behavior

Canonical URLs and other references in Framer-proxied pages now point to
`nx.dev`, ensuring proper SEO indexing.

### Implementation

Consolidated all Framer logic into a single Netlify edge function
(`rewrite-framer-urls.ts`) that:

1. Checks if the request path matches a Framer-proxied path (using
`FRAMER_REWRITES` env var)
2. Fetches directly from Framer (using `FRAMER_URL` env var)
3. Rewrites all Framer URLs to `nx.dev` in the HTML response (handles
`<link rel="canonical">`, `og:url`, etc.)
4. For non-Framer paths, passes through to Next.js

The edge function uses the `accept: ['text/html']` config to only run on
HTML requests, matching the pattern from `track-page-requests.ts` in
astro-docs.

The Next.js middleware has been removed since all Framer routing is now
handled by the edge function.

### Environment Variables

The edge function expects these env vars in Netlify (already added
previously):
- `NEXT_PUBLIC_FRAMER_URL`: e.g.,
`https://ready-knowledge-238309.framer.app`
- `NEXT_PUBLIC_FRAMER_REWRITES`: comma-separated list of paths, e.g.,
`/pricing,/enterprise`

## Demo

1. Go to https://deploy-preview-34445--nx-dev.netlify.app/
2. View source and look for canonical
3. See it is nx.dev not framer domain

<img width="1347" height="161" alt="image"
src="https://github.com/user-attachments/assets/d4a515da-e39f-41cb-a7b4-668fe0bedbbd"
/>


## Related Issue(s)

Closes CLOUD-4148
2026-02-17 10:53:46 -05:00
Steven Nance 0c14bcbe55 fix(release): remove unnecessary number from release return type (#34481)
## Current Behavior

The `release` function returned by `createAPI` has a return type of
`Promise<NxReleaseVersionResult | number>`. The `| number` union member
is inaccurate since the function always returns
`NxReleaseVersionResult`, which can mislead consumers of the
programmatic API.

## Expected Behavior

The return type is narrowed to `Promise<NxReleaseVersionResult>`,
accurately reflecting what the function actually returns and giving API
consumers correct type information.

Co-authored-by: Andreas Hörnicke <andreas.hoernicke@contentful.com>
2026-02-17 15:10:11 +00:00
MaxKless 08d899a2d2 docs(misc): update nx-mcp reference and tweak ai docs for skills (#34468)
we changed the default options of the nx mcp so we need to update docs
to reflect it
2026-02-17 22:23:39 +09:00
MaxKless 0d4160e968 docs(nx-dev): add MCP to skills blog post (#34428)
Blog post draft about the evolution from MCP tools to agent skills.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: MaxKless <MaxKless@users.noreply.github.com>
Co-authored-by: Juri Strumpflohner <juri.strumpflohner@gmail.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2026-02-17 09:28:34 +00:00
Craigory Coppola 8c15428f43 feat(core): support dependency filesets with ^{projectRoot} syntax (#34310)
## Current Behavior
`^` and `dependencies: true` only work for fileset inputs

## Expected Behavior
Adds support for inputs of the form `^{projectRoot}/**/*.ts` as
syntactic sugar for specifying a fileset input that should be collected
from dependency projects.

Previously, only named inputs could use the `^` prefix to include
dependencies (e.g., `^production`). Now filesets can also use this
syntax directly without needing to define a named input first.

Examples:
- `^{projectRoot}/**/*.ts` - include .ts files from all dependencies
- `^{workspaceRoot}/tools/**/*` - include workspace tools from
dependencies
- `{ fileset: '{projectRoot}/**/*.ts', dependencies: true }` - object
form

Detection is deterministic: if the string after `^` starts with
`{projectRoot}` or `{workspaceRoot}`, it's treated as a dependency
fileset; otherwise, it's treated as a named input reference.

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

Fixes #
2026-02-16 21:25:55 -05:00
Leosvel Pérez Espinosa 59b12edcb6 fix(core): prevent staggered and duplicate lines in dynamic output (#34462)
## Current Behavior

- In some `nx run-many` executions, terminal output can appear staggered
or visually misaligned instead of updating cleanly in place.
- For `run-many` cases that end up running a single task (especially
when TUI is not active), the spinner/status line can be rendered twice.

## Expected Behavior

- Dynamic terminal output updates should remain stable and aligned, with
clean in-place refreshes.
- Single-task `run-many` should display a single spinner/status line
with no duplicate rendering.
2026-02-16 17:31:07 +00:00
Juri dd3b79ebf4 fix(core): handle Ctrl+C gracefully in configure-ai-agents
Add uncaughtException handler for ERR_USE_AFTER_CLOSE to prevent
ugly stack trace when pressing Ctrl+C during enquirer prompts
(Node 24 stricter readline behavior). Matches existing pattern
used in nx init and create-nx-workspace.
2026-02-16 12:57:17 +01:00
Jason Jean d64e41dd99 fix(repo): revert sudo for global npm install in publish workflow (#34451)
## Current Behavior

The publish workflow uses `sudo npm install -g npm@11.5.2` which was
added in #34409. This causes issues with OIDC token permissions in the
release pipeline since `sudo` runs as a different user context.

## Expected Behavior

The publish workflow should use `npm install -g npm@11.5.2` without
`sudo`, matching the standard approach used elsewhere and avoiding
permission context issues during release.

## Related Issue(s)

Reverts #34409
2026-02-13 15:53:32 -05:00
Jack Hsu f5769f0bfb docs(misc): minor fixes for docs (#34449)
1. Consistent punctuation on intro page (periods at end of bullet
points).
2. Adjust AI detection for edge function.
2026-02-13 15:44:31 -05:00
Craigory Coppola 292a21319d feat(core): add --stdin to affected options (#34435)
- **feat(core): add `--stdin` to affected options**
- **fix(core): use newline-delimited stdin and add TTY guard for --stdin
option**

Supercedes #28770

Co-authored-by: @aaronccasanova

---------

Co-authored-by: Aaron Casanova <aaron.casanova@shopify.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
2026-02-13 15:17:38 -05:00
Jason Jean c5e1bedca2 fix(repo): replace addnab/docker-run-action with direct docker run (#34448)
## Current Behavior

The publish workflow uses `addnab/docker-run-action@v3` which is based
on `docker:20.10` (Docker API 1.41). GitHub's `ubuntu-24.04` runners now
ship Docker Engine 28.x which requires minimum API version 1.44, causing
all 4 Linux Docker builds to fail:

```
docker: Error response from daemon: client version 1.41 is too old. Minimum supported API version is 1.44, please upgrade your client to a newer version.
```

Failed run: https://github.com/nrwl/nx/actions/runs/21961139962

## Expected Behavior

Linux Docker builds (x86_64-gnu, x86_64-musl, aarch64-gnu, aarch64-musl)
complete successfully using the host's modern Docker CLI.

https://github.com/nrwl/nx/actions/runs/21996143819

## Related Issue(s)

The `addnab/docker-run-action` repo is abandoned (last release March
2021, last commit May 2021) with open issues about this exact problem.
2026-02-13 12:42:30 -05:00
Jack Hsu c0540c8846 docs(misc): improve AX for getting started pages (#34410)
## Current Behavior

Getting started pages had overlapping content and unclear focus:
- `installation.mdoc` mentioned CNW and tutorials (belongs elsewhere)
- `start-new-project.mdoc` had manual setup option (belongs on
add-to-existing)
- `start-with-existing-project.mdoc` duplicated CI examples, editor
buttons, Nx Cloud walkthrough
- `intro.mdoc` mixed messaging - some "challenges" were polyrepo
problems

## Expected Behavior

Each page is now focused with no duplication:

### intro.mdoc
- Clear problem/solution structure following Turborepo's approach
- Problem: concise (builds get slow as codebase scales)
- Solution: caching, task orchestration, affected commands
- **Removed**: Polyrepo problems from challenge list (code sharing, lost
context)
- **Removed**: Lengthy deepdive callouts
- Net reduction: 67 deletions, 14 insertions

### installation.mdoc
- Global install (npm/brew/choco/apt) + verification step
- Local install (`nx init`) for existing repos
- Update instructions
- **Removed**: CNW mention, tutorials section, "More Documentation"

### start-new-project.mdoc
- Option 1: Create locally with templates (`create-nx-workspace`)
- Option 2: Create via Nx Cloud (browser-based)
- **Removed**: Manual setup option (that's for existing projects)
- Updated terminology: "presets" → "templates"

### start-with-existing-project.mdoc
- Focused: `nx init` → run tasks → see caching → explore graph
- Links to other pages instead of duplicating content
- **Removed**: CI config examples, Nx Cloud walkthrough, editor buttons

### editor-setup.mdoc
- Added problem hook explaining why editor integration matters
- Clarified Neovim is community-maintained

### ai-setup.mdoc
- Added problem hook about AI hallucination without workspace context
- Explained MCP acronym (Model Context Protocol)
- Clarified "Ralph Wiggum loop" terminology

### sidebar.mts
- Reordered to match natural flow: Installation → Start New/Add Existing
→ Editor/AI

## Related Issue(s)

Closes DOC-405

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2026-02-13 11:09:21 -05:00
Craigory Coppola ece9b5bf4a fix(core): remove shellapi from winapi featureset to minimize AV false positives (#34208)
## Current Behavior
There's a chance that windows can falsely flag our native binaries as a
threat. We do not use the shellapi feature from winapi.

## Expected Behavior
We hope that removing this API doesn't break things, and the threat
messaging goes away

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

Fixes #https://github.com/nrwl/nx/issues/34186

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-02-12 19:32:58 -05:00
Craigory Coppola 51420790c3 chore(repo): improve copy-built-package script (#34432)
Makes copy-built-package script a bit more ergonomic and discoverable.
Adds some interactive UI for picking package / repo if they are not
specified.
2026-02-12 16:49:51 -05:00
Craigory Coppola c407de6e2b fix(core): hitting [1] or [2] should remove pinned panes if they match the current task (#34433)
## Current Behavior

Pressing `[1]` or `[2]` on a task that's already pinned to that slot
**focuses** the pane instead of unpinning it. This means there's no way
to unpin a single pane via keyboard — you can only nuke everything with
`[0]`.

This regression was introduced in #34175, which fixed a real problem:
pressing Enter on an already-pinned task would unpin it, leaving focus
on an invisible pane (a ghost pane — you're staring at nothing but the
TUI thinks you're looking at output). The fix was to make the "already
pinned to this pane" branch focus instead of unpin. The problem is that
`[1]`, `[2]`, and Enter all flowed through the same function
(`assign_current_task_to_pane`), so changing behavior for Enter changed
it for everyone. One lock got swapped out, and every door started
behaving the same way.

## Expected Behavior

`[1]` and `[2]` are **toggles**: press once to pin, press again to
unpin. Enter is a **display** action: show me this task's output and put
my cursor there — if it's already visible somewhere, just take me to it.

After this change:

- **`[1]` / `[2]`** on an already-pinned task → unpins it (pane
disappears, layout adjusts, focus returns to task list if no panes
remain)
- **Enter** on an already-pinned task → focuses whichever pane it's in
(even if it's in pane 2 and you'd normally expect pane 1)
- **Init** (startup restore of pinned tasks) → pure assignment, no
toggling, no focusing

## Approach

The old code had one function trying to serve three masters. Rather than
adding a flag parameter (`should_toggle: bool`) — which would just be a
boolean that lies about its intentions at every call site — the function
was split along the actual semantic boundaries:

| Function | Used by | "Already pinned here" behavior |
|---|---|---|
| `toggle_current_task_in_pane` | `[1]` / `[2]` keys | **Unpin** (toggle
off) |
| `assign_current_task_to_pane` | `init()` | No-op (task is where it
should be) |
| `display_and_focus_current_task_in_terminal_pane` | Enter key |
**Focus** the existing pane |

The shared logic — exiting spacebar mode, moving a task between panes,
fresh-pinning — lives in two small helpers (`exit_spacebar_and_pin`,
`move_or_pin_selection`) that both `toggle` and `assign` delegate to.
The only code that differs is the "what do we do when it's already
here?" branch, which is exactly the part that *should* differ.

**Why not keep one function with a mode parameter?** Because the three
behaviors aren't variations of the same action — they're genuinely
different user intents. A toggle is "I changed my mind." A focus is
"Take me there." An assignment is "Put this here." Encoding that as an
enum parameter just moves the branching somewhere less obvious and makes
the call sites harder to read. The function names now document the
intent at the point of use, and there's no shared state to accidentally
couple.

**Why does Enter check all panes, not just pane 0?** Because if you
pinned a task to pane 2 via `[2]` and then press Enter on it, the least
surprising thing is to jump to where it already lives — not to silently
duplicate it into pane 1 or ignore you. The task is already on screen;
Enter means "show me."

## Related Issue(s)

Fixes the regression introduced by #34175.
2026-02-12 16:21:29 -05:00
Jack Hsu 950265fc8c feat(misc): lock in CNW variant 2 with deferred connection (#34416)
## Current Behavior

CNW (Create Nx Workspace) has A/B testing logic that randomly selects
between variants 0, 1, and 2 for the Nx Cloud connection flow. Each
variant shows different prompts and banners.

## Expected Behavior

Lock in variant 2 as the permanent behavior:
- **No cloud prompt** - users are not asked about Nx Cloud during
workspace creation
- **Deferred connection** - no `nxCloudId` is written to `nx.json` (uses
`skipCloudConnect: true`)
- **Variant 2 banner** - shows "Enable remote caching and automatic
fixes when CI fails" with a link to complete setup later

### Changes
- Simplified `ab-testing.ts` - removed caching, random selection;
`getFlowVariant()` always returns `'2'`
- `shouldShowCloudPrompt()` always returns `false`
- `determineNxCloudV2()` returns `'github'` with `skipCloudConnect:
true` for deferred connection
- Removed variant 1 banner logic from `messages.ts`
- Updated tests to reflect the locked-in behavior

## Demo

https://www.loom.com/share/7f688eed6052428cbe91dd9db837cbbd

## Related Issue(s)

Closes CLOUD-4255

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 16:05:28 -05:00
Benjamin Cabanes 28fea0db0c docs(nx-dev): replace global ID with deterministic target ID for HBST (#34431)
Simplified form targeting by replacing the global `reactHubspotForm` ID
with a deterministic `targetId` that incorporates portal, form, and
calendly IDs. This improves scalability and avoids potential ID
collisions.
2026-02-12 14:03:02 -05:00
Benjamin Cabanes b5c3663126 docs(nx-dev): add back inline script (#34429) 2026-02-12 12:56:17 -05:00
MaxKless a757f40d83 fix(maven): correctly map between maven locators and nx project names (#34366) 2026-02-13 01:42:31 +09:00
Jack Hsu 7a4e052533 chore(misc): add banner content monitor workflow (#34417)
## Current Behavior

When banner content changes in Framer, the nx-docs and nx-dev sites need
to be manually redeployed to pick up the new content.

## Expected Behavior

A scheduled workflow monitors the banner URL every 15 minutes and
automatically triggers Netlify production deploys when content changes.

## How it works

1. Fetches `BANNER_URL` content (from repository variable)
2. Computes SHA256 hash
3. Compares to cached hash from previous run
4. If different → triggers both Netlify deploys, updates cache
5. If unchanged → no-op

## Required Setup

1. **Repository variable** (`Settings → Secrets and variables → Actions
→ Variables`):
   - `BANNER_URL` = Framer banner API URL

2. **Repository secret** (`Settings → Secrets and variables → Actions →
Secrets`):
   - `NETLIFY_AUTH_TOKEN` = Netlify personal access token

## Related Issue(s)

Fixes DOC-405
2026-02-12 10:37:47 -05:00
Juri 9a57042cbe docs(nx-dev): add Nx AI agent skills blog post 2026-02-12 16:28:57 +01:00
Steven Nance 754b01a066 feat(core): add negation pattern support for plugin include/exclude (#34160)
<!-- 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
Negation patterns are ignored in plugin configuration for the `include`
and `exclude` properties.

## Expected Behavior

- Negation patterns should work in the same way that they do for other
`include`/`exclude` configurations

**Example: Excluding all e2e projects except one**

```jsonc
// nx.json
{
  "plugins": [
    {
      "plugin": "@nx/jest/plugin",
      "exclude": ["**/*-e2e/**/*", "!**/toolkit-workspace-e2e/**/*"],
    },
  ],
}
```

This will exclude all e2e projects except `toolkit-workspace-e2e`.

**Example: Including packages except legacy ones**

```jsonc
// nx.json
{
  "plugins": [
    {
      "plugin": "@nx/vite/plugin",
      "include": ["packages/**/*", "!packages/legacy/**/*"],
    },
  ],
}
```

**How negation patterns work:**

- Patterns are processed in order from first to last
- A pattern starting with `!` removes files from the match set
- A pattern without `!` adds files to the match set
- The last matching pattern determines if a file is included
- If the first pattern is a negation, all files are matched initially

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-12 16:03:20 +01:00
Colum Ferry 5a1735b041 feat(misc): update PLUGIN.md files to help agents verification (#34379)
## Current Behavior
There is currently no plugin.md file for Gradle.
Other plugin.md files can be improved

## Expected Behavior
Add plugin.md file for Gradle to aid with verification with Agents.
Add plugin.md file for Vite for workspaces that have not migrated to
@nx/vitest.

## Related Issue(s)

CLOSES NXC-3843

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Coly010 <Coly010@users.noreply.github.com>
2026-02-12 12:25:10 +01:00
Josh VanAllen a0ff232ad7 feat(testing): add cacheDir option to playwright executor (#34413)
## Current Behavior

The Playwright executor does not support configuring a custom cache
directory for Playwright's internal cache (browser binaries, etc.).
Users who need to control where Playwright stores its cache, for example
in CI environments with specific disk constraints like not being able to
DTE tasks or shared caching setups, have no way to set this through the
executor configuration.

## Expected Behavior

A new `cacheDir` option is available on the Playwright executor. When
provided, it sets the `PWTEST_CACHE_DIR` environment variable on the
forked Playwright process, allowing users to control where Playwright
stores its internal cache.
  ```json
  {
    "targets": {
      "e2e": {
        "executor": "@nx/playwright:playwright",
        "options": {
          "cacheDir": "/tmp/playwright-cache"
        }
      }
    }
  }
  ```

## Related Issue(s)

Replaces #34397

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 17:36:17 -05:00
Jack Hsu 17f2f1bdc6 docs(misc): clarify security email usage in SECURITY.md (#34411)
## Current Behavior

The SECURITY.md file does not clarify what types of reports should be
sent to the security email, leading to reports about outdated
dependencies and vulnerability scanner output.

## Expected Behavior

The file now clarifies that the security email is for demonstrable,
verified vulnerabilities in the Nx codebase itself, not for:
- Outdated dependency reports
- Dependencies with CVEs that don't directly affect Nx
- General vulnerability scanner output

## Related Issue(s)

Fixes NXC-3898

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 15:08:20 -05:00
Jason Jean e48f2f3a8c fix(repo): use sudo for global npm install in publish workflow (#34409)
## Current Behavior

The `npm install -g npm@11.5.2` step in the publish workflow fails with
`EACCES: permission denied, mkdir '/usr/local/share/man/man5'` on newer
GitHub Actions runner images.

## Expected Behavior

The global npm install step completes successfully regardless of runner
image permissions on `/usr/local/share/man/`.

## Related Issue(s)

This is a known issue with GitHub Actions runners:
https://github.com/actions/runner-images/issues/9644
2026-02-11 14:49:43 -05:00
Colum Ferry 7785eae516 feat(core): extract sandbox detection into reusable utility (#34408)
Add isSandbox() utility that checks for sandbox environment variables
(SANDBOX_RUNTIME, GEMINI_SANDBOX, CODEX_SANDBOX, CURSOR_SANDBOX) and
use it to disable the daemon and plugin isolation in sandbox
environments.
2026-02-11 18:33:17 +00:00
Miroslav Jonaš 28c5d95964 fix(nx-dev): clarify project linking for workspaces (#34405)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: meeroslav <meeroslav@users.noreply.github.com>
2026-02-11 16:34:13 +00:00
Caleb Ukle 0e53c3f3d5 fix(nx-dev): add missing nx-cloud intro in sidebar (#34403) 2026-02-11 15:36:12 +00:00
Colum Ferry 6bf8c4693f feat(core): handle agentic sandboxing (#34402)
## Current Behavior
Running ai agents in sandbox mode causes issues with Nx's daemon and
plugin isolation

## Expected Behavior
Running ai agents in sandbox mode should work

## Related Issue(s)

CLOSES NXA-828
2026-02-11 15:12:49 +00:00
Philip Fulcher 8e3cff657b docs(nx-dev): add broadcom success story (#34393) 2026-02-11 09:36:42 -05:00
Colum Ferry 15d508e814 feat(core): add nxVersion to meta in shortUrl for cnw (#34401)
## Current Behavior
We do not include NxVersion when creating short urls.

## Expected Behavior
Include NxVersion when creating short urls. 

## Related Issue(s)

CLOSES NXC-3879
2026-02-11 09:27:03 -05:00
Craigory Coppola 6570674abf fix(core): handle dangling symlinks during cache restore (#34396)
When cache outputs include both glob patterns and directory patterns
containing symlinks, the cache restore fails with EEXIST (os error 17).
This happens because `fs_extra::remove_items` silently skips dangling
symlinks (since `is_dir()`/`is_file()` follow links and return false),
leaving stale symlinks that cause `symlink()` to fail.

The fix makes symlink creation idempotent by checking for and removing
any existing symlink at the destination before creating a new one, using
`symlink_metadata()` which correctly detects dangling symlinks.

Fixes #34013
2026-02-10 17:41:18 -05:00
Jason Jean 2d71d9ac65 fix(maven): use module-level variable for cache transfer between createNodes and createDependencies (#34386)
## Current Behavior

The Maven plugin's `createNodes` and `createDependencies` functions both
independently compute a hash of all pom.xml directories, then use that
hash to look up cached Maven analysis data from disk. When Maven
projects have `<includes>` or `<excludes>` in their plugin config, the
hash can differ between the two calls, causing `createDependencies` to
fail to find the data that `createNodes` stored.

## Expected Behavior

`createDependencies` reliably receives the Maven analysis data from
`createNodes` regardless of hash differences, by reading it from a
module-level variable instead of re-hashing and looking it up from disk.

This matches the pattern already used by the Gradle plugin
(`getCurrentGradleReport`).

## Related Issue(s)
2026-02-10 16:27:51 -05:00
Leosvel Pérez Espinosa f43d2028ff fix(core): make runtime cache key deterministic (#34390)
## Current Behavior

Runtime cache keys could be nondeterministic because the order of
environment variables varied, leading to inconsistent cache hits across
runs.

## Expected Behavior

Runtime cache keys are deterministic regardless of the insertion order
of env variables, improving cache stability.
2026-02-10 15:45:30 -05:00
Leosvel Pérez Espinosa 6c9f0cb46d fix(core): avoid dropping unrelated continuous deps in makeAcyclic (#34389)
## Current Behavior

Cycles in the task graph could remove unrelated `continuousDependencies`
when the cycle exists only in `dependencies`, leading to missing
continuous task edges.

## Expected Behavior

Cycle removal only removes the specific cyclic edge from the list where
it appears, preserving unrelated continuous dependencies.
2026-02-10 15:44:26 -05:00
Caleb Ukle bd13929de8 fix(nx-dev): improve plugin registry visibility (#34395)
- **fix(nx-dev): make sure "plugin registry" shows up in search**
- search ranking will be re-evaled after we work through more content
updates
<img width="768" height="1406" alt="image"
src="https://github.com/user-attachments/assets/e7ca2aff-7daf-417b-ad96-ba6722480432"
/>

- **docs(nx-dev): add plugin registry to footer**
<img width="1076" height="405" alt="image"
src="https://github.com/user-attachments/assets/4c93c5ec-1f64-4cd6-8f88-9347d5009ac9"
/>
2026-02-10 13:13:54 -06:00
Brett Burley f5a7ea1606 fix(core): clean up stale socket files before listening (#34236)
## Current Behavior

When running Nx tasks in CI environments (e.g., Buildkite) where the
host's /tmp is mounted to containers, intermittent EADDRINUSE errors
occur in PseudoIPCServer.init(). This happens because:

1. PseudoIPCServer doesn't clean up its Unix socket file before calling
listen()
2. ForkedProcessTaskRunner.createPseudoTerminal() instantiates
PseudoTerminal directly instead of using the createPseudoTerminal()
helper, bypassing shutdown callback registration

When a new container starts with the same PID as a previous run (PID
recycling), it generates the same socket path and hits EADDRINUSE
because the stale socket file still exists.

## Expected Behavior

No EADDRINUSE errors should occur. The PseudoIPCServer should
defensively remove any stale socket file before attempting to listen,
similar to how the daemon server handles this.

## Related Issue(s)

Fixes #34233
2026-02-10 13:36:34 -05:00
Benjamin Cabanes 9c42292ed8 docs(nx-dev): remove Cookiebot & GA integration, migrate all events to GTM (#34384)
Streamlined analytics tracking by removing Cookiebot and direct GA
(gtag.js) integrations. Consolidated event logging through GTM's
dataLayer for consistency and maintenance simplicity.
2026-02-10 12:17:47 -05:00
Altan Stalker ec0f51ed75 chore(core): enable cloud experimental polling (#34394)
Updated CI behavior
2026-02-10 12:05:20 -05:00
Leosvel Pérez Espinosa 5ae53ecae8 fix(core): use a consistent batch id between scheduler and task runner (#34392)
## Current Behavior

Batch IDs are generated in two places: the task scheduler uses an
incremental counter (`executorName N`) while the forked process task
runner generates its own using the process PID (`executorName-pid`).
This means the batch ID registered in metrics doesn't match the one used
everywhere else.

## Expected Behavior

Batch IDs are only created by the task scheduler. The forked process
task runner uses the scheduler-assigned ID to ensure consistency across
the system.
2026-02-10 11:33:14 -05:00
MaxKless 5066511576 fix(core): make sure that mcp args aren't overridden when running configure-ai-agents (#34381)
## Current Behavior
right now if users modify their mcp params like `--minimal`, we will
override them on `configure-ai-agents`

## Expected Behavior
We want to bring users up to latest without overriding their valid
configurations
2026-02-10 14:24:09 +01:00
Benjamin Staneck 0b6961b0d7 feat(core): update formatting of agent rules documentation (#33356) 2026-02-10 22:22:41 +09:00
Caleb Ukle 089e111fcc docs(nx-cloud): update info about GH permissions (#34380)
https://deploy-preview-34380--nx-docs.netlify.app/docs/enterprise/single-tenant/custom-github-app#configure-permissions-for-the-github-app

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
2026-02-09 12:09:17 -06:00
Jason Jean 93fddd14de chore(repo): update nx to 22.5.0-beta.5 (#34371)
Updating Nx from 22.5.0-beta.4 to 22.5.0-beta.5
2026-02-09 13:00:52 -05:00
Kai Gritun f1873b27a8 fix(core): use --lockfile-only for Bun updateLockFile (#34375)
## Current Behavior

The Bun package manager config uses `--frozen-lockfile` for
`updateLockFile`:

```typescript
updateLockFile: 'bun install --frozen-lockfile',
```

However, `--frozen-lockfile` **prevents** changes to the lockfile,
causing `nx release` to fail when trying to update the lockfile after
version bumps.

## Expected Behavior

Use `--lockfile-only` which generates/updates the lockfile without
installing dependencies:

```typescript
updateLockFile: 'bun install --lockfile-only',
```

This is consistent with other package managers:
- npm: `npm install --package-lock-only`
- pnpm: `pnpm install --lockfile-only`
- yarn berry: `yarn install --mode update-lockfile`

## Background

When Bun support was added in PR #22602 (April 2024), `--lockfile-only`
didn't exist in Bun. Bun has since added this flag.

Closes #34344

Co-authored-by: Kai Gritun <kai@kaigritun.com>
2026-02-09 10:08:19 -05:00
Jason Jean 81c157d063 fix(repo): align pnpm version in CI workflows with package.json (#34370)
## Current Behavior

Several GitHub Actions workflows hardcode pnpm version `10.11.1`, while
`package.json` specifies `pnpm@10.28.2` in the `packageManager` field.
This causes CI failures with:

```
Error: Multiple versions of pnpm specified:
  - version 10.11.1 in the GitHub Action config with the key "version"
  - version pnpm@10.28.2 in the package.json with the key "packageManager"
```

## Expected Behavior

All pnpm version references across CI workflows should match the
`packageManager` field in `package.json` (`10.28.2`).

## Related Issue(s)

N/A — Fixing CI breakage from version mismatch.

## Changes

Updated pnpm version from `10.11.1` → `10.28.2` in:
- `.github/workflows/npm-audit.yml` — `pnpm/action-setup` version
- `.github/workflows/publish.yml` — `PNPM_VERSION` env var and FreeBSD
install
- `.github/workflows/issue-notifier.yml` — `pnpm/action-setup` version
- `.github/workflows/generate-embeddings.yml` — `pnpm/action-setup`
version
2026-02-06 19:45:33 -05:00
Jason Jean 1f5520ebb1 fix(core): add missing FileType import for Windows watcher build (#34369)
## Current Behavior

The Windows build (`aarch64-pc-windows-msvc`) fails to compile with:

```
error[E0433]: failed to resolve: use of undeclared type `FileType`
  --> packages\nx\src\native\watch\types.rs:128:55
```

The `FileType` type is used inside a `#[cfg(target_os = "windows")]`
block but was not imported.

## Expected Behavior

The Windows build compiles successfully. The `FileType` import is scoped
inside the `#[cfg(target_os = "windows")]` block (matching the existing
pattern in the macOS block) so there are no unused imports on any
platform.

## Related Issue(s)

N/A — build breakage discovered during CI publish workflow.
2026-02-06 18:47:18 -05:00
Jason Jean 0aef1ef26f fix(core): reduce daemon inotify watch count by upgrading watchexec (#34329)
## Current Behavior

The daemon's file watcher uses watchexec 3.0.1 which hardcodes
`RecursiveMode::Recursive` when registering inotify watches. This means
**every** directory gets an inotify watch — including all of
`node_modules`, `.git`, and other ignored trees.

On a typical workspace with a large `node_modules`, this can consume
thousands of inotify watches, eating kernel memory and CPU. The
`WatchFilterer` only filters **events** after watches are already
registered — the watches themselves are never prevented.

## Expected Behavior

Only non-ignored directories (workspace source code) get inotify
watches. Ignored directories like `node_modules`, `.git`, `.nx/cache`,
`.nx/workspace-data`, and `.yarn/cache` are skipped entirely at the
watch registration level.

This dramatically reduces:
- **inotify watch count** (from thousands to hundreds)
- **Memory usage** (each watch consumes kernel memory)
- **CPU overhead** (fewer watches = less kernel bookkeeping)

### How it works

- Upgraded watchexec 3.0.1 → 8.0.1 which supports
`WatchedPath::non_recursive()`
- Added `create_watch_walker()` using `ignore::WalkBuilder` (same
pattern as `walker.rs`) to enumerate only non-ignored directories
- Each directory is watched with `NonRecursive` mode — like putting
security cameras only in the rooms you care about instead of every room
in the building
- New directories created at runtime are dynamically added to the watch
set via the `on_action` handler
- Event-level filtering via `WatchFilterer` is unchanged — same behavior
for gitignore/nxignore patterns

### macOS Support for Dynamic Directory Registration

The initial implementation worked on Linux and Windows but failed tests
on macOS because macOS FSEvents doesn't always provide the same
`FileEventKind` tags as Linux inotify or Windows ReadDirectoryChangesW.

**Three changes to support macOS:**

1. **watcher.rs**: On macOS, check all events for directory creation
(not just events with specific FileEventKind tags) and verify via
filesystem
2. **types.rs**: Filter directory events from JavaScript callbacks on
macOS (similar to Windows behavior)
3. **watch_filterer.rs**: Allow macOS directory events (`Create(Folder)`
and `Modify(Metadata)`) through the filter so the action handler can
register them

All changes use `#[cfg(target_os = "macos")]` for compile-time
conditional compilation, so Linux/Windows behavior is completely
unchanged and there's zero runtime overhead.

### Additional notes

- Pinned `serde` to `<1.0.220` because serde 1.0.220+ moved `__private`
to `serde_core`, breaking `swc_common 0.31.22`
- No TypeScript changes — the napi interface is identical
- `watch_filterer.rs`, `types.rs`, `utils.rs` required no changes (APIs
are compatible)

## Related Issue(s)
Fixes https://github.com/nrwl/nx/issues/33781
Fixes https://github.com/nrwl/nx-console/issues/2468
<!-- No specific issue linked yet -->

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 17:21:19 -05:00
Louie Weng 693f75149a chore(repo): re-enable gradle e2e tests (#34357)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Re-enabling tests and putting back kotlin e2e tests for gradle.

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

Fixes #
2026-02-06 13:24:48 -08:00
Craigory Coppola 5e4dd04b66 fix(core): only detect flaky tasks for cacheable tasks (#33994)
## Current Behavior

Flaky task detection warns about all tasks that have different exit
codes for the same hash, including non-cacheable tasks. This is
misleading because the flaky task warning message points users to Nx
Cloud's flaky task retry feature, which is only relevant for cached
tasks.

## Expected Behavior

Flaky task detection should only consider tasks where `task.cache ===
true`, making the warning more meaningful and avoiding noise for
non-cacheable tasks.

## Related Issue(s)

N/A - Internal improvement

## Changes Made

###
`packages/nx/src/tasks-runner/life-cycles/task-history-life-cycle.ts`
1. Added `cacheable: boolean` to the `TaskRun` interface
2. In `endTasks`, now tracks `cacheable: taskResult.task.cache === true`
for each task
3. In `endCommand`, filters to only check flaky tasks among cacheable
tasks

###
`packages/nx/src/tasks-runner/life-cycles/task-history-life-cycle-old.ts`
1. Added `cacheableHashes: Set<string>` to track which task hashes are
cacheable
2. In `endTasks`, tracks cacheable tasks by adding their hash to the set
3. In `endCommand`, only checks for flaky tasks among cacheable task
hashes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 15:39:43 -05:00
Louie Weng 8280910e48 docs(gradle): add compat table and target name prefix (#34359)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

A new version compatibility table is added to help users understand
which versions of the Gradle plugin work with which versions of the Nx
plugin. The targetNamePrefix configuration option is now documented with
an explanation of its use case in polyglot workspaces where target name
collisions may occur.

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

Fixes #
2026-02-06 12:35:33 -08:00
Craigory Coppola 37a69f0c9d feat(core): eagerly shutdown plugins that don't provide later hooks (#34253)
# Plugin Isolation Architecture

## 1. Plugin Loading Flow

### 1a. Entry Point - Isolation Decision

```mermaid
flowchart TD
    Start([getPlugins called]) --> CheckIsolation{Isolation<br/>enabled?}
    CheckIsolation -->|Yes| LoadIsolated[loadIsolatedNxPlugin]
    CheckIsolation -->|No| LoadInProcess[loadNxPluginInProcess]
    LoadIsolated --> IsolatedPath([See: Isolated Loading])
    LoadInProcess --> InProcessPath([See: In-Process Loading])
```

### 1b. Isolated Plugin Loading

```mermaid
flowchart TD
    subgraph Main["Main Process"]
        Start([loadIsolatedNxPlugin]) --> CheckCache{In cache?}
        CheckCache -->|Yes| ReturnCached([Return cached promise])
        CheckCache -->|No| StaticLoad[IsolatedPlugin.load]
        StaticLoad --> Resolve[resolveNxPlugin<br/>find plugin path]
        Resolve --> SpawnWorker[spawn child process]
    end

    SpawnWorker -.->|"start process"| WorkerStart

    subgraph Worker["Worker Process (plugin-worker.ts)"]
        WorkerStart([process starts]) --> CreateServer[create Unix socket server]
        CreateServer --> Listen[listen for connections]
        Listen --> WaitForConnect[wait for main process]
        WaitForConnect --> HandleLoad[receive 'load' message]

        subgraph InProcess["In-Process Loading (same as 1c)"]
            HandleLoad --> RequirePlugin[require plugin module]
            RequirePlugin --> NormalizePlugin[normalizeNxPlugin]
        end

        NormalizePlugin --> SendLoadResult[send 'loadResult'<br/>with hook capabilities]
        SendLoadResult --> WaitForMessages[wait for hook messages<br/>or socket close]
        WaitForMessages --> HandleHook{message<br/>received?}
        HandleHook -->|hook message| ExecuteHook[call plugin.hook]
        ExecuteHook --> SendResult[send result]
        SendResult --> WaitForMessages
        HandleHook -->|socket closed| Cleanup[cleanup & exit]
    end

    subgraph Main2["Main Process (continued)"]
        ConnectSocket[connect via<br/>Unix socket] --> SendLoad[send 'load' message]
        SendLoad --> WaitLoad[wait for 'loadResult']
        WaitLoad --> SetupHooks[setupHooks<br/>create lifecycle manager]
        SetupHooks --> CheckGraphHooks{Has graph<br/>phase hooks?}
        CheckGraphHooks -->|No| EarlyShutdown[socket.end<br/>shutdown worker]
        CheckGraphHooks -->|Yes| KeepAlive[keep worker alive]
        EarlyShutdown --> Done([Plugin ready])
        KeepAlive --> Done
    end

    SpawnWorker --> ConnectSocket
    SendLoadResult -.->|"loadResult"| WaitLoad
    EarlyShutdown -.->|"socket close"| Cleanup
```

### 1c. In-Process Plugin Loading

```mermaid
flowchart TD
    Start([loadNxPluginInProcess]) --> Resolve[resolveNxPlugin]
    Resolve --> Require[require plugin module]
    Require --> Normalize[normalizeNxPlugin<br/>wrap hooks]
    Normalize --> Done([Plugin ready])
```

## 2. Hook Execution Flow

### 2a. Isolated Hook Execution

```mermaid
flowchart TD
    Start([hook called<br/>e.g. createNodes]) --> EnsureAlive{_alive?}
    EnsureAlive -->|No| Restart[spawnAndConnect<br/>restart worker]
    Restart --> SetAlive[_alive = true]
    SetAlive --> EnsureAlive

    EnsureAlive -->|Yes| EnterHook[lifecycle.enterHook<br/>increment session count]
    EnterHook --> SendRequest[sendRequest<br/>over socket]
    SendRequest --> WaitResponse[wait for response<br/>with timeout]

    WaitResponse --> CheckSuccess{success?}
    CheckSuccess -->|No| ExitHookError[lifecycle.exitHook]
    ExitHookError --> ThrowError[throw error]

    CheckSuccess -->|Yes| ExitHook[lifecycle.exitHook]
    ExitHook --> CheckShutdown{should<br/>shutdown?}
    CheckShutdown -->|Yes| Shutdown[shutdown worker]
    CheckShutdown -->|No| Return([return result])
    Shutdown --> Return
```

### 2b. Shutdown Decision Logic

```mermaid
flowchart TD
    Start([exitHook called]) --> IsLastHook{Last hook<br/>in phase?}
    IsLastHook -->|No| NoShutdown1([return false])

    IsLastHook -->|Yes| CheckSessions{sessionCount<br/>== 0?}
    CheckSessions -->|No| NoShutdown2([return false<br/>other callers active])

    CheckSessions -->|Yes| CheckLaterPhases{Has later<br/>active phases?}
    CheckLaterPhases -->|Yes| NoShutdown3([return false<br/>needed later])
    CheckLaterPhases -->|No| YesShutdown([return true<br/>safe to shutdown])
```

## 3. Developer Workflow: Adding/Modifying Plugin Hooks

### Step 1: Design Public API

```mermaid
flowchart TD
    A1[public-api.ts] --> A2[Define context type<br/>e.g. MyHookContext]
    A2 --> A3[Export new types]
    A3 --> A4[loaded-nx-plugin.ts]
    A4 --> A5[Add hook to<br/>LoadedNxPlugin interface]
```

### Step 2: Define Message Types

```mermaid
flowchart TD
    B1[messaging.ts] --> B2[Add entry to PluginMessageDefs]
    B2 --> B3[Define payload and result types]
    B3 --> B4[Add to MESSAGE_TYPES array]
    B4 --> B5[Add to RESULT_TYPES array]
```

The messaging system uses a unified `DefineMessages` pattern. To add a
new message:

```typescript
// In PluginMessageDefs, add a new entry:
type PluginMessageDefs = DefineMessages<{
  // ... existing messages ...

  myHook: {
    payload: {
      context: MyHookContext;
    };
    result:
      | { success: true; data: MyResultData }
      | { success: false; error: Error };
  };
}>;
```

The individual message/result types (`PluginWorkerMyHookMessage`,
`PluginWorkerMyHookResult`)
are automatically derived. Export them if needed for external use:

```typescript
export type PluginWorkerMyHookMessage = MessageOf<PluginMessageDefs, 'myHook'>;
export type PluginWorkerMyHookResult = ResultOf<PluginMessageDefs, 'myHook'>;
```

### Step 3: Handle in Worker Process

```mermaid
flowchart TD
    C1[plugin-worker.ts] --> C2[Add handler in<br/>consumeMessage]
    C2 --> C3["Call plugin.myHook()"]
    C3 --> C4[Return result payload]
```

Handlers return just the result payload - the infrastructure wraps it
automatically:

```typescript
// In consumeMessage handlers:
myHook: async ({ context }) => {
  try {
    const data = await plugin.myHook(context);
    return { success: true as const, data };
  } catch (e) {
    return { success: false as const, error: createSerializableError(e) };
  }
},
```

### Step 4: Update Load Result

```mermaid
flowchart TD
    D1[messaging.ts] --> D2[Add hasMyHook to<br/>load.result in PluginMessageDefs]
    D2 --> D3[plugin-worker.ts]
    D3 --> D4[Populate hasMyHook<br/>in load handler]
```

### Step 5: Wire Up IsolatedPlugin

```mermaid
flowchart TD
    E1[isolated-plugin.ts] --> E2[Add hook property<br/>to class]
    E2 --> E3[Update LoadResultPayload<br/>type export]
    E3 --> E4[Add to registeredHooks<br/>array in setupHooks]
    E4 --> E5[Add wrapped hook<br/>implementation]
    E5 --> E6["wrap('myHook', async (ctx) => {<br/>  sendRequest('myHook', { context: ctx })<br/>})"]
```

### Step 6: Update Lifecycle Phases (if needed)

```mermaid
flowchart TD
    F1{New phase<br/>needed?} -->|Yes| F2[plugin-lifecycle-manager.ts]
    F2 --> F3[Add phase to<br/>HOOKS_BY_PHASE]
    F1 -->|No| F4[Add hook to existing<br/>phase array in HOOKS_BY_PHASE]
```

### Step 7: Add Tests

```mermaid
flowchart TD
    G1[isolated-plugin.spec.ts] --> G2[Test hook registration]
    G2 --> G3[Test hook execution]
    G3 --> G4[Test restart behavior]
    G4 --> G5[plugin-lifecycle-manager.spec.ts]
    G5 --> G6[Test phase transitions<br/>with new hook]
    G6 --> G7[Test shutdown decisions]
```

## File Reference

| File | Purpose |
| ----------------------------- |
------------------------------------------------------------- |
| `../public-api.ts` | Public types exported to plugin authors |
| `../loaded-nx-plugin.ts` | Interface definition for loaded plugins |
| `messaging.ts` | Message type definitions for worker communication |
| `plugin-worker.ts` | Worker process - receives messages, calls plugin
functions |
| `isolated-plugin.ts` | Main class - spawns worker, sends messages,
manages lifecycle |
| `plugin-lifecycle-manager.ts` | Tracks phases, decides when to
shutdown |
| `load-isolated-plugin.ts` | Caching layer for isolated plugins |
| `../get-plugins.ts` | Entry point - decides isolation mode |

## Lifecycle Phases

```
LOADED → [graph] → [pre-task] → {tasks run} → [post-task]
           │           │                           │
           │           └── preTasksExecution ──────┤
           │                                       │
           ├── createNodes                         │
           ├── createDependencies                  │
           └── createMetadata                      │
                                                   │
                                    postTasksExecution
```

**Shutdown rules:**

- Plugin shuts down after its last active phase completes
- If only `postTasksExecution`: shutdown immediately after load, restart
when needed
- Concurrent callers tracked via session count (ref counting)

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
2026-02-06 14:54:10 -05:00
Caleb Ukle 359c7fbf4e fix(nx-dev): include nx cli examples on refs page (#34367)
![wm_2026-02-06T11-26-54@2x](https://github.com/user-attachments/assets/c2814268-e921-420b-a9e2-2b90c8a89526)

https://deploy-preview-34367--nx-docs.netlify.app/docs/reference/nx-commands#nx-add

cli examples are included in the generated page now

fixes: DOC-402
2026-02-06 12:39:00 -05:00
James Henry 0d2882e1c0 fix(core): use picocolors instead of chalk in the nx package (#34305) 2026-02-06 19:17:52 +04:00
Colum Ferry 541498f58a feat(core): update cnw messaging (#34364)
CLOSES CLOUD-4235
2026-02-06 10:04:42 -05:00
Colum Ferry b85ac155cf feat(js): update swc/cli to 0.8.0 (#34365)
Update `@swc/cli` to 0.8.0 which uses chokidar v5
2026-02-06 08:47:56 -05:00
MaxKless 5f42ccc3e9 docs(maven): minor tweaks and include targetNamePrefix (#34362)
this makes the maven documentation more complete for the latest changes
2026-02-06 13:30:44 +00:00
Louie Weng 8fdfc523a8 chore(gradle): bump gradle version to 0.1.12 (#34250)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Gradle plugin to 0.1.12

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-02-05 15:32:01 -08:00
Louie Weng a44a27b29a feat(gradle): add debug env var to gradle batch executor (#34259)
<!-- 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
<!-- This is the behavior we have today -->

- No way to run the batch executor in debug mode
- Any flags passed into the nx gradle batch command get forwarded into
the `gradlew` command.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

- Allow for an env variable to be set for debug flags so that the batch
runner jar can be run with a debugger hooked in.

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

Fixes #NXC-3797

---------

Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
2026-02-05 22:26:02 +00:00
Leosvel Pérez Espinosa 0cac182b73 fix(core): avoid crash when pane area is out of bounds during resize (#34343)
## Current Behavior

In some resize/background scenarios, the TUI could crash while rendering
output panes, displaying a "Scrollbar area is empty" message.

## Expected Behavior

The TUI remains stable during resizes and backgrounding. Output panes no
longer crash when a scrollbar would render in an invalid area.
2026-02-05 17:11:47 -05:00
Louie Weng b69ff4ceb9 chore(repo): fix broken disablement command (#34355)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2026-02-05 17:11:01 -05:00
Louie Weng 4337d2e928 fix(gradle): use gradle project name when resolving dependent tasks (#34331)
<!-- 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
<!-- This is the behavior we have today -->

When Nx processes Gradle subprojects, task dependencies reference the
wrong project names. For a subproject structure like :app or :lib:core,
the generated task dependencies use only the simple project name (app or
core) instead of the full build tree path (:app or :lib:core). This
causes dependent tasks to be generated with incorrect project
references, breaking the task graph for multi-project Gradle builds.

## Expected Behavior
Task dependencies should use the full Gradle build tree path for
subprojects. When a task in :app depends on a task in :lib, the
dependency should be correctly referenced as :lib:taskName.

The fix introduces a getNxProjectName() utility function that correctly
resolves the Nx project name based on the Gradle project's
buildTreePath, and applies it consistently across all dependency
resolution logic in ProjectUtils.kt and
TaskUtils.kt. New tests verify the fix works for both single and nested
subproject structures.

Also removed --rerun-tasks from the batch and non batch runners, we
found that during parallel task executions with the non batch runner,
the flag would cause cache conflicts that would fail tasks.

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-02-05 13:44:05 -08:00
Leosvel Pérez Espinosa a0be6adcf8 fix(core): track all task outputs regardless of path depth (#34321)
## Current Behavior

When a task has outputs at different path depths, some outputs may not
be tracked. This causes:

- Deleted output files not being detected
- Cache restoration being skipped with message "existing outputs match
the cache, left as is"
- Files not being restored even though they exist in cache

## Expected Behavior

All task outputs are tracked regardless of their path depth, ensuring:

- Deleted outputs are correctly detected
- Cache restoration happens when outputs are missing
2026-02-05 16:41:39 -05:00
Leosvel Pérez Espinosa dffdfa694c fix(core): disable ignore filters for outputs expansion (#34316)
## Current Behavior

When a task output directory contains a nested `.gitignore` that hides
its contents, Nx can treat the outputs as already present and skip
restoring them from cache. This can result in generated files being
missing from disk, even though the cache entry is valid.

## Expected Behavior

Nx should restore cached outputs regardless of ignore rules inside the
output directory.

## Related Issue(s)

Fixes #32620
2026-02-05 16:37:14 -05:00
Louie Weng a40ff52db0 chore(gradle): temporarily disable e2e tests (#34351)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Disabling Gradle e2e tests until foojay toolchain service back online.

Ensures that gradle within the Nx repo uses mise to download java
toolchain, but gradle workspaces within the e2e environments download
their own toolchain.

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

Fixes #Q-175
2026-02-05 16:32:59 -05:00
Philip Fulcher bd41ce5692 docs(nx-dev): add feb 2026 webinar (#34352) 2026-02-05 16:24:18 -05:00
Philip Fulcher 1f09a5d1a5 docs(nx-dev): remove errant author from article (#34349) 2026-02-05 14:58:04 -05:00
Jack Hsu 0b99f560d4 feat(core): add AI agent detection and NDJSON output for CNW (#34320)
AI agents are detected via environment variables (CLAUDECODE, OPENCODE)
and receive NDJSON streaming output, non-interactive mode, structured
JSON results with explicit GitHub setup instructions.

Related NXC-3628

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 14:57:39 -05:00
Caleb Ukle 866d5b1e9b fix(nx-dev): use right URL for the given netlify context (#34348) 2026-02-05 13:19:17 -05:00
Caleb Ukle d4ad62f522 fix(nx-dev): fix og images wrong URL for embeds (#34346)
fixes: DOC-399

next used the VERCEL_URL by default for metadataBase. this is not
present in netlify. so resolve to netlify URLs if VERCEL_URL is not
present so metadata links are correct.

working on PR:
<img width="704" height="875" alt="image"
src="https://github.com/user-attachments/assets/4edd194e-27d6-46ce-bdd2-7da4ab70d482"
/>
<img width="976" height="204" alt="image"
src="https://github.com/user-attachments/assets/63ea32f5-20cf-4df2-96a1-a1bc2ff59411"
/>



https://6984ce9d1bad30000873247d--nx-dev.netlify.app/blog/nx-2026-roadmap
2026-02-05 17:45:12 +00:00
Louie Weng 3aff575002 docs(gradle): add reference to batch mode (#34271)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Add documentation for batch mode. Remove references to removed custom
overrides for intTest.

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

Fixes #
2026-02-05 08:07:05 -08:00
Jonathan Cammisuli 7df9d96dac feat(core): add command to download cloud client (#34333)
<!-- 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
<!-- This is the behavior we have today -->
The only way to download the cloud client is to run a specific cloud
command or a task with cloud configured.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
A new command is added where we only download the cloud client with:
```
nx download-cloud-client
```

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-02-05 10:42:55 -05:00
Caleb Ukle 05fb208fda docs(node): add bundling guide (#34244)
add guide to clarify various ways to bundle a node app for different
bundlers

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2026-02-05 15:25:42 +00:00
Philip Fulcher 33f031be04 docs(nx-dev): add 2026 roadmap article (#34327) 2026-02-05 08:47:23 -06:00
James Henry 0e11f95163 chore(repo): add dependabot config to try and remove false positives (#34341) 2026-02-05 18:26:46 +04:00
Juri Strumpflohner 2b07ac22c2 feat(core): improve AI agent rules for CLAUDE.md generation (#34304)
## Summary

Updates the generated CLAUDE.md content with improved guidance for AI
agents working with Nx workspaces.

**Changes:**
- Add "nx-workspace skill first" for workspace navigation
- Add "prefix nx commands with package manager" rule
- Add "NEVER guess CLI flags" rule
- Add "Scaffolding & Generators" section (invoke nx-generate skill
first)
- Add "When to use nx_docs" guidance (USE for advanced config, DON'T USE
for basic syntax)

## Why These Changes

Based on testing with repeated scaffolding tasks, agents were:

| Issue | Fix |
|-------|-----|
| Calling `nx_docs` for basic generator syntax | Added clear guidance on
when to use/not use nx_docs |
| Guessing CLI flags incorrectly (e.g., `nx sync --apply`) | Added
"never guess flags" rule |
| Using global nx CLI causing version mismatches | Added package manager
prefix rule |
| Not invoking nx-generate skill on scaffolding tasks | Added explicit
"Scaffolding & Generators" section |

## Related

Companion PR with skill improvements:
https://github.com/nrwl/nx-ai-agents-config/pull/26

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-02-05 21:17:59 +09:00
Jason Jean efa364f73d fix(core): preserve task selection when unrelated tasks finish (#34328)
## Current Behavior

In the TUI, when any standalone task finishes,
`handle_standalone_task_finished` unconditionally switches the user's
selection to another in-progress task — even if the finished task wasn't
the one the user had selected. This causes the selection to jump
unexpectedly while the user is watching a different task.

## Expected Behavior

Selection should only change when the task the user is actively viewing
finishes. If an unrelated background task finishes, the user's selection
should remain on whatever they chose.

## Related Issue(s)

N/A — discovered during development testing.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-02-04 21:23:22 -05:00
Craigory Coppola 82265ff157 fix(core): allow overriding daemon logging settings (#34324)
## Current Behavior
NX_NATIVE_LOGGING is hardcoded and can't be customized on the daemon
server

## Expected Behavior
Log settings can be customized by changing them in the env of the first
command to spawn the daemon

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

Fixes #
2026-02-04 21:12:23 -05:00
Jason Jean 015ff1a45b chore(repo): update nx to 22.5.0-beta.4 (#34334)
Updating Nx from 22.5.0-beta.3 to 22.5.0-beta.4
2026-02-05 00:27:21 +00:00
Caleb Ukle cdb4bb2acc fix(nx-dev): exclude large native deps from build bundle (#34335)
we were including native binaries in the final netlify function build
for nextjs which was fine until we reach the limit of 250mb causing a
failure to upload the function (AWS imposed lambda limit)

Now we strip out any deps we know we don't need for the app which are
dev deps and not runtime required.
2026-02-04 19:09:25 -05:00
Jason Jean 3c7f94e3d5 chore(repo): align canary and PR release versions with next (#34330)
## Current Behavior

- Canary releases calculate their base version by incrementing the minor
of `nx@latest`, or using `nx@next` major when majors differ
- PR releases always use `0.0.0` as their base version (e.g.
`0.0.0-pr-1234-abc1234`)
- This means canary and PR versions don't clearly relate to the current
beta release line

## Expected Behavior

- Both canary and PR releases derive their base version directly from
`nx@next`
- If next is `22.5.0-beta.5`, then:
  - Canary: `22.5.0-canary.20260204-abc1234`
  - PR: `22.5.0-pr.1234.abc1234`
- All prerelease channels now share the same base version, making it
clear which release line they belong to

## Related Issue(s)

N/A - internal improvement to release infrastructure
2026-02-04 16:36:44 -05:00
Jason Jean ef55f97df3 feat(maven): bump maven plugin version to 0.0.13 (#34318)
## Current Behavior

The Maven plugin version is `0.0.12` across all pom.xml files and the
versions.ts constant. The `bump-maven-version` generator does not update
the `batch-runner-adapters` pom files, causing version mismatches.

## Expected Behavior

The Maven plugin version is bumped to `0.0.13` in **all** pom.xml files
(including batch-runner-adapters), with a migration created for users
upgrading to Nx `22.5.0-beta.4`. The bump generator now includes the
batch-runner-adapters pom files so future bumps won't miss them.

### Changes
- Updated version from `0.0.12` to `0.0.13` in all pom.xml files (root,
maven, maven-plugin, shared, batch-runner, batch-runner-adapters,
maven3-adapter, maven4-adapter)
- Updated `mavenPluginVersion` constant in
`packages/maven/src/utils/versions.ts`
- Added `update-0-0-13` migration entry in
`packages/maven/migrations.json` targeting Nx `22.5.0-beta.4`
- Created migration file
`packages/maven/src/migrations/0-0-13/update-pom-xml-version.ts`
- Fixed `bump-maven-version` generator to include
`batch-runner-adapters` pom files
2026-02-04 14:06:18 -05:00
Jack Hsu 5880551c6a chore(repo): update docs readme with guiding principles (#34319)
This PR adds info for how we structure the docs so when we write them we
know where to put things, what to write, etc.
2026-02-04 13:40:08 -05:00
Jason Jean fb6c2982e6 fix(misc): improve freebsd build reliability with better error handling and disk cleanup (#34326)
## Current Behavior

The FreeBSD build in CI can fail silently or with unclear error messages
when:
- Disk space runs low during the build process
- The build command fails without proper error propagation
- Unnecessary files consume valuable disk space

## Expected Behavior

With these changes:
- Additional disk space is freed by removing docs/astro-docs/nx-dev
directories before building
- Build exit codes are properly captured and propagated
- Disk usage is logged after the build completes for debugging purposes
- Build failures are clearly reported with explicit error messages

This improves reliability and makes it easier to diagnose issues when
they occur.

## Related Issue(s)

<!-- No specific issue, general CI improvement -->
2026-02-04 13:34:52 -05:00
Caleb Ukle 81944b02c5 feat(nx-dev): reformat sidebar into topics (#34265)
Sidebar contains everything about the docs which is overhelming and hard
to find information a person could be looking for.

instead we move into "topics" to section the sidebar based on intention
of content, making it easier to have a journey through the docs or jump
straight to the content someone could be looking for.

This doesn't change any routes of pages, just hard links into the
sidebar (instead of autogenerate based on dir) in the future once we
solidify where everything will live, we can come back and rearrange
files to reuse the autogenerate dirs.


![wm_2026-02-04T10-48-54](https://github.com/user-attachments/assets/6add05b3-b929-492f-a54e-fde6c2929973)

![wm_2026-02-04T10-50-10](https://github.com/user-attachments/assets/e9c89621-c287-4c9a-8d14-692bd1a73739)
<img width="1385" height="1003" alt="image"
src="https://github.com/user-attachments/assets/4bbee4fe-2f7e-4d7a-ad6b-45f6064c897a"
/>

![wm_2026-02-04T11-03-15@2x](https://github.com/user-attachments/assets/10561621-5c80-4843-a7c4-a1272adf7b8e)

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
2026-02-04 11:57:47 -06:00
Jack Hsu c1cc626e52 docs(misc): filter out non-existing image requests and also only track HTML page views when requested with "Accept: text/html" (#34317)
We're getting requests to `favicon.svg.md` that are being tracked,
ignore these. Also for the server page views, we should only count them
if `text/html` is in the accept header. Browsers will send these, and AI
agents, curl, etc. do not. This allows us to compare browser traffic vs
AI/curl traffic more accurately.
2026-02-04 10:38:25 -05:00
Jason Jean 6f3d38ad3c fix(core): handle EPIPE errors gracefully in daemon socket writes (#34311)
## Current Behavior

When a client disconnects while the daemon is writing a response, a
`socket.write` call triggers an EPIPE error. The old error handler used
`console.error`, which caused the error to propagate through
`respondWithErrorAndExit` and crash the daemon process via
`process.exit(1)`. The client would then see an `internalDaemonError`
and permanently disable the daemon via `markDaemonAsDisabled`, requiring
`nx reset` to recover.

Additionally, disconnected sockets were not cleaned up from the file
watcher and project graph listener registries on socket error events,
only on `close` events. This left a window where the daemon could
attempt to write to dead sockets during notifications.

## Expected Behavior

When a client disconnects mid-response:
- The `socket.write` callback logs the error gracefully via
`serverLogger` instead of `console.error`
- The daemon process stays alive and continues serving other clients
- The `socket.on('error')` handler cleans up registered file watcher and
project graph listener sockets immediately, matching the existing
`close` handler behavior
- The daemon is never permanently disabled due to EPIPE errors

## Related Issue(s)

<!-- No linked issue -->
2026-02-04 09:43:59 -05:00
MaxKless d0e4a92738 fix(core): tweak configure-ai-agents messaging (#34307)
### Current Behavior
The nx configure-ai-agents command output is minimal - just "AI agents
set up successfully" with a
bullet list of agent names. Users don't understand what was actually
configured (plugin vs MCP,
skills, which files were created/modified).
### Expected Behavior
Clearer feedback about what gets configured for each agent:
Selection prompt improvements:
- Agents needing updates show (update available) tag
- Footer always shows result state: what will be configured
- Agent-specific descriptions (e.g., "Installs Nx plugin (MCP + skills +
agents). Updates
CLAUDE.md.")
Post-configuration output:
- Compact summary per agent showing what was set up
- Example: Claude Code: Nx plugin (MCP + skills + agents) + CLAUDE.md
Claude .mcp.json cleanup:
- When configuring Claude, removes nx-mcp from .mcp.json since it's now
handled by the plugin
- Deletes the file entirely if nx-mcp was the only entry

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-02-04 09:43:38 -05:00
Jack Hsu 2ea6961e0d fix(core): fix CNW git amend and README marker handling (#34306)
This PR fixes two issues:
1. When the README changes are amended, there's an edge case where we
don't have a commit to amend (e.g. `--skipGit`), and this fails the
entire CNW flow.
2. When user opts out of Cloud, we strip the entire `<!-- BEGIN:
nx-cloud -->` block in README rather than just the comments and leaving
the content.

Closes NXC-3812

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 08:50:42 -05:00
Benjamin Cabanes 1195565b96 docs(nx-dev): update Nx Cloud & Home features, add new components (#34149) 2026-02-03 18:04:01 -05:00
Craigory Coppola 7478cbb59d feat(core): add initial impl of task io service (#34205)
## Current Behavior
There's not an easy to use service to track PIDs being registered to nx
tasks

## Expected Behavior
There's a service to track this stuff

## Related Issue(s)
2026-02-03 17:42:17 -05:00
Jason Jean 79d878f240 fix(core): prevent command injection in getNpmPackageVersion (#34309)
## Current Behavior

The `getNpmPackageVersion` function in
`packages/workspace/src/generators/utils/get-npm-package-version.ts`
uses `execSync` with direct string interpolation of the `packageName`
parameter. When a user runs `create-nx-workspace` with a custom
`--preset` value that doesn't match a known preset, the value flows
unsanitized into a shell command:

```js
execSync(`npm view ${packageName}... version --json`)
```

This allows arbitrary command execution via shell metacharacters (e.g.,
`--preset='pkg$(malicious command)'`).

## Expected Behavior

User-supplied package names are validated against a strict npm package
name regex before being passed to any shell command. The function now
uses `execFileSync` with an args array instead of `execSync` with string
interpolation, providing defense in depth:

1. **Input validation** — rejects anything that isn't a valid npm
package name
2. **Safe execution** — arguments are passed as an array so Node.js
handles escaping, rather than concatenating into a raw shell string
2026-02-03 16:18:43 -05:00
Caleb Ukle b198606bef docs(nx-cloud): add screenshots for cache troubleshoot guide (#34296) 2026-02-03 15:35:34 -05:00
Craigory Coppola 1cb6c0b14c fix(core): nx should show help for run-one when using project short names (#34303)
## Current Behavior
Given a project name like `:foo`, you can run tasks like `nx test foo`
(note `foo` vs `:foo`), but passing --help throws an error

## Expected Behavior
`--help` works the same with the shortname vs full name

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-02-03 14:56:23 -05:00
Jason Jean 3f6bdc7ff7 fix(maven): include pom.xml and ancestor pom files as inputs for all targets (#34291)
## Current Behavior

- `pom.xml` is only included as an input when a mojo uses default inputs
- Mojos with specific input configurations (like
`maven-compiler-plugin:compile`) don't get `pom.xml` in their inputs
- Parent `pom.xml` files aren't tracked as inputs

This can lead to stale cache hits when:
1. `pom.xml` changes but a mojo has specific input config
2. A parent `pom.xml` changes (affecting inherited properties,
dependency versions, plugin config)

## Expected Behavior

- Every target should include its own `pom.xml` as an input
- Every target should include ancestor `pom.xml` files (within the
workspace) as inputs
- Cache should invalidate when any relevant `pom.xml` changes

## Related Issue(s)

N/A - discovered during code review

## Changes

- **CacheConfig.kt**: Removed `pom.xml` from `defaultInputs` (now always
added explicitly)
- **MojoAnalyzer.kt**: Added `workspaceRoot` parameter and logic to walk
up the parent chain, adding all in-workspace ancestor `pom.xml` files as
inputs
- **NxProjectAnalyzerMojo.kt**: Pass `workspaceRoot` to `MojoAnalyzer`
2026-02-03 14:26:11 -05:00
Jason Jean cc4ec68bce chore(repo): update nx to 22.5.0-beta.3 (#34295)
Updating Nx from 22.5.0-beta.2 to 22.5.0-beta.3
2026-02-03 14:20:30 -05:00
Juri 01d2f64b90 docs(nx-dev): add autonomous AI workflows blog post
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 17:26:28 +01:00
James Henry 39d8a9a6ac chore(repo): update to pnpm@10.28.2 and clean up pnpm config (#34298) 2026-02-03 17:48:01 +04:00
Jack Hsu 4f02c6b56e docs(misc): ignore /docs/og/*.png.md paths (#34289)
This PR excludes `/docs/og/*` paths from assets tracking. This is likely
added by some crawler and is additional compute/noise that we don't care
about.

<img width="1354" height="86" alt="image"
src="https://github.com/user-attachments/assets/6bfda816-0d26-46b3-b432-ae96e5976c37"
/>
2026-02-02 13:32:06 -05:00
Jack Hsu 3f77cd5927 fix(nx-dev): fix double-counting and exclude assets from page tracking (#34286)
## Current Behavior

1. **track-asset-requests** runs twice per request due to redundant path
patterns:
   ```typescript
   path: ["/*.txt", "/**/*.txt", "/*.md", "/**/*.md"]
   ```
The `/**/*` pattern already matches root level files, so `/*` is
redundant.

2. **track-page-requests** runs on many asset requests even though it
only tracks HTML page views:
   - Font files: `/docs/fonts/*.woff2`, `/docs/*.woff`
   - Images: `/docs/*.svg`, `/docs/*.png`, `/docs/og/*`
   - Pagefind search index: `/docs/pagefind/*`

## Expected Behavior

1. Asset tracking should fire only once per request
2. Page tracking should exclude all non-HTML assets at Netlify level
(zero compute)

## Changes

### track-asset-requests.ts
Simplified path patterns:
```typescript
path: ["/**/*.txt", "/**/*.md"]
```

### track-page-requests.ts
Added comprehensive exclusions:

| Category | Exclusions |
|----------|------------|
| Images | `.svg`, `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`, `.ico`,
`/images/*`, `/og/*` |
| Fonts | `/fonts/*`, `.woff`, `.woff2` |
| Search | `/pagefind/*` |

## Related Issue(s)

Fixes DOC-395
2026-02-02 12:17:32 -05:00
Jason Jean 89aa25e5d0 fix(core): resolve daemon client reconnect queue deadlock (#34284)
## Current Behavior

When the daemon dies while processing a request, the reconnect logic
adds the retry back to the promise-based queue. However, the original
request is still blocked in the queue waiting for a response that will
never come (the socket is dead). This creates a deadlock:

1. Original request (`fn1`) is blocked awaiting a promise that will
never resolve
2. Retry request (`fn2`) is queued but can't execute until `fn1`
completes
3. `fn1` can't complete because it's waiting on the dead socket

## Expected Behavior

When reconnecting after daemon death, the retry should resolve the
pending promise that the original queue entry is waiting on, allowing
the queue to proceed normally.

## Related Issue(s)

<!-- No specific issue, discovered during development -->

## Solution

Instead of re-queuing the retry through `sendToDaemonViaQueue` (which
adds to the end of the queue), we now call `sendMessageToDaemon`
directly. This resolves the pending promise that `fn1` is waiting on,
allowing it to complete naturally and the queue to proceed.

Also removed the now-unused `decrementQueueCounter` method from
`PromisedBasedQueue`.
2026-02-02 12:05:33 -05:00
Jack Hsu cdd735dc63 feat(nx-dev): add server-side page view tracking for docs (#34283)
## Current Behavior

Only markdown and text file requests are tracked server-side via the
`track-asset-requests` edge function. HTML page views are not tracked on
the server, missing requests from AI tools and curl.

## Expected Behavior

Track all doc page views server-side with a new edge function that:
- Sends `server_page_view` events to GA4 with `content_type` param to
differentiate HTML/markdown/text
- Uses Netlify's `excludedPath` config for efficient path filtering
(zero compute for excluded paths)
- Skips non-HTML requests via Accept header check

### Changes

| File | Change |
|------|--------|
| `track-page-requests.ts` | **NEW** - Edge function for HTML page view
tracking on `/docs/*` |
| `track-asset-requests.ts` | Changed event name to `server_page_view`,
added `content_type` param |
| `add-link-headers.ts` | Refactored to use `excludedPath` config
instead of runtime path checks |
| `netlify.toml` | Added edge function declaration for
`track-page-requests` |

### GA Event Schema

```javascript
{
  name: 'server_page_view',
  params: {
    content_type: 'text/html' | 'text/markdown' | 'text/plain',
    file_extension: '.html' | '.md' | '.txt',
    is_ai_tool: 'true' | 'false',
    // ... other params
  }
}
```

## Other Notes

This PR also removes the edge function entries from `netlify.toml` since
it's auto detected from `astro-docs/netlify/edge-functions`. This makes
all the configuration in the actual `.ts` file, not duplicated in the
`netlify.toml` file.

## Related Issue(s)

Closes DOC-395

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 11:15:01 -05:00
Juri Strumpflohner f59c15a410 docs(core): update AI pages and include new info about configure-ai-agents command (#34257)
changes to:
-
https://deploy-preview-34257--nx-docs.netlify.app/docs/getting-started/ai-setup
-
https://deploy-preview-34257--nx-docs.netlify.app/docs/features/enhance-ai
-
https://deploy-preview-34257--nx-docs.netlify.app/docs/reference/nx-mcp

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2026-02-02 15:58:32 +00:00
Louie Weng 94319c7531 fix(gradle): enforce that only one gradle task can be passed into gradle executor (#34269)
<!-- 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
<!-- This is the behavior we have today -->

The Gradle executor accepts a taskName option that *should not* contain
multiple space-separated tasks. When multiple tasks are provided, the
batch runner misinterprets the space-separated string as containing
project names rather than treating it as a single task argument, leading
to execution errors and confusion.

This only occurs if the taskName is manually overridden and should not
occur when task names are generated by the project graph plugin.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

The Gradle executor now validates that taskName contains only a single
task without spaces. If multiple tasks are passed, it throws a clear
error message: "Task '[taskName]' contains spaces. Only a single Gradle
task is allowed per executor invocation." This prevents the batch runner
from misinterpreting the task name and provides immediate feedback to
users about the correct usage.

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

Fixes #
2026-02-02 10:14:08 -05:00
Louie Weng 35bc17e4fe fix(gradle): ensure that batch output is not overriden for atomized targets (#34268)
<!-- 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

When running Gradle tasks in batch mode with atomized targets, if the
same task appears multiple times in the output (which happens when tasks
are atomized and executed separately), the batch runner only captures
the output from the last execution. Previous executions' output gets
overwritten because the splitOutputPerTask function replaces the entire
output for each task name it encounters.

## Expected Behavior

All output from a task should be preserved, even when the task appears
multiple times in the batch output. When the same task name is
encountered multiple times, the outputs should be concatenated rather
than replaced, ensuring developers can see the complete execution
history for atomized targets.



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

Fixes #
2026-02-02 10:12:27 -05:00
Copilot d65dcfa806 docs(dotnet): fix build target dependsOn example (#34206)
## Plan for fixing .NET incremental builds documentation

- [x] Update the "Target dependencies" section to remove `restore` from
the `dependsOn` array
- [x] Add explanation about why `restore` cannot be run through Nx for
solutions using custom frameworks
- [x] Improve explanation clarity based on review feedback
- [x] Verify the "Target configuration" section is consistent with the
changes
- [x] Complete code review and address feedback
- [x] Run security checks (no issues found)
- [x] Address PR feedback: Use JSX `<Aside>` component with import
statement instead of Markdoc tag

## Summary

Successfully fixed the documentation issue in the .NET incremental
builds guide. The changes made:

1. **Removed `restore` from the build target's `dependsOn` array** - The
documentation now correctly shows `"dependsOn": ["^build"]` instead of
`"dependsOn": ["restore", "^build"]`, matching the actual implementation
in the plugin code.

2. **Added a clear explanation** - Included an aside box explaining why
`restore` is not in the `dependsOn` array: because Nx requires NuGet
package restoration to be completed before running any tasks, and
including it would create a circular dependency.

3. **Verified consistency** - Checked that the "Target configuration"
section already showed the correct configuration, ensuring all
documentation is now consistent.

4. **Used correct Starlight component** - Changed from Markdoc `{% aside
%}` tag to JSX `<Aside>` component with proper import statement per
Starlight documentation standards.

The changes align with the actual implementation in
`packages/dotnet/analyzer/Utilities/TargetBuilder.Build.cs` where the
build target's `dependsOn` is set to `[$"^{targetName}"]` (line 56).

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>docs(dotnet): implied conflict in dependsOn of inferred
build task</issue_title>
> <issue_description>### Documentation issue
> 
> <!-- (Update "[ ]" to "[x]" to check a box) -->
> 
> - [ ] Reporting a typo
> - [ ] Reporting a documentation bug
> - [ ] Documentation improvement
> - [x] Documentation feedback
> 
> <!--
> If your issue is not regarding the documentation, please choose an
issue type:
>   https://github.com/nrwl/nx/issues/new/choose
> -->
> 
> ### Is there a specific documentation page you are reporting?
> 
>
https://nx.dev/docs/technologies/dotnet/guides/incremental-builds#target-dependencies
> 
> ### Additional context or description
> 
> The code sample provides in this doc includes `"dependsOn":
["restore", "^build"]`, but the automatically inferred `build` target
from this plugin does not actually include the `restore` target in the
dependsOn array. I assume this is by design? The docs seem to confuse it
a bit.
> </issue_description>
> 
> <agent_instructions>Remove the `restore` target from the dependsOn
block. Add a small explanation that we can't run restore through Nx
because Nx requires restore to have been completed prior to running
tasks if the solution uses a custom framework</agent_instructions>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes nrwl/nx#34150

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: AgentEnder <6933928+AgentEnder@users.noreply.github.com>
2026-02-02 08:55:21 -06:00
iceThief (민찬기) e35dcd2050 fix(core): handle multibyte UTF-8 characters in socket message consumption (#34151)
## Current Behavior

When socket data chunks split a multibyte UTF-8 character (e.g., CJK
characters like Korean, Chinese, Japanese) at an arbitrary byte
boundary, `Buffer.toString()` decodes incomplete byte sequences as
replacement characters (�), causing message corruption.

This can occur when:
- File paths contain non-ASCII characters
- Project names include multibyte characters
- Any JSON message contains international text

## Expected Behavior

Multibyte UTF-8 characters should be properly decoded even when split
across multiple socket data chunks. The fix uses Node.js `StringDecoder`
which buffers incomplete multibyte sequences until the remaining bytes
arrive.

## Related Issue(s)

Fixes socket message corruption for paths/names containing multibyte
characters.
2026-02-01 22:09:53 -05:00
Caleb Ukle 251121530d fix(nx-dev): make headers and table options linkable (#34267)
- fix(nx-dev): always link headers regardless of mdoc or markdown
content source (generated vs static file)
- fix(nx-dev): make option/property columns in table linkable
- the table column header is matched on `options`, `option`,
`properties`, and property` (case insensitive)



https://github.com/user-attachments/assets/7250b9d5-1030-4ebc-9e21-0a05f295bbf5


Note bc mdoc and `renderMarkdown` go through 2 different rendering
pipelines, this logic must bc within the markdoc config and rehype
(markdown) processing logic. tried to shared logic where I could

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 18:15:46 -05:00
Jack Hsu ec110b7bff feat(core): add decorative banners for Nx Cloud CNW completion message (#34270)
## Current Behavior

After completing the CNW (Create Nx Workspace) flow with Nx Cloud, users
see a plain text completion message with a link to finish setup.

## Expected Behavior

Users now see one of four completion message variants controlled by
`NX_CNW_FLOW_VARIANT`:
- **Variant 0**: Plain link (control) - always used for enterprise URLs
- **Variant 1**: "Try the full Nx platform" decorative ASCII banner
- **Variant 2**: "Unlock 70% faster CI" decorative ASCII banner
- **Variant 3**: "Reclaim your team's focus" decorative ASCII banner

Key changes:
- Added enterprise URL detection (non-standard Nx Cloud URLs always get
variant 0)
- Locked the cloud prompt to always show "Try the full Nx platform?" (no
longer varies by flow variant)
- Flow variant now only affects the completion banner, not the prompt
- Added `snapshot.nx.app` to standard Nx Cloud hosts
- Removed variant 2 auto-connect behavior (all variants now prompt)

## Screenshots
Variant 0:
<img width="1392" height="1065" alt="variant0"
src="https://github.com/user-attachments/assets/0b18686e-1481-4fc0-995e-1577052887ff"
/>

Variant 1:
<img width="1392" height="1065" alt="variant1"
src="https://github.com/user-attachments/assets/e5909e2e-e1d8-4d04-9721-ba6186d06891"
/>

Variant 2:
<img width="1392" height="1065" alt="variant2"
src="https://github.com/user-attachments/assets/7e9f819f-e3c0-44d7-9760-0cab1d5dd9ac"
/>

Variant 3:
<img width="1392" height="1065" alt="variant3"
src="https://github.com/user-attachments/assets/83f0499f-d807-4dc8-9390-c7eec93590a9"
/>


## Related Issue(s)

Closes CLOUD-4147

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:24:18 +00:00
Louie Weng bd627f1096 chore(repo): enable batch mode (#34245)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Enable Gradle executor to run tasks in batch mode in CI.

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

Fixes #
2026-01-30 21:25:51 +00:00
Victor Savkin e3eedf9e94 docs(misc): update the docs to use more direct language (#34264)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2026-01-30 14:43:59 -05:00
Jack Hsu eb678bfa59 docs(misc): push toc to the right side to match the alignment of the left sidebar (#34266)
This PR aligns the TOC to the right side of the page so the spacing is
more balanced.

<img width="2672" height="1527" alt="image"
src="https://github.com/user-attachments/assets/ef00906a-3788-47fb-a71d-230b3d69c201"
/>

Similar to other docs like React:

<img width="2672" height="1527" alt="image"
src="https://github.com/user-attachments/assets/e9a1cd81-f716-4e09-b148-be80a93b7aee"
/>


---

## Other screen widths

1400px:

<img width="1424" height="1025" alt="Screenshot 2026-01-30 at 12 11
57 PM"
src="https://github.com/user-attachments/assets/d9fc5029-4942-4e32-b2f2-4c66ebcb21df"
/>

1000px (TOC hidden):


<img width="1145" height="1019" alt="Screenshot 2026-01-30 at 12 12
10 PM"
src="https://github.com/user-attachments/assets/ce1cd890-193a-42d7-bb4f-3259146845a8"
/>
2026-01-30 12:42:13 -05:00
Jack Hsu dc8839365f docs(misc): reduce memory footprint of nx-dev build (#34258)
We're showing over 8 GB of memory usage on Netlify, and 11+ GB on
Agents. Let's test out a few ways to reduce the memory footprint.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 10:53:21 -05:00
Richard Roncancio 3f05214013 chore(release): Improve release performance (#33866) 2026-01-30 18:15:49 +04:00
Colum Ferry 86de174d86 fix(testing): preload vitest/node to prevent race condition on Node 24 (#34261)
Preload vitest/node ESM module early in
buildViteTargets/buildVitestTargets
functions before parallel processing occurs. This prevents the
ERR_INTERNAL_ASSERTION error that occurs when multiple vitest.config
files
are processed in parallel on Node 24+.

Fixes #34028
Fixes #33091
2026-01-30 13:33:11 +00:00
Jason Jean d9f2ed0d44 fix(testing): add timeout to runCommandUntil to prevent hanging tests (#34148)
## Current Behavior

The `runCommandUntil` e2e utility function waits indefinitely for the
expected output to appear. If the output never appears (e.g., server
fails to start, different output format, port conflict), the test hangs
forever, causing CI jobs to run for hours before being killed.

## Expected Behavior

The function should timeout after a configurable duration and fail with
a clear error message showing what output was received.

## Related Issue(s)

Fixes hanging e2e tests observed in CI (e.g.,
`e2e-node:e2e-ci--src/node-server.test.ts` hung for 1h 21m).

## Changes

- Added optional `timeout` parameter to `runCommandUntil` opts (default:
5 seconds)
- On timeout: kills the process, logs the collected output, and rejects
with a clear error
- Existing call sites work unchanged; tests needing more startup time
can pass `{ timeout: 30000 }`

---------

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FrozenPandaz <8104246+FrozenPandaz@users.noreply.github.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-01-30 00:18:26 -05:00
Jack Hsu c331bf949c fix(nx-dev): fix internal link check caching and remaining /launch-nx link (#34255)
## Current Behavior

1. The `check-links` task cache inputs only included `sitemap.xml` (the
index
file) and `sitemap-index.xml`, but not the actual `sitemap-0.xml` files
that
contain the URL data. This meant that when pages were added or removed,
the
cache wasn't properly invalidated - the check-links task would return a
   cached "passing" result even when broken links existed.

2. The `/launch-nx` page was removed in #34183 but one link in
`astro-docs/src/content/docs/reference/Nx Cloud/release-notes.mdoc`
still
pointed to it. This link was masked by being in the `validate-links.ts`
   ignore list.

## Expected Behavior

1. The `check-links` task cache is invalidated when sitemap URLs change
by
   using glob patterns (`sitemap*.xml`) to include all sitemap files.

2. All links point to valid pages. The `/launch-nx` link now redirects
to
   `/blog/launch-nx-week-recap`.

## Changes

- **astro-docs/release-notes.mdoc**: Updated `/launch-nx` link to
`/blog/launch-nx-week-recap`
- **astro-docs/validate-links.ts**: Removed `/launch-nx` from ignore
list (no longer needed)
- **nx-dev/project.json**: Fixed cache inputs to use `sitemap*.xml` glob
patterns

## Related Issue(s)

Fixes DOC-385

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 17:10:47 -05:00
Colum Ferry 3d62c8b5c1 fix(vite): handle sophisticated vite plugins (#34242)
## Current Behavior
With Vite now providing additional options (environments etc) for
framework authors, vite.config files can be much more simple for the
user.
However, this often assumes that the `root` property will be set and
provided during `Vite CLI` invocation.

When we run `resolveConfig` to determine inputs and outputs, we do not
set this `root` and expect the user to have it in their vite config
file.
For some plugins/frameworks such as Tanstack Start - this causes the
plugin to error.

The `isBuildable` conditions is also not inclusive enough and can skip
projects that should be marked as buildable.

## Expected Behavior
Ensure that sophisticated vite plugins are supported with Nx

## Related Issue(s)

CLOSES NXC-3637
2026-01-29 14:28:31 +00:00
Jack Hsu 9c3a9d7e13 feat(core): add Nx Cloud connect URL to template README (#34249)
## Current Behavior
Template-generated workspaces use a generic link in the README instead
of a per-workspace short link for Nx Cloud setup.

## Expected Behavior
When users opt into Nx Cloud (or are auto-connected via variant 2), the
template README is updated with a personalized connect URL section that
helps them finish setting up their workspace.

---
BEFORE: 

<img width="762" height="460" alt="image"
src="https://github.com/user-attachments/assets/58900071-1727-49d1-aa19-279c488b5037"
/>


AFTER: 

<img width="1032" height="599" alt="image"
src="https://github.com/user-attachments/assets/a6e3a122-5807-4ba2-90dd-441e41a3280e"
/>

---

## Related Issue(s)
Closes NXC-3783

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 09:21:20 -05:00
Drew Teachout e189dcc101 fix(core): do not throw error if worker.stdout is not instanceof socket (#34224)
deno worker.stdout is a Readable/Writeable. To provide better deno
support an error should not be thrown

<!-- 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
<!-- This is the behavior we have today -->
If `worker.stdout` or `worker.stderr` are not instanceof Socket then nx
throws an error. This is problematic in Deno where `stdout` and `stderr`
are Readable/Writable and not Socket.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
`startupPluginWorker` function should work in Deno runtime

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

- https://github.com/denoland/deno/issues/31961
- https://github.com/oven-sh/bun/issues/26505

---------

Co-authored-by: Craigory Coppola <craigorycoppola@gmail.com>
2026-01-29 07:21:09 -05:00
Craigory Coppola 4f4b9dc048 fix(core): improve plugin worker error messages and lifecycle timeouts (#34251)
## Current Behavior
Plugin workers occasionally fall over during the start up steps. 

## Expected Behavior
Improves some issues with the error handling when loading plugin workers
and adds some more logs to help understand what's went wrong here.

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

Fixes #

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
2026-01-29 01:57:54 -05:00
Jason Jean fdabc14892 chore(repo): update nx to 22.5.0-beta.2 (#34252)
Updating Nx from 22.5.0-beta.1 to 22.5.0-beta.2

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-01-29 00:57:04 -05:00
Louie Weng da3b00f961 chore(core): edit project graph aggregate error message (#34248)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Remove redundantly placed period and make error message construction
more readable when facing AggregateError

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

Fixes NXC-3766

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-01-28 22:19:44 +00:00
Jason Jean 8d5b316fdd chore(repo): update nx to 22.5.0-beta.1 (#34234)
Updating Nx from 22.5.0-beta.0 to 22.5.0-beta.1

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-01-28 16:39:46 -05:00
Jack Hsu b53fd7c7f5 docs(misc): add 1% scroll depth tracking to docs and non-docs pages (#34246)
This PR adds scroll depth event at the 10% level so we can filter out
users who actually engages with the page versus those who maybe land on
homepage just to get to docs.

<img width="2672" height="1527" alt="Screenshot 2026-01-28 at 4 00
54 PM"
src="https://github.com/user-attachments/assets/ad9be5ae-442c-48eb-9c1e-70f0b872563b"
/>


Also fix the scroll tracker for astro-docs.

<img width="2672" height="1527" alt="Screenshot 2026-01-28 at 4 00
54 PM"
src="https://github.com/user-attachments/assets/e4a24ef2-b6aa-4f5a-b10b-972b73385fee"
/>

<img width="2672" height="1527" alt="Screenshot 2026-01-28 at 2 39
09 PM"
src="https://github.com/user-attachments/assets/833c71f1-7a96-4637-bb6e-3b21227053f0"
/>


## Related Issue(s)
Closes CLOUD-4211

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 16:25:12 -05:00
Louie Weng 5a424fa8df fix(gradle): use tooling api compatible flags (#34247)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

--rerun is not tooling api compatible and therefore will break usage of
the batch executor. Replaced the flag with --rerun-tasks.

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

Fixes #
2026-01-28 21:23:21 +00:00
Jason Jean cf043b7e20 feat(maven): load Maven classes at runtime for version-agnostic batch execution (#34180)
## Current Behavior

The Maven batch runner bundles Maven 4 classes at compile time, which:
- Creates a large JAR file (~50+ MB)
- Only works with Maven 4
- Has classloader conflicts with Maven's own SLF4J

## Expected Behavior

The batch runner loads Maven classes at runtime from `MAVEN_HOME`,
which:
- Creates a small JAR (~2 MB) with no bundled Maven dependencies
- Works with both Maven 3.x and Maven 4.x
- Avoids classloader conflicts by isolating Maven in its own ClassRealm
- Outputs clean Maven-style logs (`[INFO]`, `[WARNING]`, etc.)

## Implementation

### Architecture

```
batch-runner.jar (NO Maven dependencies)
├── MavenClassRealm         → Loads Maven JARs from MAVEN_HOME at runtime
├── ResidentMavenExecutor   → Maven 4 executor (reflection-based)
├── CachingMaven3Invoker    → Maven 3 executor (reflection-based)
└── nx-maven-adapters/      → Pre-compiled adapter JARs (embedded as resources)
    ├── batch-runner-adapters-maven3.jar
    └── batch-runner-adapter-maven4.jar
```

### Key Changes

1. **Removed compile-time Maven dependencies** from batch-runner module
2. **Created batch-runner-adapters** modules for Maven 3 and Maven 4
specific code
3. **Implemented MavenClassRealm** to load Maven JARs from MAVEN_HOME at
runtime
4. **Implemented reflection-based executors** that load adapter JARs
into ClassRealm
5. **Fixed SLF4J logging** with System.out redirection for clean
Maven-style output
6. **Added shared module** for BuildStateManager, BuildStateApplier, and
BuildStateRecorder

### Benefits

- **Version agnostic**: Same JAR works with Maven 3.x and 4.x
- **Graph caching**: Project dependency graph built once, reused across
tasks
- **Build state persistence**: compile → package → install works
correctly
- **No classloader conflicts**: Maven's classes isolated in their own
ClassRealm
- **Clean output**: Standard Maven log format without SLF4J noise

## Related Issue(s)

N/A - Internal refactoring for better Maven version support

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2026-01-28 14:13:31 -05:00
Jack Hsu 7276e4cff7 docs(misc): content negotiation for LLM-friendly docs access (#34239)
## Current Behavior
LLMs and CLI tools must explicitly request the `.md` URL suffix to get
raw markdown content from documentation pages.

## Expected Behavior
When a client requests a docs page with `Accept: text/markdown` header,
the edge function rewrites to serve the `.md` version directly (no
redirect). This enables LLM tools to get markdown content by requesting
the standard URL.

Behavior:
- `Accept: text/markdown` → serves .md content (via rewrite, no
redirect)
- Default (browsers) → serves HTML with Link headers (unchanged)

Examples:
```
curl -H 'Accept: text/markdown' https://deploy-preview-34239--nx-docs.netlify.app/docs/getting-started/intro
curl -H 'Accept: text/markdown' https://deploy-preview-34239--nx-docs.netlify.app/docs/getting-started/tutorials/angular-monorepo-tutorial
```

Uses Netlify Edge Function rewrite (returns URL object) instead of
redirect for single-request response that works with all HTTP clients.

## Related Issue(s)
Closes DOC-389

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 09:06:10 -05:00
Caleb Ukle f9258c9d82 fix(nx-dev): update dead links across nx-dev UI libraries (#34238)
## Current Behavior

broken links

## Expected Behavior

links aren't broken any more and are updated to expected pages from docs
page.

## Related Issue(s)

Fixes DOC-391
2026-01-27 15:51:55 -06:00
Jack Hsu 8b245f1b0a feat(nx-dev): add llms-full.txt and HTTP Link headers for LLM discovery (#34232)
This PR adds:
1. `llms-full.txt` that is a full copy of our docs in markdown.
2. HTTP `Link` headers to our docs HTML pages so that they point to the
`.md` (markdown) version, and also to `llms.txt` and `llms-full.txt`.

The `llms-full.txt` is currently at 2.7 MB, which is much less than
other sites that are up to 5MB or more.

<img width="569" height="35" alt="Screenshot 2026-01-27 at 12 11 10 PM"
src="https://github.com/user-attachments/assets/61be02b4-2813-4c39-951c-d831af83e823"
/>

First 100 lines of `llms-full.txt`:

````
# Nx Documentation

> Complete Nx documentation compiled into a single file for LLM consumption.

Nx is a powerful, open source, technology-agnostic build platform designed to efficiently manage codebases of any scale. From small single projects to large enterprise monorepos, Nx provides intelligent task execution, caching, and CI optimization.

This file was generated from 503 documentation pages.
Individual pages are available at: https://nx.dev/docs/{slug}.md


# Quickstart

---
<!-- source: https://nx.dev/docs/quickstart.md -->
## Quickstart with Nx

Get up and running with Nx in just a few minutes by following these simple steps.

{% steps %}

1. Install the Nx CLI

   Installing Nx globally is **optional** - you can use `npx` to run Nx commands without installing it globally, especially if you're working with Node.js projects.

   {% tabs syncKey="install-method" %}
   {% tabitem label="npm" %}

   ```shell
   npm add --global nx
   ```

   **Note:** You can also use Yarn, pnpm, or Bun

   {% /tabitem %}
   {% tabitem label="Homebrew (macOS, Linux)" %}

   ```shell
   brew install nx
   ```

   {% /tabitem %}
   {% tabitem label="Chocolatey (Windows)" %}

   ```shell
   choco install nx
   ```

   {% /tabitem %}
   {% tabitem label="apt (Ubuntu)" %}

   ```shell
   sudo add-apt-repository ppa:nrwl/nx
   sudo apt update
   sudo apt install nx
   ```

   {% /tabitem %}
   {% /tabs %}

2. Start fresh or add to existing project

   For JavaScript-based projects you can **start with a new workspace** using the following command:

   ```shell
   npx create-nx-workspace@latest
   ```

   **Add to an existing project: (recommended also for non-JS projects)**

   ```shell
   npx nx@latest init
   ```

   **Get the complete experience:**
   For a fully integrated development workflow with AI-powered CI features, [start directly from Nx Cloud](https://cloud.nx.app/get-started).

   Learn more: [Start New Project](/docs/getting-started/start-new-project) • [Add to Existing](/docs/getting-started/start-with-existing-project) • [Complete Nx Experience](https://cloud.nx.app/get-started)

3. Run Your First Commands

   Nx provides powerful task execution with built-in caching. Here are some essential commands:

   **Run a task for a single project:**

   ```shell
   nx build my-app
   nx test my-lib
   ```

   **Run tasks for multiple projects:**

   ```shell
   nx run-many -t build test lint
   ```

   Learn more: [Run Tasks](/docs/features/run-tasks) • [Cache Task Results](/docs/features/cache-task-results)

4. What's next?

   Now that you've experienced the Nx basics, choose how you want to continue:

````


## Related Issue(s)
Closes DOC-236

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-01-27 16:01:48 -05:00
Benjamin Cabanes a092ed06c4 docs(nx-dev): migrate color variants to contrast design (#34077)
This design refresh emphasizes the contrast variant aesthetic across all
hero sections, pricing cards, and primary call-to-actions.

- Change 47 instances of variant="primary" to variant="contrast"
- Update ui-courses to use variant="secondary" for GitHub link
- Prefer high-contrast inverted style for primary CTAs
- Maintain proper visual hierarchy with secondary actions
- Replace all slate-* classes with zinc-* equivalents (1,158 instances)
- Replace all sky-* classes with blue-* equivalents (210 instances)
- Update opacity variants, gradients, rings, and borders
- Maintain full dark mode compatibility
2026-01-27 20:54:33 +00:00
MaxKless de67da4bc6 chore(repo): add update ai agents configuration for a bunch of ai agents (#34231)
this sets the nx repo up with the latest and greatest
2026-01-27 13:50:42 -05:00
MaxKless f89ccb091f fix(core): hide already-installed nx packages from suggestion list during nx import (#34227)
## Current Behavior
If something is in `package.json#dependencies`, we still suggest it to
be `nx add`-ed during `nx import`

## Expected Behavior
If a plugin is already installed, we don't suggest it anymore
2026-01-27 13:23:42 -05:00
Colum Ferry 2bd8ef3f72 feat(js): bump swc to latest versions (#34215)
## Current Behavior
SWC versions are a few minors behind.

## Expected Behavior
SWC versions are up to date and are being managed via PNPM Catalogs
2026-01-27 17:14:55 +00:00
MaxKless 0e8893faea feat(core): improve configure-ai-agents to copy nx skills/subagents/plugins (#34176)
## Current Behavior
The `configure-ai-agents` command sets up rules files (CLAUDE.md,
AGENTS.md, GEMINI.md) and MCP configurations for AI coding agents, but
doesn't provide extensibility artifacts like commands, skills, or
subagents.
## Expected Behavior
The command now:
- **Adds OpenCode** as a new supported agent with project-level MCP
config
- **Configures Claude plugin** via marketplace settings
(`.claude/settings.json` with `extraKnownMarketplaces`)
- **Copies extensibility artifacts** (commands, skills, subagents) from
`nrwl/nx-ai-agents-config` repo for non-Claude agents
- **Caches the config repo** in
`/tmp/nx-ai-agents-config/<commit-hash>/` with automatic cleanup of old
versions
### Agent Distribution Matrix
| Agent | Rules | MCP Config | Commands | Skills | Subagents | Plugin |
|-------|-------|------------|----------|--------|-----------|--------|
| Claude | CLAUDE.md | .mcp.json | - | - | - | ✓ (marketplace) |
| OpenCode | AGENTS.md | opencode.json | ✓ | ✓ | ✓ | - |
| Copilot | AGENTS.md | Nx Console | ✓ | ✓ | ✓ | - |
| Cursor | AGENTS.md | Nx Console | ✓ | ✓ | - | - |
| Gemini | GEMINI.md | .gemini/settings.json | ✓ | ✓ | - | - |

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: MaxKless <MaxKless@users.noreply.github.com>
Co-authored-by: FrozenPandaz <jasonjean1993@gmail.com>
2026-01-27 16:10:28 +00:00
Jason Jean f9ab939c74 chore(repo): update nx to 22.5.0-beta.0 (#34209)
Updating Nx from 22.4.0-beta.5 to 22.5.0-beta.0
2026-01-27 09:52:22 -05:00
Colum Ferry 7a446e4979 fix(web): ensure vitest config file is created (#34216)
`@nx/web:app` generator is incorrectly calling `createOrEditViteConfig`
when bundler != vite and unitTestRunner = vitest.

Ensure it is using the correct file
2026-01-27 09:41:21 +00:00
Jack Hsu 0f33fa6c40 feat(core): add variant 2 to CNW cloud prompts with promo message (#34223)
This PR uses three variants for CNW for prompting for Cloud/platform
connection.

- Variant 0: Shows "Try the full Nx platform?" prompt → platform-setup
completion
- Variant 1: Shows "Would you like remote caching..." prompt →
cache-setup completion
- Variant 2: No prompt → platform-promo completion with "Want faster
builds?"

Both template and custom flows use the same messages and prompts.


### Skip (all) -- No changes


<img width="1392" height="994" alt="cnw_all_skip_completion"
src="https://github.com/user-attachments/assets/1579df01-fc36-4324-bc74-19efc18f78af"
/>

### Variant 0 (full platform)

Template prompt:

<img width="1392" height="994" alt="cnw_template_variant_0_prompt"
src="https://github.com/user-attachments/assets/d02e9ddc-fd25-4f6f-ac61-6f6d518fe338"
/>

Template completion:

<img width="1392" height="994" alt="cnw_template_variant_0_completion"
src="https://github.com/user-attachments/assets/12e459a0-962c-4724-82fa-a4f5a3b6fbd8"
/>

Custom prompt:

<img width="1392" height="994" alt="cnw_custom_variant_0_prompt"
src="https://github.com/user-attachments/assets/8143832a-a85e-43b4-81eb-15074c223476"
/>

Custom completion:

<img width="1392" height="994" alt="cnw_custom_variant_0_completion"
src="https://github.com/user-attachments/assets/036ef6f9-4977-459a-bbd2-502670a12d01"
/>

### Variant 1 (remote cache)

Template prompt:

<img width="1392" height="994" alt="cnw_template_variant_1_prompt"
src="https://github.com/user-attachments/assets/f69b540f-7e48-46ae-99e5-f53657176424"
/>

Template completion:

<img width="1392" height="994" alt="cnw_template_variant_1_completion"
src="https://github.com/user-attachments/assets/04c17847-b0f2-4e37-b7d2-5556aa14f510"
/>

Custom prompt:

<img width="1392" height="994" alt="cnw_custom_variant_1_prompt"
src="https://github.com/user-attachments/assets/abdb38b2-611e-458b-85c0-7b89cd1b827e"
/>


Custom completion:

<img width="1348" height="950" alt="cnw_custom_variant_1_completion"
src="https://github.com/user-attachments/assets/e7d35ddb-e8ac-4ad1-889e-9fff89538900"
/>

## Variant 2 (no prompt)

Template completion:

<img width="1392" height="994" alt="cnw_template_variant_2_completion"
src="https://github.com/user-attachments/assets/07050989-a56c-46eb-a0c3-8730916856ff"
/>

Custom completion:

<img width="1392" height="994" alt="cnw_custom_variant_2_completion"
src="https://github.com/user-attachments/assets/94000828-37b2-4059-a13b-0d36972cfd3e"
/>

## Related Issue(s)

Closes CLOUD-4189

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 16:30:05 -05:00
Jack Hsu e108dac1bb Revert "Revert "feat(core): add A/B testing variant 1 to skip cloud p…rompt in CNW (#34106)" (#34191) (#34204)
This reverts commit f016664557.
2026-01-26 14:58:26 -05:00
Colum Ferry 3fcd2008ef fix(react): remove file-loader dependency and update svgr migration (#34218)
## Current Behavior
The migration for svgr requires using file-loader which is unmaintained.

## Expected Behavior
Use asset/resource instead of file-loader

## Related Issue(s)

CLOSES NXC-3667
2026-01-26 16:56:18 +00:00
Jason Jean 75f36edb8f fix(core): fall back to node_modules when tmp has noexec (#34207)
## Summary

- When `/tmp` is mounted with `noexec`, loading native modules from the
cache fails silently and causes Nx to hang indefinitely
- This adds a fallback to load from `node_modules` when permission
errors occur

## Problem

Users with `/tmp` mounted with `noexec` (a common security hardening
practice) experience Nx hanging forever, even for simple commands like
`nx --version`.

The root cause:
1. Nx copies native `.node` files to `/tmp` to avoid Windows file
locking issues
2. On `noexec` mounts, execution fails with `EACCES`/`EPERM`
3. The error wasn't caught, leading to broken native bindings and
infinite loops

## Solution

Catch permission errors when loading from the cache and fall back to the
original `node_modules` location. This:
- Works automatically without user config
- Preserves Windows file locking fix (only falls back when needed)
- No error messages for users

Closes #33991
2026-01-23 17:32:15 -05:00
Miguel 3672e1a3ea fix(devkit): allow null values in JSON schema validation (#34167)
<!-- 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
<!-- This is the behavior we have today -->

Schema validation (done, for instance, when calling an executor) fails
when an option has value "null" and schema accepts null values. I had it
in a custom executor for `nx-release-publish`, that understands that
`nxReleaseVersionData` is implicitly passed, so I define its schema:
```json
"newVersion": {
  "type": ["string", "null"],
  "description": "The new version of the project, null if no changes detected"
}
```

My code calls `getReleaseClient().releaseVersion(options)`, which gets
me a `projectsVersionData` object with version info. It contains `null`
values (allowed). I then pass it, and ends up in:
```typescript
 // nx/src/tasks-runner/task-orchestrator.ts:531-539                                                                                                                                                                      
  const combinedOptions = combineOptionsForExecutor(                                                                                                                                                                       
      task.overrides,  // ← Contains nxReleaseVersionData with null values                                                                                                                                                 
      task.target.configuration,                                                                                                                                                                                           
      targetConfiguration,                                                                                                                                                                                                 
      schema,           // ← Schema from executor                                                                                                                                                                          
      task.target.project,                                                                                                                                                                                                 
      relativeCwd,                                                                                                                                                                                                         
      isVerbose                                                                                                                                                                                                            
  );
```

which fails inside:
```typescript
 // nx/src/utils/params.js:126-201                                                                                                                                                                                        
  function validateObject(opts, schema, definitions) {                                                                                                                                                                     
      // Line 191-200: Iterate through all properties                                                                                                                                                                      
      Object.keys(opts).forEach((p) => {                                                                                                                                                                                   
          validateProperty(                                                                                                                                                                                                
              p,                              // "nxReleaseVersionData"                                                                                                                                                    
              opts[p],                        // { foo: { newVersion: null, ... }}                                                                                                                                         
              (schema.properties ?? {})[p],   // schema for nxReleaseVersionData                                                                                                                                           
              definitions                                                                                                                                                                                                  
          );                                                                                                                                                                                                               
      });                                                                                                                                                                                                                  
  }
  ```

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR -->

`null` values should be considered, as they are valid in JSON schemas. It was probably not considered, because we never think that `typeof null === "object"`, but it's unfortunately the case.

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

I will create one

Fixes https://github.com/nrwl/nx/issues/34169
2026-01-23 15:09:09 -05:00
Jack Hsu bc9b3229c6 feat(js): add NX_PREFER_NODE_STRIP_TYPES to use Node's strip types feature instead of transpilation for TypeScript files (#34202)
Transpiling through SWC or ts-node is slow compared to the native type
stripping that Node.js provides.

This PR adds `NX_PREFER_NODE_STRIP_TYPES` to allow users to use Node.js
built-in TypeScript support. There are some features that need
transpilation that won't work with type stripping:

- Enum declarations
- namespace with runtime code
- legacy module with runtime code
- parameter properties
- path aliases

See: https://nodejs.org/api/typescript.html#full-typescript-support

The speed-up is significant. My test workspace went from 22s to ~2s to
compute from cold cache.

Demo: https://www.loom.com/share/ce1db29e501b46d58109ffeec8a7a649

In the future we should enable this by default, and users have to turn
it off to use SWC/ts-node.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2026-01-23 14:13:00 -05:00
Leosvel Pérez Espinosa a15881db1a feat(core): display batch tasks in the tui (#33695)
Adds support for Batch tasks and displays them in the TUI.

---------

Co-authored-by: FrozenPandaz <jasonjean1993@gmail.com>
2026-01-23 13:48:04 -05:00
Jack Hsu 1dd4262336 docs(misc): collect usage data on .md and .txt files (#34203)
Right now GA only collects page views. This PR allow us to see which
`.md` files are being used. There are mostly useful for AI agents to
fetch without using too many tokens. We want to track usage so we can
see what techniques to guide agents actually work.

## Related Issue(s)
Closes DOC-386

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 12:38:17 -05:00
Jack Hsu 687357c82e fix(core): cloud commands are noop when not connected rather than errors (#34193)
This PR makes it so Cloud commands like `npx nx record` and `npx nx
fix-ci` still work without `nxCloudId`. We'll log a warning so that
`ci.yml` using these commands will still work. The warning let's users
know that these do not work without being connected.

Closes #NXC-3753
2026-01-23 12:29:41 -05:00
Mark Lindsey 3d1e544812 chore(repo): commit lint mention that commits should be lowercase (#34199)
<!-- 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
Commit linting does not mention requirement for commit message to be
lowercase.
<!-- This is the behavior we have today -->

## Expected Behavior
Hook message should instruct user to use all lowercase for commit
message.
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2026-01-23 11:19:42 -05:00
Jack Hsu 9bb69383b8 fix(core): consolidate GitHub URL messaging when gh push fails (#34196)
When `gh repo create` fails, users see two redundant messages. This
consolidates them into a single message with the helpful `?name=...`
parameter in the GitHub URL.

BEFORE: (We show `Could not push. Push repo to complete setup.` and then
`Push your repo (https://github.com/new)...` again at the end)

<img width="1209" height="560" alt="image"
src="https://github.com/user-attachments/assets/e22c012c-8e0f-4ff9-a6c2-de8267b69b5d"
/>

AFTER: (Only show `Could not push` as an info log, and then complete
setup is shown only once at the end)

<img width="1250" height="591" alt="image"
src="https://github.com/user-attachments/assets/3dc075c7-4418-4373-a07a-1b95f71b3b87"
/>

Closes NXC-3754

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 11:18:23 -05:00
Jonathan Cammisuli 1831ace87e docs(nx-dev): update docs to include SELF_HEALING.md information (#34200) 2026-01-23 15:12:03 +00:00
Mark Lindsey 478afc7046 docs(nx-dev): add bitbucket to self healing docs (#34198)
<!-- 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
Self-healing docs only reference being supported for GitHub, Azure, and
GitLab.
<!-- This is the behavior we have today -->

## Expected Behavior
We should show instructions for all currently supported vcs providers,
including Bitbucket.
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2026-01-23 14:48:04 +00:00
JamesHenry 1299d044eb chore(repo): remove --auto-apply-fixes, it is set in Nx Cloud UI 2026-01-23 15:41:24 +04:00
Craigory Coppola 273a474047 fix(core): handle resizing a bit better for inline_tui (#34006)
## Current Behavior
Resizing the TUI while in inline view kinda breaks things. Its
unfortunate, I'm not sure there's a ton to be done, but this PR explores
some solutions

## Expected Behavior
The TUI is less sensitive to resize events with inline mode

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

Fixes #
2026-01-22 18:54:56 -05:00
Jason Jean f016664557 Revert "feat(core): add A/B testing variant 1 to skip cloud prompt in CNW (#34106)" (#34191)
## Current Behavior

The create-nx-workspace (CNW) command includes A/B testing variant 1
which skips the cloud prompt under certain conditions.

## Expected Behavior

Revert to the previous behavior where the cloud prompt flow is
consistent without the A/B testing variant.

## Related Issue(s)

This reverts commit 2039a5e119 from PR
#34106.
2026-01-22 16:14:21 -05:00
Jason Jean 81bb7d3d17 fix(nx-dev): update broken /launch-nx links (#34192)
## Current Behavior

The internal link checker reports 3 broken links pointing to
`/launch-nx`:
- `/blog/2024-02-05-nx-18-project-crystal.md`
- `/blog/2024-02-15-launch-week-recap.md`
- `/changelog/18_0_0.md`

The `/launch-nx` page was a temporary page for the Nx 18 launch event in
February 2024 and no longer exists.

## Expected Behavior

All internal links should point to valid pages. Links to the old launch
page now redirect to the Launch Nx Week recap blog post.

## Related Issue(s)

Fixes the internal link checker errors.
2026-01-22 21:14:01 +00:00
Craigory Coppola 587659cb03 fix(core): move tui to parking lot rwlock to avoid hang (#34187)
## Current Behavior
There's a hard to reproduce hang that happens occasionally when running
the TUI

## Expected Behavior
We think this should fix it

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-01-22 15:49:58 -05:00
Benjamin Cabanes 05de3ff450 docs(nx-dev): remove Nx Conf and Advent of Code pages (#34183)
Removed Nx Conf and Advent of Code pages, associated UI components, and
references from the configuration files. Simplified package structure by
removing `@nx/nx-dev-ui-conference` package.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: bcabanes <bcabanes@users.noreply.github.com>
2026-01-22 12:10:12 -05:00
Jack Hsu 8fee466a1f chore(misc): remove banner.json files and add to gitignore (#34185)
The `banner.json` was committed as a fallback if we're not using Framer
to control the banner yet on nx.dev. Now that it is verified we can
remove the committed file.

Closes DOC-381

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 11:26:10 -05:00
MaxKless d6572f3de4 fix(core): clean up daemon workspace data directory on nx reset --onl… (#34174)
Previously, `nx reset --onlyDaemon` would only stop the daemon process
but not clean up the daemon files in `.nx/workspace-data/d`. This change
ensures the daemon workspace data directory is also removed when using
the `--onlyDaemon` flag, consistent with the behavior of a full reset.

Co-authored-by: MaxKless <MaxKless@users.noreply.github.com>
2026-01-22 16:29:08 +09:00
Jack Hsu 367986dea1 docs(core): update version on releases reference page (#34178)
This PR updates the releases page so v22 is included.

Closes #DOC-382

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-01-21 15:58:00 -05:00
Caleb Ukle 6ae0fd1217 docs(nx-dev): make sure cli nested sub commands are parsed (#34179)
commands like nx release and nx show were missing sub commands. make
sure they are now correctly parsed.

<img width="224" height="162" alt="image"
src="https://github.com/user-attachments/assets/f51c12f2-9926-44a1-a3c0-57de565434bd"
/>


also, fixed the "getting help" for plugin docs being rendered
incorrectly. and add double dash `--` to the plugin option docs to match
rest of docs.


<img width="874" height="634" alt="image"
src="https://github.com/user-attachments/assets/be7a58a3-0ea0-41d5-8ba6-98cfa0210a95"
/>
2026-01-21 20:26:30 +00:00
Jason Jean 1b12e1fc6f fix(core): improve TUI task selection and pane focus behavior (#34175)
## Current Behavior

1. When running a task with dependencies (e.g., `nx serve app` where app
depends on app2:serve), the initiating task might not be selected on
startup. Additionally, the auto-select logic could switch selection to
the initiating task at any time when it started running - even minutes
later - which felt "random" to the user.

2. When pressing Enter on an already-pinned task, it would unpin the
task, causing the pane to disappear while focus remained on it
(invisible-but-focused state).

## Expected Behavior

1. The initiating task (the one the user actually requested) should be
selected during init, and selection should never unexpectedly change
later when tasks start.

2. Pressing Enter on an already-pinned task should focus the pane, not
unpin it.

## Changes

- **Select initiating task during init**: Moved initiating task
selection to `init()` in app.rs. This only applies in `RunOne` mode
since in `RunMany` there's no single initiating task to prioritize.
Removed the "switch to initiating task" logic from `start_tasks()` in
tasks_list.rs.
- **Focus pane on Enter**: Changed behavior so pressing Enter on an
already-pinned task focuses the pane instead of unpinning it.

## Related Issue(s)

N/A - discovered during TUI testing
2026-01-21 14:02:43 -05:00
Jason Jean fc8072930a chore(repo): update nx to 22.4.0-beta.5 (#34162)
Updating Nx from 22.4.0-beta.4 to 22.4.0-beta.5
2026-01-21 13:04:47 -05:00
Juri b6ed6cbca8 docs(nx-dev): blog post about vertical and horizontal continuity with agents 2026-01-21 17:00:54 +01:00
Tomas Ptacek 162fca17c4 fix(module-federation): dev server handler accumulation (#34152)
# Current Behavior
The `beforeCompile` hook is registered inside the `watchRun` hook,
causing a new handler to be added on every recompilation. This leads to
handler accumulation, where setup operations (building static remotes,
starting file server, starting proxies) are triggered multiple times
during watch mode.

# Expected Behavior
Hooks should be registered once, outside of other hooks, to prevent
accumulation. Setup operations should only run once, not on every
recompilation.

# Related Issue(s)
Fixes https://github.com/nrwl/nx/issues/34141
2026-01-21 15:09:39 +00:00
James Henry e57848cea7 chore(repo): update self-healing ci docs (#34126)
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: JamesHenry <JamesHenry@users.noreply.github.com>
2026-01-21 08:17:16 -05:00
Tomas Ptacek 5f51a4b268 fix(angular-rspack): stats serialization and configuration (#34155)
# Current Behavior
1. **Performance bottleneck**: `statsValue.toJson()` is called with no
options, causing full serialization of all stats data on every build.
This is expensive and unnecessary when only budget checking is needed.
2. **Redundant work**: Budget checking code runs even when no budgets
are configured or when targeting server platform.
3. **User stats config ignored**: Custom stats configuration provided
via `rspackConfigOverrides` is not respected by the stats logger.
4. **Double serialization**: `rspackStatsLogger` calls `stats.toJson()`
without passing the stats options, ignoring user preferences.

# Expected Behavior
1. Only serialize what's needed for budget checking (`assets` and
`chunks`), significantly reducing overhead.
2. Early exit when budgets are not configured or on server platform,
skipping expensive `toJson()` entirely.
3. User's stats configuration is merged with defaults and respected
throughout the build output.
4. `rspackStatsLogger` uses the provided `statOptions` when serializing
stats.

# Related Issue(s)
Fixes https://github.com/nrwl/nx/issues/34145
2026-01-21 09:31:55 +00:00
Jack Hsu 2039a5e119 feat(core): add A/B testing variant 1 to skip cloud prompt in CNW (#34106)
## Current Behavior
CNW always shows the "Try the full Nx platform?" prompt and connects to
Nx Cloud to generate an onboarding URL with a token.

## Expected Behavior
For A/B testing variant 1:
- Skip cloud prompt
- Skip connectToNxCloudForTemplate() - no nxCloudId in nx.json
- Skip readNxCloudToken() - no misleading spinner
- Use GitHub flow for URL generation (accessToken: null)
- Show github.com/new hint when user hasn't pushed

Also fixes:
- Expired cache file bug: now deletes with unlinkSync() instead of
ignoring, which caused 50-50 randomization after 1-week expiry
- Adds variant-X to short URL meta property for cloud analytics

## Related Issue(s)
Closes NXC-3628

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 16:44:00 -05:00
Jason Jean 411e2e2453 chore(repo): update nx to 22.4.0-beta.4 (#34138)
Updating Nx from 22.4.0-beta.3 to 22.4.0-beta.4
2026-01-20 16:41:29 -05:00
Craigory Coppola f4bb7d734f chore(repo): remove .deb file from accidental commit and update gitignore (#34161)
removes accidentally committed file
2026-01-20 16:37:48 -05:00
Jason Jean e586896470 fix(core): prioritize nx installation path in getNxRequirePaths (#34158)
## Current Behavior

`getNxRequirePaths` returns paths in the order `[root,
getNxInstallationPath(root)]`, which means the workspace root is checked
first when resolving modules.

## Expected Behavior

The nx installation path (`.nx/installation`) should be prioritized and
checked first before falling back to the workspace root. This ensures
that modules from the nx installation directory take precedence.

## Related Issue(s)

N/A
2026-01-20 18:54:08 +00:00
Tomas Ptacek d2335186ac feat(angular-rspack): add tailwind and postcss config to component stylesheet bundler (#34153)
# Current Behavior
The Angular Rspack compiler's `ComponentStylesheetBundler` does not
receive Tailwind or PostCSS configuration. This means Tailwind
directives (like `@apply`, `@tailwind`) in component stylesheets are not
processed, resulting in broken styles.

# Expected Behavior
Component stylesheets should support Tailwind CSS and PostCSS
configurations, matching the behavior of the standard Angular CLI build
process.

# Related Issue(s)
https://github.com/nrwl/nx/issues/34098
2026-01-20 15:15:39 +00:00
Tomas Ptacek 2d7e24ce68 fix(angular-rspack): handler accumulation and watchOptions for double rebuilds (#34154)
# Current Behavior
1. **Handler accumulation**: The `compilation`, `beforeCompile`, and
`done` hooks are registered inside `watchRun`, causing new handlers to
be added on every rebuild cycle. This leads to performance degradation
and duplicate operations during watch mode.
2. **Double rebuilds**: Rapid filesystem events (e.g., editor
backup/swap files) trigger multiple rebuilds because there's no
aggregation timeout configured.
3. **No watchOptions configuration**: Users cannot customize watcher
behavior (aggregateTimeout, ignored patterns, etc.).

# Expected Behavior
1. Hooks should be registered once outside of `watchRun` to prevent
accumulation. Shared state is used to pass data between watch cycles and
compilation hooks.
2. A default `aggregateTimeout: 50` batches rapid filesystem events to
prevent double rebuilds.
3. Users can provide custom `watchOptions` to configure watcher
behavior, with user options taking precedence over defaults.

# Related Issue(s)
https://github.com/nrwl/nx/issues/34142#issuecomment-3767571208
2026-01-20 14:22:07 +00:00
Leosvel Pérez Espinosa 6bb82c0c2e fix(core): establish cpu baseline when possible to improve measurement accuracy (#34120)
## Current Behavior

New task processes show 0% CPU on their first measurement because no
baseline exists. Accurate readings only appear on the second collection
cycle (~1s later).

## Expected Behavior

New task processes get accurate CPU readings on their first measurement.
The collector establishes CPU baselines for newly registered processes
~250ms before collection, giving `sysinfo` enough time to calculate
accurate CPU deltas.

## Technical Details: Baselining & Collection Flow

The collection loop runs in 4 phases:

```
 T=0ms      T=750ms      T=1000ms    T=1750ms     T=2000ms  
   |           |             |           |            |
   v           v             v           v            v
Collect → Sleep(750ms) → Baseline → Sleep(250ms) → Collect → ...
```

1. **Collect**: Refresh all processes and gather metrics
2. **Post-collection sleep**: Wait until baseline time (interval -
250ms)
3. **Baseline**: Bulk CPU refresh for newly registered PIDs (if any)
4. **Pre-collection sleep**: Wait 250ms for accurate CPU delta
calculation
2026-01-19 11:53:07 -05:00
Craigory Coppola 0137ea2dc9 fix(core): avoid panic when inline tui can't init (#34135)
## Current Behavior
if inline tui init fails, we panic

## Expected Behavior
If inline tui init fails, inline mode is disabled. We show the reason
its disabled when someone tries to use it.

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

Fixes #
2026-01-17 23:38:00 -05:00
Jason Jean 6754cde03a fix(core): drain stdin on exit to prevent escape sequence leakage (#34134)
## Current Behavior

When exiting the TUI (especially via Ctrl+C), escape sequences leak to
the terminal:
```
^[]11;rgb:2121/2121/2121^[\^[[55;1R^[[?62;22;52c
```

This happens because the TUI queries terminal background color via OSC
11 to detect dark/light mode. The terminal responds with an escape
sequence, but if the program exits before fully consuming the response,
it appears in the terminal output.

## Expected Behavior

Clean terminal state after TUI exits, with no escape sequence artifacts.

## Related Issue(s)

N/A - discovered during development

## Solution

Added `drain_stdin()` function that polls and consumes any pending
terminal events before disabling raw mode. This clears any lingering OSC
responses (like the background color query response) before the terminal
is restored.

```rust
fn drain_stdin() {
    use std::time::Duration;
    while crossterm::event::poll(Duration::from_millis(5)).unwrap_or(false) {
        let _ = crossterm::event::read();
    }
}
```

The 5ms timeout is long enough to catch pending responses but short
enough not to noticeably delay exit.
2026-01-17 16:30:38 +00:00
Jason Jean 4202f2c760 fix(core): prevent task hashing when project graph has errors (#34116)
## Current Behavior

When the daemon encounters a project graph error during task hashing, it
extracts the partial project graph from the error and continues hashing
tasks. This can produce incorrect hashes since the graph is incomplete.

## Expected Behavior

The error should be thrown immediately, preventing any hashing attempts
with an invalid project graph. This ensures we don't produce incorrect
task hashes that could lead to cache issues.

## Related Issue(s)

N/A - Bug fix discovered during development
2026-01-16 18:30:35 -05:00
Philip Fulcher 323554b335 docs(nx-dev): fix metric number in header image for article (#34131) 2026-01-16 19:54:46 +00:00
Philip Fulcher 643a6be8be docs(nx-dev): add caseware success story article (#34127) 2026-01-16 14:31:26 -05:00
Colum Ferry 6092966ce4 feat(core): add PLUGIN.md files to testing-tools (#34125)
Add PLUGIN.md files to test related plugins

Closes NXA-789
2026-01-16 18:40:10 +00:00
Jason Jean 25442271ab chore(repo): update nx to 22.4.0-beta.3 (#34108)
Updating Nx from 22.4.0-beta.1 to 22.4.0-beta.3

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-01-16 09:28:53 -05:00
Colum Ferry e343bd27d8 feat(bundling): replace rollup-plugin-postcss with inlined version (#34110)
## Current Behavior
The `rollup-plugin-postcss` has not released a new version in 4 years.
The deps it depends on are outdated and starting to cause problems with
peer-dep conflicts.

## Expected Behavior
Recreate the plugin within the `@nx/rollup` package to maintain the
functionality/behaviour and manage dependencies ourselves.

## Related Issue(s)

Closes NXC-3644

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Coly010 <Coly010@users.noreply.github.com>
2026-01-16 13:14:42 +00:00
Leosvel Pérez Espinosa 07a68baab9 fix(vitest): prevent config double-merge causing array duplication (#34113)
## Current Behavior

Running `nx test` with Vitest browser mode fails with error:

> "The browser configuration must have a 'name' property"

Array configs like `browser.instances` and `reporters` get duplicated,
breaking tests.

## Expected Behavior

Vitest browser mode and array configurations work correctly without
duplication.

## Related Issue(s)

Fixes #33591
2026-01-16 09:51:03 +00:00
Leosvel Pérez Espinosa 7e12359221 feat(angular): add support for angular v21.1 (#34057)
## Current Behavior

Angular v21.1 is not supported.

## Expected Behavior

Angular v21.1 should be supported.
2026-01-15 15:05:50 -05:00
Nicolas Beaussart 21d1555d78 feat(core): add OpenCode AI agent detection (#34072)
## Current Behavior

Nx's AI agent detection currently identifies Claude Code, Repl.it, and
Cursor AI agents via environment variables, but does not detect
OpenCode.

## Expected Behavior

Nx should also detect when running under OpenCode AI agent by checking
for the `OPENCODE` environment variable, which OpenCode sets to `1` when
active.

## Related Issue(s)

N/A - Feature addition to improve AI agent detection coverage.

## Changes

- Added `is_opencode_ai()` function in
`packages/nx/src/native/utils/ai.rs`
- Updated `is_ai_agent()` to include OpenCode detection
- Added corresponding unit tests
2026-01-15 11:28:23 -05:00
MaxKless 1b12b392b7 fix(core): only run nx console background check if daemon is active (#33917) 2026-01-16 00:15:26 +09:00
MaxKless fe0757c981 chore(repo): update agents.md and claude.md (#34112) 2026-01-16 00:14:41 +09:00
Steven Nance 88098cc5f7 fix(core): ensure consistent yarn optional dependency hashing (#34104)
## Current Behavior

For optional packages that are not installed when using yarn, we
currently add the package version to the key for the hash. NPM and PNPM
do not do this.

The results in inconsistent hashes for package dependencies when running
in different environments. For example, trying to use the cache created
in CI on linux on a mac where native dependencies are used.

**yarn on arm mac**

_note how the key has the version in it for the linux and x64 versions
that are not installed_
```
$ nx test foo | grep @nx/nx-
...
        "npm:@nx/nx-darwin-x64@22.3.3": "14042642002999097748",
        "npm:@nx/nx-linux-x64-gnu@22.3.3": "12169496858981304476",
        "npm:@nx/nx-darwin-arm64": "1683411334940043113", 
```

**npm on arm mac**

```
$ nx test foo | grep @nx/nx-
...
        "npm:@nx/nx-darwin-x64": "14042642002999097748",
        "npm:@nx/nx-darwin-arm64": "1683411334940043113",
"9980946580833020728",
        "npm:@nx/nx-linux-x64-gnu": "12169496858981304476",
```


**pnpm on arm mac**
```
$ nx test foo | grep @nx/nx-
...
        "npm:@nx/nx-darwin-arm64": "1683411334940043113",
        "npm:@nx/nx-darwin-x64": "14042642002999097748",
        "npm:@nx/nx-linux-x64-gnu": "12169496858981304476",
```


## Expected Behavior

Optional dependencies should be handled the same way from a hashing
perspective as installed dependencies.

**yarn on arm mac**

```
$ nx test foo | grep @nx/nx-
...
        "npm:@nx/nx-darwin-x64": "14042642002999097748",
        "npm:@nx/nx-linux-x64-gnu": "12169496858981304476",
        "npm:@nx/nx-darwin-arm64": "1683411334940043113", 
```
2026-01-15 10:06:12 +01:00
Philip Fulcher acb4d3cb3d docs(nx-dev): changed pinned posts (#34109) 2026-01-14 19:35:38 -06:00
Miroslav Jonaš 95300a20cc fix(core): improve buildExplicitTypeScriptDependnecies performance (#33963)
On test repo reduces the
`nx/js/dependencies-and-lockfile:createDependencies`:
- from `10506ms`
- to `3665ms`

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-01-14 22:10:33 +01:00
Leosvel Pérez Espinosa 45f2ae303a fix(core): upgrade sysinfo to 0.37.2 and fix cpu measurement accuracy (#34101)
## Current Behavior

CPU metrics collection can report inaccurate values where:

- Individual processes show inflated CPU usage
- Total CPU aggregation across all processes exceeds the system's
maximum available CPU
- This leads to confusing and misleading metrics data  

## Expected Behavior

CPU metrics accurately reflect actual resource usage:

- Process CPU values are accurate
- Total CPU aggregation stays within system limits
- Metrics data is reliable and trustworthy

### Additional Notes

- **Root cause**: When registering a new process, we established a CPU
baseline by refreshing only that single process via `sysinfo`.
Internally, `sysinfo` calculates CPU% as `(process_cpu_time_delta /
wall_time_delta) * 100`. Refreshing a single process updates the wall
time reference but leaves the CPU time baselines of other processes
unchanged. In the next metrics collection, these other processes appear
to have consumed their CPU time over a shorter wall time period (based
on the last baseline), resulting in inflated percentages (e.g., 200%+
for single-threaded processes).
- This PR also improves initialization performance by only loading
necessary system data (processes, CPU, memory) instead of all system
information
- Upgrades `sysinfo` dependency to v0.37.2, which includes upstream CPU
measurement improvements.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-01-14 19:40:22 +01:00
Jack Hsu 4816c5514a feat(nx-dev): add scroll depth tracking for marketing pages (#34105)
## Current Behavior

Marketing pages (homepage, /react, /java, etc.) do not track scroll
depth. Only docs pages have scroll tracking via the ScrollableContent
component.

## Expected Behavior

Marketing pages now track scroll depth and fire scroll_0, scroll_25,
scroll_50, scroll_75, scroll_90 events to Google Analytics, matching the
existing docs page behavior.

## Related Issue(s)
Closes DOC-376

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 12:36:12 -05:00
Colum Ferry 42b1f144da fix(misc): deprecate setup-tailwind generators (#34097)
The setup-tailwind generators are deprecated as generating Tailwind
configuration is no longer maintained. This adds deprecation metadata
to generators.json and runtime warnings when the generators are invoked.

Affected packages: @nx/angular, @nx/react, @nx/next, @nx/remix, @nx/vue

These generators will be removed in Nx 23.

For adding Tailwind support, people can follow the official Tailwind
guides. We also
- updated our
[angular](https://nx.dev/docs/technologies/angular/guides/using-tailwind-css-with-angular-projects)
and
[react](https://nx.dev/docs/technologies/react/guides/using-tailwind-css-in-react)
docs and have a [blog
post](https://nx.dev/blog/setup-tailwind-4-angular-nx-workspace) about
it with more info.

Closes NXC-3714
2026-01-14 16:52:27 +00:00
Craigory Coppola d6b01597e4 fix(core): only init inline view if able to run (#34094)
## Current Behavior
The inline tui runs some terminal escape codes to check cursor position,
these break when stdin isn't a tty (like in a git hook)

## Expected Behavior
The inline tui is disabled if stdin isn't a tty

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-01-14 11:26:13 -05:00
Jason Jean 60e0fcde01 fix(maven): include migrations.json in published package (#34086)
## Current Behavior

The `migrations.json` file in the `@nx/maven` package is not included in
the `files` array in `package.json`. This means when the package is
published to npm, the migrations file is not included, preventing users
from running migrations.

## Expected Behavior

The `migrations.json` file should be included in the published package
so that Nx can discover and run migrations when users upgrade.

## Related Issue(s)

N/A - discovered during development
2026-01-14 10:20:02 -05:00
Leosvel Pérez Espinosa e1bb85254c chore(core): exclude handwritten files from native build outputs (#34099)
Exclude some handwritten files from the native build outputs. When those
files are updated in isolation, the build can replace them with stale
cached outputs. This is because they are not inputs of the native
builds, but are incorrectly stored as outputs of the native builds.
2026-01-14 10:08:36 -05:00
Colum Ferry 85deb8bc66 chore(core): update minimatch to latest version (#34063)
Update Minimatch to v10

Closes NXC-3661
2026-01-14 10:02:52 -05:00
Colum Ferry 574d841837 chore(core): update to latest version of tsquery (#34067)
Update to latest version of TSQuery (v6).

Closes NXC-3660

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-01-14 09:08:40 -05:00
Juri 6bf261d9d0 docs(react): update the Tailwind v4 guide 2026-01-14 10:00:48 +01:00
Juri 0777cb87cf docs(angular): update the Tailwind v4 guide 2026-01-14 10:00:48 +01:00
Juri 6cde9c075e docs(nx-dev): using Angular with Tailwind v4 in a Nx monorepo 2026-01-14 10:00:48 +01:00
Jack Hsu f23d48512e docs(misc): update footer with proper year (#34093)
This PR updates the `2025` in footer component to always be the current
year during build.

<img width="474" height="186" alt="image"
src="https://github.com/user-attachments/assets/a177d57d-e58a-411d-9002-9073b16ec007"
/>
2026-01-13 22:44:40 +00:00
Jack Hsu 246d4fd636 docs(misc): remove banner.enabled check since we only use banner.activeUntil (#34091)
This PR removes the `enabled` check for webinar banner since we don't
have the prop in Framer CMS.

## Local verification using
https://ready-knowledge-238309.framer.app/api/banners

Pages router:
<img width="2670" height="1527" alt="image"
src="https://github.com/user-attachments/assets/b7dfb6c1-6c2a-4f73-8efa-64a66d61ef0c"
/>

App router (blog):

<img width="2670" height="1527" alt="image"
src="https://github.com/user-attachments/assets/6df2bd12-06d4-4d22-bc45-3c772067b6fa"
/>
2026-01-13 13:05:10 -05:00
Leosvel Pérez Espinosa 0bb9d67f0b fix(core): prevent alias from overwriting root deps in pnpm parser (#34064)
## Current Behavior

When using pnpm aliases, the project graph may miss the actual
dependency node (the aliased package overwrites it), resulting in
incomplete or confusing dependency graphs.

## Expected Behavior

The project graph should include both the alias and the actual
dependency node, matching the behavior of other package managers.
2026-01-13 17:25:12 +01:00
Craigory Coppola df99ad50c7 fix(core): show daemon status in nx report output (#34009)
## Current Behavior
No daemon info is provided in `nx report`, but some issues are
exasperated by the daemon or may only show if the daemon is disabled.
This is useful context that we currently lack.

## Expected Behavior
`nx report` includes if the daemon is available, enabled but not
started, or disabled.

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-01-13 10:10:58 -05:00
Copilot 6be0a7eb56 feat(core): allow nx show project to infer project from cwd (#33661)
## Current Behavior

Running `nx show project` without specifying a project name fails, even
when inside a project directory:

```bash
cd packages/my-lib
nx show project
# Error: requires projectName argument
```

## Expected Behavior

When run from within a project directory, `nx show project` infers the
project from the current working directory:

```bash
cd packages/my-lib
nx show project        # Shows my-lib configuration and targets
nx show project --json # Outputs JSON for my-lib
```

Explicit project name still works:
```bash
nx show project other-project
```

If cwd is not within any project, shows a helpful error with usage
instructions.

### Changes
- `command-object.ts`: Make `projectName` positional arg optional
(`[projectName]`)
- `project.ts`: Infer project from cwd using `findProjectForPath` when
no project specified
- `project.spec.ts`: Add unit tests for cwd inference, nested
directories, root projects, and error cases

## Related Issue(s)

Fixes #31055

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `repo.gradle.org`
> - Triggering command: `/usr/lib/jvm/temurin-17-jdk-amd64/bin/java
/usr/lib/jvm/temurin-17-jdk-amd64/bin/java
--add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED
--add-opens=java.base/java.util=ALL-UNNAMED
--add-opens=java.prefs/java.util.prefs=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
--add-opens=java.base/java.util=ALL-UNNAMED
--add-opens=java.prefs/java.util.prefs=ALL-UNNAMED
--add-opens=java.base/java.nio.charset=ALL-UNNAMED
--add-opens=java.base/java.net=ALL-UNNAMED
--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED
--add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED
-XX:MaxMetaspaceSize=384m -XX:&#43;HeapDumpOnOutOfMemoryError -Xms256m
-Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en` (dns
block)
> - `staging.nx.app`
> - Triggering command: `/usr/local/bin/node node ./bin/post-install`
(dns block)
> - Triggering command: `/usr/local/bin/node /usr/local/bin/node
/home/REDACTED/work/nx/nx/node_modules/.pnpm/nx@22.2.0-beta.1_@swc-node&#43;register@1.9.1_@swc&#43;core@1.5.7_@swc&#43;helpers@0.5.11__@swc&#43;typ_e0638a3d25d549ce0cdd3a7d8bad3b61/node_modules/nx/src/project-graph/plugins/isolation/plugin-worker
/tmp/plugin3517-16-424.353971.sock @nx/enterprise-cloud` (dns block)
> - Triggering command: `/usr/local/bin/node /usr/local/bin/node
/home/REDACTED/work/nx/nx/node_modules/.pnpm/nx@22.2.0-beta.1_@swc-node&#43;register@1.9.1_@swc&#43;core@1.5.7_@swc&#43;helpers@0.5.11__@swc&#43;typ_e0638a3d25d549ce0cdd3a7d8bad3b61/node_modules/nx/src/project-graph/plugins/isolation/plugin-worker
/tmp/plugin4274-16-431.526748.sock @nx/enterprise-cloud` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/nrwl/nx/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT CODING AGENT SUFFIX -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>Feature: allow `nx show targets` to infer project from
the cwd</issue_title>
> <issue_description>### Description
> When I'm already working inside a project's folder (for example
`github/abapify/packages/adk` that has its own `project.json`), I would
love to ask Nx to list the targets that belong to that project without
having to remember or type the project name. Ideally `npx nx show
targets` could detect the `project.json` in the current working
directory and operate on that project automatically.
> 
> ### Current behavior
> Running the command from inside a project directory fails because the
CLI insists on a `--project` argument:
> 
> ```
> $ cd github/abapify/packages/adk
> $ npx nx show targets
> Please provide a project name via --project=<name>
> ```
> 
> ### Expected behavior
> If the current directory (or one of its ancestors) contains a
`project.json`, Nx should infer the project from that file and list the
targets without extra flags. This would make it much easier to explore
available targets while staying focused on a single project, especially
in large workspaces with many similarly named packages.
> 
> ### Environment
> - Nx: 21.6.3
> - Node: 24.10.0
> - Package manager: bun 1.3.1
> - OS: WSL2 (Linux 6.6.87.2-microsoft-standard-WSL2)
> </issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>

- Fixes nrwl/nx#33503

<!-- START COPILOT CODING AGENT TIPS -->
---

 Let Copilot coding agent [set things up for
you](https://github.com/nrwl/nx/issues/new?title=+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: AgentEnder <6933928+AgentEnder@users.noreply.github.com>
Co-authored-by: Craigory Coppola <craigorycoppola@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 10:10:34 -05:00
Colum Ferry 2d87134710 fix(react): target 22.3.4 patch version to address Remix CVE (#34068) 2026-01-13 13:51:20 +00:00
Leosvel Pérez Espinosa c69dd7f146 cleanup(core): reuse resolved prettier module in format command (#34088)
## Current Behavior

The `prettier` module is being resolved twice during the `format`
command execution and using a mix of `import`/`require`.

## Expected Behavior

The `prettier` module should be resolved once and reused.
2026-01-13 12:30:47 +00:00
Jason Jean 2045c829a3 fix(maven): fix Maven Central publishing for Maven 4 (#34084)
## Current Behavior

The `central-publishing-maven-plugin` with `extensions=true` does not
work with Maven 4. Running `./mvnw deploy -Prelease` completes the build
but never triggers the deploy/publish phase - it stops at install.

This is a known issue tracked as
[MNG-8584](https://issues.apache.org/jira/browse/MNG-8584).

## Expected Behavior

Running `./mvnw deploy -Prelease -pl packages/maven/maven-plugin -am`
should publish the nx-maven-plugin to Maven Central.

## Related Issue(s)

Related to Maven 4 compatibility:
https://issues.apache.org/jira/browse/MNG-8584

## Changes

- Add explicit execution binding for `central-publishing-maven-plugin`
to the deploy phase (workaround for broken extensions mechanism in Maven
4)
- Remove `extensions=true` that doesn't work with Maven 4
- Update `central-publishing-maven-plugin` from 0.9.0 to 0.10.0
- Skip standard `maven-deploy-plugin` for nx-maven-plugin module (we use
central-publishing instead)
2026-01-12 17:34:30 -05:00
MaxKless 64f2be4605 feat(gradle): add env vars to skip gradle and maven plugin computation (#34055)
## Current Behavior
the plugins are disabled on vercel and netlify but there's no easy way
to disable them otherwise.

## Expected Behavior
there's an env var to disable each of the plugins: `NX_GRADLE_DISABLE` /
`NX_MAVEN_DISABLE` just like there is one for dotnet.
2026-01-12 17:27:02 -05:00
Jason Jean 8b7dc6c8bf fix(maven): update Spring Boot to 4.0 and enable parent POM local install (#34081)
## Current Behavior

Maven e2e tests fail with two issues:
1. Spring Initializr rejects Spring Boot 3.4.0 (now requires >=3.5.0)
2. Parent POMs (`nx-parent` and `nx-maven-parent`) aren't installed
locally, causing Maven to fail when resolving `nx-maven-plugin:0.0.12`
since it's not yet published to Maven Central

## Expected Behavior

Maven e2e tests pass successfully by:
1. Using Spring Boot 4.0.0 which is supported by Spring Initializr
2. Installing parent POMs to local Maven repository so the plugin can
resolve its dependencies

## Related Issue(s)

Fixes the CI failures in maven e2e tests after the 0.0.12 version bump.
2026-01-12 16:29:02 -05:00
Caleb Ukle 6cca28c798 docs(nx-cloud): add missing 2025.07.4-.7 release notes (#34079) 2026-01-12 17:16:17 +00:00
Jack Hsu 4e7e9468fe fix(misc): update banner validation to match Framer API format (#34076)
## Current Behavior
The prebuild-banner script requires an `enabled` boolean field that the
Framer API does not return, causing validation failures.

## Expected Behavior
Validation matches the actual API response format which uses
`activeUntil` for determining banner visibility instead of `enabled`.

Closes #CLOUD-4071

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 11:28:33 -05:00
Craigory Coppola 7f68286bad fix(core): pipe plugin stdout to avoid inconsistent terminal state (#33369)
<!-- 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
After running commands which spawn plugin workers on the main process
(`nx show project`, or any command with the daemon disabled) some users
(and notably @FrozenPandaz) experienced terminal issues that resulted in
↑ / ↓ printing escape codes instead of scrolling command history.

## Expected Behavior
This pull request updates how plugin worker processes handle their
input/output streams to improve terminal behavior and debugging
capabilities. The main change is switching the worker's stdio from
`inherit` to `pipe`, and then manually piping the worker's stdout and
stderr to the main process. This avoids terminal state issues and
enables better debugging.

**Plugin worker process I/O handling:**

* Changed the worker process `stdio` option from `'inherit'` to `'pipe'`
in `startPluginWorker`, preventing terminal state issues (such as broken
arrow key functionality) after Nx execution.
* Added logic to pipe the worker's `stdout` and `stderr` to the main
process, making it easier to debug and allowing plugins to communicate
metrics. Increased the max listener count on `process.stdout` and
`process.stderr` to avoid warnings from multiple listeners.

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

Fixes #
2026-01-10 14:13:36 +00:00
Craigory Coppola 42a8a44b26 fix(core): validate native file cache size before applying it (#33683)
## Current Behavior
We dont validate the size of the native file cache after copying it,
which sometimes fails and corrupts the data. This failure results in a
different size, so we can detect it. In certain situations, the
corruption causes node to hang instead of throw.

## Expected Behavior
We detect the corruption

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

Fixes #30653
Fixes #31300
2026-01-09 18:29:14 -05:00
Jack Hsu 0fe39b2931 fix(linter): delete override block when update returns undefined in replaceOverride (#34070)
I found regression in `replaceOverride` behavior that isn't guarded
against. There is migration from v17
(https://github.com/nrwl/nx/blob/20.8.x/packages/next/src/migrations/update-17-2-7/remove-eslint-rules-patch.ts#L17)
that shows that when `update` function returns `undefined`, then that
override entry should be removed.

We had no other unit tests to cover this case previously, so it was
missed until I tried cherry-picking the fix to `20.8.x` branch.

There was also a bug with flat config in v20 and v21 where not passing
`update` function for flat config leads to an error due to
`update(data)` being called without checking if `update` exists (since
it's optional). We never actually skip on passing `update` (which makes
`replaceOverride` useless since it's noop), so I marked it as required
arg now.

## Current Behavior

When `replaceOverride` is called with an update function that returns
`undefined`, the override block is not removed. This is inconsistent
with the JSON code path which uses `splice` to remove the override.

## Expected Behavior

When the update function returns `undefined`, the entire override block
should be deleted from the flat config, matching the JSON path behavior.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 15:16:10 -05:00
Philip Fulcher fb93570d09 docs(nx-dev): add missing multiplier article (#34069) 2026-01-09 13:02:34 -06:00
Leosvel Pérez Espinosa 4462a72f46 fix(core): allow dte to handle continuous tasks termination (#34018)
## Current Behavior

When running a task graph with continuous tasks and one of them is
terminated, the reverse continuous task deps that have no other tasks
that depend on them are also automatically terminated. This is fine in a
non-DTE context, but when running in a DTE context, the DTE task runner
must own the lifecycle of the continuous tasks, and Nx shouldn't
automatically terminate them.

## Expected Behavior

Nx shouldn't automatically terminate continuous tasks when running in a
DTE context.
2026-01-09 18:16:49 +00:00
Leosvel Pérez Espinosa cc5d173ed0 fix(core): disallow Vitest & Angular unit test runner when bundler is not esbuild in cnw (#34023)
## Current Behavior

The `create-nx-workspace` incorrectly offers `Vitest & Angular` as a
valid unit test runner choice when the bundler is something other than
`esbuild`.

## Expected Behavior

The `create-nx-workspace` should only offer `Vitest & Angular` as a
valid unit test runner choice when the bundler is `esbuild`.

## Related Issue(s)

Fixes #34014
2026-01-09 16:11:45 +00:00
Leosvel Pérez Espinosa 9230a8c515 fix(core): make process metrics registration in critical paths non-blocking (#34019)
## Current Behavior

On systems under heavy load, plugin loading can fail with:

```bash
Plugin Worker exited because no plugin was loaded within 10 seconds of starting up.
```

The initialization of the process metrics collection could potentially
cause this by blocking the loading of the plugin.

## Expected Behavior

Process metrics initialization no longer blocks critical startup paths,
allowing plugin loading to succeed regardless of system load.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2026-01-09 10:50:37 -05:00
Leosvel Pérez Espinosa 88c6baaf19 fix(core): display shared running tasks in the in progress section of the tui (#34059)
## Current Behavior

Shared running tasks (tasks running in another process) do not appear in
the In Progress section of the TUI. They show the throbber as being in
progress, but are located in the Pending/Completed section.

## Expected Behavior

Shared running tasks (tasks running in another process) should appear in
the In Progress section of the TUI.
2026-01-09 10:45:55 -05:00
Colum Ferry beb5ef585b feat(react): update react-router and remix versions to address CVEs (#34058)
Update to patched versions of React Router (7.12.0, 6.30.3) and Remix
(2.17.3) to address CVEs:

https://github.com/remix-run/react-router/security/advisories/GHSA-3cgp-3xvw-98x8

https://github.com/remix-run/react-router/security/advisories/GHSA-9583-h5hc-x8cw

https://github.com/remix-run/react-router/security/advisories/GHSA-9jcx-v3wj-wh4m

https://github.com/remix-run/react-router/security/advisories/GHSA-h5cw-625j-3rxh

https://github.com/remix-run/react-router/security/advisories/GHSA-2w69-qvjg-hvjx

https://github.com/remix-run/react-router/security/advisories/GHSA-8v8x-cx79-35w7
2026-01-09 13:23:11 +00:00
MaxKless dbedd19d68 fix(core): set windowsHide:true in package installation (#34053)
## Current Behavior
package installation does not set `windowsHide` so it flashes a terminal
window

## Expected Behavior
there should be no flashing terminal window

Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
2026-01-09 12:48:02 +09:00
Craigory Coppola 7f32f2c75f chore(repo): add copy-built-package script (#34035)
Adds a sm utility script to ease quickly checking changes against local
repos. Not a replacement for local registry + install, but good for
quick checks
2026-01-08 18:30:02 -05:00
Louie Weng a5c1388804 chore(gradle): bump version to 0.1.11 (#34054)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Bump gradle project graph plugin version to 0.1.11

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

Fixes #
2026-01-08 22:31:26 +00:00
Jason Jean a13f5eb0d8 chore(repo): update nx to 22.4.0-beta.1 (#33968)
Updating Nx from 22.3.0-beta.3 to 22.4.0-beta.1
2026-01-08 17:24:34 -05:00
Caleb Ukle e38d2857f2 docs(nx-cloud): add new scopes for BB when using Nx Cloud onboarding (#34052) 2026-01-08 13:23:05 -05:00
Louie Weng 4af608013d feat(gradle): excludeDependsOn based on provider relationships (#33923)
<!-- 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
<!-- This is the behavior we have today -->

We have a hard coded list of task targets to not exclude depends on. 

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

We resolve a gradle task such that we can identify if there are provider
dependency relationships involved. If there are, then do not exclude
depends on since Gradle needs the dependsOn tasks to fulfill providers.

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

Fixes #
2026-01-08 17:59:05 +00:00
Louie Weng d73fd46d6e fix(gradle): resolve dependencies after capturing project tasks (#34045)
<!-- 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
<!-- This is the behavior we have today -->

When processing Kotlin Multiplatform (KMP) projects, the Nx Gradle
plugin encounters ConcurrentModificationException errors because KMP
dynamically modifies the Gradle project's task and configuration
containers during dependency resolution. The plugin was resolving
configuration dependencies before processing tasks, which triggered
KMP's hierarchy finalization and dynamic task creation while the plugin
was still iterating over these collections.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

The Gradle plugin should handle Kotlin Multiplatform projects without
errors by:
1. Processing tasks before resolving configuration dependencies,
preventing KMP from modifying task containers during iteration
2. Creating immutable snapshots of task and configuration collections
before iteration to avoid concurrent modification issues

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

Fixes NXC-3633
2026-01-08 08:32:27 -08:00
Louie Weng 99a9216c43 fix(gradle): force gradle executor to always rerun tasks (#34024)
<!-- 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
<!-- This is the behavior we have today -->

The Nx Plugin uses Nx as the backing mechanism, but Gradle still does
some caching behind the scenes. When using Nx and Gradle's caching at
the same time, there can be times where Gradle does not recognize input
changes and will not execute tasks that it mistakenly deems unchanged.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Ensure that the batch executor always reruns tasks and is not impacted
by the Gradle build cache.

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

Fixes NXC-3649
2026-01-08 08:31:12 -08:00
Rares Matei 66488a2dc2 docs(nx-cloud): document how to set working directory in nx agents (#34033)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

---------

Co-authored-by: Caleb Ukle <caleb@nrwl.io>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2026-01-08 12:43:09 +00:00
Colum Ferry 2cdaffc850 feat(release): special-case 0.x versions for semver bumps (#34031)
For 0.x versions, shift semver bump types down to follow the common
convention where breaking changes bump minor, and new features bump
patch:

- major -> minor
- premajor -> preminor
- minor -> patch
- preminor -> prepatch
- patch -> patch (unchanged)

This ensures that `nx release` with a breaking change on a 0.x package
(e.g., 0.1.0) bumps to 0.2.0 instead of 1.0.0.

Fixes NXC-3638

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Coly010 <Coly010@users.noreply.github.com>
2026-01-08 10:23:06 +00:00
Jack Hsu 9fb5a6ce59 fix(linter): handle variable references in replaceOverride (#34026)
The migration generator (`@nx/plugin:migration`) fails when due to
ESLint flat config not being parsed correctly, leading to an error.

This happens because `replaceOverride` uses `parseTextToJson` to parse
the config, which fails for non-JSON-serializable JavaScript
expressions.

This PR fixes the issue by using AST parsing, like we did for
`hasOverrides` here https://github.com/nrwl/nx/pull/33548.

Fixes #34010

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 12:56:31 -05:00
Leosvel Pérez Espinosa 92f821d281 fix(js): avoid duplicate @nx/js/typescript plugin entries for non-buildable libs (#34021)
## Current Behavior

When adding a non-buildable JS library (`bundler: 'none'`) to a
workspace with an existing `@nx/js/typescript` plugin registration that
has build options configured, a duplicate plugin entry is unnecessarily
created in `nx.json`.

## Expected Behavior

Non-buildable libraries reuse the existing plugin registration when
`skipBuildCheck: true` is not specified, thereby avoiding duplicate
entries in `nx.json`. The `@nx/js/typescript` plugin will infer the
project as non-buildable because the library's `package.json` will have
entry points pointing to source files, so there's no need for a separate
plugin registration.

## Related Issue(s)

Fixes #33981
2026-01-07 09:18:39 +01:00
Colum Ferry 0119275ffd fix(module-federation): pin rspack to 1.6.8 (#34022)
## Current Behavior
Rspack 1.7.0 is failing to create factories for internals with Module
Federation.

## Expected Behavior
Pin Rspack to 1.6.8 for now to ensure continued functioning of Module
Federation
2026-01-06 10:00:42 -05:00
Andrey Chalkin 80cde6a950 feat(release): add option to opt-out commit scope filter (#33382)
## Current Behavior

PR #32915 changed how conventional commits determine version, making
them rely on commit scope:
commits with types configured to bump minor / major version bumps only
patch if commit scope exists and it does not include project name

## Expected Behavior

In our project we do not use projectName as commit scope, so we would
like to bring back old behavior, this can be achieved by adding option
to opt-out such behavior

---------

Co-authored-by: Colum Ferry <cferry09@gmail.com>
2025-12-30 14:51:07 -05:00
David Antoon caee7c6ee4 feat(rspack): add typeCheckOptions, runtimeDependencies, and cache options (#33931)
## Current Behavior

- The `skipTypeChecking` option is a simple boolean that only allows
enabling/disabling type checking
- Rspack executor is missing the `runtimeDependencies` option that
webpack has
- The `cache` configuration is hardcoded and cannot be overridden by
users

## Expected Behavior

- New `typeCheckOptions` option allows configuring type checking with `{
async: true }` to run type checking in a separate process without
blocking the build
- The deprecated `skipTypeChecking` option is maintained for backward
compatibility
- Rspack now supports `runtimeDependencies` option for adding runtime
dependencies to generated `package.json` (useful for Docker installs)
- New `cache` option allows users to override webpack/rspack caching
behavior while maintaining backward-compatible defaults

## Related Issue(s)

N/A - Standalone feature

## Changes Made

### typeCheckOptions (webpack & rspack)
- Added `TypeCheckOptions` interface with `async` property
- Added `typeCheckOptions` option to plugin options interfaces
- Updated `apply-base-config.ts` to normalize `typeCheckOptions` from
deprecated `skipTypeChecking` for backward compatibility
- Added schema definitions to `schema.json` and `schema.d.ts`

### runtimeDependencies (webpack & rspack)
- Added `runtimeDependencies` option to `NxAppRspackPluginOptions`
- Updated `GeneratePackageJsonPlugin` to resolve and include runtime
dependencies
- Added schema definitions to `schema.json` and `schema.d.ts`

### cache (webpack & rspack)
- Added `cache` option to plugin options interfaces
- Updated `apply-base-config.ts` to check `'cache' in options` before
applying defaults
- Allows explicit `cache: undefined` to force cache to be disabled
- Maintains backward-compatible defaults:
  - Webpack: `{ type: 'memory' }` for Node targets in watch mode
- Rspack: `true` for Node targets in watch mode, `true` in dependent
config

## Files Changed

**Webpack:**
-
`packages/webpack/src/plugins/nx-webpack-plugin/nx-app-webpack-plugin-options.ts`
-
`packages/webpack/src/plugins/nx-webpack-plugin/lib/apply-base-config.ts`
- `packages/webpack/src/executors/webpack/schema.json`
- `packages/webpack/src/executors/webpack/schema.d.ts`
- `packages/webpack/src/plugins/generate-package-json-plugin.ts`

**Rspack:**
- `packages/rspack/src/plugins/utils/models.ts`
- `packages/rspack/src/plugins/utils/apply-base-config.ts`
-
`packages/rspack/src/plugins/utils/plugins/generate-package-json-plugin.ts`
- `packages/rspack/src/executors/rspack/schema.json`
- `packages/rspack/src/executors/rspack/schema.d.ts`

**Documentation:**
- `astro-docs/.../webpack/Guides/webpack-plugins.mdoc`
- `packages/webpack/docs/webpack-build-executor-examples.md`

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-12-30 13:37:13 -05:00
Kasper Christensen 5ef02e4c96 fix(testing): set moduleResolution to node in Cypress tsconfig to prevent TS5095 error (#33726)
When generating Cypress component testing in Angular workspaces, the
base tsconfig sets moduleResolution to 'bundler' which causes TS5095
errors because 'bundler' requires module to be 'preserve' or 'es2015+'.

Cypress runs in Node.js and should use Node.js module resolution
instead. This fix sets moduleResolution to 'node' for Cypress
tsconfig.json templates.

## Current Behavior

When generating Cypress component testing configuration in Angular
workspaces, the generated `cypress/tsconfig.json` inherits
`moduleResolution: "bundler"` from the workspace base config. Since
Cypress uses `module: "commonjs"` for Node.js runtime, this causes
TypeScript compiler error TS5095: "Option 'bundler' can only be used
when 'module' is set to 'preserve' or to 'es2015' or later."

## Expected Behavior

The generated `cypress/tsconfig.json` should explicitly set
`moduleResolution: "node"` to match the `module: "commonjs"` setting,
preventing TS5095 errors. This aligns with how NestJS applications
handle the same issue (see #33607).

---------

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
2025-12-30 10:45:45 -05:00
kazuki nakai ab01b2113f docs(core): add Docker development guidance (#33848)
## Summary

Adds comprehensive Docker development guidance to the Nx Daemon
documentation.

Related to #33263, #30359, #14126

## What's included

This PR expands the existing Nx Daemon docs with a new "Running Nx in
Docker" section that covers:

- **Why the daemon often fails in Docker** - ephemeral filesystems,
inode/mtime changes from volume mounts, container restarts, IPC issues
- **Recommended approach** - disable daemon with `NX_DAEMON=false`
- **Example docker-compose setup** - minimal reproducible configuration
for local development
- **CI/CD best practices** - when to prefer stateless builds over daemon
caching

## Context

Several issues have been opened around daemon behavior in containers,
but the existing docs only briefly mention socket location
customization. Users are left wondering:
- Why doesn't the daemon work reliably in Docker?
- What's the recommended workflow for containerized development?
- How should CI pipelines handle this?

Issue #33263 specifically describes daemon crashes when running nx
between Docker and non-docker environments - this PR documents the
recommended workaround (`NX_DAEMON=false`) and explains why.

## Preview

The new section appears under the existing "Customizing the socket
location" heading and includes:
- Explanation of Docker-specific challenges
- Code examples for Dockerfile, docker-compose, and CLI
- Rule of thumb callout for quick reference

Open to feedback on structure or placement.

---------

Co-authored-by: kazuki <kazuki@kazukinoMacBook-Air.local>
Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
2025-12-29 15:42:08 -05:00
Copilot 84450f66db docs(core): add --tui and --no-tui flags to terminal UI documentation (#33303)
The `--tui` and `--no-tui` command-line flags were added after the
terminal UI documentation was written. Docs need to reference these
flags alongside the existing configuration methods.

## Changes

Updated `astro-docs/src/content/docs/guides/Tasks &
Caching/terminal-ui.mdoc`:
- Added `--tui` and `--no-tui` flags to the "Enable/Disable the Terminal
UI" section
- Restructured as bulleted list showing all four configuration methods

## Usage

Users can now control the Terminal UI via:
- `--tui` / `--no-tui` flags: `nx run-many -t build --no-tui`
- `NX_TUI` environment variable
- `tui.enabled` in `nx.json`

Fixes https://linear.app/nxdev/issue/NXC-3371

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `repo.gradle.org`
> - `staging.nx.app`
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/nrwl/nx/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT CODING AGENT SUFFIX -->



<details>

<summary>Original prompt</summary>

> Issue Title: Update
https://nx.dev/docs/guides/tasks--caching/terminal-ui#enabledisable-the-terminal-ui
to reference the `--tui` and `--no-tui` flags
> Issue Description: These were added after the other methods, docs need
to be updated to have them in the nrwl/nx repo
> Fixes
https://linear.app/nxdev/issue/NXC-3371/update-httpsnxdevdocsguidestasks-cachingterminal-uienabledisable-the
> 
> 
> Comment by User 4215f3ef-50bd-4f09-85a0-b489c88057b6:
> [https://github.com/nrwl/nx](https://github.com/nrwl/nx)
> 
> Comment by User d484ef82-7f7d-4a95-be09-9d82ca3905dc:
> 📋 I wasn't able to determine which GitHub repository to work in.
> 
> I think it's one of these, but can you tell me which one is right?
> 
> Comment by User :
> This thread is for an agent session with githubcopilot.
> 
> 


</details>



<!-- START COPILOT CODING AGENT TIPS -->
---

 Let Copilot coding agent [set things up for
you](https://github.com/nrwl/nx/issues/new?title=+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: AgentEnder <6933928+AgentEnder@users.noreply.github.com>
Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-12-29 15:28:35 -05:00
Rafayel Hovhannisyan 97fde57f7f feat(linter): add peerDepsVersionStrategy option to dependency-checks (#33417)
Adds a new peerDepsVersionStrategy option that allows configuring how
peer dependencies versions are set when auto-fixing. When set to
'workspace', peer dependencies will use 'workspace:*' instead of the
installed or root package version. Defaults to 'installed' to maintain
backward compatibility.

## Current Behavior
A concrete peer dependency version is being fixed.

## Expected Behavior
User can choose between `installed` and `workspace` version strategies.

---------

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
2025-12-29 15:24:43 -05:00
Copilot 0da6921ac3 docs(nx-dev): fix inputs syntax and document missing object formats (#33298)
## Plan to Fix Inputs Documentation

Based on the issue, I need to correct the inputs documentation at
`/astro-docs/src/content/docs/reference/inputs.mdoc`. The problems are:

- [x] Fix the invalid syntax in "Source Files" section - currently shows
inputs as an object instead of an array
- [x] Document the `{ input: someNamedInput, projects: [] }` format for
referencing named inputs from specific projects
- [x] Document the `{ input: someNamedInput, dependencies: true }`
format for referencing named inputs from dependencies
- [x] Document the object form for fileset inputs (e.g., `{ fileset:
string }`)
- [x] Ensure all documented formats match the TypeScript type definition
- [x] Fix typo found in code review (to to -> to)
- [x] Remove targetDefaults wrapper from examples (per review feedback)
- [x] Use string syntactic sugar forms in examples and explain
equivalence to object forms
- [x] Fix comment to show object form equivalence instead of repeating
string form

## Changes Made

1. **Fixed Source Files section syntax**:
   - Changed from invalid object syntax to correct array syntax
   - Removed unnecessary targetDefaults wrapper per review feedback
   - Added documentation for the object format with fileset property

2. **Added new section "Named Inputs from Other Projects"**:
   - Documents `{ input: "production", projects: "mylib" }` format
- Documents `{ input: "production", projects: ["mylib", "myapp"] }`
format for multiple projects
- Uses string syntactic sugar `"production"` and `"^production"` in
examples
- Explains equivalence: `"production"` is shorthand for `{ "input":
"production" }`, `"^production"` is shorthand for `{ "input":
"production", "dependencies": true }`

3. **Fixed typo**: Changed "to to not invalidate" to "to not invalidate"

All changes validated with prettier formatting checks.

<!-- START COPILOT CODING AGENT SUFFIX -->



<details>

<summary>Original prompt</summary>

> Issue Title: Docs: correct inputs syntax and document missing formats
> Issue Description: The inputs docs appear inaccurate at
[nx.dev/docs/reference/inputs#source-files](https://nx.dev/docs/reference/inputs#source-files).
> 
> * The shown inputs syntax isn’t valid; it should be an array.
> * The page doesn’t mention the `{ input: someNamedInput, projects: [\]
}` format.
> * It also doesn’t cover the object form for `deps`/`self` inputs.
> 
> Valid types reference:
[https://github.com/nrwl/nx/blob/master/packages/nx/src/config/workspace-json-project-json.ts#L206](https://github.com/nrwl/nx/blob/master/packages/nx/src/config/workspace-json-project-json.ts#L206)
> 
> Working with \[GitHub
Copilot\](User:d484ef82-7f7d-4a95-be09-9d82ca3905dc) on this.
> Fixes
https://linear.app/nxdev/issue/NXC-3369/docs-correct-inputs-syntax-and-document-missing-formats
> 
> 
> Comment by User 4215f3ef-50bd-4f09-85a0-b489c88057b6:
> [https://github.com/nrwl/nx](https://github.com/nrwl/nx)
> 
> Comment by User d484ef82-7f7d-4a95-be09-9d82ca3905dc:
> 📋 I wasn't able to determine which GitHub repository to work in.
> 
> I think it's one of these, but can you tell me which one is right?
> 
> Comment by User 4215f3ef-50bd-4f09-85a0-b489c88057b6:
> Side not, copilot assignment didn't work. Would have been neat 🙂
> 
> Comment by User d484ef82-7f7d-4a95-be09-9d82ca3905dc:
> Waiting for https://linear.app/nxdev/profiles/craigory to link their
GitHub account. [Click to authorize
→](https://linear.business.githubcopilot.com/linear/auth)
> 
> Comment by User :
> This thread is for an agent session with githubcopilot.
> 
> Comment by User :
> Created issue
[NXC-3369](https://linear.app/nxdev/issue/NXC-3369/docs-correct-inputs-syntax-and-document-missing-formats)
> 
> Comment by User 4215f3ef-50bd-4f09-85a0-b489c88057b6:
> This comment thread is synced to a corresponding [thread in
Slack](https://nrwl.slack.com/archives/CT3CQ2F0D/p1761762896195989?thread_ts=1761762896.195989&cid=CT3CQ2F0D).
All replies are displayed in both locations.
> 
> Comment by User 4215f3ef-50bd-4f09-85a0-b489c88057b6:
> @Linear create a docs issue, assign it to me and copilot
> 
> Comment by User f5ae6d50-28e9-4ee7-ad51-3da8208d5914:
> Send a PR? 🙏
> 
> Comment by User 4215f3ef-50bd-4f09-85a0-b489c88057b6:
> See these valid types:
[https://github.com/nrwl/nx/blob/master/packages/nx/src/config/workspace-json-project-json.ts#L206](https://github.com/nrwl/nx/blob/master/packages/nx/src/config/workspace-json-project-json.ts#L206)
> 
> Comment by User 4215f3ef-50bd-4f09-85a0-b489c88057b6:
> Also on the same page, I don't see any mention of the `{ input:
someNamedInput, projects: [] }` format, nor the object form for deps /
self inputs
> 
> 


</details>



<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: AgentEnder <6933928+AgentEnder@users.noreply.github.com>
2025-12-29 14:00:42 -05:00
Austin Fahsl 75ff26630b docs(misc): remove redundant checkout conditional for GHA DTE example (#33829)
## Current Behavior

The GitHub Actions DTE example includes a redundant conditional checkout
step that has separate configurations for pull request and default
branch events, both performing the same checkout operation.

## Expected Behavior

The GitHub Actions example should use a single, simpler checkout
configuration that works for both pull request and default branch
events, removing redundant code.

## Related Issue(s)

This change simplifies the documentation example by removing redundant
checkout steps while maintaining the same functionality.
2025-12-29 13:56:04 -05:00
Anthony Shew c43ceb3a67 docs(misc): update Turborepo documentation with visualization details (#33970)
Updated Turborepo section to include robust browser-based graph
visualizations and Graphviz image exports.

---------

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
2025-12-29 13:54:04 -05:00
QING LIN 3735641f62 fix(core): convert filePath to an absolute path before typescript resolves the module (#34001)
<!-- 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
<!-- This is the behavior we have today -->
TypeScript’s module resolution stop at project's root when resolving
modules.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
TypeScript’s module resolution will walk up to the workspace root when
resolving modules

## Changes Made
Convert the filePath to an absolute path inside findProjectFromImport
before calling resolveImportWithTypescript, because TypeScript’s module
resolution will not correctly traverse up the directory tree toward the
workspace root when given a relative path.

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

Fixes #33985
2025-12-29 12:06:18 -05:00
Philip Fulcher 768c580f1d docs(nx-dev): add year of webinars article (#33980) 2025-12-28 15:19:49 +00:00
Colum Ferry d959d70185 fix(vitest): skip target inference for root workspace configs with projects (#33977)
When a vitest config file is at the workspace root and contains a
`projects` property in the test configuration, the plugin now skips
inferring test targets for that config. This is because root workspace
configs act as orchestrators - the actual tests live in the individual
project configs referenced by `projects`.

Fixes #32471
2025-12-22 13:55:24 +00:00
Colum Ferry 7cd296ba18 fix(vitest): add guard rails for vitest llm migration (#33976)
Edit guard rails for Vitest 4 LLM migration
2025-12-22 12:31:17 +00:00
Philip Fulcher ee4c687492 docs(nx-dev): add 2025 review article (#33973) 2025-12-20 23:07:22 -05:00
Copilot 9790910fbe fix(angular): only throw "define" error when options.define has keys (#33969)
## Current Behavior

The dev-server builder throws an error about the "define" option not
being supported in Angular < 21, even when users don't configure it. The
validation uses a truthy check that treats empty objects `{}` as true.

## Expected Behavior

The error should only throw when users explicitly configure define with
actual keys.

## Related Issues

Fixes #33964

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: leosvelperez <12051310+leosvelperez@users.noreply.github.com>
2025-12-20 10:40:12 +00:00
Craigory Coppola dd7ec3016b feat(core): support cwd specific hashes (#33879)
## Current Behavior
There is no straight-forward way to use the cwd as part of a tasks hash

## Expected Behavior
You can use `{workingDirectory: 'absolute'}` to factor the working
directory into the hash

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

Fixes #33684
2025-12-20 01:37:12 -05:00
Miroslav Jonaš ab82bfed92 fix(core): improve package-json createNode performance (#33960)
On test repo, the
`package-json:createNodes:isInPackageManagerWorkspacesTime` takes:
- Before the PR: 2356ms
- With PR: 23ms

This is achieved by avoiding unnecessary use of `minimatch` when a
direct string comparison is sufficient.

It also makes creation and logging of entire graph come down from
`23.6s` down to `18.5s`

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: meeroslav <meeroslav@users.noreply.github.com>
2025-12-19 17:38:23 -05:00
Bendegúz Hajnal 8b83502114 feat(linter): add bulk suppression support for ESLint v9.24.0+ (#32184)
Add support for ESLint's new bulk suppression features introduced in
v9.24.0.

- Add `suppressAll` option to suppress all existing violations
- Add `suppressRule` option to suppress specific rule(s)
- Added `suppressionsLocation` option to specify custom location for the
suppressions file (defaults to eslint-suppressions.json)
- Include proper version checking for ESLint v9.24.0+
- Add related tests and documentation
- Update schema and TypeScript types

This allows teams to incrementally adopt stricter lint rules without
being overwhelmed by legacy violations.

<!-- 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
<!-- This is the behavior we have today -->
The `@nx/eslint` package currently doesn't support ESLint's bulk
suppression features. When teams want to enable new lint rules, they
must fix all existing violations first, which can be a significant
barrier to adopting stricter linting standards.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
The @nx/eslint package now supports ESLint v9.24.0+'s bulk suppression
features through new flags:
- `suppressAll`: Suppresses all existing violations
- `suppressRule`: Suppresses specific rules
- `suppressionsLocation`: specifies a custom location for the
suppressions file (defaults to eslint-suppressions.json)

```json
{
  "lint": {
    "executor": "@nx/eslint:lint",
    "options": {
      "suppressAll": true 
    }
  }
}
```

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

https://github.com/nrwl/nx/discussions/30620
2025-12-19 17:26:20 -05:00
Jack Hsu 5f5a0b0ab3 fix(misc): remove CNW A/B testing flow branching (#33967)
This PR removes the variant check for deciding whether to use GitHub
templates for CNW. Moving forward, the first-level options are all
`nrwl/*` templates. The `Custom` option allows users to go back to the
previous presets.
2025-12-19 16:43:12 -05:00
Jack Hsu 137ab459fe docs(nx-dev): support .md URLs and llms.txt for AI agents (#33958)
This PR allows `.md` to be append to any docs URL to return raw markdown
content. Also adds `/llms.txt` that links to each markdown URL in the
docs site.

This allows AI agents to read content without having to parse HTML,
saving tokens.

Preview of `llms.txt`:
https://deploy-preview-33958--nx-docs.netlify.app/docs/llms.txt
Preview of page markdown content:
https://deploy-preview-33958--nx-docs.netlify.app/docs/concepts/buildable-and-publishable-libraries.md

Closes DOC-368
2025-12-19 15:00:07 -05:00
Leosvel Pérez Espinosa 61c41c9a75 docs(core): add missing env vars for nx migrate (#33962)
Documents the `NX_MIGRATE_SKIP_INSTALL` and `NX_MIGRATE_USE_LOCAL`
environment variables.
2025-12-19 17:57:09 +01:00
Philip Fulcher 19fa732eb0 docs(nx-dev): add 21.3 release article and changelog (#33939)
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: Caleb Ukle <caleb@nrwl.io>
2025-12-19 11:23:08 -05:00
Colum Ferry 5242d61717 docs(module-federation): add guide for using Tailwind CSS with Module Federation (#33959)
Explains how to configure Tailwind CSS so that classes used in remote
applications are properly compiled by the host application. Covers both
Tailwind v3 (content array) and v4 (@source directive) configurations.
2025-12-19 10:51:00 -05:00
Jack Hsu 7bb90bf1c9 docs(misc): use middleware for Framer proxy to keep pages static (#33956)
This PR fixes the `/changelog` page.

With `getStaticProps`, files were read at build time when copy-docs had
already copied them. With `getServerSideProps`, files are read at
request time on serverless functions where those files don't exist.

This PR reverts the changes to use `getServerSideProps` and uses a
middleware instead. This also has the benefit of keeping the pages
static, so we do not need edge functions to run their server function.

Fixed: https://nx-dev-git-doc-372-nrwl.vercel.app/changelog

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2025-12-19 10:37:29 -05:00
Caleb Ukle 3e32862622 fix(misc): remove auto CI Optimization card from AI page (#33955)
Fixes DOC-371
2025-12-19 15:33:45 +01:00
Leosvel Pérez Espinosa 691bb320ce feat(angular): support cypress component testing with zoneless projects (#33941)
## Current Behavior

Cypress Component Testing for zoneless Angular projects is not
supported.

## Expected Behavior

Cypress Component Testing for zoneless Angular projects should be
supported.
2025-12-19 14:17:05 +01:00
MaxKless be5bd5f8e2 docs(core): document NX_USE_LOCAL env var (#33952) 2025-12-19 14:13:55 +01:00
Leosvel Pérez Espinosa 5659d50e11 fix(linter): honor setParserOptionsProject in flat config (#33953)
## Current Behavior

When generating Angular apps/libs with `setParserOptionsProject`, the
ESLint flat config output did not include the project-level
`parserOptions.project`, so type-aware lint rules still fail unless
users edit the config manually.

## Expected Behavior

Enabling `setParserOptionsProject` produces the appropriate
project-level `parserOptions.project` configuration in both flat ESLint
config and legacy `.eslintrc.json`, so type-aware linting works out of
the box.

## Related Issue(s)

Fixes #33944
2025-12-19 14:12:22 +01:00
Leosvel Pérez Espinosa 5a4b345a3a fix(angular): support @angular/cli package update during nx migrate (#33918)
## Current Behavior

When migrating Angular packages the `@angular/cli` package is not
updated as part of the `nx migrate` initial package updates to the
`package.json` file. Instead, it's updated at a later stage with a
migration generator. This happens for a couple of reasons:

- Angular CLI package group will update all the packages using a `^`,
which can result in workspaces getting a minor version of the packages
installed before Nx adds support for that minor version.
- Angular CLI migrations can error due to some assumptions that are not
always correct in Nx workspaces.
- The `nx migrate` command currently doesn't have the ability to ignore
the package group or migrations of a given package.

This is why the `@angular/cli` package is migrated "manually" in a
migration generator.

## Expected Behavior

The `@angular/cli` package should be updated as part of the package
updates performed by the `nx migrate` command while ignoring its package
group and migrations. The `@nx/angular` package already provides the
same set of migrations and more.

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
2025-12-19 08:07:06 -05:00
Leosvel Pérez Espinosa c23dcfb649 fix(core): fix vitest test runner options for angular in cnw (#33921)
## Current Behavior

Creating a new Angular workspace with Vitest results in no test setup
being generated. This happens because the `vitest` option is no longer
available, and instead, there are two options: `vitest-angular` and
`vitest-analog`.

## Expected Behavior

Creating a new Angular workspace should prompt for Vitest with Angular
or Vitest with Analog to set up the tests.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: leosvelperez <leosvelperez@users.noreply.github.com>
Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
2025-12-19 08:06:55 -05:00
Colum Ferry 841f1ef8ec fix(module-federation): skip non-npm external dependencies in getDependencies (#33951)
The getDependentPackagesForProject function was crashing when processing
projects with non-npm external nodes (e.g., cargo: prefixed nodes from
@monodon/rust plugin). The code only handled npm: prefixed externals and
treated everything else as workspace libraries, causing undefined access
errors when cargo externals were encountered.

This fix adds a check to skip external nodes that aren't npm-prefixed by
detecting the presence of a colon in the dependency target. Only npm:
prefixed externals are processed as npm packages, and other external
prefixes (cargo:, maven:, etc.) are now properly skipped.

Fixes #32819
2025-12-19 12:31:57 +00:00
Colum Ferry 32bc89e078 docs(release): clarify ignorePatternsForPlanCheck syntax #30324 (#33926)
## Current Behaviour

The ignorePatternsForPlanCheck configuration option in nx.json for
version plans lacks
documentation about the pattern syntax. Users attempting to use negation
patterns (e.g.,
["*", "!src/"]) may experience unexpected behavior because gitignore
semantics don't work
  as intuitively expected with such patterns.

 ## Expected Behaviour

  The documentation and JSDoc comments now clearly explain:
  - That ignorePatternsForPlanCheck follows gitignore semantics
  - Working patterns like ["**/*.spec.ts"] and ["**/*.ts", "!**/src/**"]
- Non-working patterns like ["*", "!src/"] and why they don't work as
expected
- Recommended approach of using file extension patterns instead of
wildcards when trying to
   ignore all files except those in specific directories

 ## Related Issues

  Fixes #30324

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Coly010 <Coly010@users.noreply.github.com>
2025-12-19 12:31:47 +00:00
Colum Ferry e31aea073f fix(module-federation): use localhost as default host #33909 (#33947) 2025-12-19 10:38:47 +00:00
Colum Ferry 531163ea11 docs(react): remove apps preset from cnw command #31841 (#33943)
Closes #31841
2025-12-19 10:00:38 +00:00
Leosvel Pérez Espinosa 98bbec7fc7 feat(angular): support ngrx v21 (#33940)
## Current Behavior

NgRx v21 is not supported.

## Expected Behavior

NgRx v21 should be supported.
2025-12-19 09:14:42 +00:00
Craigory Coppola 390602b7c7 chore(core): revert wasm changes in get_mod_time (#33929)
WASM changes are breaking the build
2025-12-18 18:31:20 -05:00
Craigory Coppola 32783dfb09 feat(core): add inline-tui view mode (#32718)
## Current Behavior
When running single tasks we have a "minimal" tui, but that minimal tui
still makes it really hard / impossible to use some of the terminals
built in features... like:

- Find (can only find what's currently rendered by tui)
- Text select + copy (can only select what's rendered to screen, copied
text includes the frame around the tui / scrollbar)

## Expected Behavior
When running single tasks we can use an inline viewport to render some
tui widgets at the bottom of the viewport, and terminal output can be
printed above.

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

Fixes #
2025-12-18 18:31:07 -05:00
Louie Weng ab488f7e75 chore(maven): disable e2e tests (#33936)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Disabling Maven e2e tests since something with e2e setup breaks when we
try to update the spring boot version.

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

Fixes #
2025-12-18 18:08:50 -05:00
Caleb Ukle cb2cbb6930 fix(nx-dev): make sure canonical urls are always nx.dev (#33932)
make sure canonical always points to nx.dev and not a subdomain preview
incase they're index.
<img width="1728" height="863" alt="image"
src="https://github.com/user-attachments/assets/8e7d91c1-277b-4a2a-91ec-732f7f4f37ae"
/>
also confirm that robots.txt still has deny for non prod builds. 

this is done via middleware since canonical url is controlled via astro
config 'site' property. which is used to control other aspects that we
do want to be preview URL domains (like navigation). so we have a
middleware to always override the url to match prod.

also nextjs side was already overriding this in `_app.tsx`
2025-12-18 16:25:08 -05:00
Jack Hsu 9016f8d842 docs(nx-dev): add dynamic banner support to nx.dev (#33793)
This PR adds the ability to consumer banner data for nx.dev (both astro
and next.js) from a remote JSON file. This is only enabled if
`BANNER_URL` environment variable is set.

The `banner-config.json` files are committed for both astro and next.js,
so before we consume banner JSON from Framer, we can use this as the
source of truth rather than update the component code.

Once we switch completely to Framer CMS, we can remove the committed
JSON files.

Note: A redeploy is required for banner changes to take effect. In the
future we may be able to do this dynamically in Astro.

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-18 16:21:11 -05:00
Louie Weng 0a04c920b1 revert(maven): revert maven plugin back down to 0.0.11 (#33930)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Maven plugin was complaining about Spring-boot version being behind 3.5
when running e2e suite. Also bumped down maven plugin version since
version 0.0.12 could not be found at the time of this PR.

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

Fixes #
2025-12-18 15:42:46 -05:00
Caleb Ukle 22cce83550 fix(nx-dev): make sure only prod is indexed (#33922)
Note: required updating inputs for tasks to make sure env vars are
correctly cache busting.

Prod
<img width="1459" height="724" alt="image"
src="https://github.com/user-attachments/assets/1289b745-b68f-4176-9812-ef783d03ba26"
/>
non prod
<img width="1585" height="589" alt="image"
src="https://github.com/user-attachments/assets/dd0603b2-6487-4690-8bed-4c3d82644304"
/>
2025-12-18 13:03:26 -05:00
Caleb Ukle e31f815a6b docs(nx-cloud): clarify nx cloud run details when disabling nx cache (#33925) 2025-12-18 16:51:56 +00:00
Caleb Ukle 014d229b4a docs(core): add include/exclude plugin options to inferred tasks docs (#33924)
## Current Behavior

The inferred tasks documentation at
https://nx.dev/docs/concepts/inferred-tasks does not mention the
`include` or `exclude` options on plugins, even though this is a common
and useful feature for scoping plugins to specific projects.

## Expected Behavior

The inferred tasks documentation now includes a new section called
"Scope Plugins to Specific Projects" that explains:
- How to use `include` and `exclude` properties in plugin configuration
- What the glob patterns match against
- Use cases for this feature (scoping plugins, applying different
options to different projects)

This aligns with the existing documentation in the nx.json reference
guide.

## Related Issue(s)

Fixes DOC-367
2025-12-18 11:50:00 -05:00
Colum Ferry 1bc16c86dc fix(react): set up module federation with webpack and ts soln correctly #31029 (#33920)
## Current Behavior

When generating a React Module Federation remote with webpack bundler in
a TypeScript
Solution setup, the generator incorrectly sets the production webpack
config path in the
project configuration. Additionally, the sourceRoot property is not
being set in
package.json for TS Solution setups, which causes issues with module
federation's ability
  to locate source files correctly.

 ## Expected Behavior

  When using a TypeScript Solution setup:
- The production webpack config should not be explicitly set in the
build target's
  production configuration (it will be inferred correctly)
- The sourceRoot property should be set in package.json under the nx
configuration to
  properly identify the project's source directory
- The typecheck target should be added as a dependency for both build
and serve targets

 ## Related Issue(s)

  Fixes #31029
2025-12-18 15:42:08 +00:00
Leosvel Pérez Espinosa d9ca27bc3d fix(testing): ensure jest v30 migration is run (#33916)
## Current Behavior

The `replace-removed-matcher-aliases` migration from `@nx/jest` is not
run when migrating to Angular v21 (and updating Jest to v30). That
migration targets the original package update for Jest v30 (Nx 21.3.0),
which was incompatible with Angular < 21, so it wouldn't have run for
Angular workspaces at the time. Now that Angular is being updated to
v21, Jest is updated to v30, but the migration generator is not running.

## Expected Behavior

The `replace-removed-matcher-aliases` migration from `@nx/jest` should
run when migrating to Angular v21 (and updating Jest to v30).
2025-12-18 10:06:47 -05:00
Jason Jean d6a4b7d7ba chore(maven): update Maven version to 4.0.0-rc-5 (#33914)
## Current Behavior

The Maven version used for development dependencies is currently set to
3.9.11 in both pom.xml and mise.toml.

## Expected Behavior

The Maven version should be updated to 4.0.0-rc-5 to align with the
Maven 4 version already used in the batch-runner component.

## Related Issue(s)

N/A - This is a dependency version update to ensure consistency across
the Maven plugin ecosystem.

## Changes

- Updated `maven.version` property in pom.xml from 3.9.11 to 4.0.0-rc-5
- Updated maven tool version in mise.toml from 3.9.11 to 4.0.0-rc-5

This ensures that developers working on the Nx Maven plugin use the same
Maven 4.0.0-rc-5 version across all components.
2025-12-18 10:06:23 -05:00
Jason Jean 0cb91b85cb chore(maven): bump Maven plugin version to 0.0.12 (#33913)
## Current Behavior

The Maven plugin version is currently at 0.0.11.

## Expected Behavior

This PR bumps the Maven plugin version to 0.0.12 and creates a migration
for Nx 22.4.0-beta.0. This allows users to automatically update their
pom.xml files when they upgrade to the next version of Nx.

## Related Issue(s)

N/A - Version bump
2025-12-18 10:06:07 -05:00
Jason Jean f154b70196 fix(core): daemon client reconnection on server restart (#33432)
## Current Behavior

The daemon currently depends on client requests failing with a
`LOCK_FILES_CHANGED` error to trigger a restart. This creates several
issues:
- The daemon may stay running with stale dependencies if no requests
come in
- The client must wait for a request to fail to trigger reconnection
- Special-case error handling is scattered across the client code

## Expected Behavior

The daemon should proactively restart itself when lock files change, and
the client should gracefully reconnect with exponential backoff for any
server shutdown scenario.

## Changes

### Client-Side: Exponential Backoff Reconnection
- Add `handleConnectionError()` method that retries with exponential
backoff (10ms → 5000ms, 30 attempts max)
- Preserve pending messages during reconnection and resend them once the
new daemon is available
- Remove special-case handling for `LOCK_FILES_CHANGED` and
`NX_VERSION_CHANGED` errors
- Remove `retryMessageAfterNewDaemonStarts()` method as it's no longer
needed

### Server-Side: Self-Restart on Lock File Changes  
- Add `startNewDaemonInBackground()` to spawn a replacement daemon
before shutdown
- Add `handleServerProcessTerminationWithRestart()` for restartable
shutdown scenarios
- Detect lock file changes and proactively start a new daemon before
responding with an error
- Keep version change handling simple (just exit, no restart)

## Benefits
- **More Resilient**: Client recovers from any server shutdown, not just
specific errors
- **Cleaner Architecture**: Server manages its own lifecycle, client
doesn't need special cases
- **No Request Dependency**: Daemon doesn't wait for requests to detect
changes
- **Reduced Error Spam**: Exponential backoff prevents connection error
floods
- **Future-Proof**: Foundation for other restart scenarios (plugins,
config changes)

## Related Issue(s)

Fixes https://github.com/nrwl/nx/issues/30514
Fixes https://github.com/nrwl/nx/issues/29118
2025-12-17 23:02:08 -05:00
Jason Jean fed034a32d feat(maven): add batch executor for multi-task Maven execution (#33228)
## Summary

Adds a batch executor for Nx Maven that enables parallel multi-task
execution with significant performance improvements. The batch runner
keeps Maven resident in memory, avoiding cold start overhead for each
task.

## Changes

### 1. Batch Runner JAR (`packages/maven/batch-runner`)
- **ResidentMavenExecutor**: Uses Maven 4.x's `ResidentMavenInvoker` to
keep Maven in memory
- **NxMaven**: Custom Maven wrapper that caches project graphs and
sessions across invocations
- **CachingResidentMavenInvoker**: Preserves session state so artifacts
from `jar:jar` are visible to `install:install`
- **BuildStateManager**: Applies/records build states for
cross-invocation caching
- Maven 4.x dependencies are shaded into the JAR for standalone
execution

### 2. TypeScript Executors (`packages/maven/src/executors/maven`)
- **maven.impl.ts**: Single-task executor using `mvnw`/`mvn`
- **maven-batch.impl.ts**: Batch executor that invokes the batch runner
JAR
- Automatic Maven version detection and executable resolution

### 3. Shared Utilities (`packages/maven/shared`)
- `BuildState`, `BuildStateApplier`, `BuildStateRecorder` for
cross-invocation state
- `MavenCommandResolver` for detecting Maven executable
- Reusable across batch-runner and maven-plugin modules

### 4. Maven Plugin Updates (`packages/maven/maven-plugin`)
- Updated to use `@nx/maven:maven` executor (batch-aware)
- Improved `GitIgnoreClassifier` for nested .gitignore handling
- Cache config tweaks for compiler inputs

## Performance

| Scenario | Before | After |
|----------|--------|-------|
| Cold start per task | 100-500ms | N/A (one-time init) |
| Per-task execution | 100-500ms | ~1.3ms (cached) |
| Improvement | - | **75-385x faster** |

## Version Support

- **Maven 4.x**: Full support with ResidentMavenExecutor (optimized)
- **Maven 3.x**: Falls back to ProcessBasedMavenExecutor (subprocess)

## Testing

- E2E tests for Maven 4.0.0-rc-4, 4.0.0-rc-5
- Unit tests for TypeScript executors
- Tests for GitIgnoreClassifier

## Current Behavior

Uses subprocess execution via `mvnw`/`mvn` for each task.

## Expected Behavior

Batch execution keeps Maven resident, dramatically reducing per-task
overhead.

## Related Issue(s)

Part of Maven integration improvements.

---------

Co-authored-by: Max Kless <maxk@nrwl.io>
2025-12-17 22:49:54 -05:00
Philip Fulcher 62b3c91be9 docs(nx-dev): remove December 2025 webinar notifier (#33911) 2025-12-17 22:17:04 -05:00
Craigory Coppola 9475bb4386 fix(core): ensure no tui on single tasks (#33910)
## Current Behavior
The tui shouldn't show for single tasks

## Expected Behavior
The tui isn't shown for single tasks

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

Fixes #
2025-12-17 23:43:01 +00:00
Craigory Coppola c7cdd2a9b9 fix(dotnet): fix dependency graph for multi-targeting and transitive deps (#33908)
## Current Behavior

  Two issues with the .NET dependency graph:

1. Issue #33653: When a .NET project uses multi-targeting
(<TargetFrameworks> plural), its project reference dependencies
disappear from the Nx graph.
2. Issue #33397: Transitive dependencies are incorrectly shown as direct
dependencies. For example, if A → B → C, the graph shows A depending on
both B and C, when it should only show A → B.

##  Expected Behavior

1. Multi-targeting projects should correctly show their dependencies in
the graph.
2. Only direct dependencies should be shown, not transitive ones. Nx
handles transitive dependencies through the dependency chain.

 ### Solution

  Multi-targeting fix (#33653)

  MSBuild creates multiple nodes for multi-targeting projects:
  - An "outer build" with TargetFrameworks set but TargetFramework empty
  - "Inner builds" for each target framework with TargetFramework set

The fix groups nodes by project file path and prefers inner builds
(which have properly resolved references) over outer builds.

 ### Transitive dependency fix (#33397)

Changed from using ProjectGraphNode.ProjectReferences (which includes
transitive dependencies in multi-targeting scenarios) to
ProjectInstance.GetItems("ProjectReference") which returns only direct
references defined in the project file.

 ## Related Issue(s)

  Fixes #33653
  Fixes #33397

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 18:22:01 -05:00
Jason Jean 6e426514e2 chore(repo): update nx to 22.3.0-beta.3 (#33907)
Updating Nx from 22.3.0-beta.2 to 22.3.0-beta.3
2025-12-17 14:42:51 -05:00
Jack Hsu 6323dba876 fix(core): convert * to workspace:* for pnpm/yarn/bun in CNW (#33893)
Templates use `"*"` for workspace dependencies in individual
package.json files. This works for npm but breaks pnpm, yarn, and bun
which require the `workspace:` protocol for proper symlinking.

For pnpm, yarn, and bun: automatically convert `"*"` dependencies to
`"workspace:*"` in all workspace package.json files. npm is left
unchanged since it handles `"*"` natively.

Also adds support for 2-level nested projects (e.g.,
`libs/shared/models/package.json`).

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 14:11:06 -05:00
Jack Hsu 5c404e669f docs(misc): add "Copy page" button to copy markdown content (#33905)
This PR adds a `Copy page` action under the ToC in the right sidebar.

<img width="608" height="861" alt="image"
src="https://github.com/user-attachments/assets/9d3c7444-1163-4682-87dc-a399178e750d"
/>

The helps get the content into LLMs and AI agents.
2025-12-17 13:53:17 -05:00
Leosvel Pérez Espinosa 6f85b83fd3 cleanup(repo): format all files (#33902)
Format all files after Prettier v3 was merged.
2025-12-17 17:15:06 +00:00
Berend de Boer a5fc0d6b6e docs(misc): add link to new nx-biome plugin (#33854)
This plugin supports --batch for very fast formatting and linting.
2025-12-17 17:13:06 +01:00
Leosvel Pérez Espinosa e3777677b8 fix(core): invalidate sync generator cache on file changes and use up-to-date project graph (#33780)
## Current Behavior

Sync generators are processed in the background by the daemon server.
Their results are cached and reprocessed when the project graph is
recomputed. There are currently two issues:

- The cache is only invalidated after the project graph finishes
recomputing, which means that there's an interval between files changed
(triggering the project graph recomputation) and the recomputation
finishes, where the cache is not invalidated, and it's stale. During
that interval, any request to get the sync generator changes will use
the stale cache.
- Sync generators are scheduled to be processed after the project graph
is recomputed, so a quick succession of recomputations can be coalesced.
The problem is that the scheduled closure uses the project graph from
the initial scheduling, rather than the latest available project graph
at the time it runs. This results in the usage of stale data to process
the sync generators.

## Expected Behavior

Getting sync generators changes should always return up-to-date
information.
2025-12-17 10:36:48 -05:00
Leosvel Pérez Espinosa 99d226fd6b fix(core): improve database initialization error handling (#33820)
## Current Behavior

When database initialization fails due to filesystem issues, permission
problems, or environment incompatibilities (like WAL mode not being
supported), Nx shows generic error messages that don't provide
actionable guidance to users. For example:
- "Unable to create db lock file: PermissionDenied"
- "Unable to set journal_mode: <sqlite error>"

This makes it difficult for users to diagnose and resolve issues,
especially in restricted environments like Docker containers, network
filesystems, or WSL1.

## Expected Behavior

With this PR, database initialization errors now provide:

1. **Context-specific error messages** - Different guidance based on the
error type:
- Permission denied: Instructions about file ownership, Docker volume
permissions, and read-only filesystems
   - Storage full: Suggestions to free disk space
   - Already exists: Guidance about stale files from crashed processes

2. **Automatic WAL mode fallback** - When WAL journal mode is not
supported by the filesystem, Nx now automatically falls back to DELETE
journal mode instead of failing. This improves compatibility with:
   - Network filesystems (NFS, CIFS)
   - Some Docker volume configurations
   - Other environments with limited locking support

3. **WSL1 detection** - Proactively detects WSL1 environments (which
have known WAL incompatibilities) and uses DELETE mode from the start,
avoiding failed attempts and retries.

4. **Better cleanup on retry** - When database initialization fails and
needs to retry, all auxiliary files (WAL and SHM files) are also cleaned
up, not just the main database file.

5. **Actionable reporting instructions** - All error messages now
include:
- How to capture detailed logs
(`NX_NATIVE_FILE_LOGGING=nx::native::db=trace`)
   - Link to create an issue
   - Suggestion to run `nx reset`
2025-12-17 10:25:18 -05:00
Leosvel Pérez Espinosa 6f7830088e feat(core): add hints and status messages to the tui (#33838)
## Current Behavior

When users press unhandled keys in the TUI (e.g., pressing `i` on a
completed task, or typing in a non-interactive terminal pane), nothing
happens and there's no feedback explaining why.

Similarly, when users press certain key bindings like `c` to copy
output, the action succeeds but there's no visual confirmation.

## Expected Behavior

### Hint Popups for Unhandled Keys

Users now see helpful hint popups when pressing keys that don't work in
the current context:

- Pressing `i`, `c`, or `Ctrl+A` in the dependency view (task hasn't
started yet)
- Pressing `i` on a task that doesn't support interactive mode
- Pressing character keys in a terminal pane that's not in interactive
mode

The hints explain what's happening and guide users on how to proceed.

### Status Messages for "Invisible" Actions

When users perform actions without obvious visual feedback, a status
message now appears in the terminal pane's bottom border:

- `Output copied` when pressing `c` to copy
- `Sent to assistant` when pressing `Ctrl+A`

### Configuration Option

Users who prefer not to see hint popups can disable them in `nx.json`:

```json
{
  "tui": {
    "suppressHints": true
  }
}
```
2025-12-17 10:14:11 -05:00
Colum Ferry a64d1b237e fix(storybook): use helper to find correct version when pnpm catalogs are used (#33900)
Current Behavior

When using pnpm catalogs to manage dependency versions, the Storybook
utilities and ESLint version-utils read package.json directly using
readJson() or readJsonFile(). This approach doesn't resolve catalog
references like catalog:default, causing version detection to fail or
return incorrect values.

  For example, if package.json contains:
  {
    "devDependencies": {
      "storybook": "catalog:default"
    }
  }

The current code would return "catalog:default" as the version string
instead of resolving it to the actual version (e.g., "8.5.0").

  Expected Behavior

Use the getDependencyVersionFromPackageJson() helper from @nx/devkit
which properly handles pnpm catalog resolution. This ensures that
version detection works correctly regardless of whether dependencies are
specified directly or via pnpm catalogs.

  The helper:
  - Resolves catalog: references to their actual versions
  - Falls back gracefully when catalogs aren't in use
  - Maintains consistent behavior across different package managers

  Related Issue(s)

Fixes issues with pnpm catalog compatibility in Storybook generators and
ESLint utilities.

  Related to #29772

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Coly010 <Coly010@users.noreply.github.com>
2025-12-17 14:44:40 +00:00
Leosvel Pérez Espinosa 62c13c5477 feat(misc): support prettier v3 (#33898)
## Current Behavior

Nx doesn't generate projects with Prettier v3.

## Expected Behavior

Nx should generate projects with Prettier v3.

## Related Issue(s)

Fixes #30801
2025-12-17 09:26:13 -05:00
Leosvel Pérez Espinosa c29834c0a7 fix(angular): ensure jest and jest-preset-angular are updated correctly for angular v21 (#33896)
## Current Behavior

There's a deadlock between the Angular and Jest package updates
requirements (`requires` and `incompatibleWith`) that prevents updating
Jest to v30 and `jest-preset-angular` to v16.

## Expected Behavior

Updating to Angular v21 should result in updating Jest to v30 and
`jest-preset-angular` to v16.

This is ensured by moving the `jest-preset-angular` package update
definition to the `@nx/jest` package and processing the `@nx/angular`
package updates before `@nx/jest`. That way, by the time `@nx/jest` is
processed, the migrator would have collected the Angular v21 updates,
and the requirements will be met.
2025-12-17 08:48:34 -05:00
Jack Hsu 3384b1dc91 docs(nx-dev): add Framer rewrite support for nx-dev (#33677)
## Current Behavior
The nx-dev Next.js app can only serve pages from its own codebase or
proxy to Astro docs.

## Expected Behavior
Support proxying specific pages to a Framer site via environment
variables:
- `NEXT_PUBLIC_FRAMER_URL`: Base URL of the Framer site
- `NEXT_PUBLIC_FRAMER_REWRITES`: Comma-separated paths for new pages

For existing pages like `/ai`, the proxy is handled in
`getServerSideProps`.

## Related Issue(s)
Closes DOC-349

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-17 08:16:00 -05:00
Leosvel Pérez Espinosa a24119303c feat(angular): add migration to replace jest-preset-angular/setup-jest imports (#33899)
Replaces the removed `jest-preset-angular/setup-jest` import with the
new `setupZoneTestEnv` function from
`jest-preset-angular/setup-env/zone`.
2025-12-17 14:10:36 +01:00
Chau Tran 8d5ca12b30 fix(graph): serve full project graph when navigating from PDV (#33897) 2025-12-17 18:56:32 +07:00
Jan Sudczak 4493157fb0 fix(js): allow copying generated Prisma client (asset) from 'node_modules' (#33822)
Removed 'node_modules' from the ignore list for asset copying.

<!-- 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
<!-- This is the behavior we have today -->
Updating Nx to v22 breaks my app. Some projects use generated Prisma
clients which, because of how Prisma binaries work, have to be generated
to `node_modules` in order to work both locally and in Docker context.
With Nx v22 Prisma client is not copied when project is built using
`@nx/esbuild:esbuild` (or any other executor supporting `assets`
property) without any error or warning. It took mi couple of hours to
pinpoint the exact line of code responsible for this. `node_modules` dir
is hardcoded there without any possibility to be overridden.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
Prisma client can be copied from `node_modules` to project output
directory when building.
Ignoring `node_modules` is removed **or can be overridden**. I'm open to
any solution which will let me update Nx in my repository.

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

Fixes #

---------

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 21:26:04 -05:00
Jason Jean f33d7e7c96 chore(repo): update nx to 22.3.0-beta.1 (#33873)
Updating Nx from 22.2.0-beta.4 to 22.3.0-beta.1

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2025-12-16 17:02:40 -05:00
Jack Hsu cf7ecc9111 fix(core): reduce error rate with dir validation and add more debugging data (#33887)
This PR adds a validation to the directory prompt, so users should not
hit the error as often. Only possible now if they pass the arg from CLI
_and_ they are in non-interactive mode.

We also added some more data to help debug problems, such as node
version, template/preset chosen, etc. And updated the message in
"custom" preset prompt to align with the more effective "full platform"
prompt.

Note: Also update the error message (if it hits) to be the same in new
flow and old flow.

## Related Issue(s)
Closes NXC-3624

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 22:00:24 +00:00
Copilot ffc5f69320 docs(core): document argv in task execution hook contexts (#33322)
The `argv` field was already implemented in `PreTasksExecutionContext`
and `PostTasksExecutionContext` but lacked tests and documentation for
plugin authors to discover and use it.

## Changes

- **Added unit tests**
(`packages/nx/src/daemon/server/handle-tasks-execution-hooks.spec.ts`)
validating that `argv` flows correctly through hook handlers for
different command patterns (direct, affected, run-many)

- **Enhanced existing documentation** in
`astro-docs/src/content/docs/extending-nx/task-running-lifecycle.mdoc`
with a new section covering:
  - Context property definitions showing the `argv` field
- Examples showing how to detect command types (direct execution,
affected, run-many)
- Example demonstrating conditional analytics based on the original
command
  - Common command patterns reference
  - Best practices for defensive argv parsing

## Usage

```typescript
import type { NxPlugin, PostTasksExecutionContext } from '@nx/devkit';

export const myPlugin: NxPlugin = {
  name: 'my-plugin',
  
  postTasksExecution: async (options, context: PostTasksExecutionContext) => {
    // Distinguish between nx build my-app vs nx affected -t build
    if (context.argv.includes('affected')) {
      console.log('Running in affected mode');
    }
  }
};
```

Fixes
https://linear.app/nxdev/issue/NXC-3382/add-contextargv-to-task-execution-hook-contexts

<!-- START COPILOT CODING AGENT SUFFIX -->



<details>

<summary>Original prompt</summary>

> Issue Title: Add context.argv to task execution hook contexts
> Issue Description: Expose the original CLI arguments on the plugin
worker so hooks can distinguish how execution was started (e.g., `nx
build nx-api` vs `nx affected -t build`). Proposal: include the invoking
argv on the hook context (e.g., `context.argv`).
> Fixes
https://linear.app/nxdev/issue/NXC-3382/add-contextargv-to-task-execution-hook-contexts
> 
> 
> Comment by User 4215f3ef-50bd-4f09-85a0-b489c88057b6:
> [https://github.com/nrwl/nx](https://github.com/nrwl/nx)
> 
> Comment by User 4215f3ef-50bd-4f09-85a0-b489c88057b6:
> Aha! that worked - so you can tell it to assign to copilot instead of
"me and copilot"
> 
> Comment by User d484ef82-7f7d-4a95-be09-9d82ca3905dc:
> 📋 I wasn't able to determine which GitHub repository to work in.
> 
> I think it's one of these, but can you tell me which one is right?
> 
> Comment by User :
> Created issue
[NXC-3382](https://linear.app/nxdev/issue/NXC-3382/add-contextargv-to-task-execution-hook-contexts)
> 
> Comment by User 4215f3ef-50bd-4f09-85a0-b489c88057b6:
> This comment thread is synced to a corresponding [thread in
Slack](https://nrwl.slack.com/archives/C070BJ2JYLW/p1761928859857989?thread_ts=1761928859.857989&cid=C070BJ2JYLW).
All replies are displayed in both locations.
> 
> Comment by User :
> This thread is for an agent session with githubcopilot.
> 
> Comment by User 4215f3ef-50bd-4f09-85a0-b489c88057b6:
> @Linear make a ticket and assign it to copilot
> 
> Comment by User f5ae6d50-28e9-4ee7-ad51-3da8208d5914:
> Makes sense to me
> 
> Comment by User 4215f3ef-50bd-4f09-85a0-b489c88057b6:
> Sure, context.argv?
> 
> Comment by User f5ae6d50-28e9-4ee7-ad51-3da8208d5914:
> We can add them as `argv`?
> 
> Comment by User f5ae6d50-28e9-4ee7-ad51-3da8208d5914:
> Yeah they would run on the plugin worker so it's not there
> 
> Comment by User 4215f3ef-50bd-4f09-85a0-b489c88057b6:
> @jason we could add `originalArgv` to the contexts?
> 
> Comment by User 4215f3ef-50bd-4f09-85a0-b489c88057b6:
> Eh, probably not... they run on the plugin worker
> 
> Comment by User 4215f3ef-50bd-4f09-85a0-b489c88057b6:
> Yeah, I don't think the hooks know.... I'd be curious if process.argv
would just have that info though
> 
> Comment by User 439b15a6-827b-4258-971a-d86133ad59de:
> payfit does
> 
> Comment by User 74901385-a023-4825-8470-fe68b1b55664:
> I can’t see anything about that in the docs - so I would assume the
hooks are agnostic to how the tasks were triggered?
> 
> Comment by User 74901385-a023-4825-8470-fe68b1b55664:
> so they’re asking is there’s a way to tell the difference between `nx
build nx-api` or `nx affected -t build` in the task hook?
> 
> Comment by User 74901385-a023-4825-8470-fe68b1b55664:
> > I’ve been playing around with the Task Execution Hooks, specifically
the postTasksExecution hook, and I think it will be really useful for me
to grab some detailed metrics for our specific use cases.
> > What I feel like it’s missing is a way to see what command actually
started the task execution, whether it was a specific target or an
affected command. As long as it was a specific target, I think the tasks
are sorted in order so the last taskResult will probably be the actual
target of the command but for affected it seems a bit more random what
the last result will be.
> > Is there a way to know exactly which command kicked off the ‘task
execution’?
> 
> 


</details>



<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: AgentEnder <6933928+AgentEnder@users.noreply.github.com>
Co-authored-by: Craigory Coppola <craigorycoppola@gmail.com>
Co-authored-by: Caleb Ukle <caleb@nrwl.io>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Copilot <Copilot@users.noreply.github.com>
2025-12-16 16:15:17 -05:00
Leosvel Pérez Espinosa 035e0fd872 fix(core): prevent pinning the same task in multiple panes in the tui (#33863)
## Current Behavior

The same task can be pinned in multiple terminal panes of the TUI. This
causes one pane to scroll the other because they share the same data.

## Expected Behavior

The same task can only be pinned in a single terminal pane of the TUI.
2025-12-16 16:09:23 -05:00
Jason Jean 4ebbe9735c fix(web): update e2e test regex for SWC decorator metadata (#33892)
## Current Behavior

The e2e test `should emit decorator metadata when using --compiler=swc`
fails because the regex `/Foo=.*?_decorate/` expects the old transpiled
output format where classes were assigned to variables.

## Expected Behavior

The test should pass by matching the current SWC output format which
uses native ES class syntax.

## Solution

Updated the regex from `/Foo=.*?_decorate/` to `/class
Foo.*_ts_metadata/` which:
- Matches `class Foo` (native ES class syntax)
- Verifies `_ts_metadata` is present (decorator metadata)
2025-12-16 15:53:36 -05:00
Leosvel Pérez Espinosa d61ae25b2a fix(core): display task output in TUI when native command runner is disabled (#33881)
## Current Behavior

When `NX_NATIVE_COMMAND_RUNNER=false` is set, tasks running in the TUI
don't display any output in the terminal pane. The pane remains empty
even though the task is running.

## Expected Behavior

Task output is displayed in the TUI terminal pane regardless of the
`NX_NATIVE_COMMAND_RUNNER` setting.

## Related Issues

Fixes #32803
2025-12-16 15:21:07 -05:00
Caleb Ukle 7d1ea67cf0 chore(repo): remove legacy community/approved-plugins.json file (#33869)
use astro-docs/src/content/approved-community-plugins.json instead. 


Fixes DOC-363

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
2025-12-16 15:20:30 -05:00
Caleb Ukle 80501c9848 docs(core): add examples for dependentTasksOutputFiles (#33870) 2025-12-16 15:10:48 -05:00
MaxKless e7758aa6cc cleanup(gradle): fix failing nightly (#33884)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2025-12-16 14:32:43 -05:00
Leosvel Pérez Espinosa 71bfc216c3 feat(angular): add migration to set isolateModules: true to jest tsconfig files (#33889)
## Current Behavior

When upgrading to Angular 21 with Jest, users may encounter TypeScript
compilation issues because their `tsconfig.spec.json` files don't have
`isolatedModules: true` set, which is required for compatibility with
Jest and `jest-preset-angular`.

## Expected Behavior

After running `nx migrate`, Angular projects using Jest will
automatically have `isolatedModules: true` added to their
`tsconfig.spec.json` files (or custom test tsconfig files referenced by
`@nx/jest:jest` tasks) if not already set or inherited from a parent
tsconfig.
2025-12-16 19:30:42 +01:00
Louie Weng 4931fbfdad docs(nx-cloud): fix references to metrics enablement (#33888)
## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Update references to disablement variable for metrics collection for Nx
Cloud enterprise users.

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-12-16 10:25:02 -08:00
Colum Ferry 497345ab74 chore(misc): add agents.md and gemini to codeowners (#33886) 2025-12-16 17:05:35 +00:00
Colum Ferry 3db0fb2ce9 fix(node): use @swc/helpers instead of tslib when compiler is swc (#33885)
When using `@nx/node:library` generator with `--compiler=swc`, the
generator
was incorrectly adding `tslib` as a dependency instead of
`@swc/helpers`.

This change fixes two issues:
1. Pass the correct bundler (matching the compiler) to
jsLibraryGenerator
so it adds the correct helper dependency to the project's package.json
2. Update ensureDependencies to only add tslib when compiler is tsc

Fixes #31202
2025-12-16 17:02:42 +00:00
Caleb Ukle db33a7b9c9 chore(nx-dev): update agent files (#33883)
update claude/agent.md with info about how to use docs
2025-12-16 11:16:53 -05:00
Tine Kondo af003c1a0c feat(nx-plugin): allow customizing the location of the companion E2E project (#32073)
Fixes #32069

<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

---------

Co-authored-by: Colum Ferry <cferry09@gmail.com>
2025-12-16 15:44:13 +00:00
Leosvel Pérez Espinosa 6d34960175 fix(core): add back ability to create cache_outputs table without a foreign key (#33880)
Add back the ability to create the `cache_outputs` table without a
foreign key to `task_details`. Nx Cloud still needs this.
2025-12-16 09:02:35 -05:00
Kasper Christensen 5ccc0a8c4b fix(misc): use string type for fetchDepth in azure-pipelines.yml (#33727)
The Azure Pipelines schema requires fetchDepth to be a string, but the
generator was outputting a number.
This fix changes the value to a string to match the official schema
specification.

## Current Behavior
The generator creates `azure-pipelines.yml` with `fetchDepth: 0`
(number), which causes YAML schema validation error because the Azure
Pipelines schema expects `fetchDepth` to be a string.

According to the [Azure Pipelines
schema](https://raw.githubusercontent.com/microsoft/azure-pipelines-vscode/master/service-schema.json),
`fetchDepth` is defined as:
```json
"fetchDepth": {
    "description": "Depth of Git graph to fetch",
    "$ref": "#/definitions/string"
}
```

## Expected Behavior
The generator should output `fetchDepth: '0'` (string) to match the
schema specification and prevent validation errors.

Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
2025-12-16 14:00:42 +00:00
Charlie Croom d5bd57e697 fix(core): include PNPM patches in externalDependencies hash computations (#33551)
## Current Behavior
If a workspace uses pnpm and adds a local patch to a dependency (e.g.
`vitest`), this patch is not taken into account when computing that
dependency's hash for purposes of determining cache changes. In
practice, you could patch vitest locally, and tests would pull from the
cache.

## Expected Behavior
Patches can alter behavior in the same way that updating the version
could, it's just that the version is not created and the patch is
applied locally.

This updates the pnpm lockfile parsing functionality to read the patches
field into a map and then combine the patch hash with the integrity
hash. The integrity hash ONLY represents the remote / tarball
intergrity, so these have to be combined in order to create a proper
key.

## Related Issue(s)
(Could not find any, but saw this in my work today)

---------

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2025-12-16 13:53:55 +01:00
teawithfruit de966a21c0 fix(js): adjusted stdout and stderr handling to support the latest @swc/cli version (#32685)
<!-- 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
<!-- This is the behavior we have today -->
Due to this PR https://github.com/swc-project/pkgs/pull/53 at SWC, it is
not possible to use the latest version of @swc/cli in NX.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
stdout and stderr are now handled more precisely, allowing you to update
to the latest version of @swc/cli.

---------

Co-authored-by: Colum Ferry <cferry09@gmail.com>
2025-12-16 12:22:08 +00:00
Zachary DeRose 68d4d4e994 fix(js): check package.json for name when project.json exists but has no name (#31887)
## Current Behavior

When a project has a `project.json` file but no `name` field, the
`addBuildAndWatchDepsTargets` function in
`packages/js/src/plugins/typescript/util.ts` returns early without
creating build and watch deps targets, even if the project has a valid
name in its `package.json`.

## Expected Behavior

The function should fall back to checking `package.json` for the project
name when `project.json` exists but has no `name` field, allowing the
build and watch deps targets to be created properly.

## Related Issue(s)

This fixes an issue where projects with `project.json` files missing the
`name` field would not get proper build and watch dependency targets
generated.

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Colum Ferry <cferry09@gmail.com>
2025-12-16 11:05:58 +00:00
Craigory Coppola 98e479210d fix(js): detect changes to pnpm.overrides and overrides in package.json (#31914)
## Current Behavior

`getProjectPathsAffectedByDependencyUpdates` in
`@packages/nx/src/plugins/js/project-graph/affected/lock-file-changes.ts`
doesn't return projects affected when updating `pnpm.overrides` or
`overrides` in package.json.

## Expected Behavior

When `overrides`, `resolutions`, or `pnpm.overrides` fields are changed
in package.json, the affected projects should be properly detected and
returned.

## Related Issue(s)

This addresses reports that affected project detection isn't working
properly when package manager override configurations are changed.

## Changes Made

- Enhanced `getTouchedNpmPackages` function to detect changes to
`overrides`, `resolutions`, and `pnpm.overrides` fields
- When a known package is changed in overrides, only that specific
package is marked as affected
- When an unknown package is changed in overrides, all projects are
marked as affected (since overrides can affect transitive dependencies)
- Added comprehensive tests for all override scenarios

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
2025-12-16 11:05:37 +00:00
Asif Rahman 28c9673887 docs(storybook): fix incorrect version references in storybook v9 docs (#32727)
### Summary:
This PR updates the Nx documentation for the Storybook migration
generator to ensure clear and accurate guidance for migrating to
Storybook version 9. It replaces outdated references to version 8,
corrects migration links, and updates example configurations for Angular
and React (Vite) projects to reflect Storybook v9. These improvements
help users follow the correct steps and avoid confusion when upgrading
their workspace to the latest major release.

### Key Updates:

- Updated all migration documentation links and text to target Storybook
v9 resources.
- Corrected example .storybook/main.js|ts file descriptions for Angular
and React projects to reference version 9.
[[1]](diffhunk://#diff-2bd0403b5cc6e0c92d83a89400b36d55ad50eb0f82688aa976ecb3c93ff69eceL44-R44)
[[2]](diffhunk://#diff-2bd0403b5cc6e0c92d83a89400b36d55ad50eb0f82688aa976ecb3c93ff69eceL61-R61)
- Ensured users will be directed to the right guides and migration steps
for a smoother upgrade experience.

### Type of Change:
Documentation only; no changes to code or functionality.

<!-- 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
<!-- This is the behavior we have today -->
N/A - Docs update

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
N/A - Docs update

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->
N/A
2025-12-16 10:25:20 +00:00
Raphael Araújo 45cdecef50 fix(nextjs): accept fileName option to generate page (#30013)
## Current Behavior
The `pageGenerator` has the option `fileName`, but it is not affecting
anything.

## Expected Behavior
The `pageGenerator` has the option `fileName`, it will define the page
file name.
2025-12-16 10:08:23 +00:00
Jason Jean 02b4dbe08b fix(misc): send connectUrl in completion metadata (#33878)
## Current Behavior

The `recordStat` telemetry for `create-nx-workspace` and
`create-nx-plugin` completion events does not include the Nx Cloud
connect URL.

## Expected Behavior

The connect URL (e.g., `https://cloud.nx.app/connect/{shortlinkId}`) is
now included in the completion metadata sent to `/nx-cloud/stats`.

## Related Issue(s)

N/A - Internal telemetry enhancement
2025-12-15 23:31:42 +00:00
Jack Hsu 63306c01ae chore(repo): fix nightlies (#33875)
NODE_VERSION was set only on the mise-action step, so subsequent steps
defaulted to the wrong node version and corepack couldn't create the
pnpm shim.

Also update corepack first, otherwise you might run into intermittent
integrity check issues:
- https://github.com/nodejs/corepack/issues/612
- https://vercel.com/kb/guide/corepack-errors-github-actions

---

  Before (NODE_VERSION at step-level):

  1. mise-action runs with NODE_VERSION=20
    - mise installs Node 20
- mise adds /home/runner/.local/share/mise/installs/node/20.x.x/bin/ to
PATH
2. corepack enable runs - NODE_VERSION is NOT set anymore (step env is
gone)
    - corepack shim calls mise
- mise reads mise.toml template: node = "{{ env['NODE_VERSION'] |
default(value='24.11.0') }}"
    - NODE_VERSION is unset → defaults to 24.11.0
    - mise runs corepack from Node 24's install
    - corepack creates pnpm shim in Node 24's bin directory
  3. pnpm install runs
    - PATH has Node 20's bin (from step 1)
    - pnpm is in Node 24's bin (from step 2)
    - pnpm not found!

  After (NODE_VERSION at job-level):

  1. mise-action runs with NODE_VERSION=20 (from job env)
    - mise installs Node 20, adds its bin to PATH
  2. corepack enable runs - NODE_VERSION=20 is still set
    - corepack shim calls mise
    - mise sees NODE_VERSION=20
    - corepack runs from Node 20's install
    - pnpm shim created in Node 20's bin
  3. pnpm install runs
    - PATH has Node 20's bin ✓
    - pnpm is in Node 20's bin ✓
    - Works!
---

Closes NXC-3620

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-15 17:36:30 -05:00
Philip Fulcher b9ca315b71 docs(nx-dev): updating blog posts related to Powerpack (#33798) 2025-12-15 17:29:33 -05:00
Jason Jean 2be4dde7ce fix(core): restore linkTaskDetails param for backwards compatibility (#33874)
## Current Behavior

The `linkTaskDetails` parameter was removed from the `NxCache`
constructor in #33843, which broke Nx Cloud since it still passes this
parameter.

## Expected Behavior

The `NxCache` constructor should accept the `linkTaskDetails` parameter
(even if unused) to maintain backwards compatibility with Nx Cloud.

## Related Issue(s)

Fixes
https://github.com/nrwl/nx/commit/ed09ee1daed597b7be60255f0cebe52efdd1ae69#r172894152
2025-12-15 21:19:05 +00:00
Philip Fulcher c5dac1eb95 docs(nx-dev): add changelog for 22.2 (#33795) 2025-12-15 15:06:28 -06:00
Jack Hsu e864b6a266 fix(core): update CNW messaging and remove cancel event from SIGINT (#33872)
Updates CNW messages and removes `cancel` event from being recorded in
SIGINT handler, since it didn't work.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2025-12-15 14:19:46 -05:00
Colum Ferry 68d539c19c fix(module-federation): check port availability before starting remote proxies (#33871)
When multiple MF dev servers run concurrently and share the same remote,
they would both attempt to start proxies on the same port, causing
EADDRINUSE errors.

This fix checks if a port is already in use before attempting to start
a proxy. If the port is occupied (likely by another MF dev server that
started earlier), the proxy is skipped for that remote since it's
already being served.

Uses the existing `waitForPortOpen` utility with retries: 0 to perform
an immediate check.

Fixes #33470
2025-12-15 17:53:34 +00:00
Colum Ferry ae0a47aaf1 docs(misc): clarify dryRun behavior for releasePublish (#33868)
Update the programmatic API documentation to clarify that the dryRun
option for releasePublish does not prevent the underlying commands
from being executed. Instead, it forwards the flag to the executor
and sets the NX_DRY_RUN environment variable.

This makes it clear that:
- The built-in @nx/js:release-publish executor handles dryRun correctly
- Custom nx-release-publish executors must implement dryRun support
themselves

Fixes #33443
2025-12-15 17:01:36 +00:00
Colum Ferry 2516974bd6 docs(release): add independent versioning guidance for publish workflow (#33867)
The publish workflow template was designed for fixed versioning strategy
(where all packages share the same version). This commit adds:

- A callout explaining that the template works best with fixed
versioning
- A new section covering considerations for independent versioning
- Documentation of GitHub's 3-tag event limitation
- Alternative approaches: workflow_dispatch, branch-based triggers, or
batch tag pushing

Fixes #33502
2025-12-15 17:00:45 +00:00
Craigory Coppola 72c47e7452 fix(core): preserve command output in TUI summary for non-cached tasks (#33673)
## Current Behavior

The `printTaskTerminalOutput` callback in the TUI summary life cycle
overwrites terminal output for all tasks when output is provided. This
causes the command line information (the actual command that was run) to
be lost for non-cached tasks because non-cached tasks stream their
output via `appendTaskOutput`, which includes the command information.

## Expected Behavior

For non-cached tasks (those with 'failure' or 'success' status), the
output should be preserved from the streaming via `appendTaskOutput`
which includes the complete command line that was executed. Only cached
tasks should have their output overwritten by `printTaskTerminalOutput`
since they don't go through the streaming path.

## Related Issue(s)

<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
2025-12-15 11:50:07 -05:00
Colum Ferry 026756cf80 fix(nest): ensure library is generated with correct outputPath for TS Soln #32060 (#33864)
## Current Behavior
NestJs libraries are generated with output path pointing to workspace
level dist folder. With TS Soln setups, we expect the dist folder to be
local to the project.

## Expected Behavior
Ensure the outputPath generated is correct

## Related Issue(s)

Fixes #32060
2025-12-15 16:29:00 +00:00
Colum Ferry 999d9e32a2 chore(misc): update codeowners to reflect latest ownership (#33860)
Update codeowners
2025-12-15 13:31:19 +00:00
Leosvel Pérez Espinosa ae8612fba6 fix(core): do not invoke prettier with --write and --list-different when unsupported (#33857)
## Current Behavior

`nx format:write` fails with Prettier 4+ (and Prettier 3.6+ with the
experimental CLI enabled) with the error:

```bash
Incompatible options: "write" and "list-different" cannot be used together
```

## Expected Behavior

`nx format:write` works seamlessly across all Prettier versions (2.x,
3.x, and 4.x).

## Related Issue(s)

Fixes #33658 
Fixes #31951

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-12-15 14:22:25 +01:00
Jason Jean c3ace6deba chore(repo): add root Maven and Gradle files to Java reviewers in CODEOWNERS (#33714)
## Current Behavior

Root Maven and Gradle build files (pom.xml, build.gradle.kts,
settings.gradle.kts) are not explicitly assigned to the Java reviewers
in CODEOWNERS.

## Expected Behavior

With this PR, the Java reviewers (@FrozenPandaz @MaxKless @lourw) will
be automatically added as reviewers when changes are made to:
- `/pom.xml` - Root Maven build file
- `/build.gradle.kts` - Root Gradle build file  
- `/settings.gradle.kts` - Gradle settings file

This ensures the Java team has visibility into changes affecting the
root Java build configuration.

## Related Issue(s)

N/A - Maintenance improvement to CODEOWNERS
2025-12-15 08:21:36 -05:00
Rares Matei 099dc7db1a docs(nx-cloud): remove broken on-premise auth-single-admin redirect (#33840)
## Current Behavior

The `/ci/recipes/enterprise/on-premise/auth-single-admin` and
`/ci/recipes/on-premise/auth-single-admin` paths redirect to
`https://github.com/nrwl/nx-cloud-helm`, but the documentation that
should exist at these paths no longer has a target location.

## Expected Behavior

These redirect rules are removed so the broken links don't mislead users
with incorrect redirects.

## Related Issue(s)

Fixes CLOUD-4007
2025-12-15 21:56:25 +09:00
Leosvel Pérez Espinosa b6051f07af fix(angular): install compatible vitest version for angular projects (#33858)
#### Current Behavior

When creating a new Nx workspace with Angular v20 and selecting Vitest
as the unit test runner, the installation fails with an npm peer
dependency conflict:

```bash
npm error ERESOLVE could not resolve
npm error peerOptional vitest@"^3.1.1" from @angular/build@20.3.13
npm error Found: vitest@4.0.15
```

## Expected Behavior

Workspace creation completes successfully when selecting Angular with
Vitest as the unit test runner.

## Related Issue(s)

Fixes #33770
2025-12-15 11:47:51 +01:00
Jonathan Gelin ad5d9b726d fix(release): {releaseGroupName} not interpolated in changelog tag/releaseTagPattern (#33779) 2025-12-14 09:36:34 +00:00
Jason Jean 0a58d4c7f8 fix(repo): install correct Rust target for x86_64 macOS build (#33853)
## Current Behavior

The publish workflow was installing `aarch64-apple-darwin` Rust target
but attempting to build for `x86_64-apple-darwin`, causing the build to
fail with:

```
error[E0463]: can't find crate for `core`
  = note: the `x86_64-apple-darwin` target may not be installed
  = help: consider downloading the target with `rustup target add x86_64-apple-darwin`
```

## Expected Behavior

The workflow should install the correct Rust target
(`x86_64-apple-darwin`) before attempting to build for it.

## Related Issue(s)

N/A - Bug found during publish workflow debugging
2025-12-13 20:55:21 -05:00
Miroslav Jonaš ad7dfe7885 fix(core): improve performance of buildExplicitPackageJsonDependencies (#33791)
Further improvement of the graph creation.

Improving the `buildExplicitPackageJsonDependencies`.

| | Before | After |
| ---- | ----- | ---- |
| buildExplicitPackageJsonDependencies | 128 | 12 |
| isPackageJsonAtProjectRoot | 114 | 1 |

Fixes #

---------

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2025-12-13 16:02:17 +00:00
Leosvel Pérez Espinosa ed09ee1dae fix(core): create all tables upfront when creating the database (#33843)
Create all the tables upfront when creating the database. This prevents
some issues in some scenarios where a missing table is reported.
2025-12-12 14:56:29 -05:00
Leosvel Pérez Espinosa 15a7d954fc fix(angular): improve error message when using esbuild-based build targets and generating cypress ct (#33846)
## Current Behavior

When running `nx g @nx/angular:cypress-component-configuration` on an
Angular project that uses esbuild (the default bundler since Angular
17), users receive a confusing error message:

```bash
Unable to find a valid build configuration. Try passing in a target for an Angular app.
```

This doesn't explain why the configuration fails or what the actual
limitation is.

## Expected Behavior

Users now receive a clear, informative error message that explains:
- Cypress Component Testing for Angular requires a webpack-based build
target
- Their project uses an esbuild-based executor (and which one)
- Cypress only supports webpack as the bundler for Angular component
testing

This helps users understand the limitation and make informed decisions
about how to proceed.

## Related Issue(s)

Fixes #33329
2025-12-12 18:36:48 +00:00
Adwait Athale 4ef85ffec2 chore(module-federation): optimize path mappings and remote resolution (#33752)
## Current Behavior

### 1. typescript.ts - readTsPathMappings was O(n²)

The function was spreading the accumulator object on every iteration:

```
┌─────────────────────────────────────────────────────────────┐
│                    BEFORE: O(n²)                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  For each path alias (n=100):                               │
│    tsPathMappings.set(tsConfigPath, {                       │
│      ...tsPathMappings.get(tsConfigPath),  ← SPREAD n items │
│      [alias]: paths                                         │
│    });                                                      │
│                                                             │
│  Iteration 1: spread 0 items                                │
│  Iteration 2: spread 1 item                                 │
│  Iteration 3: spread 2 items                                │
│  ...                                                        │
│  Iteration n: spread n-1 items                              │
│                                                             │
│  Total: 0+1+2+...+(n-1) = n(n-1)/2 = O(n²) operations       │
│                                                             │
│  For 100 aliases: 4,950 spread operations                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

### 2. get-remotes-for-host.ts - Multiple inefficiencies

- `Object.keys()` called twice on same object
- `replace()` called twice on same string
- Multiple array spreads for port calculation

## Expected Behavior

### 1. typescript.ts - Now O(n)

```
┌─────────────────────────────────────────────────────────────┐
│                     AFTER: O(n)                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  const processedPaths = {};                                 │
│  for (const [alias, paths] of entries) {                    │
│    processedPaths[alias] = paths.map(normalize);            │
│  }                                                          │
│  tsPathMappings.set(tsConfigPath, processedPaths);          │
│                                                             │
│  Total: n iterations, each O(1) = O(n)                      │
│                                                             │
│  For 100 aliases: 100 operations (vs 4,950)                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

### 2. get-remotes-for-host.ts - Optimized

```
┌─────────────────────────────────────────────────────────────┐
│                  OPTIMIZATIONS                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────────┐         ┌─────────────────┐            │
│  │ Object.keys(x)  │  ───►   │ const keys =    │            │
│  │ Object.keys(x)  │         │   Object.keys(x)│            │
│  │ (2 calls)       │         │ // use keys     │            │
│  └─────────────────┘         └─────────────────┘            │
│                                                             │
│  ┌─────────────────┐         ┌─────────────────┐            │
│  │ r.replace(...)  │  ───►   │ const norm =    │            │
│  │ r.replace(...)  │         │   r.replace(...)│            │
│  │ (2 calls)       │         │ // use norm     │            │
│  └─────────────────┘         └─────────────────┘            │
│                                                             │
│  ┌─────────────────┐         ┌─────────────────┐            │
│  │ Math.max(       │  ───►   │ for (port of p) │            │
│  │  ...[...a,...b] │         │  if (port>max)  │            │
│  │ )               │         │    max = port   │            │
│  │ (3 arrays)      │         │ (0 extra arrays)│            │
│  └─────────────────┘         └─────────────────┘            │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

## Why Accept This PR

1. **Significant complexity reduction**: O(n²) → O(n) for path mappings
processing
2. **Zero behavior change**: Test passes, no functional changes
3. **Clean implementation**: Simple refactoring using idiomatic patterns
4. **Complementary to PR #33734**: Optimizes files not touched by that
PR

## Related Issue(s)

Performance improvement for Module Federation path mappings and remote
resolution.

 ## Merge Dependencies

This PR has no dependencies and can be merged independently.

---
2025-12-12 18:21:28 +00:00
James Kraus fe2bf86a8b fix(react): update template comment to be valid css (#33169)
<!-- 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 `//` comment in the styled template [is not valid
css](https://stackoverflow.com/questions/12298890/is-it-bad-practice-to-prefix-single-lines-of-css-with-as-a-personal-comment-s/20192639#20192639)
and is causing [stylelint](https://stylelint.io/) to throw errors upon
creating new apps

## Expected Behavior
It should be valid css

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

https://github.com/nrwl/nx/issues/33579

---------

Co-authored-by: Colum Ferry <cferry09@gmail.com>
2025-12-12 18:20:45 +00:00
Jack Hsu 192099af44 fix(js): resolve nx binary from workspace root in node executor (#33842)
## Current Behavior

When running `nx serve` with a NestJS project (and other node apps using
`runBuildTargetDependencies`), the node executor attempts to resolve the
`nx` binary using `require.resolve('nx')`. This fails with because
`nx/package.json` does no longer has a `main` field.

## Expected Behavior

The node executor should correctly resolve and use the `nx` binary from
the workspace where it's always installed.

This is fixed by using `nx/bin/nx.js` instead of just `nx` -- as we do
in other places.

## Related Issue(s)

Fixes #33776

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-12 12:59:36 -05:00
Timo Santi 30e6f85b48 fix(js): handle workspace packages when nx.name differs from package.json.name (#33583)
## Current Behavior
<!-- This is the behavior we have today -->

When a workspace library has a `name` field set in its `nx`
configuration (e.g., `"nx": { "name": "buildable" }`), the
`@nx/js:prune-lockfile` executor fails to include transitive
dependencies from that library in the pruned lockfile.

The issue occurs because `addNodesAndDependencies` attempts to retrieve
workspace nodes using `graph.nodes[name]` where `name` is the package
name from `package.json`, but `graph.nodes` is keyed by the project name
(from `nx.name`). When these differ, the lookup fails and transitive
dependencies are not traversed.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

The `@nx/js:prune-lockfile` executor should include all transitive
dependencies from workspace libraries regardless of whether the library
has a `name` field set in its `nx` configuration.

The fix uses the workspace node from the `workspacePackages` map (which
is keyed by package name) instead of attempting to look it up in
`graph.nodes` (which is keyed by project name).

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

Fixes #33582
2025-12-12 12:59:20 -05:00
Leosvel Pérez Espinosa 80523ef09a fix(js): prevent crash when terminating task using the @nx/js:swc executor (#33845)
## Current Behavior

When terminating a task using the `@nx/js:swc` executor before it ever
got to execute its post-compilation logic, a `TypeError: disposeFn is
not a function` error is thrown.

## Expected Behavior

Terminating a task using the `@nx/js:swc` executor should not error.

## Related Issue(s)

Fixes #31938
2025-12-12 17:58:11 +00:00
Leosvel Pérez Espinosa f6189359e6 fix(angular): collect known tsconfig files from non-buildable angular libraries in migration (#33834)
## Current Behavior

The `update-21-2-0/update-module-resolution migration` doesn't process
any tsconfig files of non-buildable libraries.

## Expected Behavior

The `update-21-2-0/update-module-resolution migration` should process
common/known tsconfig files of non-buildable libraries.

## Related Issue(s)

Fixes #33705
2025-12-12 17:50:35 +00:00
Yevhenii Yusenkov 54eed65774 feat(js): improve SWC compilation error logging (#33297)
Currently, when SWC compilation fails, Nx logs only a generic message:

  "SWC compilation failed"

There is no `error.message`, no `stderr` and no `stdout` printed.  
In many cases the actual cause of failure is completely hidden, which
makes debugging very difficult, especially in CI.

This PR improves the logging by printing:

- error.message (or the error itself)
- stderr if available
- stdout if available

This makes SWC failures visible and debuggable again.



## Current Behavior
Only a generic "SWC compilation failed" message is logged. No error
message or stdout are shown.

## Expected Behavior
Include error.message, stderr, and stdout (when available) so developers
can understand and debug failures.
2025-12-12 17:40:56 +00:00
Hamza Khan 7f6db63f91 fix(node): sourceMaps option to sourceMap in webpack config (#33333)
## Current Behavior
when I run the below nx workspace command
nx g @nx/express:app kafka-service --directory=apps/kafka-service
--e2eTestRunner=none

the apps/kafka-service/webpack.config.json is generated with the below
lines

const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
const { join } = require('path');

module.exports = {
  output: {
    path: join(__dirname, 'dist'),
    ...(process.env.NODE_ENV !== 'production' && {
      devtoolModuleFilenameTemplate: '[absolute-resource-path]',
    }),
  },
  plugins: [
    new NxAppWebpackPlugin({
      target: 'node',
      compiler: 'tsc',
      main: './src/main.ts',
      tsConfig: './tsconfig.app.json',
      assets: ["./src/assets"],
      optimization: false,
      outputHashing: 'none',
      generatePackageJson: true,
      sourceMaps: true,
    })
  ],
};

there is no such property in NxAppWebpackPluginOptions called
**sourceMaps**, hence source maps are not generated
the correct property is **sourceMap**


## Expected Behavior
module.exports = {
  output: {
    path: join(__dirname, 'dist'),
    ...(process.env.NODE_ENV !== 'production' && {
      devtoolModuleFilenameTemplate: '[absolute-resource-path]',
    }),
  },
  plugins: [
    new NxAppWebpackPlugin({
      target: 'node',
      compiler: 'tsc',
      main: './src/main.ts',
      tsConfig: './tsconfig.app.json',
      assets: ["./src/assets"],
      optimization: false,
      outputHashing: 'none',
      generatePackageJson: true,
      sourceMap: true,
    })
  ],
};

## Related Issue(s)

Fixes #
2025-12-12 17:40:39 +00:00
Leosvel Pérez Espinosa 8136eaf568 feat(angular): support angular v21 (#33378)
## Current Behavior

Angular v21 is not supported.

## Expected Behavior

Angular v21 should be supported.

## Blockers

### Required

- [x] `jest-preset-angular`:
  - [x] PR: https://github.com/thymikee/jest-preset-angular/pull/3485
- [x] Release:
https://github.com/thymikee/jest-preset-angular/releases/tag/v16.0.0

### Optional

We may release Angular v21 support without waiting for these packages to
support it.

- [ ] NgRx
  - [x] PR: https://github.com/ngrx/platform/pull/5025
  - [ ] Release: N/A
- [ ] Cypress (Component Testing doesn't support Zoneless apps)
  - [ ] PR: https://github.com/cypress-io/cypress/pull/33004
  - [ ] Release: N/A

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-12-12 18:39:13 +01:00
Jack Hsu 6828a36979 fix(core): pass more error detail for CNW (#33844)
We're missing messages and variant when errors happen during CNW. This
will help us track down potential problems.

We also want to know when CNW is cancelled in order to know that we're
not missing any events.
2025-12-12 17:26:08 +00:00
Berend de Boer 32ff9e3532 docs(misc): update description for @berenddeboer/nx-aws-cdk (#33002)
Description update for @berenddeboer/nx-aws-cdk plugin: this has become
self-inferring.

---------

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2025-12-12 16:45:55 +00:00
Adwait Athale aeb7122f76 chore(module-federation): consolidate getModuleFederationConfig implementations (#33735)
## Current Behavior

The `getModuleFederationConfig` function is implemented separately in 4
places with 70-80% duplicate code:
- `with-module-federation/webpack/utils.ts` (161 lines)
- `with-module-federation/rspack/utils.ts` (150 lines)
- `with-module-federation/angular/utils.ts` - async version (~80 lines)
- `with-module-federation/angular/utils.ts` - sync version (~80 lines)

Each implementation repeats the same core logic:
1. Get project from graph
2. Get and filter dependencies
3. Share workspace libraries and npm packages
4. Apply eager packages
5. Map remotes

## Expected Behavior

A single shared implementation with framework-specific configuration via
a `FrameworkConfig` interface. Each bundler utility becomes a thin
wrapper that provides its specific configuration.

### Changes

| File | Before | After | Change |
|------|--------|-------|--------|
| `webpack/utils.ts` | 161 lines | 54 lines | -107 lines |
| `rspack/utils.ts` | 150 lines | 51 lines | -99 lines |
| `angular/utils.ts` | 273 lines | 119 lines | -154 lines |
| **NEW** `module-federation-config.ts` | - | 289 lines | +289 lines |

**Net reduction**: 41 lines, with significantly improved maintainability

### New Shared Utility

Created
`packages/module-federation/src/utils/module-federation-config.ts` with:

- `FrameworkConfig` interface for bundler-specific customization
- `ModuleFederationConfigResult` interface for type-safe return values
- `getModuleFederationConfigAsync()` - for webpack/angular async configs
- `getModuleFederationConfigSync()` - for rspack/angular sync configs
- `createDefaultRemoteUrlResolver()` - shared remote URL generation
- Caching for `NX_MF_DEV_SERVER_STATIC_REMOTES` env variable parsing
(performance)

### Benefits

1. **Single source of truth**: Bug fixes and improvements only need to
be made once
2. **Better maintainability**: Framework-specific behavior is clearly
separated via config
3. **Performance**: Added caching for env variable parsing
4. **Type safety**: New interfaces provide better IntelliSense and
compile-time checks
5. **Backward compatible**: All existing exports and behavior preserved

## Related Issue(s)

N/A - This is a refactoring for improved code maintainability and
performance.

## Merge Dependencies

**Must be merged AFTER:** #33734

---
2025-12-12 16:09:28 +00:00
Jay Bell 11992be147 fix(core): swc register base url missing when using tsgo (#33332)
<!-- 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
<!-- This is the behavior we have today -->

With the new tsgo `baseUrl` has been completely removed, this breaks
compilation of plugins using swc when calling them with nx due to swc
needing the baseUrl. I patched my company workspace with this fix and it
did resolve it, not sure if its the right fix or what the ramifications
are so happy to discuss that more. Since `baseUrl` is removed in tsgo
(and recommended against in general), we need to find a way to provide
it to swc (potentially through an `.swcrc` alternatively, I tried adding
that to my workspace though and it didn't do anything).

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2025-12-12 16:07:35 +00:00
Colum Ferry cf742e7271 fix(expo): set projectRoot to workspaceRoot for Expo SDK 54+ compatibility (#33836)
Expo CLI 54.0.12+ changed how originModulePath is determined in Metro
resolvers - from workspace root to project root. This caused the Nx
custom resolver to double-path modules when resolving workspace
libraries.

This fix:
- Adds projectRoot: workspaceRoot to the Metro config to ensure
  originModulePath remains workspace-relative
- Adds defensive path normalization in pnpmResolver to handle edge cases

Fixes #33597
2025-12-12 16:04:48 +00:00
Mark Lindsey 2a3684b325 docs(nx-cloud): fix self-healing docs to include gitlab and azure devops (#33841)
<!-- 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
Self-healing docs only reference being supported for GitHub. 
<!-- This is the behavior we have today -->

## Expected Behavior
We should show instructions for all currently supported vcs providers,
including GitLab and Azure Devops.
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2025-12-12 09:43:58 -05:00
Jack Hsu 302905ea9e feat(core): add CnwError class for typed error handling in create-nx-workspace (#33839)
Replace process.exit(1) calls with typed CnwError exceptions for
structured error reporting and telemetry tracking. Update recordStat
meta to use typed JSON objects with named keys instead of arrays.

Examples of what's sent as `meta`.

```
{"type":"start","flowVariant":"1"}
{"type":"complete","flowVariant":"1","setupCIPrompt":"which-ci-provider","setupCloudPrompt":"cloud-v2-remote-cache-visit","nxCloudArg":"skip","nxCloudArgRaw":"","pushedToVcs":"SkippedGit","template":"nrwl/empty-template"}
{"type":"start","flowVariant":"1"}
{"type":"start","flowVariant":"0"}
{"type":"complete","flowVariant":"0","setupCIPrompt":"which-ci-provider","setupCloudPrompt":"enable-caching2","nxCloudArg":"skip","nxCloudArgRaw":"","pushedToVcs":"SkippedGit","template":"custom"}
{"type":"start","flowVariant":"1"}
{"type":"error","errorCode":"DIRECTORY_EXISTS"}
{"type":"start","flowVariant":"1"}
{"type":"error","errorCode":"DIRECTORY_EXISTS"}
{"type":"start","flowVariant":"1"}
{"type":"complete","flowVariant":"1","setupCIPrompt":"which-ci-provider","setupCloudPrompt":"cloud-v2-green-prs-visit","nxCloudArg":"yes","nxCloudArgRaw":"","pushedToVcs":"FailedToPushToVcs","template":"nrwl/empty-template"}
{"type":"start","flowVariant":"1"}
{"type":"complete","flowVariant":"1","setupCIPrompt":"which-ci-provider","setupCloudPrompt":"cloud-v2-fast-ci-visit","nxCloudArg":"yes","nxCloudArgRaw":"","pushedToVcs":"FailedToPushToVcs","template":"nrwl/empty-template"}
{"type":"start","flowVariant":"1"}
{"type":"start","flowVariant":"1"}
{"type":"complete","flowVariant":"1","setupCIPrompt":"which-ci-provider","setupCloudPrompt":"cloud-v2-green-prs-visit","nxCloudArg":"skip","nxCloudArgRaw":"","pushedToVcs":"SkippedGit","template":"nrwl/typescript-template"}
{"type":"start","flowVariant":"1"}
{"type":"error","errorCode":"WORKSPACE_CREATION_FAILED"}
```

Known errors like "directory exists" does not print stack trace:

<img width="1061" height="362" alt="image"
src="https://github.com/user-attachments/assets/8f29f303-3839-4297-b789-d23ac3af6d52"
/>

Another known error (invalid custom preset):

<img width="1091" height="391" alt="image"
src="https://github.com/user-attachments/assets/c7f6e586-42a8-493b-b595-f7d77743683f"
/>

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-12 09:25:58 -05:00
Andreas Jagiella 85558dce76 fix(rspack): enable build mode for TypeScript checker in TS solution setups (#33447)
<!-- 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
<!-- This is the behavior we have today -->
When using Nx React Module Federation with Rspack, running `nx run-many
-t e2e` before `nx run-many -t typecheck`, it causes typecheck to fail.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
`nx run-many -t typecheck` should succeed regardless of whether Rspack
(via `nx preview`) was executed before it.

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

Fixes https://github.com/nrwl/nx/issues/33445
2025-12-12 14:03:27 +00:00
Colum Ferry e588a0e5fb fix(js): make CopyAssetsHandler per-file logs opt-in via verbose mode (#33835)
The CopyAssetsHandler was logging every copied file to the console,
causing noisy output when a project copies many files. This could
cause build errors to be cut off in terminals with scroll limits.

Change logger.log() to logger.verbose() so per-file logging only
appears when --verbose is passed or NX_VERBOSE_LOGGING=true.

Fixes #33521
2025-12-12 13:50:29 +00:00
Colum Ferry ea97487a52 fix(js): display pnpm publish errors without requiring --verbose (#33837)
The release-publish executor was only displaying npm-style errors
(error.summary
and error.detail), but pnpm returns errors with a different format
(error.code
and error.message). This caused pnpm publish errors to be invisible
unless users
passed the --verbose flag.

This fix adds handling for pnpm's error format so that error messages
are
properly displayed to users without requiring --verbose.

Fixes 33537
2025-12-12 13:50:21 +00:00
Aaro Karell 60fffd3c1a feat(js): add option for using tsgo compiler when inferring build and typecheck tasks (#33821)
Adds a 'compiler' option to the @nx/js/typescript plugin configuration,
with options 'tsc' and 'tsgo'. Affects both typecheck and build targets.

## Current Behavior

The `@nx/js/typescript` plugin always uses `tsc` as the compiler, with
no way to use the native `tsgo` preview.

## Expected Behavior

The `@nx/js/typescript` plugin can be configured to use `tsgo` for
building and typechecking.

## Related Issue(s)

Related discussion #32591.
2025-12-12 14:13:01 +01:00
Colum Ferry 1409648739 feat(webpack): add support for merging externals to NxAppWebpackPlugin (#33833)
This pull request introduces a new option to the Nx Webpack plugin that
allows users to control whether the plugin should merge its external
dependencies configuration with any existing Webpack externals
configuration. This provides greater flexibility when customizing how
external dependencies are handled during the build process.

Configuration enhancements:

* Added a new `mergeExternals` boolean option to the
`NxAppWebpackPluginOptions` interface, allowing users to specify whether
to combine the plugin's externals configuration with the existing
Webpack config.
* Updated the logic in `apply-base-config.ts` so that the `externals`
array is set based on the new `mergeExternals` option, defaulting to not
merging unless specified.

---------

Co-authored-by: David Antoon <davidmantoon@gmail.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-12-12 12:03:34 +00:00
Jack Hsu b367b5437b fix(core): add pnpm/yarn support for CNW templates (#33827)
Currently the template flow will only set up `npm`, even if you run
`yarn create` or `pnpx create-nx-workspace`. This PR adds support back
for other package managers.
2025-12-11 20:29:11 -05:00
Caleb Ukle 1310ee6f28 docs(misc): mcp client list cleanup (#33826)
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
2025-12-11 20:09:13 +00:00
Kamenskih Dmitriy 205daee6e6 fix(webpack): interpolate process.env more verbosely to reduce bundle size with DefinePlugin (#30826)
## Current Behavior
When we prepare ENVs for the DefinePlugin, we are creating the
`process.env` object.
For example:
```
// .env
NX_PUBLIC_VALUE1=1
NX_PUBLIC_VALUE2=2
NX_PUBLIC_VALUE3=3
```
As result we will have:
```js
{
   'process.env': {
      "NX_PUBLIC_VALUE1": "1",
      "NX_PUBLIC_VALUE2": "2",
      "NX_PUBLIC_VALUE3": "3"
   }
}
```

As a result, in the final bundle, we will replace process.env with this
object.
The issue:
If I use all 3 values in my application DefinePlugin will inject this
object 3 times, instead of injecting it once.
It will look like that:
```js
const a = {
      "NX_PUBLIC_VALUE1": "1",
      "NX_PUBLIC_VALUE2": "2",
      "NX_PUBLIC_VALUE3": "3"
}.NX_PUBLIC_VALUE1
const b = {
      "NX_PUBLIC_VALUE1": "1",
      "NX_PUBLIC_VALUE2": "2",
      "NX_PUBLIC_VALUE3": "3"
}.NX_PUBLIC_VALUE2
const c = {
      "NX_PUBLIC_VALUE1": "1",
      "NX_PUBLIC_VALUE2": "2",
      "NX_PUBLIC_VALUE3": "3"
}.NX_PUBLIC_VALUE3
```

## Expected Behavior
DefinePlugin injects values instead of env object in each place
```js
const a = "1"
const b = "2"
const c = "3"
```

## Fixes
- fixed this issue for webpack
- fixed this issue for storybook
- fixed this issue for rspack

TLDR:
now we have object like so:
```js
{
    "process.env.NX_PUBLIC_VALUE1": "1",
    "process.env.NX_PUBLIC_VALUE2": "2",
    "process.env.NX_PUBLIC_VALUE3": "3"
}
```

---------

Co-authored-by: Colum Ferry <cferry09@gmail.com>
2025-12-11 18:42:14 +00:00
Jonathan Wilbur b6aa097cdc fix(js): recognize NodeNext as ESM (#31508)
<!-- 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
NodeNext is not recognized as ESM. This causes this warning message to
be logged, even when you have `"type": "module",` in the `package.json`
file and are compile TypeScript to `"module": "NodeNext"`.

```
Package type is set to "module" but "cjs" format is included. Going to use "esm" format instead. You can change the package type to "commonjs" or remove type in the package.json file.
```

## Expected Behavior
Don't log this message. It is incorrect.

---------

Co-authored-by: Colum Ferry <cferry09@gmail.com>
2025-12-11 16:53:56 +00:00
Nicholas Cunningham 2c043bc670 fix(testing): update jest ci target to forward top level args (#31379)
This pull request refactors the `dependsOn` configuration for Jest
targets in the Nx plugin to improve flexibility and maintainability. The
changes replace string-based dependencies with structured objects,
ensuring better alignment with Nx's target configuration standards.

This PR updates the `dependsOn` configuration for Jest `ciTarget` to
ensure that top-level args are passed on if the parent target has a
dependsOn for other targets.

For example if i pass `nx run-many e2e-ci -- --json
--outputFile=my-test-results.json` the options:
- `--json`
- `--outputFile`

Should be forwarded to the dependent targets.

---------

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2025-12-11 15:36:47 +00:00
Jack Hsu 8df9d50061 chore(misc): fix release script to check GITHUB_ACTIONS not NODE_AUTH_TOKEN (#33824)
The check should be for `GITHUB_ACTIONS` since that is the intention.
The token may not be set due to Trusted Publisher flow.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-12-11 09:53:52 -05:00
Guilherme Siquinelli 2917b3e545 fix(vite): update worker configuration in generator to follow Vite's … (#30465)
…new convention

## Current Behavior

Currently, the @nx/vite plugin generates a `vite.config.ts` file where
the worker configuration is commented out, but uses the old format:

```ts
// worker: {
//  plugins: [ nxViteTsPaths() ],
// }
```

If uncomment, this format triggers a warning from Vite, as the worker
configuration should now be a function that returns an array of plugins.
While Vite automatically converts the old format for compatibility, it
is not ideal to rely on this behavior.

## Expected Behavior

With the changes in this PR, the @nx/vite plugin will generate a Vite
configuration where the worker configuration follows the new convention,
avoiding warnings and ensuring compatibility with future versions of
Vite. The updated configuration will look like this:

```ts
// worker: {
//  plugins: () => [ nxViteTsPaths() ],
// }
```

This change ensures that the generated configuration aligns with Vite's
recommended practices and eliminates unnecessary warnings.

---------

Co-authored-by: Colum Ferry <cferry09@gmail.com>
2025-12-11 15:19:53 +01:00
ResonAtom 0f2c2c4ff8 fix(webpack): show webpack chunks when verbose (#30960)
The NxAppWebpackPlugin option 'verbose' should show chunk output during
webpack build when true, and hide them when false. It's currently the
reverse, causing a lot of console spam during dev, and the hiding the
info during ci/cd.

## Current Behavior
Setting the NxAppWebpackPlugin option 'verbose' to false shows chunk
output.

<img width="848" alt="chunky"
src="https://github.com/user-attachments/assets/4cd5502d-d059-4ace-9e42-28eb160bc1d0"
/>

## Expected Behavior
Setting the NxAppWebpackPlugin option 'verbose' to false hides chunk
output.
2025-12-11 11:26:28 +00:00
Alexey Balmasov 6c2c49cd03 fix(bundling): correct project path for createTmpTsConfig (#31314)
Resolve issue when
projectRoot was created from
join workspaceRoot and projectNode.data.root
but method createTmpTsConfig also make join

<!-- 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
```
 method withNx create
 const projectRoot = join(workspaceRoot, projectNode.data.root);

```
method createTmpTsConfig 
apply also join
```
  const tmpTsConfigPath = join(
    workspaceRoot,
    'tmp',
    projectRoot,
    process.env.NX_TASK_TARGET_TARGET ?? 'build',
    `tsconfig.generated.${randomUUID()}.json`
  );
```

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #31522
2025-12-11 11:26:09 +00:00
Khalil LAGRIDA 0acce33d4e chore(core): nx plugin submission @gridatek/nx-supabase (#33718) 2025-12-11 11:21:47 +00:00
Svyatoslav Zaytsev db1b8f5a3a feat(testing): add option to playwright preset to open html report (#31282)
<!-- 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
No option to manage opening html report after run.

## Expected Behavior
Added option to manage opening html report after run.

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

Fixes #

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2025-12-11 12:03:33 +01:00
Altan Stalker 620f6ea0ad chore(repo): lock default node version to 24.11.0 (#33801) 2025-12-11 14:08:57 +04:00
Caleb Ukle c4af67343f docs(misc): add nx-mcp reference page (#33767)
fixes: DOC-341

https://deploy-preview-33767--nx-docs.netlify.app/docs/reference/nx-mcp

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
2025-12-10 15:54:01 -06:00
Jason Jean 4147b62a16 fix(repo): revert to older nightly Rust for WASM builds (#33797)
## Current Behavior

The nightly-2025-12-10 Rust version removed `mtim()` from the WASI
`MetadataExt` trait, causing the WASM build to fail with:

```
error[E0599]: no method named `mtim` found for reference `&std::fs::Metadata` in the current scope
```

## Expected Behavior

WASM builds should compile successfully.

## Solution

Revert to `nightly-2025-05-09` which still has the `mtim()` API
available in the WASI `MetadataExt` trait.
2025-12-10 16:18:35 -05:00
Jason Jean 6cdbeb6e1a fix(repo): use RUSTUP_TOOLCHAIN env var for WASM builds (#33794)
## Current Behavior

The `build:wasm` script uses `rustup override set nightly-2025-12-10` to
set the Rust toolchain. However, when mise is configured to manage Rust
(e.g., `rust = "1.90.0"` in `mise.toml`), it sets the `RUSTUP_TOOLCHAIN`
environment variable which has higher precedence than directory
overrides.

This causes the WASM build to fail with:
```
error[E0554]: `#![feature]` may not be used on the stable release channel
```

## Expected Behavior

WASM builds should use nightly Rust regardless of mise configuration.

## Solution

Set `RUSTUP_TOOLCHAIN=nightly-2025-12-10` directly in the script, which
overrides any existing env var from mise or other sources.
2025-12-10 14:57:27 -05:00
Caleb Ukle be035dce59 docs(misc): add reference for Nx Console settings (#33363)
## Current Behavior

The Nx Console settings reference lacks explanation of VSCode's user vs
workspace settings and incorrectly states that Project Viewing Style is
unavailable in JetBrains IDEs.

## Expected Behavior
Nx consoles are documented for vscode/jetbrains editors


https://deploy-preview-33363--nx-docs.netlify.app/docs/reference/nx-console-settings

fixes: DOC-315

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-10 19:15:13 +00:00
Jason Jean 0d7ecb937b fix(repo): install nightly Rust for WASM build in publish workflow (#33792)
## Current Behavior

After the mise migration (#33772), the `publish.yml` workflow fails
during the "Build Wasm" step with:

```
error[E0554]: `#![feature]` may not be used on the stable release channel
 --> packages/nx/src/lib.rs:2:33
  |
2 | #![cfg_attr(target_os = "wasi", feature(wasi_ext))]
```

The WASM build requires nightly Rust because it uses the unstable
`wasi_ext` feature. The `build:wasm` script attempts to switch to
nightly via `rustup override set`, but after the mise migration, the
nightly toolchain is no longer pre-installed, causing the build to fail
with the stable compiler.

## Expected Behavior

The WASM build should successfully compile using nightly Rust with the
`wasi_ext` feature.

## Related Issue(s)

Fixes the publish workflow regression introduced in #33772
2025-12-10 14:08:45 -05:00
Miroslav Jonaš 72d91de8c4 fix(core): improve node creation for pnpm parser (#33788)
| | Before | After |
| ---- | ----- | ---- |
| Total createNodes | 812 | 104 |
| Total matchPropValue | 672 | 2 |

## Current Behavior
The `createNode` function is slow for pnpm due to suboptimal
`matchPropValue` function.

## Expected Behavior
The `createNode` function should be fast and not slowdown the graph
creation.

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

Fixes #
2025-12-10 13:54:27 -05:00
Leosvel Pérez Espinosa 04bd4dfdab fix(core): ensure terminalOutput is always a string in task results (#33782)
## Current Behavior

When some tasks fail during execution, it can result in a cryptic:

```bash
Failed to convert JavaScript value 'Undefined' into rust type 'String'
```

This happens because the reported `terminalOutput` for the errored tasks
can be `undefined`, and it hides the actual error that occurred.

## Expected Behavior

Error handling paths should always provide a valid string for
`terminalOutput`, using the error stack/message, or an empty string as a
fallback.

## Related Issue(s)

Fixes #32675
2025-12-10 13:25:09 -05:00
Jason Jean 33c3adaa15 fix(repo): restore mise tools in e2e-matrix workflow (#33785)
## Current Behavior

The inline `mise_toml` config in `e2e-matrix.yml` was overwriting the
entire `mise.toml` file, causing rust, dotnet, bun, and java to NOT be
installed by mise. This resulted in slow package installs as these tools
were downloaded during `pnpm install` instead.

## Expected Behavior

All tools from `mise.toml` (rust, dotnet, bun, java) should be installed
by mise, with only the node version varying based on the matrix.

## Solution

Use mise's template syntax to make node version configurable via
`NODE_VERSION` env var while preserving all other tools from
`mise.toml`:

```toml
node = "{{ env['NODE_VERSION'] | default(value='24') }}"
```

Then in the workflow, set the env var instead of overriding the entire
config:

```yaml
- name: Setup dev tools with mise
  uses: jdx/mise-action@v3
  env:
    NODE_VERSION: ${{ matrix.node_version }}
```

## Related Issue(s)

Fixes slow install times in nightly e2e-matrix workflow after #33772.
2025-12-10 11:46:59 -05:00
Jason Jean b2219f2cd0 fix(repo): fix dotnet installation on Windows (#33786)
## Current Behavior

The mise vfox-dotnet plugin fails on Windows with:
```
mise ERROR Failed to install vfox:mise-plugins/vfox-dotnet@9:
     0: error converting Lua table to PreInstall (no version returned from vfox plugin)
```

This prevents dotnet from being installed via mise on Windows CI
runners.

## Expected Behavior

Dotnet should install successfully on all platforms including Windows.

## Related Issue(s)

Related upstream issue: https://github.com/jdx/mise/discussions/4738

## Solution

1. **mise.toml** - Made dotnet installation conditional on Linux/macOS
only using the `os` option
2. **.github/workflows/publish.yml** - Added `winget install` to install
.NET SDK 9 on Windows CI runners

This approach works around the buggy vfox plugin by using the native
Windows package manager instead.
2025-12-10 11:46:50 -05:00
Leosvel Pérez Espinosa eb6712e738 fix(angular): process only the in progress entry points in ng-packagr-lite's write bundles transform function (#33784)
## Current Behavior

When building Angular libraries with `ng-packagr` >20.3.0, the build
fails with:

```bash
TypeError: Cannot read properties of undefined (reading 'outputCache')
```
This occurs because `ng-packagr` v20.3.1 introduced a memory
optimization
([ng-packagr#3172](https://github.com/ng-packagr/ng-packagr/pull/3172))
that calls `dispose()` on entry points after they're processed, setting
`entry.cache = undefined`.

Nx's custom `writeBundlesTransform` was iterating over **all** entries
in the graph, including already-disposed entry points, causing the crash
when accessing their cache.

## Expected Behavior

Angular library builds should succeed with `ng-packagr` >20.3.0,
including libraries with secondary entry points. Workspaces using lower
versions of `ng-packagr` should remain unaffected.

## Solution

Align with `ng-packagr`'s own pattern by using
`graph.find(isEntryPointInProgress())` to process only the currently
in-progress entry point, rather than iterating over all graph entries.

**Key changes:**

- Use `isEntryPointInProgress()` instead of iterating all entries with
`isEntryPoint()`
- Remove unused `BuildGraph` import (no longer creating a new graph)
- Update package node only when processing the primary entry point (more
efficient)
- Return nothing from the transform (original graph passes through, same
as ng-packagr)

This approach:

- Matches `ng-packagr`'s `writeBundlesTransform` implementation pattern
- Only accesses cache of the in-progress entry point (guaranteed not to
be disposed)
- Works with all supported `ng-packagr` versions (v19+) since
`isEntryPointInProgress()` has been available since v19

## Related Issue(s)

Fixes #33560
2025-12-10 17:13:24 +01:00
Jack Hsu e4b9e5822d fix(core): fix record stat on initial CNW call (#33783)
This PR fixes an issue with CNW where the initial `recordStat` call is
not working due to a logic error on passing `directory` that isn't
initialized yet.
2025-12-10 10:48:19 -05:00
Miguel 8da37b04f3 fix(core): exit with error when generator prompts fail (#33691)
## Current Behavior

If there are issues with values passed to generators via prompt, we
still see a green output and exit code 0.

A colleague found out about this by pressing `Ctrl+C` when being
prompted for parameters for a generator, and this led to the CLI simply
continuing execution and showing no issue.

## Expected Behavior

CLI fails.
2025-12-10 16:45:02 +01:00
Andrew Ovens 691a64532b feat(core): add NX_DEFAULT_OUTPUT_STYLE env var (#33493)
Allows setting a default output style instead of having to include it on
every command

Closes #27490

## Current Behavior
We must specify --outputStyle on every command

## Expected Behavior
Should allow overriding the default with an environment variable

## Related Issue(s)
#27490

Fixes #27490
2025-12-10 12:22:46 +01:00
Ashish Shanker cc369a3e11 fix(core): set max listeners for process in task orchestrator (#33596)
When 8+ dependent tasks exist, each adds an `exit` listener to track
completion. This listener attaches to `process`. So we apply the same
fix that worked for `stdout` and `stderr`, and was merged through [PR
16693](https://github.com/nrwl/nx/pull/16993)

<!-- 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
<!-- This is the behavior we have today -->
For `nx` targets with 8+ dependent targets, we encounter
`maxListenersExceededWarning`:
```
(node: 22553) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 SIGINT listeners added to [process]. MaxListeners is 10. Use emitter.setMaxListeners() to increase limit.
(node: 22553) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 SIGTERM listeners added to [process]. MaxListeners is 10. Use emitter.setMaxListeners() to increase limit.
(node: 22553) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 SIGHUP listeners added to [process]. MaxListeners is 10. Use emitter.setMaxListeners() to increase limit.
```
## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
No `MaxListenersExceededWarning` should be thrown on account of the nx
run.
## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #32439

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2025-12-10 11:45:13 +01:00
Adwait Athale badc998c65 fix(core): share visited Set across affected graph traversal (#33756)
## Current Behavior

In `filterAffectedProjects`, a **new visited Set is created for each
touched project**:

```typescript
ctx.touchedProjects.forEach((p) => {
  addAffectedNodes(p, reversed, result, new Set());  // NEW Set per project!
});
ctx.touchedProjects.forEach((p) => {
  addAffectedDependencies(p, reversed, result, new Set());  // NEW Set per project!
});
```

This defeats the purpose of the visited Set for deduplication. If
projects A and B both depend on shared project C, then C gets visited
**twice**.

## Expected Behavior

Share a single visited Set across all touched projects:

```typescript
const visitedNodes = new Set<string>();
const visitedDeps = new Set<string>();
for (const p of ctx.touchedProjects) {
  addAffectedNodes(p, reversed, result, visitedNodes);  // SHARED Set
}
for (const p of ctx.touchedProjects) {
  addAffectedDependencies(p, reversed, result, visitedDeps);  // SHARED Set
}
```

## Performance Impact

```
Before (separate Sets):              After (shared Sets):
┌─────────────────────────┐         ┌─────────────────────────┐
│  touchedProjects: [A,B] │         │  touchedProjects: [A,B] │
└───────────┬─────────────┘         └───────────┬─────────────┘
            │                                   │
    ┌───────┴───────┐                   ┌───────┴───────┐
    ▼               ▼                   ▼               ▼
┌───────┐       ┌───────┐           ┌───────┐       ┌───────┐
│ A     │       │ B     │           │ A     │       │ B     │
│visited│       │visited│           │       │       │       │
│= {}   │       │= {}   │           │ shared visitedNodes   │
└───┬───┘       └───┬───┘           └───┬───┘       └───┬───┘
    │               │                   │               │
    ▼               ▼                   ▼               ▼
┌───────┐       ┌───────┐           ┌───────────────────────┐
│visit C│       │visit C│           │ visit C (ONCE)        │
│(dup!) │       │(dup!) │           │ skip C from B         │
└───────┘       └───────┘           └───────────────────────┘

Complexity:                         Complexity:
O(touched × shared_deps)            O(total_nodes)
```

**Example**: With 50 touched projects sharing 100 common dependencies:
- Before: 50 × 100 = 5,000 node visits
- After: ~150 node visits (each node visited once)

## Why Accept This PR

1. **Bug-like behavior**: The current code defeats the purpose of the
visited Set
2. **Significant impact**: Affects every `nx affected` command
3. **Zero risk**: Same traversal logic, just shared deduplication
4. **Common scenario**: Monorepos often have shared dependencies (utils,
types, etc.)
## Related Issue(s)

Contributes to #32265

## Merge Dependencies

This PR has no dependencies and can be merged independently.

---

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2025-12-10 10:21:44 +01:00
Adwait Athale 58a69f99b1 fix(core): optimize pnpm lockfile parsing with pre-built indexes (#33750)
## Current Behavior

When parsing pnpm lockfiles to build the project graph:

### matchPropValue function
- Uses separate `Object.values()` + `Object.keys()` iterations
- Two passes over the same data to find a value and get its key

### Hoisted Dependencies Lookup
- For each package, calls `Object.keys(hoistedDeps).find(k =>
k.startsWith(...))`
- O(n) search performed m times = O(n*m) total

## Expected Behavior

### Single-pass Iteration

```
BEFORE: matchPropValue
┌─────────────────────────────────────────────────────────────┐
│  const index = Object.values(record).findIndex(v === key)   │
│  if (index > -1)                                            │
│    return Object.keys(record)[index]  ← Another iteration!  │
│                                                             │
│  = 2 iterations over the same data                          │
└─────────────────────────────────────────────────────────────┘

AFTER: Object.entries() single pass
┌─────────────────────────────────────────────────────────────┐
│  for (const [name, version] of Object.entries(record)) {    │
│    if (version === key) return name  ← Early exit           │
│  }                                                          │
│                                                             │
│  = 1 iteration with early exit on match                     │
└─────────────────────────────────────────────────────────────┘
```

### Pre-built Index for Hoisted Dependencies

```
BEFORE: O(n*m) Hoisted Lookup
┌─────────────────────────────────────────────────────────────┐
│  for each package (n packages):                             │
│    Object.keys(hoistedDeps).find(k => k.startsWith(...))    │
│    ← O(m) search where m = hoisted deps                     │
│                                                             │
│  Total: O(n * m)                                            │
│                                                             │
│  Example: 500 packages × 200 hoisted deps                   │
│         = 100,000 string comparisons                        │
└─────────────────────────────────────────────────────────────┘

AFTER: Pre-built Index Map O(n+m)
┌─────────────────────────────────────────────────────────────┐
│  Build hoistedKeysByPackage Map once:  O(m)                 │
│    Map<packageName, hoistedKey>                             │
│                                                             │
│  for each package (n packages):                             │
│    hoistedKeysByPackage.get(packageName)  O(1)              │
│                                                             │
│  Total: O(n + m)                                            │
│                                                             │
│  Example: 500 packages + 200 hoisted deps                   │
│         = 700 operations (vs 100,000)                       │
└─────────────────────────────────────────────────────────────┘
```

## Impact

For large pnpm monorepos:

| Metric | Before | After | Improvement |
|--------|--------|-------|-------------|
| matchPropValue iterations | 2 | 1 | 50% fewer iterations |
| Hoisted lookup complexity | O(n×m) | O(n+m) | ~100x for large repos |
| String comparisons | n×m | n+m | Dramatic reduction |

## Related Issue(s)

Contributes to #32669, #32254

## Merge Dependencies

This PR has no dependencies and can be merged independently.

**Must be merged BEFORE:** #33751

---
2025-12-10 10:20:49 +01:00
Khalil LAGRIDA 6feae2e1fb docs(misc): update github username (#32652)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

Co-authored-by: khalilou88 <32600911+khalilou88@users.noreply.github.com>
Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2025-12-10 07:31:57 +00:00
Joe Prisk bff97e01cb feat(rspack): add support for cssFilename config #32498 (#32506)
## Current Behavior
Passing cssFilename does not change the outputted css bundle

## Expected Behavior
Specifying cssFilename in the rspack.config will be honoured by
@nx/rspack

## Related Issue(s)
https://github.com/nrwl/nx/discussions/32498

Co-authored-by: Joe Prisk <joe.prisk@elmosoftware.com.au>
Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2025-12-10 08:18:34 +01:00
Jason Jean 029df7a649 chore(repo): migrate GitHub workflows to use mise for dev tools (#33772)
## Summary

Migrates GitHub workflows to use [mise](https://mise.jdx.dev/) for
managing development tool installations instead of individual setup
actions.

## Changes

- **mise.toml**: Added pnpm@10.11.1 to tool configuration
- **ci.yml**: Replaced pnpm, node, rust, and java setup actions with
`mise-action@v3` in both Linux and macOS jobs
- **e2e-matrix.yml**: Replaced all tool setup actions with mise-action
in preinstall and e2e jobs
- **publish.yml**: Replaced tool setup actions with mise-action in build
and publish jobs
- **codeql workflows**: Updated to use `mise-action@v3`

## Benefits

- **Single source of truth**: All tool versions defined in `mise.toml`
- **Faster CI setup**: Mise provides better caching than individual
actions
- **Consistency**: Same tool versions across local dev and CI
- **Easier maintenance**: Update versions in one place

## Test Plan

- [ ] CI workflow passes on Linux
- [ ] CI workflow passes on macOS
- [ ] E2E matrix builds successfully
- [ ] Publish workflow can run (test with dry-run if possible)
- [ ] CodeQL scans complete successfully

Fixes #ISSUE_NUMBER
2025-12-09 16:08:01 -05:00
Philip Fulcher 7342e603b3 docs(nx-dev): update 22.1 release article (#33773) 2025-12-09 14:03:48 -06:00
Colum Ferry 60920310c0 docs(vitest): add guide on testing without building deps (#33769)
## Current Behavior
We do not have a guide showing how to use Vitest with custom conditions

## Expected Behavior
Add a guide showing how to use Vitest with custom conditions
2025-12-09 16:16:25 +00:00
Jack Hsu 22c0f002fd docs(nx-dev): add search and filter controls to plugin registry (#33765)
The Plugin Registry page in astro-docs displays a static grid of plugins
without any search or filtering capabilities, making it hard to find
specific plugins.

Users can search plugins by name or description, and sort by release
date, npm downloads, GitHub stars, or Nx version compatibility.

<img width="975" height="1059" alt="image"
src="https://github.com/user-attachments/assets/a08e2a12-697e-4e3b-b9c0-2983d50fdad8"
/>


Closes DOC-343

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2025-12-09 11:00:06 -05:00
Kasper Christensen cb5510d277 fix(storybook): conditionally include node imports only for non-angular frameworks (#33728)
## Current Behavior
The fileURLToPath and dirname imports are only used in the
getAbsolutePath function, which is only generated for non-Angular
Storybook projects.

## Expected Behavior
This change prevents unnecessary imports from being added to Angular
Storybook configurations.
2025-12-09 11:00:44 +00:00
Adwait Athale 68783a9c78 fix(module-federation): normalize workspace protocol versions in requiredVersion (#33733)
## Current Behavior

When using pnpm with workspace protocol (`workspace:*`, `workspace:^`,
etc.), module federation sets `requiredVersion` to the raw protocol
string (e.g., `workspace:*`) instead of resolving it to the actual
semver version from the library's package.json.

This causes issues like:
- `requiredVersion: "workspace:*"` which is not a valid semver
- Module federation failing to properly share workspace libraries
- Warnings about unable to find required versions

Example of the broken output:
```json
{
  "version": "*",
  "singleton": true,
  "requiredVersion": "^*"
}
```

## Expected Behavior

When a workspace protocol version is detected, it should be resolved to
the actual version from the library's package.json:

```json
{
  "version": "2.0.0",
  "singleton": true,
  "requiredVersion": "2.0.0"
}
```

## Changes Made

1. **Added helper functions** in `share.ts`:
- `isWorkspaceProtocolVersion()` - Detects workspace protocol versions
(`workspace:*`, `workspace:^`, `*`, `file:`)
- `normalizeWorkspaceProtocolVersion()` - Resolves protocol versions to
actual semver by looking up the library's package.json

2. **Applied normalization in `shareWorkspaceLibraries()`**:
- After getting version from `getDependencyVersionFromPackageJson`,
normalize it if it's a workspace protocol
- Simplified the `workspaceLibrariesAsDeps` loop by using the helper
function (removed duplicated logic)

3. **Updated `getNpmPackageSharedConfig()`**:
- Added a check to warn and return undefined when workspace protocol
versions are passed
- Helps users understand that workspace libraries should be configured
properly

4. **Added comprehensive tests** (13 new tests):
- 6 tests for workspace protocol version normalization in
`shareWorkspaceLibraries`
- 7 tests for `getNpmPackageSharedConfig` handling workspace protocol
versions

## Related Issue(s)

Fixes #31397

## Merge Dependencies

This PR has no dependencies and can be merged independently.

**Must be merged BEFORE:** #33734

---
2025-12-09 10:23:34 +00:00
Jason Jean 52e2995917 chore(repo): update nx to 22.2.0-beta.4 (#33722)
Updating Nx from 22.2.0-beta.3 to 22.2.0-beta.4

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2025-12-08 17:07:27 -05:00
Adwait Athale 5d597ee55c fix(js): use Set for O(1) package.json root lookup (#33757)
## Current Behavior

In `buildExplicitPackageJsonDependencies`, for every file in the project
file map, we call `isPackageJsonAtProjectRoot` which uses
`Array.find()`:

```typescript
function isPackageJsonAtProjectRoot(nodes, fileName) {
  return (
    fileName.endsWith('package.json') &&
    nodes.find((projectNode) =>  // O(n) lookup per file!
      joinPathFragments(projectNode.root, 'package.json') === fileName
    )
  );
}
```

This is O(files × projects) complexity.

## Expected Behavior

Build a Set of valid package.json paths once, then use O(1) Set lookup:

```typescript
const projectPackageJsonPaths = new Set(
  Object.values(ctx.projects).map((project) =>
    joinPathFragments(project.root, 'package.json')
  )
);

// Later: O(1) lookup
if (projectPackageJsonPaths.has(f.file)) { ... }
```

## Performance Impact

```
Before (Array.find per file):       After (Set.has):
┌─────────────────────────┐         ┌─────────────────────────┐
│ For each file:          │         │ Build Set once:         │
│   nodes.find(...)       │         │   O(projects)           │
│   O(projects) per file  │         └───────────┬─────────────┘
└───────────┬─────────────┘                     │
            │                                   ▼
            ▼                         ┌─────────────────────────┐
┌─────────────────────────┐         │ For each file:          │
│ Total: O(files×projects)│         │   Set.has(f.file)       │
└─────────────────────────┘         │   O(1) per file         │
                                    └───────────┬─────────────┘
                                                │
                                                ▼
                                    ┌─────────────────────────┐
                                    │ Total: O(files+projects)│
                                    └─────────────────────────┘
```

**Example**: With 5,000 files and 200 projects:
- Before: 5,000 × 200 = 1,000,000 comparisons (worst case)
- After: 200 (build Set) + 5,000 (lookups) = 5,200 operations

## Additional Changes

- Replaced `forEach` with `for...in/of` loops
- Removed unused `isPackageJsonAtProjectRoot` function
- Removed unused `ProjectConfiguration` import
- Net reduction of 7 lines

## Why Accept This PR

1. **Significant complexity reduction**: O(n²) → O(n)
2. **Hot path**: Called during dependency graph construction for every
file
3. **Cleaner code**: Removed unused function, fewer lines

## Related Issue(s)

Contributes to #32265

## Merge Dependencies

This PR has no dependencies and can be merged independently.

---
2025-12-08 16:52:12 -05:00
Louie Weng e6a5a7ed84 fix(gradle): do not add gradle plugin to plugins block if using version catalogs (#33763)
<!-- 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
<!-- This is the behavior we have today -->
We would add the gradle project graph plugin to your build.gradle files
if we did not already detect it. However, this did mechanism did not
recognize aliases for the project graph plugin that came from version
catalogs.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

When adding the project graph plugin to build.gradle.kts, we check if a
version catalogue exists, and if it does we add the alias for the
project graph plugin.

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

Fixes #

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-12-08 15:09:14 -05:00
Adwait Athale 300493ec0b fix(core): use Set for O(1) visited node lookup in hasPath (#33754)
## Current Behavior

The `hasPath` function in `graph.ts` uses an array with `indexOf()` for
tracking visited nodes during recursive graph traversal:

```typescript
function hasPath(graph, target, node, visited: string[]) {
  for (let d of graph.dependencies[node] || []) {
    if (visited.indexOf(d.target) > -1) continue;  // O(n) lookup
    visited.push(d.target);
    // recursive call...
  }
}
```

This results in O(n) lookups per node visited, making worst-case
traversal O(n²).

## Expected Behavior

Use `Set` for O(1) visited node tracking:

```typescript
function hasPath(graph, target, node, visited: Set<string>) {
  for (const d of graph.dependencies[node] || []) {
    if (visited.has(d.target)) continue;  // O(1) lookup
    visited.add(d.target);
    // recursive call...
  }
}
```

## Performance Impact

```
Before (Array + indexOf):              After (Set + has):
┌─────────────────────────┐           ┌─────────────────────────┐
│   hasPath() called      │           │   hasPath() called      │
└───────────┬─────────────┘           └───────────┬─────────────┘
            │                                     │
            ▼                                     ▼
┌─────────────────────────┐           ┌─────────────────────────┐
│ visited.indexOf(target) │           │  visited.has(target)    │
│      O(n) lookup        │           │      O(1) lookup        │
└───────────┬─────────────┘           └───────────┬─────────────┘
            │                                     │
            ▼                                     ▼
┌─────────────────────────┐           ┌─────────────────────────┐
│   visited.push(target)  │           │   visited.add(target)   │
│        O(1)             │           │        O(1)             │
└───────────┬─────────────┘           └───────────┬─────────────┘
            │                                     │
            ▼                                     ▼
    Complexity: O(n²)                     Complexity: O(n)
    for full traversal                    for full traversal
```

**Example with 500 nodes:**
- Before: 500 nodes × avg 250 indexOf lookups = ~125,000 comparisons
- After: 500 nodes × 1 Set lookup each = 500 operations

## Why Accept This PR

1. **Zero risk**: Same semantics, just faster data structure
2. **Standard pattern**: Set is the idiomatic choice for visited
tracking in graph algorithms
3. **Measurable impact**: Graph filtering with `--focus` flag will be
significantly faster on large monorepos
## Related Issue(s)

Contributes to #32265

## Merge Dependencies

This PR has no dependencies and can be merged independently.

---
2025-12-08 14:03:23 -05:00
Philip Fulcher c6b2a26156 docs(nx-dev): add december 2025 webinar (#33760) 2025-12-08 14:52:54 +00:00
Louie Weng 60d019e0c7 Revert "docs(nx-cloud): update resource usage minimum version to 22.2" (#33725)
Reverts nrwl/nx#33723
2025-12-05 19:18:48 +00:00
Philip Fulcher 6c2c50d84c docs(nx-dev): update youtube link in resource usage article (#33724) 2025-12-05 18:22:26 +00:00
Louie Weng f70a9c1cc7 docs(nx-cloud): update resource usage minimum version to 22.2 (#33723)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Correcting docs to mention that resource collection on Nx Cloud will be
availabe from 22.2 onwards.

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

Fixes #
2025-12-05 17:32:26 +00:00
Philip Fulcher 3cd1c73d3d docs(nx-dev): add resource usage article (#33721)
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: philipjfulcher <philipjfulcher@users.noreply.github.com>
2025-12-05 10:31:43 -06:00
Colum Ferry 19e6404eb5 fix(release): ensure --preid flag considers stable tags for version determination (#33703)
When using `nx release version --preid=alpha`, the version determination
now correctly considers both prerelease tags AND stable release tags to
determine the "latest" version. Previously, it would only look at
prerelease tags matching the preid, ignoring stable releases that should
have become the new baseline.

For example, with tags: 1.1.0, 1.1.0-alpha.0, 1.1.0-alpha.1, 1.1.1
- Before: Would return 1.1.0-alpha.1 → bump to 1.1.0-alpha.2
- After: Returns 1.1.1 (stable >= preid base) → bump to 1.1.2-alpha.0

Fixes #33343
2025-12-05 12:28:01 +00:00
Colum Ferry f0252323f8 fix(misc): update output location of ai-migration files (#33696)
Place `ai-migration` files into `tools/ai-migrations`
2025-12-04 17:42:10 -05:00
Jason Jean 71bfd7eb7e feat(maven): update Maven plugin version to 0.0.11 (#33713)
## Current Behavior

The Maven plugin version is currently at 0.0.10 across all pom.xml files
in the repository.

## Expected Behavior

With this PR, the Maven plugin version will be updated to 0.0.11. This
includes:
- Updating the version in the root pom.xml
- Updating the version in packages/maven/maven-plugin/pom.xml
- Updating the mavenPluginVersion constant in
packages/maven/src/utils/versions.ts
- Adding a migration script to automatically update user pom.xml files
from 0.0.10 to 0.0.11

## Related Issue(s)

N/A - Version bump for the Maven plugin
2025-12-04 17:35:01 -05:00
Jack Hsu 2fdf5b278d chore(repo): add debug logging to hanging webpack e2e tests (#33712)
Webpack e2e tests occasionally hang in CI without clear indication of
where the test gets stuck.

Debug logs will help identify which step the test hangs at, making it
easier to diagnose and fix the root cause.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-04 17:02:17 -05:00
Louie Weng 0f45aaff8a chore(gradle): bump version to 0.1.10 (#33711)
<!-- 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
<!-- This is the behavior we have today -->

Current gradle plugin version is at 0.1.9

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Take gradle plugin to 0.1.10

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

Fixes #
2025-12-04 21:31:36 +00:00
Jason Jean 4627345d4e chore(repo): update nx to 22.2.0-beta.3 (#33706)
Updating Nx from 22.2.0-beta.2 to 22.2.0-beta.3
2025-12-04 20:43:21 +00:00
Jack Hsu e807320d74 docs(nx-dev): add global Cmd+K search shortcut for non-docs pages (#33709)
Pressing Cmd+K (or Ctrl+K) on non-docs pages does nothing. The Pagefind
search is only accessible when already on the documentation pages.

Pressing Cmd+K on any non-docs page redirects to the docs and
automatically opens the search modal with focus on the input field.


https://www.loom.com/share/72fcee74620640cab28639e9ad33d962


Closes DOC-314

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-04 14:57:23 -05:00
Jason Jean 0f24bf559d chore(repo): update ocean repo to use pnpm (#33707)
## Current Behavior

The `tools/update-repos/config/repos.json` configuration has the ocean
repository set to use `npm` as its package manager.

## Expected Behavior

The ocean repository should be configured to use `pnpm` as its package
manager, reflecting the actual package manager used by the repository.

## Related Issue(s)

N/A - Configuration update to reflect actual repository state.
2025-12-04 14:30:18 -05:00
Jack Hsu aba0eb280d fix(core): cnw sends correct selectedRepositoryName; prints instructions when user Ctrl+C (#33699)
This PR adds `SIGINT` handling when user kills the process via `Ctrl+C`
during CNW. This only prints when the workspace setup is complete, and
we also print the Cloud onboarding URL if it has been set up.

Also fixes an issue where `selectedRepositoryName` is never sent during
CNW.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-04 14:27:49 -05:00
Benjamin Cabanes ba2c982ae8 docs(nx-dev): add redirect for Self-Healing CI feature (#33708)
Add self-healing redirect.
2025-12-04 14:23:54 -05:00
MaxKless d2e85ba720 feat(gradle): add targetNamePrefix option to mark all gradle targets (#33685)
## Current Behavior
you can mark some targets generated by gradle by specifying options.

## Expected Behavior
you can apply a prefix to all targets generated by gradle. This is
useful for targetDefaults, for example.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Adds a Gradle option to prefix all generated Nx target names
(including dependencies and CI targets) with tests to avoid
double-prefixing.
> 
> - **Gradle project graph**:
> - Apply optional `targetNamePrefix` to all target names and dependency
rewrites in `createNodeForProject`, `processTargetsForProject`, and
`getDependsOnForTask`.
> - Wire prefix through plugin/task: read in
`NxProjectGraphReportPlugin`, expose on `NxProjectReportTask`, and pass
to processing functions.
> - Ensure CI targets (`ciTestTargetName`, `check-ci`, `build-ci`) are
correctly prefixed and not double-prefixed; update dependency
replacement logic accordingly.
>   - Add logging for prefix usage.
> - **Plugin options (TS)**:
> - Extend `GradlePluginOptions` with `targetNamePrefix` in
`packages/gradle/src/plugin/utils/gradle-plugin-options.ts`.
> - **E2E tests**:
> - Add tests validating prefixed targets exist and run, and that CI
test targets are not double-prefixed in `e2e/gradle/src/gradle.test.ts`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9a5160b8855a32d6c13c33c97379e7aa143a0737. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
2025-12-04 13:57:41 -05:00
Philip Fulcher c5e9489f2f docs(nx-dev): add nx vs diy article (#33704) 2025-12-04 16:11:45 +00:00
Caleb Ukle 1a877efc98 docs(nx-cloud): update guide for ci resource usage (#33697) (#33701) 2025-12-04 08:13:06 -05:00
Berend de Boer 8352d40df5 fix(core): optimize bun lockfile parser (#33623)
Key optimisations:

1. Pre-computed PackageIndex - Built once during lockfile parsing:
   - byName: Map from package name → array of versions (O(1) lookup)
   - workspaceNames: Set of workspace package names (O(1) lookup)
   - workspacePaths: Set of workspace paths (O(1) lookup)
- packagesWithWorkspaceVariants: Set of packages with workspace-specific
variants (O(1) lookup)
   - patchedPackages: Set of patched package names (O(1) lookup)
2. findResolvedVersion: Changed from O(n) scan through all packages to
O(1) map lookup + O(k) where k = number of versions for that package
(typically 1-3)
3. isWorkspacePackage: Changed from O(n) scan to O(1) set lookup
4. hasWorkspaceSpecificVariant: Changed from O(n) scan to O(1) set
lookup
5. isNestedPackageKey: Now uses pre-computed workspace paths/names sets
instead of computing them each call

On my 40 project typescript monorepo my time goes from about 30 seconds
to 4.5s, a speed-up of 6-7x.

---------

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2025-12-04 11:52:22 +01:00
Caleb Ukle 77692feae4 docs(nx-cloud): add guide for ci resource usage (#33697)
add info about how to use the Nx 22.1+ task metric gathering w/ Nx Cloud


https://deploy-preview-33697--nx-docs.netlify.app/docs/guides/nx-cloud/task-resource-usage

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: barbados-clemens <barbados-clemens@users.noreply.github.com>
2025-12-03 14:35:58 -06:00
Copilot 3ca68887de docs(nx-cloud): standardize terminology to "Access token" (#33334)
## Current Behavior

The Bitbucket integration documentation uses inconsistent terminology:
"App Password" for Bitbucket Cloud and "HTTP Access Tokens" for
Bitbucket Data Center.

## Expected Behavior

Documentation should use consistent "Access token" terminology across
both Bitbucket Cloud and Data Center sections.

## Changes

- Updated section headers to use "Acces token" terminology
- Replaced all instances of "app password" with "API token"
- Fixed plural "HTTP Access Tokens" → "HTTP Access Token"
- Updated image alt text for consistency
- Updated aside note title: "User linked access tokens" → "User linked
API tokens"

## Related Issue(s)

Fixes
https://linear.app/nxdev/issue/DOC-322/update-bitbucket-docs-to-use-api-tokens-terminology

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `staging.nx.app`
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/nrwl/nx/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT CODING AGENT SUFFIX -->



<details>

<summary>Original prompt</summary>

> Issue Title: Update Bitbucket docs to use API tokens terminology
> Issue Description: Update the Nx Cloud Bitbucket source control
integration docs to reference API tokens instead of App Passwords.
Update the language on the docs page accordingly:
[bitbucket.mdoc](https://github.com/nrwl/nx/blob/master/astro-docs/src/content/docs/guides/Nx%20Cloud/Source%20Control%20Integration/bitbucket.mdoc)
> Fixes
https://linear.app/nxdev/issue/DOC-322/update-bitbucket-docs-to-use-api-tokens-terminology
> 
> 
> Comment by User 439b15a6-827b-4258-971a-d86133ad59de:
> [https://github.com/nrwl/nx](https://github.com/nrwl/nx)
> 
> Comment by User d484ef82-7f7d-4a95-be09-9d82ca3905dc:
> 📋 I wasn't able to determine which GitHub repository to work in.
> 
> I think it's one of these, but can you tell me which one is right?
> 
> Comment by User d484ef82-7f7d-4a95-be09-9d82ca3905dc:
> Waiting for https://linear.app/nxdev/profiles/caleb to link their
GitHub account. [Click to authorize
→](https://linear.business.githubcopilot.com/linear/auth)
> 
> Comment by User :
> Created issue
[DOC-322](https://linear.app/nxdev/issue/DOC-322/update-bitbucket-docs-to-use-api-tokens-terminology)
> 
> Comment by User 439b15a6-827b-4258-971a-d86133ad59de:
> This comment thread is synced to a corresponding [thread in
Slack](https://nrwl.slack.com/archives/C04ML056D99/p1762090527735769?thread_ts=1762090527.735769&cid=C04ML056D99).
All replies are displayed in both locations.
> 
> Comment by User :
> This thread is for an agent session with githubcopilot.
> 
> Comment by User 439b15a6-827b-4258-971a-d86133ad59de:
> @Linear make a docs issue to update the language for the bitbucket
source control integration to talk about api tokens instead of app
passwords.
> Assign it to copilot. 
> Here is the docs page in question 
>
[https://github.com/nrwl/nx/blob/master/astro-docs/src/content/docs/guides/Nx%20Cloud/Source%20Control%20Integration/bitbucket.mdoc](https://github.com/nrwl/nx/blob/master/astro-docs/src/content/docs/guides/Nx%20Cloud/Source%20Control%20Integration/bitbucket.mdoc)
> 
> 


</details>



<!-- START COPILOT CODING AGENT TIPS -->
---

 Let Copilot coding agent [set things up for
you](https://github.com/nrwl/nx/issues/new?title=+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Caleb Ukle <caleb@nrwl.io>
2025-12-03 20:29:17 +00:00
Jack Hsu 2e442d56b4 feat(core): add template support to create-nx-workspace (#33468)
This PR simplifies the CNW process so we only prompt for a starter (TS,
NPM Packages, React, Angular) and we clone a full example to showcase Nx
monorepo for the given starter. This speeds up CNW drastically and
allows users to get the workspace in 5-10 seconds vs 1-3 minutes.

Users can choose `Custom` to fall back to the previous prompts, which
will ask framework, unit test runner, e2e runner, etc.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-03 13:12:55 -05:00
Colum Ferry 7792d80258 fix(core): sanitize project names for valid git tag names in nx release (#33692)
Gradle multi-module projects have project names with colons (e.g.,
`:common:iam-client`)
which are invalid in git tag names. This adds a
`sanitizeProjectNameForGitTag()` function
that replaces colons with slashes and other invalid git ref characters
with hyphens.

The sanitization is applied when:
- Creating git tags in `createGitTagValues()`
- Creating the `ReleaseVersion` class gitTag property
- Matching existing tags in `getLatestGitTagForPattern()`

Fixes #33262
2025-12-03 16:32:18 +00:00
Colum Ferry e6eed35426 feat(expo): support Expo 54 (#33612)
## Current Behavior
We only support Expo 53

## Expected Behavior
Add support for Expo 54
Allow existing workspaces wishing to remain on Expo 53 to continue to be
supported
Add migrations allowing LLMs to handle migrating from Expo 53 to Expo 54


## Related Issue(s)

Closes NXC-3526

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Coly010 <Coly010@users.noreply.github.com>
2025-12-03 10:37:24 -05:00
Colum Ferry 5895c9acf6 fix(angular-rspack): ensure rebuild logs are only printed once (#33694)
## Current Behavior
Rebuild logs during serve of Angular Rspack applications are logged an
exponential number of times with each change.

## Expected Behavior
Log only once
2025-12-03 15:26:48 +00:00
Colum Ferry 2ee5d69ca3 fix(react): update @emotion/styled to latest version #31252 (#33690)
## Current Behavior
We currently install an outdated version of `@emotion/styled` that
causes Typecheck issues.

## Expected Behavior
Use latest version of Emotion

## Related Issue(s)

Fixes #31252
2025-12-03 13:48:57 +00:00
Colum Ferry b740baf57a fix(angular-rspack): use CJS when serving applications for HMR #33106 (#33693)
## Current Behavior
Angular Rspack outputs ESM for build and serve. However, with serve, it
causes issue for HMR.

## Expected Behavior
Use CJS for serve to allow HMR to work correctly

## Related Issue(s)

Fixes #33106
2025-12-03 13:31:22 +00:00
Jack Hsu b314dd187b chore(testing): add jest migration example (#33687)
This  adds the missing example for the new `jest.config.cts` migration.
2025-12-02 18:29:21 -05:00
Colum Ferry 30acb10c89 feat(vitest): make initial generation for JS projects more lightweight (#33670)
## Expected Behavior
Generate only `vitest.config.mts` file when not bundling with Vite
Use `vite.config` file if it exists already
Add `testMode` option to the `@nx/vitest` Inference Plugin to allow
easier switching between `vitest` and `vitest run`.

## Related Issue(s)

Fixes NXC-3334
2025-12-02 16:29:13 +00:00
MaxKless adc6d0757e fix(core): stop adding outdated vscode/cursor rule files to gitignore (#33680)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Removes legacy additions of `.cursor/rules/nx-rules.mdc` and
`.github/instructions/nx.instructions.md` to `.gitignore` across code,
templates, and migrations.
> 
> - **.gitignore behavior**:
> - Remove logic in
`packages/nx/src/command-line/init/implementation/utils.ts` that
appended `.cursor/rules/nx-rules.mdc` and
`.github/instructions/nx.instructions.md`.
>   - Clean up root `.gitignore` to exclude those entries.
> - Update new workspace templates
(`packages/workspace/.../__dot__gitignore`) to omit those entries.
> - **Migrations**:
> - Remove migration `21-1-0-add-ignore-entries-for-nx-rule-files` from
`packages/nx/migrations.json` and delete its implementation and spec.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7863fa5beee127777f819a5155ae17239c5b16cd. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
2025-12-02 11:18:46 -05:00
Colum Ferry 804d4c2e0c feat(vitest): update @analogjs/vitest-angular to 2.1.2 #33602 (#33681)
## Current Behavior
Trying to create a new workspace is failing on npm peer dep conflicts
when trying to use Vitest with Angular.
The version of `@analogjs/vitest-angular` only supports Vitest <4.

## Expected Behavior
Update to latest version of `@analogjs/vitest-angular` to support Vitest
4

## Related Issue(s)

Fixes #33602
2025-12-02 15:45:21 +00:00
Colum Ferry 5f8540488b fix(bundling): set buildLibsFromSource in normalize options for Rollup (#33679)
## Current Behavior
`buildLibsFromSource` defaults to true only in the `@nx/rollup:rollup`
executor.
In the normalize options helper for the executor, it is not handled at
all. Programmatic usage would therefore result in `undefined`.

For pure Inference Plugin usage, `buildLibsFromSource` is also not
handled in normalize options.
Therefore, it always defaults to `undefined`.

## Expected Behavior
To reduce breaking changes, force `buildLibsFromSource` to be false for
Inference Plugin usage.
Explicitly set it in executor's normalize options helper to true to
match the schema default.

## Related Issue(s)

Fixes NXC-3537
2025-12-02 14:03:52 +00:00
Jonathan Gelin 4923c15e7e fix(release): interpolate releaseGroupName in getLatestGitTagForPattern (#33674)
# Fix: Pass releaseGroupName to getLatestGitTagForPattern for proper tag
resolution

## Problem

When using `releaseTag.pattern: "{releaseGroupName}@{version}"`, Nx
fails to resolve versions from git tags because the `{releaseGroupName}`
placeholder is not interpolated.

For example, with git tag `my-group@2.9.0`:
- **Expected**: Extract version `2.9.0`
- **Actual**: Extracts `"my-group"` → Error: `Invalid semver version
'my-group' provided`

## Root Cause

In `release-graph.ts:627-631`, only `projectName` is passed to
`getLatestGitTagForPattern()`, missing `releaseGroupName` needed for
interpolation.

## Solution

Pass `releaseGroupName` to the interpolation data (1-line change at
`release-graph.ts:631`):

```typescript
latestMatchingGitTag = await getLatestGitTagForPattern(
  releaseTagPattern,
  {
    projectName: projectGraphNode.name,
    releaseGroupName: releaseGroupNode.group.name, //  Added
  },
  { ... }
);
```

## Backward Compatibility

 Fully backward compatible:
- `releaseGroupNode.group.name` is always defined (user-defined or
`"__default__"`)
- Unused interpolation data is safely ignored
- Existing patterns (`v{version}`, `{projectName}@{version}`) continue
to work

## Tests

Added test case in `git.spec.ts` for `{releaseGroupName}@{version}`
pattern that verifies correct tag matching and version extraction.

## Files Changed

- `packages/nx/src/command-line/release/utils/release-graph.ts` (1 line)
- `packages/nx/src/command-line/release/utils/git.spec.ts` (1 test case)

Co-authored-by: James Henry <james@henry.sc>
2025-12-02 10:23:26 +00:00
Jonathan Gelin 8207c94617 feat(docker): auto-select version scheme when only one is available (#33671) 2025-12-02 11:27:40 +04:00
Jonathan Gelin a4c13212ab fix(docker): fix releasing non docker projects (#33667) 2025-12-02 11:26:11 +04:00
Jason Jean 02c01e5daf fix(repo): enable wayland-data-control feature for arboard (#33675)
## Current Behavior

The arboard crate is used without the `wayland-data-control` feature,
which means clipboard operations may not work properly on Wayland-based
Linux systems.

## Expected Behavior

With the `wayland-data-control` feature enabled, arboard can interact
with the clipboard on Wayland systems using the wlr-data-control
protocol.

## Related Issue(s)

N/A - Enhancement for better Wayland support
2025-12-01 21:57:22 -05:00
Jason Jean a5015d3992 chore(repo): update nx to 22.2.0-beta.2 (#33676)
Updating Nx from 22.2.0-beta.1 to 22.2.0-beta.2
2025-12-01 21:57:06 -05:00
Jason Jean c888ac72c6 fix(maven): remove incorrect threadSafe to parallelism mapping (#33678)
## Current Behavior

The Maven plugin incorrectly maps Maven's `isThreadSafe` mojo property
to Nx's `parallelism` target property. Maven's `isThreadSafe` indicates
whether a mojo can safely run in parallel with other mojos of the same
type within the same Maven build (multi-threaded Maven builds).

## Expected Behavior

Nx's `parallelism` controls whether the target can run in parallel
alongside anything else - a fundamentally different concept. All Maven
targets now default to `parallelism: true`, letting Nx handle
parallelism based on its own task graph analysis rather than using
Maven's unrelated thread-safety concept.

## Related Issue(s)

N/A - Internal cleanup based on code review feedback.
2025-12-01 16:58:24 -05:00
Jack Hsu 731aba377a fix(testing): remove --no-experimental-strip-types flag from @nx/jest/plugin + migrate to jest.config.cts if needed (#33657)
## Current Behavior
On Node.js v24+, the `@nx/jest/plugin` sets
`--no-experimental-strip-types` in NODE_OPTIONS which causes an error:
"node: --no-experimental-strip-types is not allowed in NODE_OPTIONS".

Additionally, `jest.config.ts` files using ESM syntax (`export default`,
`import`) fail to load correctly under Node.js type-stripping when the
project is configured for CommonJS.

## Expected Behavior
- Remove the NODE_OPTIONS manipulation that adds
`--no-experimental-strip-types`
- Add a migration (22.2.0-beta.2) that converts `jest.config.ts` files
from ESM to CJS syntax for projects using `@nx/jest/plugin`
- The migration only runs when `@nx/jest/plugin` is registered in
`nx.json`
- Projects with `type: module` are warned as they're incompatible with
the plugin
- Files using ESM-only features (import.meta, top-level await) are
skipped with a warning for manual conversion

## Demo

https://www.loom.com/share/8a157a0b01d144ae8d6ae48b9b0cd0e4


## Related Issue(s)
Closes NXC-3541

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-01 09:43:26 -05:00
Colum Ferry 8ff2768aaa feat(vite): add migration to add @nx/vitest (#33669)
## Current Behavior
We don't have a migration to migrate users to use the new @nx/vitest
package if they're currently using @nx/vite
Given that we have Vitest-related operations marked as deprecated when
used via @nx/vite, we should have a migration.

## Expected Behavior
Add a migration that:
1. Installs @nx/vitest
2. Switches @nx/vite:test executor usage to use @nx/vitest:test executor
usage
3. Splits `@nx/vite/plugin` in nx.json that sets up vitest test targets
to use `@nx/vitest` instead
2025-12-01 13:37:24 +00:00
Colum Ferry 637daf5343 fix(vite): vitest executor to return the async iterable #33588 (#33668)
## Current Behavior
The `@nx/vite:test` executor is not returning the async iterable. This
causes a destructuring issue.

## Expected Behavior
Ensure the `@nx/vite:test` executor returns the async iterable.

## Related Issue(s)

Fixes #33588
2025-12-01 10:33:58 +00:00
Jason Jean 6df1d8891a chore(repo): update nx to 22.2.0-beta.1 (#33650)
Updating Nx from 22.2.0-beta.0 to 22.2.0-beta.1

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-11-28 16:53:05 -05:00
Jack Hsu ba5b78e910 chore(repo): disable docker from macos nightlies since it does not work without vm-in-vm (#33659)
Disable but add a comment that we could enable it on macos intel if we
need to. For now it's covered by linux.
2025-11-28 15:06:27 -05:00
Jack Hsu f8f05b4086 fix(linter): update generators to use ESLint v9 compatible versions (#33633)
This PR updates the `workspace-rule` generator so use ESLint v9 by
default. It currently forces the unsupported ESLint v8.

In theory this is only useful if not using workspaces and you need
tsconfig paths to be mapped and resolved correctly. For workspaces, you
can easily just generate any library to be used to contain custom rules.

Closes NXC-3500

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-11-28 11:00:11 -05:00
Jack Hsu 7ff4f19529 docs(misc): update blog post links to new enterprise paths (#33654)
## Current Behavior
Blog posts contain broken links pointing to old `/powerpack` and
`/docs/enterprise/powerpack/*` paths that no longer exist.

## Expected Behavior
Links should point to the new enterprise documentation paths:
- `/powerpack` → `/enterprise`
- `/docs/enterprise/powerpack/*` → `/docs/enterprise/*`
- `/docs/reference/powerpack/*` → `/docs/reference/*`

## Related Issue(s)
Closes DOC-354

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-28 10:43:33 -05:00
James Henry f161603d37 fix(core): nx-schema default value for preserveMatchingDependencyRanges should have changed in v22 (#33587)
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
2025-11-28 15:42:18 +00:00
Jason Jean 191e492c05 fix(core): ensure perf logs are flushed before exit in graph command (#33621)
## Current Behavior

When running `NX_PERF_LOGGING=true nx graph --file graph.json`, many
performance logs are missing (e.g., `create-project-graph-async`,
`retrieve-project-configurations`).
  Only plugin-specific logs like `createDependencies` appear.

  ## Expected Behavior

All performance timing logs should appear, matching the output of
`NX_PERF_LOGGING=true nx show projects`.

  ## Related Issue(s)

  N/A - Internal improvement for debugging/profiling.

  ## Solution

The `graph.ts` file had `process.exit(0)` calls that terminated the
process immediately, not giving the async `PerformanceObserver` callback
time to fire.

Added `await new Promise((res) => setImmediate(res))` before
`process.exit(0)` to give the event loop one tick to process pending
callbacks. This follows the existing
  pattern in `show/projects.ts` and `show/project.ts`.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-11-28 15:28:08 +00:00
Jason Jean 9ffe2fd715 fix(core): prevent Nx Console prompt from blocking non-interactive commands (#33646)
## Current Behavior

The Nx Console installation prompt blocks commands when run in
non-interactive contexts such as:
- CI environments
- AI agents
- Piped commands

The prompt only checked `process.stdout.isTTY` but not
`process.stdin.isTTY`, causing it to wait indefinitely for input that
would never arrive.

## Expected Behavior

Commands should complete without prompting when run in non-interactive
environments.

## Related Issue(s)

Fixes #33552

## Solution

Updated the check to verify:
1. Both `stdin` and `stdout` are TTY (truly interactive terminal)
2. Not running in a CI environment (using existing `isCI()` utility)

This ensures the prompt only appears when the user can actually provide
input.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-11-28 09:53:46 -05:00
Jason Jean 3ca0e475ab fix(core): suppress git stderr output in parseGitOutput (#33645)
## Current Behavior

Since Nx 21.6.1, running `nx graph` or other commands that calculate
affected projects prints git errors to stderr when the default branch is
not fetched:

```
fatal: ambiguous argument 'main': unknown revision or path not in the working tree.
```

This causes CI pipelines with strict stderr checking to fail, even
though the nx commands succeed.

## Expected Behavior

Git error messages should not be printed to stderr. The errors are
already caught and handled gracefully - they just shouldn't be visible
to the user.

## Related Issue(s)

Fixes #33330

## Solution

Added `stdio: 'pipe'` to the `execSync` call in `parseGitOutput()`. This
suppresses stderr output while still allowing the command to throw on
failure (which is already caught by the try-catch in `graph.ts`).

This matches the pattern used in `getMergeBase()` which already uses
`stdio: 'pipe'`.
2025-11-28 14:52:46 +00:00
Jason Jean 2c1bfa30b1 fix(core): include create-nx-workspace in migration package group (#33643)
## Current Behavior

When running `nx migrate latest`, the `create-nx-workspace` package is
not updated along with other Nx packages, even though it's a core part
of the Nx ecosystem that users may have as a dependency (especially when
extending the install package pattern).

## Expected Behavior

The `create-nx-workspace` package should be updated to the same version
as `nx` and other `@nx/*` packages when running migrations.

## Related Issue(s)

Fixes #33585

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-11-28 14:46:13 +00:00
Jason Jean 2cfb746272 fix(nuxt): update preset test for v4 app directory structure (#33648)
## Current Behavior

The nuxt preset test was checking for `apps/${name}/src/app.vue`, but
since the generator now defaults to Nuxt v4 which uses the app directory
structure, this file is no longer created at that path.

## Expected Behavior

Tests should pass on master.

## Solution

Updated the test to check for `apps/${name}/app/app.vue` which is the
correct path for Nuxt v4's app directory structure.
2025-11-28 12:19:04 +04:00
Jack Hsu 363457c2a8 fix(nuxt): do not import base eslint config for root project (#33642)
If you generate a standalone/root project then there's no
`eslint.config.mjs` to import from base.

<img width="1269" height="355" alt="image"
src="https://github.com/user-attachments/assets/b9658f08-48ff-48e7-bab8-fcd7ff5c349a"
/>
2025-11-27 14:52:19 -05:00
Jack Hsu 49fc6d54ff chore(misc): fix e2e tests for CNW + Nuxt 2025-11-27 14:01:20 -05:00
Caleb Ukle 5071217c30 docs(nx-dev): powerpack docs cleanup/deprecations (#33635)
closes: DOC-338

---------

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
2025-11-27 12:10:47 -05:00
Leosvel Pérez Espinosa 21783402b7 fix(core): kill child process tree in different running tasks (#33636)
## Current Behavior

When Nx commands finish or receive termination signals (SIGINT, SIGTERM,
SIGHUP), child processes spawned by continuous tasks (such as `nx
serve`) can remain orphaned in certain scenarios. This happens because
only the direct child process is killed using `childProcess.kill()`,
leaving grandchild processes running.

## Expected Behavior

When Nx terminates, all processes in the spawned process tree should be
properly terminated and no orphaned processes should remain.

## Related Issue(s)

Fixes #32438
Fixes #33460 

## Changes

- Updated signal handlers in `RunningNodeProcess` to use `this.kill()`
instead of `this.childProcess.kill()`, leveraging the existing
`tree-kill` implementation
- Added `tree-kill` to `NodeChildProcessWithNonDirectOutput` and
`NodeChildProcessWithDirectOutput` kill methods to ensure entire process
trees are terminated
2025-11-27 11:53:47 -05:00
Jack Hsu c08e83c73d chore(repo): remove hack that enables legacy peer deps so we can catch errors (#33634)
We missed a peer dep error in the Nuxt 4 PR since CI allowed install to
go through, but in a real repo it would have failed.

We _may_ need to still have the `prefer-frozen-lockfile=false` option,
but let's let CI run with this first.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-11-27 09:57:55 -05:00
Benjamin Cabanes 9fecf1416a docs(nx-dev): rename "Nx Enterprise" to "Enterprise" (#33641)
Rename "Nx Enterprise" to "Enterprise" across UI Header components.
2025-11-27 09:54:19 -05:00
Colum Ferry a0581d717f feat(nuxt): support nuxt v4 (#33611)
## Current Behavior
We currently do not support Nuxt 4. We still generate Nuxt 3.

## Expected Behavior
Support Nuxt 4.
New workspaces will get Nuxt 4.
Existing Workspaces that use Nuxt 3 intentionally will continue to use
Nuxt 3.
Add a migration to update users to Nuxt 4
Handle ESLint flat config

## Related Issue(s)

Closes NXC-3525
Closes NXC-3497

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Coly010 <Coly010@users.noreply.github.com>
2025-11-27 09:17:29 -05:00
Colum Ferry f87e20fe75 fix(linter): base eslint config should ignore out-tsc directories (#33639)
## Current Behavior
The base `eslint` config will ignore `**/dist` but not `**/out-tsc`.
This can cause issues if lint is run after a `typecheck` which has
placed `.d.ts` files into an `out-tsc` directory.

## Expected Behavior
Base eslint config should ignore `**/out-tsc`

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Coly010 <Coly010@users.noreply.github.com>
2025-11-27 13:50:15 +00:00
Colum Ferry 25b8550adc feat(storybook): support storybook 10.1 (#33637)
## Current Behavior
Storybook support is not explicitly set to 10.1 which has just been
released.

## Expected Behavior
Explicitly set storybook version to 10.1 to ensure support for Angular
21

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Coly010 <Coly010@users.noreply.github.com>
2025-11-27 13:13:26 +00:00
Jack Hsu 3558a4cdfe docs(testing): update atomizer documentation for Vite and Vitest plugins (#33620)
## Current Behavior

The atomizer/task splitting documentation for Vite and Vitest was
incomplete:
- The @nx/vite/plugin introduction page was missing the dual
configuration example for both E2E and unit tests
- The @nx/vitest introduction page was missing all atomizer-related
sections (splitting E2E tests, ciTargetName, ciGroupName)
- The split-e2e-tasks feature page only referenced @nx/vite for Vitest,
not the dedicated @nx/vitest plugin
- The @nx/vitest docs had incorrect option name (targetName instead of
testTargetName)

## Expected Behavior

- @nx/vitest introduction page now have complete atomizer documentation
- The split-e2e-tasks page now references both @nx/vitest and @nx/vite
options for Vitest users
- Configuration examples use the correct option names matching the
actual plugin interfaces
- Users can easily find how to configure task splitting for Vitest
whether they use @nx/vite or @nx/vitest
---

Affected pages:
-
https://deploy-preview-33620--nx-docs.netlify.app/docs/features/ci-features/split-e2e-tasks#update-an-existing-project-to-use-automated-task-splitting
-
https://deploy-preview-33620--nx-docs.netlify.app/docs/technologies/build-tools/vite/introduction
-
https://deploy-preview-33620--nx-docs.netlify.app/docs/technologies/test-tools/vitest/introduction

Closes DOC-346

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-26 09:49:56 -05:00
Jack Hsu e3a4233cfe chore(repo): add Node 24 to e2e nightly matrix (#33542)
- E2E nightly tests only run on Node 20 and 22.
- E2E nightly tests now also run on Node 24, 22, and 20 for linux. For
Windows and Mac run only 24.

Did a test run from this branch, and Node 24 passes where other versions
pass, and fails where other versions fail. It shouldn't make any golden
tests fail just due to Node 24, but it's possible that things will flake
more since the matrix has expanded. We just have to make them more
robust.

<img width="920" height="1089" alt="image"
src="https://github.com/user-attachments/assets/90ee4d04-68d5-4d0d-9729-60cacfbc99db"
/>


Close NXC-3491
2025-11-26 09:43:08 -05:00
Colum Ferry 1ecbd8082c fix(nextjs): make migration to next 16 optional (#33627)
## Current Behavior
The Next 16 AI Migration Instructions are always created, regardless of
existing Next version

## Expected Behavior
Make the Next 16 Migration optional

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Coly010 <Coly010@users.noreply.github.com>
2025-11-26 14:22:46 +00:00
Jack Hsu b6958b3e88 docs(linter): add custom workspace eslint rules guide (#33618)
There is no documentation on how to create and use custom ESLint rules
in Nx workspaces.

Users can follow a guide to create custom ESLint rules using either:
1. Package Manager Workspaces (npm/yarn/pnpm/bun) - create a dedicated
ESLint plugin package that's symlinked via the package manager
2. `loadWorkspaceRules` utility from `@nx/eslint-plugin` - load rules
from any directory with automatic TypeScript transpilation

The guide includes:
- Comparison table for choosing the right approach
- Step-by-step instructions for both approaches
- TypeScript execution options (build first, Node.js native support,
tsx)
- Rule testing with `@typescript-eslint/rule-tester`
- Best practices and troubleshooting tips

Page:
https://deploy-preview-33618--nx-docs.netlify.app/docs/technologies/eslint/guides/custom-workspace-rules

Closes DOC-339

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-11-26 09:20:25 -05:00
Colum Ferry 00e4c0c69a feat(vite): add vitest 4 migration for users using @nx/vite (#33630)
## Current Behavior
Despite @nx/vite depending on @nx/vitest it only does so in the same
version that introduces the migration for Vitest 4.
This means the user does not get any migrations for Vitest 4

## Expected Behavior
Add the Vitest 4 migrations to the @nx/vite package to allow users to
migrate.
2025-11-26 14:05:19 +00:00
Jack Hsu 017ad93d35 fix(bundling): replace rollup-plugin-copy with nx copy assets plugin (#33601)
There's a problem when `@nx/rollup` is installed with yarn@1.22, and
typechecks.

This is caused by the transitive dependency chain:

```
rollup-plugin-copy@3.5.0 -> globby@10.0.1 -> @types/glob@7.2.0 -> @types/minimatch
```

When users run tsc without explicit `types` configuration, TypeScript
auto-discovers `@types/minimatch` from `node_modules` but can't properly
resolve it.

Note: This doesn't happen with NPM and PNPM, nor newer yarn versions.

Verified fix with this repro: https://github.com/jaysoo/rollup-251124

Fixes #32398

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2025-11-26 08:55:46 -05:00
Philip Fulcher 081bec53cf docs(nx-dev): add 22.1 article and changlog (#33617)
https://nx-dev-git-philip-nx22-1-article-nrwl.vercel.app/blog/nx-22-1-release
2025-11-25 18:42:57 -05:00
Jack Hsu 67059ccf10 docs(storybook): update Storybook docs for version 10 (#33619)
## Current Behavior
- Storybook generator docs banner says "Nx uses Storybook 7"
- Separate storybook-9-setup.mdoc page exists
- No documentation for migrate-10 generator

## Expected Behavior
- Update banner to "Nx uses Storybook 10"
- Consolidate storybook-9-setup into upgrading-storybook guide
- Add migrate-10-generator-examples.md with AI-assisted migration docs
- Update all references to point to new consolidated guide

---

Main content is here:
https://deploy-preview-33619--nx-docs.netlify.app/docs/technologies/test-tools/storybook/guides/upgrading-storybook

Need to follow-up on the sidebar ordering as it doesn't seem to take it
into account for technologies section.

Fixes DOC-347
2025-11-25 18:42:05 -05:00
Colum Ferry 098d3ed9c9 fix(storybook): remove upper bound of migration requires (#33613)
## Current Behavior
The upper bound of the requires is too restrictive and causing issues

## Expected Behavior
Remove the upper bound
2025-11-25 18:41:10 -05:00
Jason Jean 9eb254c964 chore(repo): update nx to 22.2.0-beta.0 (#33614)
Updating Nx from 22.1.0-rc.5 to 22.2.0-beta.0

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-11-25 17:11:12 -05:00
Leosvel Pérez Espinosa 7e00ec431f fix(core): propagate continuous task failures to dependent tasks (#33492)
## Current Behavior

When a continuous task depends on another continuous task and the
dependent task exits with an error, the parent task continues running
indefinitely. The task execution never terminates, leaving processes
running in the background.

For example, if task `a` (continuous) depends on task `b` (continuous),
and task `b` exits with error code 1, task `a` will continue running
even though its dependency failed.

## Expected Behavior

When a continuous task exits (with any exit code), the failure should be
propagated to dependent tasks:

1. The failed continuous task should be marked as failed
2. Dependent continuous tasks should be marked as skipped
3. All affected continuous tasks should be killed
4. Task execution should terminate with an error

---

## Changes Made

### 1. Restore Error Handling in Continuous Task Exit Handlers

- Re-added the `cleaningUp` flag that was removed in a previous
TUI-related commit
- Modified `onExit` handlers for both regular and shared continuous
tasks to:
  - Check if the task exited during normal cleanup vs. unexpectedly
  - Call `complete()` with 'failure' status for unexpected exits
  - Log error messages for debugging

### 2. Fix `cleanUpUnneededContinuousTasks()` Logic

The previous implementation always added `initializingTaskIds` to the
needed set, even when those tasks were already completed. This prevented
dependency tasks from being killed when the top-level task exited.

Fixed by:

- Only adding tasks from `initializingTaskIds` if they are still
incomplete
- Keeping dependencies of incomplete tasks alive
- This ensures continuous tasks are killed when no longer needed,
whether a dependency fails or a top-level task exits

### 3. Prevent Status Overwrites

Added a check in `onExit` handlers to only set status to `Stopped` if
the task hasn't already been completed. This prevents the async `onExit`
callback from overwriting the correct status (like 'skipped' or
'failure') with 'Stopped'.

### 4. Fix Signal Handling in `PseudoTtyProcess.kill()`

The Rust pseudo-terminal defaults to SIGINT when no signal is provided,
which does not reliably terminate child processes in PTY sessions.

Fixed by:

- Defaulting to SIGTERM in the JavaScript wrapper (rather than changing
the Rust default)
- The JS wrapper is the API boundary that should match Node.js
semantics, where `childProcess.kill(undefined)` defaults to SIGTERM
- The Rust default of SIGINT is appropriate for interactive use
(Ctrl-C), while programmatic cleanup needs SIGTERM
- This ensures child processes are properly killed when
`runningTask.kill()` is called

**File:** `packages/nx/src/tasks-runner/pseudo-terminal.ts`

## Technical Details

The fix leverages the existing task failure propagation mechanism in
`complete()` instead of using `process.exit(1)`, which:

- Allows proper cleanup through normal execution flow
- Respects the `--bail` flag configuration
- Works correctly with both TUI and non-TUI modes
- Maintains consistency with how other task failures are handled
2025-11-25 09:49:11 -05:00
MaxKless 80322f921f fix(core): use nx-mcp for older nx versions instead of nx mcp (#33553)
<!-- 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
Older versions don't support the `nx mcp` command yet - but they CAN use
the `nx-mcp` package via npx

## Expected Behavior
We generatee the proper command into their MCP config by matching on
their version

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

Fixes #
2025-11-25 09:47:20 -05:00
Jason Jean 71470480bb feat(core): add multiple Nx version detection to nx report (#33599)
## Current Behavior

When multiple versions of the `nx` package are installed in a workspace
(e.g., due to a third-party package incorrectly depending on nx), users
have no visibility into
  this issue through `nx report`.

  ## Expected Behavior

The `nx report` command now detects when other packages depend on a
different version of nx than the workspace version and reports this
clearly:

  ⚠️ Multiple Nx versions detected

Your workspace uses nx@20.0.0, but other packages depend on a different
version:
  - some-package → @scope/tool → nx@19.0.0

These packages should not have nx as a dependency. Please report this
issue to the package maintainers.
  Run pnpm why nx@19.0.0 for more details.

This helps users identify and report problematic packages that bundle
their own version of nx.

  ## Related Issue(s)

N/A - This is a proactive improvement to help users diagnose workspace
issues.
2025-11-25 09:41:53 -05:00
MaxKless 7e51d85b1b cleanup(gradle): fix nightly e2e test where verbose was being called (#33610)
<!-- 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
nightly tests fail on gradle because of gradle parsing

## Expected Behavior
nightly tests should pass
2025-11-25 09:35:30 -05:00
Colum Ferry 1eea5edb50 feat(nextjs): add migration to add AI instructions for upgrading to Next 16 (#33608)
## Current Behavior
We do not generate AI Instructions to aid with upgrading from Next 15 to
Next 16

## Expected Behavior
Add a migration generator to create a file containing instructions for
an LLM to upgrade Next 15 to Next 16

## Related Issue(s)

Closes NXC-3418

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-11-25 13:33:03 +00:00
Colum Ferry cac7f6c3e8 fix(node): set generatePackageJson:false for TS Solution workspaces (#33606)
## Current Behavior
In TS Solution setups, we generate webpack config with
`generatePackageJson: true`. This is confusing and unneeded.
It should be set to false in TS Solution repos.

## Expected Behavior
Set `generatePackageJson: false` in webpack config for TS Solution
Setups


Closes NXC-3521
2025-11-25 08:13:22 -05:00
Kasper Christensen 3c5e40be68 fix(nest): set moduleResolution to node to prevent TS5095 error (#33607)
When generating NestJS applications in Angular workspaces, the base
tsconfig sets moduleResolution to 'bundler' which causes TS5095 errors
because 'bundler' requires module to be 'preserve' or 'es2015+'.

NestJS applications should use Node.js module resolution instead. This
fix sets moduleResolution to 'node' for NestJS applications (except when
using TS solution setup, which uses 'nodenext').

Fixes #33589
2025-11-25 12:23:25 +00:00
Colum Ferry 6c2b3ee37d fix(release): ensure emoji is not repeated in breaking changes summary (#33605)
## Current Behavior
The ⚠️ emoji at the beginning of bc commits is duplicated in the bc
section of the changelog.
This is unneeded.

## Expected Behavior
Ensure the ⚠️ is not repeated in the bc section of the changelog

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Coly010 <Coly010@users.noreply.github.com>
2025-11-25 11:14:48 +00:00
Chau Tran d70c888a93 fix(graph): surface task graph client error via error toast (#33600)
Close NXC-3516

<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2025-11-25 09:12:40 +01:00
Jason Jean f31bef701a fix(core): make daemon socket path unique per process to prevent race condition (#33580)
## Current Behavior

1. **Socket Race Condition**: All daemon servers listen on the same
socket path, causing a race condition where shutting down daemons remove
sockets that newly started
  daemons are listening on.

2. **Daemon Console Check Blocks**: The daemon availability check runs
synchronously and blocks the main thread.

3. **Version Mismatch Issues**: Packages using a different nx version
than what's installed in the workspace could still use the daemon,
leading to potential issues.

  ## Expected Behavior

1. Each daemon server creates a unique socket path based on its process
ID, preventing race conditions.

  2. The daemon console check runs in the background without blocking.

3. The daemon is disabled when there's a version mismatch between the
running nx and the workspace's installed version.

  ## Changes

  ### 1. Unique Daemon Socket Paths
- Include `process.pid` in the socket directory hash to make each
daemon's path unique
- Store the socket path in `server-process.json` so clients know where
to connect
  - Clients read the socket path from the file instead of calculating it

  ### 2. Backgroundable Daemon Check
- Reapplied #33491 which makes the Nx Console install check run on the
daemon in the background
- This was previously reverted due to the socket race condition (now
fixed by change 1.)
- Running in background also allows pulling the latest check logic from
npm

  ### 3. Version Mismatch Check
  - Added `isNxVersionMismatch()` check in `DaemonClient.enabled()`
- Created shared utility `is-nx-version-mismatch.ts` for version
comparison
  - Refactored server.ts to use the shared utility
- Uses `require.resolve('nx/package.json', { paths: [workspaceRoot] })`
to properly resolve the workspace's installed nx version

  ## Related Issue(s)

Fixes daemon socket path race condition and improves daemon reliability.
2025-11-24 23:45:28 +00:00
Philip Fulcher 12f42ca798 chore(nx-dev): remove november webinar (#33598) 2025-11-24 16:17:39 -05:00
Colum Ferry 70bbbe9ff6 fix(js): ensure copy-workspace-modules copies transitive workspace dependencies (#33570)
## Current Behavior
`copy-workspace-modules` executor only copies workspace dependencies 1
level deep.
If that workspace library depends on another workspace library, it is
not copied correctly.

## Expected Behavior
Copy transitive workspace modules

## Related Issue(s)

Fixes NXC-3466
2025-11-24 09:16:37 -05:00
Jack Hsu b7cfee16e2 fix(testing): remove declare global wrapper from cypress commands.ts template (#33573)
When adding Cypress to a library, the generated commands.ts causes
TS2669 error because declare global requires the file to be a module.
Changed to use declare namespace Cypress directly.

Fixes #32930
2025-11-24 08:35:51 -05:00
Juri 8fcef1e81a docs(misc): fix listing of oxlint community plugin 2025-11-24 10:46:48 +01:00
Laney Pouzet 5fd57badb9 fix(core): filter out automated release commits in getCommitsRelevantToProjects (#33482) 2025-11-23 16:19:51 +04:00
Jason Jean 626fb0873e Revert "feat(core): make console daemon check backgroundable and pull… (#33578)
## Current Behavior
PR #33491 introduced a daemon call into every command and caused
unexpected issues...

  ## Expected Behavior
the change is reverted while we investigate a proper fix

  ## Changes
This reverts commit 9471207767 from PR
#33491.

  ## Related Issue(s)
  Fixes #33472
2025-11-21 23:14:11 +00:00
Austin Fahsl 68eee382dc docs(nx-cloud): use GitHub's default ref in manual DTE workflow (#33575)
## Current Behavior

The manual DTE workflow explicitly sets the `ref` parameter to `${{
github.event.pull_request.head.sha }}` to checkout the actual branch
HEAD instead of the merge commit.

## Expected Behavior

Use GitHub's default ref behavior instead of explicitly overriding it,
as the default behavior now handles this correctly.

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-21 14:47:52 -07:00
Jack Hsu 8750521b32 fix(react): exclude tailwind from CSS modules syntax in component generator (#33574)
## Current Behavior
When generating a React component with --style=tailwind, the component
template incorrectly includes `className={styles['container']}` and
attempts to import CSS modules.

## Expected Behavior
Components generated with --style=tailwind should not include CSS
modules imports or `styles['container']` references, since Tailwind
doesn't use CSS modules.

## Related Issue(s)
Closes NXC-3511

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-21 16:18:30 -05:00
Jason Jean 9a6c7adddf feat(nx-cloud): prepend nx version to stats metadata (#33568)
<!-- 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
<!-- This is the behavior we have today -->

Stats don't come along with versions which makes it hard to see if it
was specific changes that make a difference.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Stats are tagged with the version so we can compare stats between
versions

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-11-21 12:19:58 -05:00
Jack Hsu 57f28bac5e fix(storybook): remove STORYBOOK_PROJECT_ROOT when running automigrate to prevent hanging (#33567)
This PR fixes an issue where migrations can hang due to out invocation
of `storybook automigrate`. We are passing both `--config-dir` and
`STORYBOOK_PROJECT_ROOT`, the latter causes hanging with Storybook v9.

https://www.loom.com/share/39bbb350595c4a13aef86ec29f4b748f

## Current Behavior
Hangs

## Expected Behavior
Does not hang

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

Fixes #32492
2025-11-21 11:34:29 -05:00
Jack Hsu 1c8796a4d7 docs(misc): update migration docs to use supported markdown syntax (#33563)
This PR cleans up the markdown files under `packages/`. We previously
had to support Next.js docs and translate it for astro docs with proper
markdown syntax. This applies to generators, executors, and migrations.

Also removes the function to do the translation in astro app since it's
no longer needed.

## Code block (migrations)
<img width="1086" height="800" alt="Screenshot 2025-11-20 at 1 23 53 PM"
src="https://github.com/user-attachments/assets/bd9acb9b-7960-4e41-9d26-22d29da6658e"
/>

## Aside (generators)
<img width="802" height="443" alt="Screenshot 2025-11-20 at 1 43 17 PM"
src="https://github.com/user-attachments/assets/e2999821-8783-46ed-a984-2193f6f8eafa"
/>
2025-11-21 09:25:34 -05:00
Craigory Coppola 1eecf46e4a fix(core): provide error when nested graph construction would occur invoked during createNodes (#33541)
## Current Behavior
During createNodes, if a file is imported and a function in said file
invokes the Nx project graph creation process, there's an infinite loop
that results in all nx commands hanging with little feedback.
Theoretically this loop would terminate at around the 10 minute mark,
but throughout the loop we would be digging deeper and deeper into
recursive territory so its possible that the node process could become
overwhelmed and hang.

## Expected Behavior
If recursive graph creation is detected, Nx terminates and logs the call
stack so it can be investigated properly.

## Related Issue(s)

Fixes #29618

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: AgentEnder <AgentEnder@users.noreply.github.com>
2025-11-21 01:37:19 -05:00
Jack Hsu 239a4dbb2d feat(linter): add util to load eslint rules from a directory (#33543)
This PR adds the ability for users to import ESLint rules from arbitrary
location in the workspace rather than storing them in
`tools/eslint-rules`. This is useful for monorepo not using
npm/yarn/pnpm workspaces and need a mechanism to load from any custom
rules location without them being installed/symlinked.

It also handles TS files automatically.

Demo: https://www.loom.com/share/3c32af4555614eeab4f81fce8db0c955

Example:

```js
import baseConfig from "../../eslint.config.mjs";
import { loadWorkspaceRules } from "@nx/eslint-plugin";

const customRules = await loadWorkspaceRules("foo/bar/eslint-rules");

export default [
  ...baseConfig,
  {
    ignores: ["**/out-tsc"],
  },
  {
    files: ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"],
    plugins: {
      custom: { rules: customRules },
    },
    rules: {
      "custom/valid-command-object": "error",
    },
  },
];
```

---------

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
2025-11-20 17:16:03 -05:00
Craigory Coppola 9f7414e32a fix(core): daemon command should exit at end (#33547)
## Current Behavior
Daemon command hangs at end instead of exiting

## Expected Behavior
Daemon command exits

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

Fixes #
2025-11-20 16:54:32 -05:00
Craigory Coppola 236177b8a3 chore(repo): fixup some issues with jest config (#33549)
## Current Behavior
There's some issues with the jest configs in the repo, CJS files having
`import` in them, etc.

## Expected Behavior
CJS files don't have `import`

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

Fixes #
2025-11-20 16:49:18 -05:00
Craigory Coppola 0e500dc64f fix(core): don't presume a task is long running if its marked cacheable (#33545)
## Current Behavior
`cache: true` is overridden if task name is dev

## Expected Behavior
`cache: true` has priority

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

Fixes #32610

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-11-20 16:48:28 -05:00
MaxKless aa38b256a7 fix(graph): align exclude flag with others by using findMatchingProjects (#33550) 2025-11-19 18:18:51 -05:00
Jack Hsu 618c3344af fix(vite): generate .mts config files to force ESM (#33518)
Using .mts extension forces files to always be treated as ESM modules,
ensuring consistent behavior regardless of package.json or tsconfig
settings.

This matters for Node 24 because by default Node will strip types from
`.ts` files and then they are resolved through normal Node resolution.
In the past we can control CJS/ESM through tsconfig options, but now
only extension or `type` in `package.json` matters.

Changes:
- Updated all createOrEditViteConfig calls to pass useEsmExtension: true
- Updated normalizeViteConfigFilePathWithTree to check for .mts files
first
- Updated test files to expect .mts config files
- Updated snapshots to reflect new .mts extension

Closes NXC-3446
2025-11-19 16:49:25 -05:00
Jack Hsu 05bd3a4c16 fix(linter): handle various flat config override structures (#33548)
Flat config overrides util may fail when it isn't a plain JS object.
This PR makes the `hasOverrides` function more robust against these
cases.


Fixes #31796
2025-11-19 16:40:46 -05:00
MaxKless 3401c7ec78 cleanup(gradle): fix gradle dsl e2e test in verbose mode (#33546)
<!-- 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 JSON parsing is broken because in verbose mode, the gradle plugin
returns more than just JSON.

## Expected Behavior
JSON parsing in the test should work

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

Fixes #
2025-11-19 14:59:07 -05:00
Colum Ferry 7b9970f499 fix(release): ensure file change calculation matches nx affected #33413 (#33539)
## Current Behavior
We naively mark WholeFileChange for commits when getting the relevant
commits for projects.
There is already logic to perform better diff checking for lock files,
especially in the case of pnpm catalog usage

## Expected Behavior
Reuse existing logic to determine file changes more accurately

## Related Issue(s)

Fixes #33413
2025-11-19 17:35:09 +00:00
Craigory Coppola 219e82d4cd fix(core): default input should indeed be default (#33533)
<!-- 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

If no inputs or named inputs are defined, this area of code was hit:

```
const DEFAULT_INPUTS: ReadonlyArray<InputDefinition> = [
  {
    fileset: '{projectRoot}/**/*',
  },
  {
    dependencies: true,
    input: 'default',
  },
];

export function getNamedInputs(
  nxJson: NxJsonConfiguration,
  project: ProjectGraphProjectNode
) {
  return {
    default: [{ fileset: '{projectRoot}/**/*' }],
    ...nxJson.namedInputs,
    ...project.data.namedInputs,
  };
}
```

This resulted in weird behavior when the user would define `default` in
named inputs, but it would seemingly only be applied to the project's
deps and not the project itself

## Expected Behavior
The `default` input is the default for both

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

Fixes #https://github.com/nrwl/nx/issues/32924
2025-11-19 10:28:58 -05:00
Craigory Coppola f5c876b82e fix(core): avoid leaking memory due by creating an unref'd interval for each daemon connection (#33532)
## Current Behavior
Every time a daemon connection is opened, we create a new interval and
unref it. This results in the daemon checking its process termination at
an ever increasing rate, which presents as increased memory usage and
practically means the daemon is just doing a lot more work than it needs
to in this area.

## Expected Behavior
The interval is registered only on initial server startup.

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

Fixes #29836
2025-11-19 10:28:30 -05:00
Jack Hsu 6b56665857 docs(js): update dual format guide with correct types and hint to check arethetypeswrong tool (#33531)
This PR updates the guide here to also include type entries (which we
generate by default):
https://nx.dev/docs/technologies/typescript/guides/compile-multiple-formats

Update the content to account for the new inferred `@nx/rollup/plugin`
setup, but still mentions the executor. And also link to a tool that can
be used to check for types correctness.

Closes #33258

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>
2025-11-18 18:22:41 -05:00
Caleb Ukle f5915fa165 docs(nx-cloud): update private registry example script (#33528) 2025-11-18 23:14:42 +00:00
Caleb Ukle e418217dde fix(nx-dev): error out when failing to parse plugin manifests (#33498)
if there is an error parsing a schema file for generators/executors then
we should fully error out to prevent caching a "bad" build even if the
site techincally works with missing plugin info.
2025-11-18 16:19:54 -06:00
Jason Jean 3206c35fb2 chore(repo): re-enable metrics collection (#33508)
## Current Behavior

Metrics collection is currently disabled in the CI workflow via the
`NX_CLOUD_ENABLE_METRICS_COLLECTION` environment variable set to
'false'.

## Expected Behavior

Metrics collection should be enabled to gather build and performance
data from CI runs.

## Related Issue(s)

Reverts the change from #33497

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-11-18 13:36:49 -05:00
Rares Matei 40b99940f9 chore(repo): use recommended pnpm cache location (#33529)
This also fixes pnpm caching on the nx repo.
2025-11-18 18:07:20 +00:00
Caleb Ukle 0d84a6788f docs(webpack): update externalDependencies comment to correct reflect the defalt value (#33461)
default is not 'none' is now 'all'

https://github.com/nrwl/nx/blob/master/packages/webpack/src/plugins/nx-webpack-plugin/lib/apply-base-config.ts#L53
2025-11-18 17:57:46 +00:00
Leosvel Pérez Espinosa 6b3b0c679b fix(js): sync external references to project's tsconfig.json file if it includes any files (#33524)
## Current Behavior

The `@nx/js:typescript-sync` generator never syncs external project
references to `tsconfig.json` files if a runtime tsconfig file exists.

## Expected Behavior

The `@nx/js:typescript-sync` generator should sync external project
references to `tsconfig.json` files if it includes any files or a
runtime tsconfig file doesn't exist.
2025-11-18 14:24:43 +01:00
Jason Jean 2dc4cb53ac chore(repo): update nx to 22.1.0-rc.5 (#33519)
Updating Nx from 22.1.0-rc.3 to 22.1.0-rc.5

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-11-17 19:49:59 -05:00
Jason Jean 41dec8ee78 fix(core): resolve all lock ordering deadlocks in metrics collector (#33513)
## Summary
This PR fixes a critical deadlock issue in the metrics collector that
occurred due to inconsistent lock acquisition order between the
collection thread and registration threads. The fix involved
restructuring lock scopes across multiple functions to maintain a
consistent lock hierarchy.

## Changes
- Fixed lock acquisition order in 4 registration functions
(register_main_cli_process, register_main_cli_subprocess,
register_task_process, register_batch)
- Restructured collect_metrics() to minimize system lock scope and
release it before acquiring other locks
- Fixed collection helper methods to read PIDs in scoped blocks without
holding system lock
- Added comprehensive trace logging for debugging lock contentions
- Added concurrent test case to verify no deadlocks occur under stress

## Testing
- All 12 metrics tests pass
- Comprehensive concurrent stress test added:
test_concurrent_group_creation_with_subprocess_updates
- Lock ordering consistency test added:
test_lock_order_consistency_across_registration_threads

## Lock Ordering Rule
Established and enforced this hierarchy across all threads:
1. Acquire system lock first
2. Release system lock
3. Then acquire registration/PID locks

This prevents circular wait conditions (A→B / B→A) that cause deadlocks.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-11-17 17:02:52 -05:00
Benjamin Cabanes 02e5c4af8e docs(nx-dev): add click event to header navigation links (#33516)
Added `sendCustomEvent` calls to track clicks on primary header and
mobile header navigation links.
2025-11-17 15:38:20 -05:00
Jack Hsu ed3ddebde5 fix(storybook): normalize version range before comparison (#33515)
When Storybook is installed with a version range like `^10.0.0` or
`~8.5.3`, the configuration generator fails with error:
```
NX   Invalid Version: ^10.0.0
TypeError: Invalid Version: ^10.0.0
```

This occurs because `gte()` from semver doesn't accept version ranges on
the left-hand side - only valid semver versions are allowed there.

The Storybook configuration generator should work with version ranges by
extracting the actual version number before comparison.

Fixes #33514
2025-11-17 14:55:30 -05:00
Jack Hsu e8576a8bb2 docs(angular): update dynamic module federation to use enhanced modules (#33512)
This updates the MF dynamic remotes docs for Angular to match new setup.

Closes DOC-327
2025-11-17 13:48:10 -05:00
Miroslav Jonaš 4bfc1e8e29 feat(core): apply parent env to atomized target (#33013)
<!-- 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
Env variables from the parent target are not propagated to the atomized
target e.g.
`.test-ci.env` will be only applied to **no-op** `test-ci` but not to
`test-ci--path/to/test/file`.

## Expected Behavior
Running an atomized target will load from the parent's env files.

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

Fixes #

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-11-17 17:30:07 +01:00
Nas3nmann 961e2379fe chore(core): nx plugin submission nx-oxlint 2025-11-17 17:10:10 +01:00
MaxKless de8a0205fd feat(gradle): allow specifying project and task configuration from gradle build files (#33264)
## Current Behavior 
Gradle projects in Nx workspaces can only configure metadata through
Gradle's built-in mechanisms. There's no way to specify Nx-specific
project metadata (like tags) or customize task target configurations
other than overriding with `project.json`

 ## Expected Behavior

Developers can now configure Nx-specific metadata for both projects and
tasks using a type-safe Kotlin/Groovy DSL:

 ### Project-level metadata (in build.gradle.kts):
  ```
nx {
    set("name", "my-service")
    array("tags", "scope:backend", "type:api")
    set("description", "Payment processing service")
  }
```

 ### Task-level metadata (in build.gradle.kts):
```
  tasks.named("integrationTest") {
    nx {
      set("cache", false)
      array("tags", "integration", "slow")
    }
  }
```

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: MaxKless <MaxKless@users.noreply.github.com>
2025-11-17 10:44:46 -05:00
Craigory Coppola d86fb5d244 fix(core): prevent hanging between command end and process exit (#33500)
## Current Behavior

In certain scenarios, Nx commands would hang between command completion
and process exit. This was caused by inefficient message end detection
in the
daemon socket communication, where the check for `MESSAGE_END_SEQ` could
fail when TCP packets were fragmented.

  ## Expected Behavior

With this PR, the message end detection is more robust and handles TCP
packet fragmentation correctly, preventing the hanging issue. The
changes also
add better performance tracking and logging to help diagnose similar
issues in the future.

  ## Changes Made

- **Improved message end detection**
(`consume-messages-from-socket.ts`): Added a preliminary check of the
last character's code point before checking
the full MESSAGE_END_SEQ, which prevents false negatives when TCP
packets are fragmented
- **Enhanced performance tracking** (`daemon/client/client.ts`,
`daemon-socket-messenger.ts`): Added message-type-specific performance
marks and
  measures for better debugging
- **Added server-side logging** (`daemon/server/server.ts`): Added
logging for message receipt, serialization, and response to help
diagnose
  communication issues

  ## Related Issue(s)

This fix addresses hanging issues observed in daemon communication when
commands complete but the process doesn't exit.
2025-11-17 09:57:34 -05:00
Colum Ferry b96b8e32e3 feat(docker): add skipDefaultTag option to build target (#33477) (#33506)
Add a skipDefaultTag option to the DockerTargetOptions interface that
allows users to opt out of the automatic default tag that is prepended
to build targets.

This is useful for multi-platform builds that need to push during build
(e.g., using --platform linux/amd64,linux/arm64 --push), where the
default tag causes build failures because it attempts to push a tag that
was not configured.

- Add skipDefaultTag?: boolean to DockerTargetOptions interface
- Modify buildTargetOptions to conditionally skip default tag when
skipDefaultTag is true
- Inherit skipDefaultTag from parent target in configurations
- Add comprehensive unit tests for skipDefaultTag functionality
- Add e2e test to verify skipDefaultTag works end-to-end
- Maintains backward compatibility (default behavior unchanged when
option not specified)

Fixes #33477
2025-11-17 09:55:31 -05:00
Jason Jean f54364eb67 chore(repo): update nx to 22.1.0-rc.3 (#33496)
Updating Nx from 22.1.0-rc.2 to 22.1.0-rc.3

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2025-11-15 11:29:32 -05:00
Craigory Coppola c1b942fd1c fix(core): include require paths when resolving specified plugins (#33495)
## Current Behavior
Loading local plugins that are relative paths from workspace root, that
point to a JS file, still require preliminary data from default plugins
despite being resolvable. This is because we aren't passing `paths` to
`require.resolve`, so it is trying to resolve relative to the nx package
instead of the workspace.

## Expected Behavior
The straight JS path resolves

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

Fixes #
2025-11-14 21:27:26 -05:00
Philip Fulcher a9def426a1 docs(nx-dev): add monorepo myths article (#32944)
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-11-14 16:35:05 -05:00
Chau Tran a1dcd09172 chore(repo): disable metrics collection (#33497)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2025-11-14 16:09:16 -05:00
Jason Jean b3e6b03d82 chore(core): restructure metrics collector for performance and maintainability (#33483)
## Current Behavior

The metrics collector has several inefficiencies and architectural
issues:
- Complex hierarchical data structure (`ProcessTreeMetrics`) that
doesn't align with how the data is consumed
- Separate `MetadataStore` struct with unnecessary indirection
- Full metadata resent to all subscribers on every collection cycle
- Mutable parameters passed through collection functions instead of
functional return values
- Repeated allocations and clones across collection cycles
- `CollectionRunner` tightly coupled to NAPI, making it untestable in
pure Rust

## Expected Behavior

This PR restructures the metrics collector for better performance,
testability, and maintainability:

### Architectural Changes

1. **Flat Process Model**: Replaced hierarchical `ProcessTreeMetrics`
with a flat `Vec<ProcessMetrics>`, simplifying data flow

2. **Group-Based Organization**: Introduced `GroupInfo` and `GroupType`
to logically organize processes:
   - `MainCLI` - Nx CLI process and its subprocesses
   - `Daemon` - Nx daemon and its children
   - `Task` - Individual task execution processes
   - `Batch` - Batch execution with multiple tasks

3. **Incremental Metadata Updates**:
- Track which groups and processes have been sent using
`Arc<DashMap<String, GroupInfo>>` and `Arc<DashMap<String,
ProcessMetadata>>`
- Only send new metadata to subscribers instead of full state every
cycle
- New subscribers receive full metadata on first update via
`needs_full_metadata` flag
   - Automatic cleanup of dead process/group metadata

4. **Shared State with Arc**:
- Metadata maps shared between `ProcessMetricsCollector` and
`CollectionRunner` using `Arc<DashMap>`
   - Eliminated duplicate metadata storage
   - Single source of truth for all metadata

5. **Functional Programming Pattern**:
- Collection functions now return `Result<MetricsCollectionResult>`
instead of mutating parameters
   - Cleaner error handling with `inspect_err` and `map`
   - Easier to reason about data flow
   - Removed ~100 lines of code by consolidating logic

6. **Channel-Based Communication**:
   - Decoupled `CollectionRunner` from NAPI using `crossbeam_channel`
   - Collection thread sends metrics via channel to listener thread
   - Listener thread receives metrics and notifies NAPI subscribers
   - `CollectionRunner` is now NAPI-free and fully testable in pure Rust
- Non-blocking collection (subscriber callbacks don't block metrics
collection)

### Performance Optimizations

- Pre-allocated `Vec` capacity when combining metrics from different
sources
- Eliminated unnecessary `HashMap` clones during metadata updates
- Single-pass insertion into `DashMap` during string key conversion
- Reduced memory allocations in hot paths
- Collection thread never blocks on JavaScript callbacks

### Code Quality Improvements

- **Testability**: Added 7 pure Rust unit tests for `CollectionRunner`:
  - Group creation with different registration types
  - Incremental metadata updates
  - Dead group cleanup
  - All tests pass without requiring NAPI/Node.js runtime
- Clearer separation of concerns between collection and notification
- Better comments explaining incremental update strategy
- More idiomatic Rust patterns throughout
- Updated TypeScript type exports to match new structure

### Threading Model

**Before:**
```
CollectionRunner (mixed collection + NAPI notification)
```

**After:**
```
CollectionRunner (pure Rust, testable)
  └─> Channel
      └─> Listener Thread
          └─> NAPI ThreadsafeFunction
              └─> Subscribers
```

## Testing

-  241 Rust tests passing (including 7 new `CollectionRunner` tests)
-  Native module builds successfully
-  TypeScript types updated and exports verified

## Related Issue(s)

Part of ongoing metrics collector optimization work.
2025-11-14 16:56:51 +00:00
MaxKless 9471207767 feat(core): make console daemon check backgroundable and pulling from latest (#33491)
## Current Behavior
The Nx Console install check for the prompt happens in the main process,
adding some overhead to each invocation of nx.

## Expected Behavior
We want this check to happen on the daemon so that it's running in the
background. If it's still running when nx is invoked, we can just skip
the prompt since it's non-critical.
Running it in the background also allows us to pull the latest version
of the logic from npm when executing - that way we can keep the logic
older versions up-to-date even when ppl don't migrate to latest.
2025-11-14 16:14:13 +00:00
Jason Jean 7fd2cb4e3b chore(maven): bump Maven plugin version to 0.0.10 (#33485)
## Current Behavior

The Maven plugin is currently at version 0.0.9.

## Expected Behavior

This PR bumps the Maven plugin to version 0.0.10 and creates the
necessary migration for users to automatically update their pom.xml
files.

## Related Issue(s)

N/A - Routine version bump
2025-11-14 10:59:05 -05:00
MaxKless 2088eaaf22 fix(maven): skip maven plugin computation on vercel/netlify (#33486)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2025-11-14 09:28:59 -05:00
Jack Hsu 001e2ba4bb fix(misc): handle ERR_USE_AFTER_CLOSE gracefully in nx init and create-nx-workspace (#33469)
https://www.loom.com/share/560ceccdad45462e9fd3e3f185fc9fa5

Node 24 has stricter readline behavior, and enquirer is not checking for
closed state when invoking operations, resulting in an
ERR_USE_AFTER_CLOSE error when users press Ctrl+C during interactive
prompts.

This commit fixes the issue by adding uncaughtException handler to
ignore ERR_USE_AFTER_CLOSE errors.

When users press Ctrl+C, the process now exits cleanly without showing
an ugly error stack trace.

Fixes NXC-3412

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-14 09:28:50 -05:00
Nicole Oliver 1ef2614519 docs(nx-cloud): remove references to standalone powerpack (#33471)
Updates the Nx Powerpack docs and marketing page to make it clear that
Powerpack packages are included with Nx Enterprise, and cannot be
purchased separately, and remove references to the Nx Powerpack trial.

<!-- 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. -->

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: Caleb Ukle <caleb@nrwl.io>
2025-11-13 14:37:40 -08:00
Jack Hsu 54f6206f1b docs(js): clarify non-buildable libs can be in devDependencies for TS… (#33481)
The recipe for switching to TS project references states "If you
reference a local library project with its own `build` task" which
caused confusion. Users thought only buildable libraries should be
included in devDependencies, leading them to create unnecessary path
aliases for non-buildable libraries.

Closes DOC-149

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-13 17:29:34 -05:00
Jason Jean 20653ab15a chore(misc): record stat for initial invocation of create-nx-workspace (#33480)
## Current Behavior
Currently, telemetry stats are only recorded when `create-nx-workspace`
completes successfully. This doesn't capture how many times the command
is invoked vs completed.

## Expected Behavior
Record a stat when `create-nx-workspace` is first invoked (before any
prompts), enabling analysis of drop-off between initial invocation and
workspace completion.

## Changes Made

### Telemetry
- Added `recordStat()` call in `normalizeArgsMiddleware()` immediately
after welcome message and before any user prompts
- Records with command name `create-nx-workspace` and metadata
`['start']` to distinguish from completion stat
- Allows correlation of invocation and completion events for drop-off
analysis

### AI Agents Prompt
- This is being temporarily disabled because we noticed a dip in
create-nx-workspace completions that lines up when this was released.
Disabling it temporarily to see if the dip is recovered by disabling the
prompt.

### React Framework Selection
- Added early returns in `determineReactFramework()` for cases where
framework is already provided or interactive mode is disabled
- Improves performance by avoiding unnecessary prompt interactions

### Code Quality
- Reorganized imports in alphabetical order for better maintainability
- Removed unused import (`printSocialInformation`)

## Related Issue(s)
WIP - Draft for discussion
2025-11-13 20:16:58 +00:00
Louie Weng 0014ae66d8 fix(gradle): bump gradle migration version (#33479)
Ensure that we bump up Nx plugin for Gradle version to 0.1.9 when going
from 22.1.0-rc.3
2025-11-13 10:43:09 -08:00
Jack Hsu 4e3f475f63 fix(vite): support vitest v4 (#33478)
This PR ports the vitest v4 logic back to `@nx/vite` even though users
should be using `@nx/vitest`, we still support it until v23. Otherwise
running `@nx/vite:configuration --includeVitest` will always fail.

Generator working:
https://www.loom.com/share/246c401e114348818b998e0abed8754e
Suppressing warning:
https://www.loom.com/share/f769507de6684d4e9cb720cdc277e56a
2025-11-13 12:44:17 -05:00
Jason Jean 76c030a82e fix(core): capture stderr in nx add command for better error messages (#33462)
## Current Behavior

When `nx add @nx/s3-cache` fails due to incompatible peer dependencies
or other installation errors, users see only a generic error message
without the actual error details from the package manager.

## Expected Behavior

The command should display complete error messages from the package
manager (both stdout and stderr), including peer dependency conflicts
and other important diagnostic information.

## Changes

Fixed the exec callback in the `installPackage` function to:
1. Capture the `stderr` parameter (was previously ignored)
2. Log both stdout and stderr with a newline separator for clarity
3. Ensure users see all error information from package managers

## Why It Matters

Package managers write installation errors and peer dependency warnings
to stderr. By ignoring stderr, users had no visibility into what
actually failed, making it difficult to diagnose and fix issues.

Fixes issue with `nx add` not showing proper error messages.
2025-11-13 09:25:42 -05:00
Jason Jean 50cf84f758 chore(repo): update nx to 22.1.0-rc.2 (#33464)
Updating Nx from 22.1.0-beta.8 to 22.1.0-rc.2
2025-11-13 08:53:58 -05:00
Rares Matei 37cbdee1a2 docs(nx-cloud): recommend set sha action in manual dte (#33476)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2025-11-13 14:38:28 +01:00
Jason Jean 455891eaf5 fix(js): skip TS project references migration for non-TS-solution workspaces (#33467)
## Current Behavior

The `remove-redundant-ts-project-references` migration fails with an
error when run on workspaces that don't have a root `tsconfig.json`
file, such as nx-examples.

## Expected Behavior

The migration should skip workspaces that are not using TypeScript
solution setup instead of throwing an error.

## Related Issue(s)

Fixes the issue encountered when running the migration on
nrwl/nx-examples repo.

## Changes

- Added check to skip migration if workspace is not using TS solution
setup
- Updated test setup to properly configure TS solution for existing
tests
- Added new test cases to verify skip behavior

The migration now uses `isUsingTsSolutionSetup()` to detect if:
- `tsconfig.base.json` exists
- `tsconfig.json` exists and extends the base
- Package manager workspaces are configured
- Proper TS solution structure is in place

Workspaces missing any of these requirements will have the migration
skip silently.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-12 22:58:31 +00:00
Jack Hsu 1997d950af docs(misc): replace Java cup logo with Duke mascot (#33466)
Use Duke logo rather than the cup logo. Also fix an alignment issue for
sidebar icons.

<img width="1352" height="707" alt="image"
src="https://github.com/user-attachments/assets/dff634e8-3b51-48c6-bbdb-7898e671e118"
/>

<img width="1067" height="596" alt="image"
src="https://github.com/user-attachments/assets/3c2075fd-8577-4a99-bb6b-66f901dd8f1e"
/>


Closes DOC-297

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-12 16:37:14 -05:00
Jason Jean 26df170c54 chore(js): update migration version to 22.1.0-rc.1 (#33465)
## Current Behavior

The migration for removing redundant TypeScript project references is
set to version `22.1.0-beta.8`.

## Expected Behavior

The migration should be updated to version `22.1.0-rc.1` to align with
the release candidate version.

## Related Issue(s)

N/A - Version update as requested.
2025-11-12 20:17:27 +00:00
Leosvel Pérez Espinosa 36b9f7ab32 fix(js): remove redundant typescript project references (#33438)
## Current Behavior

The `@nx/js:typescript-sync` generator adds project dependencies as
TypeScript project references to each project's `tsconfig.json` and
runtime tsconfig file (e.g., `tsconfig.app.json`, `tsconfig.lib.json`,
etc.). This is redundant since projects' `tsconfig.json` files already
reference the runtime tsconfig file, which would reference the
dependencies.

## Expected Behavior

The `@nx/js:typescript-sync` generator should add project dependencies
as TypeScript project references to each project's runtime tsconfig file
(e.g., `tsconfig.app.json`, `tsconfig.lib.json`, etc.). If the project
only has a `tsconfig.json` file, it should add them to it.

We've observed some performance improvement with this change while
running the `typecheck` tasks.
2025-11-12 17:48:26 +00:00
Jason Jean 5c565ad37f fix(core): optimize batch task scheduling to prevent redundant traversals (#33455)
## Summary

This PR combines two critical performance optimizations for batch task
scheduling and task hashing:

### 1. Batch Scheduling Fix

Fixed a correctness bug in the batch scheduling optimization where the
`visitedInBatch` tracking happened too early. Now tasks are only marked
as visited AFTER all scheduling checks pass, ensuring tasks can be added
to the batch from any valid dependency path.

**Files Modified:**
- `packages/nx/src/tasks-runner/tasks-schedule.ts`

**Impact:**
- Prevents task splitting across unnecessary batch boundaries
- Maintains correctness while optimizing performance
- All batch scheduling tests pass

### 2. Task Output Hashing Optimization

Added a DashMap-based cache to the Rust TaskHasher to prevent redundant
hashing when multiple tasks depend on the same outputs.

**Files Modified:**
- `packages/nx/src/native/tasks/task_hasher.rs` - Added
task_output_cache field
- `packages/nx/src/native/tasks/hashers/hash_task_output.rs` - Implement
cache logic

## Root Cause of Issue #33366

Large project graphs with high dependency fanout exhibit slow
`hashMultipleTasks` because:
- 100+ tasks may depend on the same 10 build tasks' outputs  
- This generates 1,000+ separate `TaskOutput` hash instructions
- Each instruction independently:
  - Lists output files from disk (filesystem I/O)
  - Builds glob patterns
  - Hashes the same files
- Result: Same files hashed 100× redundantly

## Solution: Task Output Cache

The cache key combines glob pattern and sorted output paths. When
identical outputs are hashed with the same pattern:
- First task: computes hash (~milliseconds) and stores in cache
- Remaining 99 tasks: cache hits (~nanoseconds each)

### Cache Lifetime
- `TaskHasher` instantiated once per `hashMultipleTasks` call
- Cache persists for entire hashing session
- Discarded when `hashMultipleTasks` completes
- Optimal scope for cache hit maximization

## Performance Impact

**Expected Improvements:**
- Best case (100 tasks, 10 shared deps): 100× speedup
- Typical monorepo: 10-20× speedup
- No shared deps: No regression (cache lookup negligible)

**Issue #33366 Analysis:**
- Current: `Time for 'hashMultipleTasks' 49351.488518` (49 seconds)
- Expected with optimization: ~5-10 seconds (depending on actual
dependency structure)

## Testing

-  All task scheduling tests pass (2262 passed, 0 new failures)
-  Batch mode tests pass (6/6)
-  Native build completed successfully
-  No regressions in existing functionality

## Design Notes

- Task output cache follows same pattern as `workspace_files_cache`,
`external_cache`, `runtime_cache`
- Thread-safe using DashMap with Arc for Rayon parallel processing
- Instrumented with trace-level logging for cache hits/misses
- Cache automatically cleaned up when TaskHasher is dropped
2025-11-12 12:08:18 -05:00
Leosvel Pérez Espinosa ba893a13b0 cleanup(angular): handle ng-packagr changes to browserslist (#33457)
Updates the `ng-packagr` executors to support a breaking change in v21.
This needs to be done in advance because we use the published
`@nx/angular` executors to build the `@nx/angular` source code. To
update to Angular v21, we need this change to be merged, released, and
installed in the Nx repository so that we can build the `@nx/angular`
package containing the support for Angular v21.
2025-11-12 10:44:41 -05:00
Leosvel Pérez Espinosa 19dbf55206 fix(core): remove system metrics collection and reporting (#33456)
Removes system metrics collection and reporting.
2025-11-12 09:55:09 -05:00
Jack Hsu 3d48b75202 feat(core): export TypeScript schema definitions via wildcard patterns (#33454)
Users cannot import TypeScript schema definitions or schema.json files
from Nx packages due to strict package exports introduced in Nx 21.0.0.

Users can now import both TypeScript definitions and JSON schemas from
generator/executor/builder paths using wildcard export patterns. Both
first-level (`*`) and second-level (`*/*`) patterns are supported to
handle different import depths.

Note: For old plugins that had `src/...` deep imports we keep those in
`exports`, but for newer plugins that always used `exports` we skip
`src/` in the export path. So `@nx/nuxt/generators` instead of
`@nx/nuxt/src/generators`.

Fixes #33336
2025-11-12 09:43:12 -05:00
MaxKless 26a7e4fca7 feat(core): pull nx init from latest before executing (#33446)
## Current Behavior
nx init is executed with whatever version is installed globally by npm
(might be outdated)

## Expected Behavior
we pull down the latest version from npm (if it has provenance) and run
that when executing.
Also introduced a new `NX_USE_LOCAL` env var that will be respected by
all commands that have this pulling-from-latest behaviour.
2025-11-12 12:01:37 +01:00
Benjamin Cabanes 7ca6680e03 docs(nx-dev): add Pricing link to Nx Cloud navigation menus (#33452)
Added a "Pricing" link to the Nx Cloud navigation sections.
2025-11-11 20:11:11 +00:00
Jack Hsu 5fa1c18dea chore(repo): bump to Node 24 (#33441)
Update CI to Node 24. Note that the e2e-release changes are pulled from
the original PR.

Note: There are changes to NPM 11 (Node 24) to make it run slower than
NPM 10 (Node 20/22) for publish. (https://github.com/nrwl/nx/pull/31934)

e.g. https://github.com/npm/cli/releases/tag/v11.0.0-pre.1 (`Upon
publishing, in order to apply a default "latest" dist tag, the command
now retrieves all prior versions of the package.` which incurs more
network cost)
2025-11-11 15:10:09 -05:00
Jason Jean 647d75116b chore(repo): update nx to 22.1.0-beta.8 (#33451)
Updating Nx from 22.1.0-beta.7 to 22.1.0-beta.8
2025-11-11 14:26:09 -05:00
Jason Jean 12422ae3ea fix(graph): add nx:build-native dependency to typecheck target (#33428)
## Current Behavior

The typecheck target in graph/client/project.json only depends on
^typecheck targets from other projects.

## Expected Behavior

The typecheck target now includes nx:build-native as a dependency to
ensure native dependencies are built before type checking.

## Related Issue(s)

This fix resolves typecheck failures caused by missing native
dependencies.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com>
2025-11-11 13:38:11 -05:00
Philip Fulcher db09e106e9 docs(nx-dev): add video link to task analytics article (#33450) 2025-11-11 12:20:24 -06:00
MaxKless ab7db78b04 feat(maven): add option to prefix all maven targets (#33420)
## Current Behavior
there is no way to generally influence how maven goals/phases are
represented as targets in nx. This could be useful though for organizing
targets in nx, for example through nx.json `targetDefaults`

## Expected Behavior
There's a `targetNamePrefix` plugin option that can be passed.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: MaxKless <MaxKless@users.noreply.github.com>
2025-11-11 13:16:01 -05:00
Jason Jean 6121a12368 chore(repo): update nx to 22.1.0-beta.7 (#33431)
Updating Nx from 22.1.0-beta.6 to 22.1.0-beta.7
2025-11-11 17:07:01 +00:00
Leosvel Pérez Espinosa 8f3b0b22a7 fix(core): resolve lockfile cache regression with keyMap state (#33448)
After PR #33256 split lockfile parsing into separate node and dependency
caches, a regression occurred where dependencies could be regenerated
without nodes, leaving a shared module-level variable (`keyMap`) empty
and causing incorrect dependency resolution.

Changes:
- Serialize `keyMap` with nodes cache to maintain state between phases
- Remove module-level shared state from pnpm, npm, and yarn parsers
- Move `keyMap` creation inside `getNodes` functions for better
encapsulation
- Update `readCachedExternalNodes` to deserialize `keyMap` internally
2025-11-11 16:52:05 +00:00
Jack Hsu 3c85af93af chore(misc): upgrade macOS GitHub Actions runners (#33444)
Update from the macos-13 is in brownout and will be gone soon.

- macos-15-intel for x86_64-apple-darwin (Intel) builds
- macos-latest for aarch64-apple-darwin (ARM64) builds

Closes NXC-3444
2025-11-11 11:51:49 -05:00
Colum Ferry 00a247be3f feat(vitest): support vitest 4 (#33424)
## Current Behavior
We currently only generate vitest projects using Vitest 3

## Expected Behavior
Use Vitest 4 when generating new projects

## Related Issue(s)

Closes NXC-3343
Closes NXC-3379

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-11-11 10:20:14 -05:00
Leosvel Pérez Espinosa 6d0523e326 fix(core): clean up dead processes from metrics (#33437)
Fixes a regression where dead processes were not being cleaned up from
the metrics reporting.
2025-11-11 09:53:37 -05:00
James Henry 3439ff10e7 feat(release): add resolveVersionPlans option to changelog CLI and API (#33435) 2025-11-11 18:53:14 +04:00
Nicole Oliver 806e9a83af docs(nx-cloud): clarify Github integration details (#33433)
Clarifies some details of the Nx Cloud GitHub integration, such as which
features are available when you use the base integration vs a GitHub
powered organization.

<!-- 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` -->
2025-11-11 09:33:43 -05:00
Colum Ferry 4509d95b3b fix(release): changelog renderer should render commit title with breaking changes (#33439)
## Current Behavior
We do not render the commit title in the BC section of generated
changelogs.

## Expected Behavior
We should render the commit title in the BC section of generated
changelogs along with the Remote Release Client reference to the commit.

## Related Issue(s)

Closes NXC-3290
2025-11-11 13:20:46 +00:00
Colum Ferry 9513a1f89c fix(vitest): do not fail when cleanedAngularVersion is of incorrect type (#33436)
## Current Behavior
There may be a scenario when `cleanedAngularVersion` is of type `object`
rather than `string` which proceeds to error when passed to
`semver.major()`.

## Expected Behavior
If `cleanedAngularVersion` is not `string`, assume the latest version
will be installed. Similar to how no found angular version is handled.

## Related Issue(s)

Fixes #33347
2025-11-11 11:25:33 +00:00
Leosvel Pérez Espinosa 843c041396 fix(js): improve typescript plugin performance (#33425)
- Fix for a bug with the external project references cache
- Add more caching for repeated operations
- Skip tsconfig files processing based on which targets should be
inferred

Fixes #33076
2025-11-11 10:04:43 +01:00
Jason Jean 93e0b21d97 fix(js): update vitest generator import in library generator (#33430)
## Current Behavior
The library generator has an unused import and incorrect import pattern
for the vitest generator.

## Expected Behavior
Clean imports with the correct way to access the configurationGenerator
from @nx/vitest.

## Changes
- Removed unused imports (logger, readJson)
- Updated vitest generator import to use direct require instead of
ensurePackage pattern for accessing the generator

Fixes #
2025-11-10 22:31:21 +00:00
Jack Hsu 98b2ab42e6 chore(repo): force storybook@9 so types resolve (#33429)
Master has v9 in lockfile, but it's not a guarantee. This forces v9
until we have a better solution to resolve v10 types.
2025-11-10 16:47:16 -05:00
Colum Ferry 6b54d6acf6 fix(storybook): remove optional nature of migration (#33427)
## Current Behavior
The Storybook 10 migration was originally intended to be optional.

## Expected Behavior
Make Storybook 10 migration add the migration generator to
migrations.json always. Users can remove it from here if they do not
want it, or they can use the Migrate UI from Nx Console to choose not to
run it.
2025-11-10 20:11:43 +00:00
Jason Jean 73ecb30491 chore(repo): update nx to 22.1.0-beta.6 (#33423)
Updating Nx from 22.1.0-beta.5 to 22.1.0-beta.6
2025-11-10 19:11:25 +00:00
Colum Ferry e581c3c437 feat(vitest): split entrypoint into plugin, generators, executors (#33426)
Split entry point of `@nx/vitest` into `index.ts` for the Inference
Plugin, `generators.ts` for Generators, `executors.ts` for the
Executors.
Ensure the `README.md` is copied to the correct output directory

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Coly010 <Coly010@users.noreply.github.com>
2025-11-10 18:29:37 +00:00
Colum Ferry 685e497c4f feat(vitest): split vitest into @nx/vitest plugin (#33311)
Split `vitest` out of `@nx/vite` and create a new `@nx/vitest`.

This allows for each plugin to have a single responsibility. One for
bundling, one for testing.

It should allow for lighter setups where Vite for Bundling is not
required, but users still want to use vitest for testing.

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Coly010 <Coly010@users.noreply.github.com>
2025-11-10 16:22:47 +00:00
Jason Jean 7a3179241e chore(repo): update storybook (#33422)
<!-- 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
<!-- This is the behavior we have today -->

Storybook was accidentally downgraded to 9.1.9

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Storybook is upgraded back to 10.0

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

Fixes #
2025-11-10 10:51:17 -05:00
Leosvel Pérez Espinosa 22618b6be9 feat(testing): support cypress v15 (#33393)
## Current Behavior

Cypress v15 is not supported.

## Expected Behavior

Cypress v15 should be supported.

## Related Issue(s)

Fixes #33304

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: leosvelperez <leosvelperez@users.noreply.github.com>
2025-11-10 10:50:50 -05:00
Jack Hsu 60089cc998 chore(expo): run export before e2e to mitigate timeout (#33414)
CI and nightlies can flake out during expo test if cypress or playwright
times out waiting for webserver. This makes is to the `export` that
powers `static-serve` is run before running e2e.

This is not usually a problem in new workspaces with inference, but this
legacy test uses executors so continuous task dependency isn't set up.
2025-11-10 10:19:57 -05:00
Louie Weng a0a3289112 chore(gradle): bump plugin for gradle version to 0.1.9 (#33419)
<!-- 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
<!-- This is the behavior we have today -->

Nx plugin for Gradle is at version 0.1.8

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Nx plugin for Gradle is at version 0.1.9

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

Fixes #
2025-11-10 09:53:48 -05:00
Leosvel Pérez Espinosa 373066a379 feat(core): track system metrics and link plugins to workers when possible (#33411)
- Track relevant CPU and memory system metrics.
- Link plugins to workers when possible.
- Refactor collector code by splitting it into two separate structs.
2025-11-07 23:29:36 +00:00
Caleb Ukle 7458b52b4e docs(nx-cloud): document new flaky tasks analytics (#33253)
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-11-07 16:10:30 -05:00
Jack Hsu 4170c2f82b docs(js): update node compat matrix (#33415)
Update it for v22.
2025-11-07 16:10:03 -05:00
Caleb Ukle 2182cea451 cleanup(repo): use mise for agent toolchain installs (#33299)
also dedupe agent launch templates with yaml anchors for better
readability
2025-11-07 14:01:48 -06:00
Philip Fulcher 777217618e docs(nx-dev): add task analytics article (#33407)
https://nx-dev-git-philip-task-analytics-article-nrwl.vercel.app/blog/nx-cloud-release-introducing-enterprise-task-analytics
2025-11-07 13:37:39 -06:00
Jason Jean 746b89a901 feat(maven): bump version from 0.0.8 to 0.0.9 (#33405)
## Current Behavior

Maven plugin is currently at version 0.0.8.

## Expected Behavior

Maven plugin should be bumped to version 0.0.9 with a corresponding
migration for users.

## Changes Made

- Updated parent POM version to 0.0.9
- Updated package.json version to 0.0.9  
- Updated mavenPluginVersion constant to 0.0.9
- Added new migration (0-0-9) to update user pom.xml files from 0.0.8 to
0.0.9
- Scheduled migration for Nx v22.1.0-beta.6

## Testing

-  Maven package tests pass
-  Build succeeds
-  Linting passes
2025-11-07 13:07:36 -05:00
MaxKless b395cec4cd feat(maven): add ci-workflow generator (#33346)
Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
2025-11-07 16:21:15 +00:00
James Henry a6948665e6 fix(core): correctly identify local workspace dependencies on windows (#33408) 2025-11-07 15:08:45 +04:00
Philip Fulcher 790358af91 docs(nx-dev): add november 2025 webinar (#33403)
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: philipjfulcher <philipjfulcher@users.noreply.github.com>
2025-11-06 14:13:29 -06:00
MaxKless e9146c7862 fix(core): prevent args from being split by spaces when executing through nx wrapper (#33362)
<!-- 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
Because `./nx` is passing args with `$@`, args are being split by
spaces. Reference for this behaviour:
https://www.gnu.org/software/bash/manual/html_node/Special-Parameters.html#Special-Parameters-1

This results in this set of process args when running `./nx start-ci-run
--distribute-on="3 linux-medium-jvm"`

```
[
  "<user path>/.nvm/versions/node/v22.19.0/bin/node",
  "<user path>/Projects/OTW/mm-test/.nx/nxw.js",
  "start-ci-run",
  "--distribute-on=3",
  "linux-medium-jvm",
]
```

## Expected Behavior
the arg with whitespace should not be split before being passed to nx:
```
[
  "<user path>/.nvm/versions/node/v22.19.0/bin/node",
  "<user path>/.nx/nxw.js",
  "start-ci-run",
  "--distribute-on=3 linux-medium-jvm",
]
```
2025-11-06 13:42:07 -05:00
Jack Hsu 62d0ad7f25 chore(repo): rename jest.config.ts to jest.config.cts to be compat with Node 24 strip types (#33401)
This PR is just for the repo itself to use `.cts` to explicitly use CJS
for jest config. Node 24 strip types so having `.ts` files with ESM
syntax even though we're previously transpiling them to CJS is a
problem.
2025-11-06 13:36:44 -05:00
Leosvel Pérez Espinosa e470b2c64a feat(core): disable interactivity by default for run-one task outputs in tui (#33358)
Make run-one task terminal outputs in the TUI non-interactive by
default. Most tasks don't need interactivity, and it causes TUI to
ignore all its key bindings because it forwards them to the underlying
program. If interactivity is needed, users can press `i` to enable it.
2025-11-06 13:25:07 -05:00
Louie Weng 28e778a1f9 feat(gradle): use gitignore to determine dependant task output files (#33402)
<!-- 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
<!-- This is the behavior we have today -->

Currently we detect if inputs are found in the build directory to
determine if they are considered dependent task output files. We can use
a simpler heuristic instead.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

If an input is gitignored (and therefore not hashed by Nx), then we
consider it a dependant task output file. This gitignore classifier will
be a mirror of the class used within the Maven plugin. There will be
another PR to move this classifier into a shared kotlin project that can
be used between both projects.

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

Fixes #
2025-11-06 13:20:06 -05:00
Jason Jean 61442118cf fix(maven): forward parameters through target dependencies (#33365)
## Current Behavior

Maven target dependencies are defined as simple strings that reference
other targets. Currently, parameters are not forwarded through these
dependencies when Maven goals are executed.

## Expected Behavior

Target dependencies in Maven should forward parameters (args) to their
dependency targets, enabling better parameter propagation through the
build pipeline.

## Changes Made

Modified `NxTargetFactory.kt` to transform simple string dependency
references into structured dependency objects with explicit parameter
forwarding:

- Install dependencies now forward parameters
- Phase dependencies now forward parameters  
- Test dependencies now forward parameters
- CI target dependencies now forward parameters

This ensures that when a Maven goal executes, any parameters passed to
it are properly forwarded to all transitive target dependencies.

## Related Issue(s)

This change enables parameter passing through Maven target dependencies
via the new dependency object format with `"params": "forward"`.
2025-11-06 11:56:14 -05:00
Jack Hsu 9b5768e7fe fix(testing): use .cts config files for Jest 30+ to fix __dirname issues (#33349)
When using Jest 30 with SWC, users are seeing an error where `__dirname`
is not defined for ESM modules. This is because the `.ts` extension is
type-stripped by Node 22.17/24+ via checking for
[`process.features.typescript`](https://github.com/jestjs/jest/blob/fe7f28c9d1941f5c2726831cd9d9e479b401610e/packages/jest-config/src/readConfigFileAndSetRootDir.ts#L46).

This means that instead of using the `commonjs` we set for `ts-node`,
normal Node resolution kicks in, and is now treating `jest.config.ts` as
ESM.

This PR fixes this issue by using an explicit `.cts` extension, which
forces CommonJS that we assume for Jest configs.

Note: For Jest 29 or earlier we need to keep `jest.config.ts` since the
`.cts` extension is not supported prior to Jest 30.

There's also a fix for an existing issue where using `module.exports` of
anything else from `@types/node` will error out if `tsconfig.json` has a
`types` field but does not include `node`. See:
https://www.loom.com/share/7ebe3c90a70e4ec7bfa53cbcccaaea7d

Fixes #32236

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-06 10:25:39 -05:00
MaxKless cde5ee8c83 docs(misc): add information about nx console debug logging (#33398) 2025-11-06 15:42:01 +01:00
Colum Ferry f2072f01f2 feat(storybook): generate ai instructions for converting from CJS to ESM after migration (#33395)
## Current Behavior
Storybook 10 Changelog states that CJS is no longer supported.
The migration does not do this automatically.

https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#the-storybookmain-file-and-other-presets-must-be-valid-esm

## Expected Behavior
Generate instructions for an AI Agent to find and convert CJS Storybook
Config files to ESM.

## Related Issue(s)

Fixes NXC-3409
Fixes NXC-3336
2025-11-06 14:28:18 +00:00
Juri 2e5844c61b docs(module-federation): change terminal output to shell frame 2025-11-06 14:52:17 +01:00
Juri 58cbbf20bd docs(nx-dev): link nx 22 release video 2025-11-06 14:51:56 +01:00
Jack Hsu 603e7c0bb6 docs(misc): fix ToC overflow and height stretching issues (#33384)
This PR fixes the ToC so it does not overflow to the footer. It adjusts
the height calculation such that it takes up the entire height of the
main frame.

The extra top margin is removed from the footer to remove the extra gap
between main frame and footer.

BEFORE: 

<img width="1387" height="915" alt="image"
src="https://github.com/user-attachments/assets/e7f4d31c-a206-48ab-81e6-9fddfee11b18"
/>


AFTER:

<img width="1385" height="916" alt="image"
src="https://github.com/user-attachments/assets/cf6e2662-3c3d-4d37-9769-235b901cc188"
/>

<img width="1382" height="918" alt="image"
src="https://github.com/user-attachments/assets/9e142edf-259b-482a-b676-9333857ed776"
/>



Fixes DOC-224

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-06 08:43:56 -05:00
Jack Hsu f5d97e3047 fix(nx-dev): fix GitHub star button styling in mobile view (#33385)
This PR fixes the GitHub star widget in the left sidebar such that it
only shows in smaller screens (e.g. mobile). For desktop we have it in
the ToC.

Also styles it to be consistent with the login and sign up buttons.

Large screen, don't show:

<img width="1483" height="881" alt="image"
src="https://github.com/user-attachments/assets/d3c88d87-4905-4c3f-85c4-b7b4c14546d4"
/>


Smaller screen, show:

<img width="1136" height="811" alt="image"
src="https://github.com/user-attachments/assets/22aa652f-c523-493f-a01e-87e55934e1c9"
/>

Mobile view, show:

<img width="511" height="880" alt="image"
src="https://github.com/user-attachments/assets/283ffca2-4e4e-4706-811f-ce27b02e607b"
/>


Fixes DOC-325
2025-11-06 08:43:26 -05:00
Juri a032099138 docs(dotnet): add paragraph about adding a .net app 2025-11-06 14:40:40 +01:00
Colum Ferry f549ef290f feat(vite): add vitest 4 to peerDep range to prevent conflicts (#33394)
## Current Behavior
`@nx/vite` has a peerDep range of only `1 | 2 | 3` for `vitest`.
This will cause peer dep conflicts for using wishing to use Vitest 4.

## Expected Behavior
Add Vitest 4 to the peerDep range of `@nx/vite` to prevent conflicts.
2025-11-06 10:36:10 +00:00
MaxKless a020954987 fix(core): handle various directories when importing prettier (#33383)
<!-- 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
when trying to format with prettier while outside of the workspace (for
example in a `tmp` nx installation like is created during
`configure-ai-agents`), resolving prettier could fail even though it's
present in the actual workspace.

## Expected Behavior
resolving prettier works if it's available in either the proper
workspace or the tmp one by specifying `paths` in `require.resolve`
2025-11-05 17:02:32 -05:00
Jason Jean cfcf109450 chore(repo): enable NX_CLOUD_ENABLE_METRICS_COLLECTION in CI (#33387)
Enables NX_CLOUD_ENABLE_METRICS_COLLECTION in the CI workflow.
2025-11-05 16:48:03 -05:00
Jason Jean ba6ca6c5ae chore(repo): update nx to 22.1.0-beta.5 (#33386)
Updating Nx from 22.1.0-beta.4 to 22.1.0-beta.5
2025-11-05 15:40:45 -05:00
Leosvel Pérez Espinosa a98b524f06 feat(core): collect resource usage (#32946)
Adds resource usage collection while running tasks.
2025-11-05 18:56:12 +00:00
Colum Ferry f6bc122c0b feat(nextjs): add support for next 16 (#33296)
## Current Behavior
We currently support Next 14 and 15.

## Expected Behavior
Add support for Next 16, bringing support to 14, 15, 16.
Existing workspaces will continue to use the version they are on.
New workspaces will use Next 16.

Refer to Next 16 Migration Guide for migrating from Next 15 to 16

## Related Issue(s)

Fixes #33207

---------

Co-authored-by: Eric Büttner <eric.buettner@tuffz.com>
2025-11-05 17:31:31 +00:00
Craigory Coppola b97f666a4e chore(repo): remove --fix-tasks config that exists to exclude removed task (#33371)
This pull request makes a minor update to the CI workflow configuration.
The change simplifies the `Start CI Run` step by removing the
`--fix-tasks="!*check-commit*"` option from the `npx nx-cloud@next
start-ci-run` command.
2025-11-05 10:46:31 -05:00
Colum Ferry 1b7d0955a2 fix(module-federation): update @module-federation packages to fix Koa vulnerability (#33285) (#33380)
Updates @module-federation packages from 0.18.0 to 0.21.2 and
@module-federation/node from 2.7.11 to 2.7.21 to address Koa Open
Redirect vulnerability (CVE: GHSA-g8mr-fgfg-5qpc).

The vulnerability was in transitive dependencies:
@nx/react → @nx/module-federation → @module-federation/enhanced →
@module-federation/dts-plugin → koa@3.0.1-3.0.2

Changes:
- Updated package.json dependencies in @nx/module-federation and
@nx/rspack
- Updated version constants in Angular and React utils/versions.ts
- Added 22.2.0 migrations to all affected packages

Fixes #33285
2025-11-05 10:41:28 -05:00
Jack Hsu bc47ab8ce9 docs(react): update SVGR documentation for Nx 22 (#33370)
This PR clarifies that Nx 22 removed SVGR support from Next.js and React
(Webpack/Rspack).

<img width="942" height="1185" alt="image"
src="https://github.com/user-attachments/assets/6ea8393f-b037-489f-804b-eb06d8d07e4c"
/>

Previously we had this option `svgr: true` but was configurable and
didn't align with current best practices like `import Logo from
'./logo.svg?react'`. We removed it from Nx 22, provided a migration, but
users will be confused by the docs.

Fixes DOC-326
2025-11-05 10:21:50 -05:00
Juri Strumpflohner 26aca9e5ec docs(nx-dev): fix broken URL to monorepo tools (#33381)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #
2025-11-05 09:32:30 -05:00
Juri Strumpflohner 18557f8af4 docs(misc): various updates embedding videos in docs pages 2025-11-04 21:54:36 +01:00
Leosvel Pérez Espinosa c933660b88 cleanup(core): remove unused mouse event listeners from tui (#33368)
Cleans up unused mouse event listeners from the TUI.
2025-11-04 13:21:10 -05:00
MaxKless c2fba1f6fc cleanup(core): update the nx orb version used in circle ci generators (#33364) 2025-11-04 14:47:56 +00:00
Colum Ferry 83051c5c62 fix(vite): ensure createVitest looks only from projectRoot (#33361)
## Current Behavior
`createVitest` is looking at the full workspace every time. It should
only look at the directory with the config file.

## Expected Behavior
Pass the root as the projectRoot of the config file found.
2025-11-04 09:11:45 -05:00
Jason Jean 2d78f571b4 chore(repo): update nx to 22.1.0-beta.4 (#33350)
Updating Nx from 22.1.0-beta.3 to 22.1.0-beta.4
2025-11-03 17:56:26 -05:00
Jason Jean 4017b61ede feat(core): add OSC 9;4 progress indicator support to TUI (#33325)
## Current Behavior

The Nx TUI doesn't provide any visual feedback about task progress
outside of the terminal window itself. Users need to keep the terminal
visible to see task completion status.

## Expected Behavior

With this PR, the TUI now displays real-time task completion progress in
the terminal window chrome (tabs, title bars, dock icons) using the OSC
9;4 escape sequence. This provides at-a-glance progress feedback even
when the terminal is minimized or in the background.

## Related Issue(s)

N/A - This is a new feature enhancement

## Implementation Details

### What is OSC 9;4?
OSC 9;4 is a terminal escape sequence for displaying progress
indicators, originally from ConEmu and now supported by multiple modern
terminals.

### Key Changes
- Added `update_ghostty_progress()` method to calculate and display task
completion percentage
- Added `clear_ghostty_progress()` method to hide progress when done
- Integrated progress updates into task lifecycle (start, status update,
exit)
- Uses ST terminator (`\x1b\\`) for maximum terminal compatibility
- Writes to stderr to avoid conflicts with TUI rendering on stdout

### Supported Terminals
- **Ghostty** - Full support
- **Windows Terminal** (v1.6+) - Full support
- **VTE-based terminals** (GNOME Terminal, Ptyxis) - Full support
- **Other terminals** - Gracefully ignore sequences (no errors)

### Terminal Compatibility Note
The implementation uses the ST (String Terminator) escape sequence
rather than BEL, as this is preferred by Ghostty and required by
VTE-based terminals, while remaining compatible with Windows Terminal.

## Testing

Tested with:
- Building the native module successfully
- Rust formatting and linting passes
- Running nx commands with the TUI active

The progress indicator updates in real-time as tasks complete and clears
automatically when the TUI exits.
2025-11-03 13:27:18 -05:00
Jason Jean 0acc8b0988 feat(core): batch hash tasks without custom hashers (#33327)
## Current Behavior

When processing scheduled batches, tasks are hashed one at a time even
though the hasher has a `hashTasks` method for batch hashing.

Results from a batch with 109 tasks.
```
hash batch: 8.297s
```

## Expected Behavior

Tasks without custom hashers should be batch-hashed using the hasher's
`hashTasks` method for better performance.

Results from a batch with 109 tasks.
```
hash batch: 991.725ms
```

## Related Issue(s)

This is a performance optimization for task hashing.

---

**Changes:**

- Added a new `hashTasks` function that intelligently separates tasks
with custom hashers from those without
- Tasks with custom hashers are hashed individually using `Promise.all`
- Tasks without custom hashers are batch-hashed using the hasher's
`hashTasks` method
- The function automatically filters out tasks that already have a hash
- Updated `processScheduledBatch` in task-orchestrator to use this new
function
2025-11-03 13:27:06 -05:00
Colum Ferry a084f205f9 fix(vite): ensure atomizer does not consider projects outside the project root (#33344)
## Current Behavior
Vitest's `createVitest` can be over-eager and include other projects in
the workspace when finding relevant test specifications.
This leads atomizer to look at relative paths outside the project root.

## Expected Behavior
Ensure that the plugin does not look at projects outside the project
root.
2025-11-03 16:46:57 +00:00
Jason Jean 8cc052f351 chore(repo): update nx to 22.1.0-beta.3 (#33341)
Updating Nx from 22.1.0-beta.2 to 22.1.0-beta.3
2025-11-03 11:30:25 -05:00
Jason Jean d64f45879b fix(maven): set migration version to 22.1.0-beta.4 (#33345)
## Current Behavior

The Maven migration version was incorrectly set to `0.0.8-beta.0` in the
migrations.json file.

## Expected Behavior

The migration version should be set to `22.1.0-beta.4` to align with the
Nx release version.

## Related Issue(s)

Fixes the migration version discrepancy in the Maven plugin.
2025-11-03 11:30:12 -05:00
Juri Strumpflohner 8f7c635894 docs(nx-cloud): embed self-healing ci videos (#33338)
Embeds videos about self-healing CI into the corresponding feature doc

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-11-03 11:25:03 -05:00
Jason Jean 7e0f66dbf3 feat(maven): upgrade to version 0.0.8 with automated migration (#33315)
## Current Behavior

The Maven plugin is at version 0.0.7 with no automated migration path
for users to upgrade their pom.xml files.

## Expected Behavior

Users can upgrade to Maven plugin 0.0.8 and have their pom.xml files
automatically updated via the Nx migration system.

## Changes Made

- Updated Maven plugin version from 0.0.7 to 0.0.8 in:
  - `packages/maven/package.json`
  - `packages/maven/src/utils/versions.ts`
  - `packages/maven/maven-plugin/pom.xml`

- Created `updateNxMavenPluginVersion()` utility function with:
  - Proper XML parsing using `@xmldom/xmldom` DOM API
  - Targeted updates only for `dev.nx.maven:nx-maven-plugin` elements
- Safe handling of all other version elements (dependencies, parent,
project, etc.)
  - Comprehensive error handling

- Added migration `0-0-8/update-pom-xml-version.ts` that:
  - Automatically runs when users upgrade to 0.0.8
  - Updates root pom.xml files via the utility function
  - Logs status of migrations performed

- Registered migration in `migrations.json`

- Added comprehensive unit tests (9 test cases):
  - Updates only the nx-maven-plugin version
  - Does not update other plugin versions
  - Handles missing files gracefully
  - Preserves XML formatting and structure
  - Handles multiple plugin references
  - Handles whitespace correctly
  - Only updates plugins, not parent/project versions
  - All tests passing (27/27)

## Test Plan

- [x] Unit tests pass (27 passing tests)
- [x] XML parsing correctly identifies and updates only
`dev.nx.maven:nx-maven-plugin`
- [x] Other version elements remain untouched
- [x] Migration registration validated
2025-11-03 10:49:18 -05:00
Craigory Coppola b401e6e348 feat(core): enable tui by default on windows (#33314)
## Current Behavior:

Tui is working, but only able to be enabled on windows via env vars or
explicit command line config

## Expected Behavior:

Tui is default on
2025-11-03 09:56:26 -05:00
Craigory Coppola a5d34fd9f9 chore(repo): add .NET format check + codeowners and unify native target handling (#33323)
## Current Behavior
Maven and .NET use a bespoke script to handle skipping an optional
native target in case a system is not setup on a dev's machine.

.NET isn't in codeowners

## Expected Behavior
This pull request introduces improvements to the build and formatting
workflows for the `.NET` and Maven plugins, streamlining the execution
of native targets and updating code ownership assignments. The changes
focus on refactoring build scripts to use a unified runner, adding new
formatting capabilities for .NET projects, and updating the CODEOWNERS
file for clearer team responsibilities.

**Build and Format Workflow Improvements**

* Refactored the `.NET` analyzer build command in
`packages/dotnet/project.json` to use the new `run-native-target.js`
script, replacing the previous direct script invocation.
[[1]](diffhunk://#diff-036c1a7f2e7d98f5a3207441f2ff1cb25b5b5a03343672ce473f4ff0189a5946L25-R25)
[[2]](diffhunk://#diff-42d990ddcbf8d3585553503097ee8b8d1fff8cb6e25e0cd545a87e11d64c03a8L1-L7)
* Added new `format-native` and `_format-native` targets to
`packages/dotnet/project.json`, enabling verification and fixing of code
formatting for the .NET analyzer using `dotnet format`.

**Unified Native Target Runner**

* Introduced the `scripts/run-native-target.js` script to standardize
running native build and install targets, controlled by environment
variables for skipping builds.

**Maven Plugin Build Refactor**

* Updated the Maven plugin's install workflow in
`packages/maven/maven-plugin/project.json` to use the new native target
runner, and removed the obsolete `scripts/build-maven-analyzer.js`
script.
[[1]](diffhunk://#diff-2763fe8a7c2989643f53370a14a08c06616e85c29340fd5bcfa1a67d0deaee7aL11-R11)
[[2]](diffhunk://#diff-972edab06956ad35145cbc20b8e250e7067fbb288b1f99c92661c24f64d3e69dL1-L7)

**Ownership Updates**

* Updated the `CODEOWNERS` file to assign `.NET`-related directories to
`@FrozenPandaz` and `@AgentEnder`, clarifying team responsibilities.

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

Fixes #
2025-11-01 13:30:41 -04:00
Colum Ferry 4507b5a03b feat(storybook): add support for storybook 10 (#33277)
## Current Behavior
We support Storybook 8 and 9


## Expected Behavior
Add support for Storybook 10, bringing Storybook support to 8, 9 and 10

## Related Issue(s)

Fixes #33141
2025-10-31 17:11:22 +00:00
Colum Ferry d7c8f6e772 chore(repo): add vitest scope (#33317) 2025-10-31 17:05:10 +04:00
Jason Jean 4fcdc9542e fix(maven): resolve maven dependencies from project roots (#33313)
## Current Behavior

Maven dependencies were not being resolved correctly from project roots,
which affected the dependency analysis in monorepos with Maven projects.

## Expected Behavior

Maven dependencies should be properly resolved from each project's root,
allowing Nx to correctly understand the project graph for Maven-based
projects.

## Changes Made

- Updated Maven plugin Kotlin code to properly resolve dependencies from
project roots
- Fixed devkit internal utilities to properly handle Maven dependency
resolution
- Updated TypeScript dependencies plugin to align with the new
resolution logic

## Files Changed

-
`packages/maven/maven-plugin/src/main/kotlin/dev/nx/maven/NxProjectAnalyzer.kt`
-
`packages/maven/maven-plugin/src/main/kotlin/dev/nx/maven/NxProjectAnalyzerMojo.kt`
- `packages/maven/src/plugins/dependencies.ts`
- `packages/dotnet/src/plugins/create-dependencies.ts`
- `packages/devkit/internal.ts`
- `packages/nx/src/devkit-internals.ts`

Fixes #XXXXX

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-10-30 18:17:48 -04:00
Craigory Coppola 29a61429a5 chore(repo): enable codeql for csharp code (#33301)
## Current Behavior
CodeQL is not enabled for C#, but C# is in the nx repo

## Expected Behavior
CodeQL is enabled on C#

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

Fixes #

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-30 17:33:30 -04:00
Jack Hsu b28366395f fix(vite): prevent race-condition when importing @vitejs/plugin-vue (#33307)
This PR primes the cache for `@vitejs/plugin-vue`, similar to how we
already do for `esbuild`. When `vite.config.ts` is compiled into CJS,
then doing `require('@vitejs/plugin-vue')` may error with a race
condition if an `import` of the same module is in progress.

Fixes #NXC-3289

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-10-30 12:33:47 -04:00
Colum Ferry 4ec3a99544 chore(node): do not have assertions around killPorts (#33294) 2025-10-30 10:35:33 -04:00
Jack Hsu 9c326bb8e9 chore(repo): use vitest.config.mts to force ESM (#33310)
If it is resolved as CJS it may run into issues?
2025-10-30 10:34:26 -04:00
MaxKless 0347e67334 feat(misc): remove CI investigation recommendations from agent rules (#33309)
<!-- 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
there are recommendations for using the CIPE fixing tools but they are
being removed

## Expected Behavior
removed tools should not be mentioned anymore.

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

Fixes #
2025-10-30 10:33:14 -04:00
Copilot ad0b44f05f docs(maven): add nx show projects, update command example to nx verify, and simplify configuration (#33302)
Completed Maven documentation updates:

- [x] Add `nx show projects` command to display Maven projects after
initialization
- [x] Change example from `nx build` to `nx verify` 
- [x] Simplify configuration section to use `plugins: ["@nx/maven"]`
with defaults
- [x] Update configuration description to accurately explain how targets
are created

## Summary

Successfully updated the Maven plugin documentation:

1. **Added `nx show projects` command** - Shows users how to list
discovered Maven projects after running `nx init`
2. **Changed example to `nx verify`** - Uses a more appropriate Maven
lifecycle phase that includes tests and verification
3. **Simplified configuration** - Updated the configuration section to
show the simpler string array syntax `plugins: ["@nx/maven"]`
4. **Corrected target creation description** - Updated the text to
accurately explain that `@nx/maven` automatically retrieves information
about projects from Maven and creates targets for each phase, goal, and
some additional targets for CI

<!-- START COPILOT CODING AGENT SUFFIX -->



<details>

<summary>Original prompt</summary>

> Expand this section
https://nx.dev/docs/technologies/java/maven/introduction#add-nx-to-a-maven-workspace
> 
> With instructions to run the following
> 
> nx show projects
> 
> To see a list of Maven projects
> 
> And change nx build Maven project to nx verify Maven project
> 


</details>



<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: FrozenPandaz <8104246+FrozenPandaz@users.noreply.github.com>
2025-10-30 10:05:00 -04:00
MaxKless ac8b58191a chore(repo): refactor dev container setup to work with mise (#33291)
<!-- 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
devcontainer wasn't working reliably

## Expected Behavior
devcontainer should work reliably and reuse the configuration setup we
have for all these different tools that are needed
2025-10-30 09:45:13 -04:00
MaxKless 56633a7b1b fix(core): also look in .nx installation when reading nx.json extends (#33306)
<!-- 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
in a `.nx` installation, `require.resolve` won't find the `extends`
preset nx.json file because there are no root `node_modules`

## Expected Behavior
in a `.nx` installation, the nested `.nx/installation/node_modules` are
also used to try and resolve the preset.
2025-10-30 09:10:50 -04:00
Eric Büttner 2f3b7d09b5 fix(nextjs): ensure eslint-config-next matches Next.js 14 and 15 versions (#30259)
This PR builds on the previous fix that ensured `eslint-config-next` was
correctly installed when using Next.js 15. #30258

Now, the logic has been further refined to dynamically determine the
installed Next.js version and install the corresponding
`eslint-config-next` version accordingly.

<!-- 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

- `next@~15.1.4` is installed
- `eslint-config-next@14.2.16` is installed (incorrect for Next.js 15)

### Expected Behavior

If Next.js 15 is detected -> eslint-config-next@15.1.4 is installed
If Next.js 14 is detected -> eslint-config-next@14.2.16 is installed

### GitHub Repo

https://github.com/tuffz/new-nx-with-preset-nextjs

### Steps to Reproduce

1. Run the following command from the official documentation:
`npx create-nx-workspace@latest --preset=next`
3. Open `package.json` and check the installed dependencies

- `next@~15.1.4` is installed
- `eslint-config-next@14.2.16` is installed

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

Fixes #30257 (& #30258)
2025-10-29 22:53:04 +00:00
Copilot 4a07faf15c docs(nx-dev): add GitHub star widget back to documentation sidebar (#33289)
Adds the "Give us a star" CTA back to the Astro documentation in both
the left navigation sidebar and right table of contents sidebar.

## Implementation

- **Middleware** (`github-stars.middleware.ts`): Fetches star count from
`nrwl/nx` via GitHub GraphQL API with 1-hour cache. Exports
`DEFAULT_STAR_COUNT` (23k) for fallback when `GITHUB_TOKEN` unavailable.

- **Components**: Integrated existing `GitHubStarWidget` React component
into `Sidebar.astro` (bottom of nav) and `TableOfContents.astro` (above
"On this page") using `client:load` hydration.

- **Configuration**: Added middleware to `astro.config.mjs` route
middleware chain.

## Screenshot

![GitHub star widget in
documentation](https://github.com/user-attachments/assets/3d746408-d05b-429d-98ec-1fc8c886646d)

Widget appears in both sidebars showing star count and linking to
https://github.com/nrwl/nx with analytics tracking.

Fixes https://linear.app/nxdev/issue/DOC-268/add-give-us-a-star-cta-back

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `api.npmjs.org`
> - `repo.gradle.org`
> - `staging.nx.app`
> - `telemetry.astro.build`
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/nrwl/nx/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT CODING AGENT SUFFIX -->



<details>

<summary>Original prompt</summary>

> Issue Title: Add "Give us a star" CTA Back
> Issue Description: e.g.
`nx-dev/ui-common/src/lib/github-star-widget.tsx`
> 
> This goes in the sidebar, but we can also see if we want to put it
elsewhere in the new docs.
> Fixes
https://linear.app/nxdev/issue/DOC-268/add-give-us-a-star-cta-back
> 
> 
> Comment by User 5261ea6c-c70c-4295-a64f-a792be93af22:
> [https://github.com/nrwl/nx](https://github.com/nrwl/nx)
> 
> Comment by User d484ef82-7f7d-4a95-be09-9d82ca3905dc:
> 📋 I wasn't able to determine which GitHub repository to work in.
> 
> I think it's one of these, but can you tell me which one is right?
> 
> Comment by User d484ef82-7f7d-4a95-be09-9d82ca3905dc:
> Waiting for https://linear.app/nxdev/profiles/james to link their
GitHub account. [Click to authorize
→](https://linear.business.githubcopilot.com/linear/auth)
> 
> Comment by User :
> This thread is for an agent session with githubcopilot.
> 
> 


</details>



<!-- START COPILOT CODING AGENT TIPS -->
---

 Let Copilot coding agent [set things up for
you](https://github.com/nrwl/nx/issues/new?title=+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: JamesHenry <900523+JamesHenry@users.noreply.github.com>
Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
2025-10-29 14:50:12 -04:00
Caleb Ukle 84b0debba8 docs(nx-cloud): re-split out vcs guides to prevent header overlap in ToC (#33282)
guides couldn't be merged into one page w/ tabs and keep consistent
headers. so we're back to splitting them out. but all under a
source-control-integration parent route. so we don't need to do any
redirects and such as the index route will contain the links to each one
2025-10-29 13:15:19 -05:00
Philip Fulcher b876ced24f docs(nx-dev): revise Nx 22 release article (#33287)
---------

Co-authored-by: Juri <juri.strumpflohner@gmail.com>
2025-10-29 11:59:59 -04:00
Philip Fulcher f52d58675a docs(nx-dev): remove webinar notifier for October webinar (#33295) 2025-10-29 10:06:29 -05:00
Ajit Panigrahi e56abcf517 docs(core): remove duplicate install instructions (#33278)
Removed duplicate information about installing Nx globally.

<!-- 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
<!-- This is the behavior we have today -->
Duplicate line.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
Removed duplicate line.

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

Fixes #
2025-10-29 08:37:31 -05:00
Juri 6b95de3ede docs(nx-dev): add article about Storybook and watching buildable libs 2025-10-29 14:30:34 +01:00
Craigory Coppola 3e6e0681d0 chore(repo): remove files accidentally committed while investigating socket issues (#33284)
Some investigation files were accidentally included in a merge
2025-10-28 18:40:27 -04:00
Jason Jean e97b3fa0e3 chore(repo): update nx to 22.1.0-beta.2 (#33283)
Updating Nx from 22.1.0-beta.1 to 22.1.0-beta.2
2025-10-28 18:24:29 -04:00
Caleb Ukle 221ad580d8 docs(nx-cloud): document missing env vars (#33281)
- add `NX_CLOUD_API` (and nxCloudUrl for nx.json)
- add `NX_NO_CLOUD`

https://6900e6fdb1379200085c29ca--nx-docs.netlify.app/docs/reference/environment-variables#nx-cloud-environment-variables
2025-10-28 15:56:49 -04:00
MaxKless eb4281d7dd fix(core): make sure that gemini contextFileName is string before trying to resolve (#33280)
<!-- 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 implementation is brittle and will fail if `contextFileName` is not
a string

## Expected Behavior
we should just not handle other things that folks are putting in there.
but not fail

---------

Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-10-28 19:34:07 +00:00
Leosvel Pérez Espinosa f76f1ce3df chore(repo): dogfood pnpm catalogs (#33232)
Dogfoods the Pnpm Catalogs feature in the Nx repo. This is the first
step to move all dependencies to Pnpm Catalogs definitions. More work
will be done incrementally later as we consolidate package versions
across the repository.

The initial list of dependencies moved to Pnpm Catalogs is:

- Angular packages
- React packages
- TypeScript packages
- Jest packages
- Rspack packages
- Some common utilities
2025-10-28 19:09:07 +00:00
Jason Jean 54a4eb4da7 chore(repo): update nx to 22.1.0-beta.1 (#33271)
Updating Nx from 22.1.0-beta.0 to 22.1.0-beta.1

---------

Co-authored-by: Craigory Coppola <craigorycoppola@gmail.com>
2025-10-28 14:04:53 -04:00
Craigory Coppola d1653eca05 fix(core): turn v8 serializer off by default but fallback to it if json serialization fails (#33274)
## Current Behavior
We have tried to enable v8 serialization again... but it still seems
problematic. We don't want to revert again... so we evaluated some
options:

1. Disable by default
2. Disable for the single client method we think may be problematic
3. Fall back to JSON if v8 fails
4. Disable by default and still fall back if JSON fails

## Expected Behavior
We decided to update Nx such that the default behavior will be a
combination of #4, and #2. So by default we use JSON, if that
serialization fails we'll try v8... but there's an exception so the
method we know to be an issue will never try v8.

If you opt in to v8 by default, the combo changes to #3 + #2. So, by
default we'd use v8... if it fails try json... never try v8 for
processInBackground

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

Fixes #
2025-10-28 14:03:58 -04:00
Juri Strumpflohner 160b4cce34 feat(nx-dev): add downloadable resources page and React book blog post 2025-10-28 16:12:39 +01:00
Emilio Heinzmann 1089ffc41b fix(docker): guard commitSha null in plugin interpolation (#33275)
## Current Behavior
Docker plugin assumed `commitSha` was always non-null; when `null`,
`shortCommitSha.slice` caused a runtime error during target
interpolation.

## Expected Behavior
Plugin should succeed even if latest commit SHA cannot be resolved,
simply omitting shortCommitSha-based substitutions.

## Changes
- Added null guard: `shortCommitSha` now set to `commitSha ?
commitSha.slice(0,7) : null`.
- Added test "should not throw when commitSha is null" verifying node /
target creation succeeds.
- No breaking changes; only broadens safe input surface.

## Additional notes
Logic only executes when `commitSha` was previously null (error case);
normal paths unchanged. If consumers interpolate `{shortCommitSha}`,
they should handle possible null (unchanged if interpolation is already
optional).
2025-10-28 13:43:06 +00:00
James Henry f2649cbaa6 feat(vite): add atomizer support for vitest (#33265) 2025-10-28 15:52:34 +04:00
Juri 43a5e163ce docs(nx-cloud): self-healing CI classification customization 2025-10-27 21:44:12 +01:00
Jack Hsu 39df8c9b76 chore(nx-dev): remove link checker from build so it is only checked during CI not deploy (#33272)
This PR removes the need to check links during deploy and instead
enforces it in CI. This removes the need to build astro-docs when
building next.js app.

Reduces Vercel build from 10-11 mins to 6.5 mins.

<img width="1231" height="94" alt="image"
src="https://github.com/user-attachments/assets/ad5d4459-f917-4609-8c00-151f61dc29d6"
/>
2025-10-27 15:58:15 -04:00
Louie Weng 29467dac05 docs(nx-cloud): edit release notes for 2025.07.3 (#33270)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Update release notes entry tor 2025.07.3 - short link support for DTE
summary

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

Fixes #
2025-10-27 17:08:15 +00:00
Rares Matei 18b3c52a3c chore(repo): run workspace create and rollup tests serially (#33252)
<!-- 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
<!-- This is the behavior we have today -->

You can see the issue here:
https://staging.nx.app/cipes/68fba96042d3126ee8ec0d19/analysis?runGroup=18785923031-1-linux

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes BAC-1387
2025-10-27 16:35:43 +00:00
Jack Hsu f36c61f530 fix(webpack): prevent errors when importing @nx/webpack before typescript is installed (#33251)
This PR wraps one of the exports of `@nx/webpack` within a dynamic
function that ultimately requires `tsquery`. This causes an issue in
yarn v1 where `typescript` cannot be resolved thus causing an error when
`@nx/webpack` is imported.

The errors happens on every new workspace that starts from empty:

```
npx create-nx-workspace --preset=ts --pm=yarn
nx add @nx/web
nx g @nx/web:app apps/demo --bundler=webpack
```

Results in:

```

 NX   Cannot find module 'typescript'

Require stack:
- /private/var/folders/p4/6tvkdn_11xlc_2j999ybhbkr0000gn/T/tmp-59809-4kedkj5a1XsO/node_modules/@phenomnomnominal/tsquery/dist/src/ast.js
- /private/var/folders/p4/6tvkdn_11xlc_2j999ybhbkr0000gn/T/tmp-59809-4kedkj5a1XsO/node_modules/@phenomnomnominal/tsquery/dist/src/index.js
- /private/var/folders/p4/6tvkdn_11xlc_2j999ybhbkr0000gn/T/tmp-59809-4kedkj5a1XsO/node_modules/@nx/webpack/src/generators/convert-config-to-webpack-plugin/lib/extract-webpack-options.js
- /private/var/folders/p4/6tvkdn_11xlc_2j999ybhbkr0000gn/T/tmp-59809-4kedkj5a1XsO/node_modules/@nx/webpack/src/generators/convert-config-to-webpack-plugin/convert-config-to-webpack-plugin.js
- /private/var/folders/p4/6tvkdn_11xlc_2j999ybhbkr0000gn/T/tmp-59809-4kedkj5a1XsO/node_modules/@nx/webpack/index.js
- /private/tmp/web4/node_modules/@nx/devkit/src/utils/package-json.js
- /private/tmp/web4/node_modules/@nx/devkit/src/generators/to-js.js
- /private/tmp/web4/node_modules/@nx/devkit/public-api.js
- /private/tmp/web4/node_modules/@nx/devkit/index.js
- /private/tmp/web4/node_modules/@nx/web/src/generators/application/application.js
- /private/tmp/web4/node_modules/nx/src/config/schema-utils.js
- /private/tmp/web4/node_modules/nx/src/command-line/run/executor-utils.js
- /private/tmp/web4/node_modules/nx/src/project-graph/utils/project-configuration-utils.js
- /private/tmp/web4/node_modules/nx/src/utils/package-json.js
- /private/tmp/web4/node_modules/nx/bin/nx.js
Pass --verbose to see the stacktrace.

error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
```

Note: Other generators like React/Vue are fine since they have
dependency on tsquery, which installs typescript.

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-10-27 12:31:56 -04:00
Craigory Coppola 98e510b47e fix(core): split lockfile cache and other performance improvements (#33256)
## Summary
This PR includes three performance and correctness improvements:

1. **Split lockfile cache into separate node and dependency caches** -
Previously, both createNodes and createDependencies would read/write the
entire cache. Now each manages its own cache independently:
   - `parsed-lock-file.nodes.json` for external nodes
   - `parsed-lock-file.dependencies.json` for dependencies

2. **Prevent duplicate plugin resolution calls with promise cache** -
Added a promise cache to prevent concurrent duplicate calls to
`retrieveProjectConfigurationsWithoutPluginInference` when multiple
plugins fail to resolve simultaneously

3. **Normalize targets in separate loop after validation** - Moved
target normalization out of the validation loop to ensure proper
sequencing

## Test plan
- [ ] Tests pass (currently failing in CI - needs investigation)
- [ ] Build succeeds
- [ ] Lint passes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-27 10:33:18 -04:00
Jack Hsu 514005a7c9 fix(core): prevent undefined importer crash in pnpm lockfile parsing (#33223)
When stringifying a pnpm v9 lockfile with workspace packages, Nx crashes
with: "Cannot destructure property 'specifiers' of 'projectSnapshot' as
it is undefined."

This occurs when:
- The lockfile has a root importer with `link:` references to workspace
packages
- But the lockfile is missing the workspace package importer entries
- The code tries to access `importers[importerPath]` which returns
undefined
- This undefined value gets added to the output lockfile
- During serialization, it crashes when trying to destructure undefined

Workspace packages with missing importers are now silently skipped
during lockfile serialization. This prevents the crash and allows Nx to
continue operating with out-of-sync lockfiles.

The fix adds a null check before adding workspace dependency importers
to the output lockfile.

Closes NXC-3244
2025-10-27 10:27:38 -04:00
Craigory Coppola a52e7b0f6e Reapply "fix(core): add option to use v8 for daemon message serialization (#33192)
This reverts commit 54db861b72.

## Current Behavior
Daemon messaging is all done over JSON messages

## Expected Behavior
Daemon messages use v8 serialization to avoid string length issues

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-27 10:11:54 -04:00
Sander Boelhouwers 3f7119a821 fix(core): add accept header to http remote cache get (#33093)
With the Accept header in place during the retrieval of cache, the
client always expects an octet-stream from the server.

<!-- 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
When the `Accept` header is missing, you might not get the correct data
depending on the underlying implementation of a self hosted cache
solution. We use AWS API Gateway which has a hard requirement for
`Accept` to determine how it should convert the data.


Fixes #33092
2025-10-26 20:52:04 -04:00
Juri a082693838 docs(misc): add webinar banner to astro docs 2025-10-25 19:06:57 +02:00
Caleb Ukle 630d227a5f docs(gradle): update gradle links and improve graph comps (#33255)
- **docs(gradle): make sure gradle refs point to /java/gradle now**
- **docs(gradle): add syntax highlighting for diff codeblock**
- **fix(nx-dev): improve graph loading behavior to prevent pop-in
flash**
2025-10-24 19:48:48 -04:00
Jack Hsu 66a437a42a docs(misc): add nx-cloud start-agent command to CLI reference (#33250)
This PR adds the `nx-cloud start-agent` command used for manual DTEs to
the reference page.

Also update table code elements such that they don't wrap.

<img width="872" height="584" alt="image"
src="https://github.com/user-attachments/assets/b73a038d-e0de-421a-b430-2d76c0ec4345"
/>


Closes DOC-273, DOC-310

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-24 16:08:49 -05:00
Philip Fulcher 7712d2a656 docs(nx-dev): update Nx 22 release article (#33245) 2025-10-24 13:35:31 -04:00
Louie Weng 215876c398 feat(gradle): add custom installation path to options (#33187)
<!-- 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
<!-- This is the behavior we have today -->

We search for the gradle wrapper of a project by first looking at the
project root, then traversing upwards to the workspace root. If a
workspace has a separate gradle project defined that does not contain a
wrapper, then Nx will error.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Add a field to the gradle plugin that will allow users to specify a
custom gradle installation within their workspace. Nx will check for a
gradle wrapper that the specified location when executing gradle tasks.

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

Fixes NXC-3147
2025-10-24 17:14:33 +00:00
Craigory Coppola 7021056fae fix(core): ensure daemon writes project graph cache to disk consistently (#33217)
## Current Behavior

When the Nx daemon returns a cached project graph from memory (without
recomputing), it does not write the graph to disk. This creates a
cache/daemon mismatch scenario:

1. Daemon has valid project graph in memory
2. A non-daemon process (fallback when daemon fails) encounters errors
and writes cache to disk with those errors
3. Parent process gets clean graph from daemon
4. Forked executor processes read from disk cache which contains errors
5. The errors cause `readProjectGraphCache()` to return `null` (when no
`minimumComputedAt` is provided)
6. This triggers a misleading "No cached ProjectGraph is available"
error instead of surfacing the actual errors

This issue manifests intermittently in CI environments, especially when:
- Daemon connection timeouts occur
- Multiple concurrent processes are running (DTE scenarios)
- File system latency is high

## Expected Behavior

The daemon should always write its current project graph to disk
whenever it returns it, ensuring the disk cache stays synchronized with
the daemon's in-memory cache. This prevents stale or errored caches from
persisting when the daemon has a valid graph.

## Related Issue(s)

Fixes NXC-3030

## Implementation Details

Modified `getCachedSerializedProjectGraphPromise()` in
`packages/nx/src/daemon/server/project-graph-incremental-recomputation.ts`
to write the project graph cache to disk after retrieving the result,
even when reusing the in-memory cached graph.

The fix ensures that:
- Any errored cache written by a non-daemon process gets overwritten by
the daemon's valid graph
- Forked executor processes always read a consistent cache that matches
what the daemon served to the parent process
- Real errors are properly surfaced instead of being hidden by a generic
"no cache available" message

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-24 16:56:40 +00:00
Jack Hsu 442f745b23 fix(vite): nxViteTsPaths supports local path aliases (#33241)
<!-- 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
Local `tsconfig.app.json` is never picked up due to wrong resolved path.

## Expected Behavior
Local `tsconfig.app.json` is picked up and the path aliases are added to
Vite.

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

Fixes #33231
2025-10-24 12:53:57 -04:00
Benjamin Cabanes 7c978ed8c9 docs(nx-dev): sunset Explain with AI for Self-Healing CI (#33243)
Removed "Explain with AI" feature documentation and redirected all URLs
to Self-Healing CI. Added sunset notice to blog posts, updated
configuration files, and preserved historical content for reference.

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-10-24 12:45:27 -04:00
Colum Ferry e57c8a71b2 fix(docker): handle dockerfile at project root tag (#33236)
## Current Behavior
When `Dockerfile` is at project root, we attempt to append `--tag .`
which is invalid for docker.

## Expected Behavior
Ensure that if `Dockerfile` is at project root, we use `workspaceRoot`
to determine the `--tag`.
Note, this tag is primarily used as a deterministic method for Nx to
find the correct docker image when calling `docker run` and `nx release`
2025-10-24 17:36:49 +01:00
Hugo Burton 4a4b780685 fix(core): stream without prefixes showing tui (#33194)
<!-- 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
When using `--output-style=stream-without-prefixes` nx incorrectly shows
the TUI instead of streaming

## Expected Behavior
When using `--output-style=stream-without-prefixes`, nx should stream
with no prefixes just like it does with `--output-style=stream`

## Related Issue(s)


Fixes #32535

Co-authored-by: Hugo Burton <hugo.burton@westpac.com.au>
2025-10-24 12:31:31 -04:00
Jason Jean 1cf2c6665f chore(core): improvements to native build and error handling (#33238)
## Current Behavior

`node_modules` are being copied during copy-local-native

## Expected Behavior

`node_modules` are not being copied during `copy-local-native`
2025-10-24 12:13:18 -04:00
Jason Jean 2f1712f894 chore(repo): update nx to 22.1.0-beta.0 (#33244)
Updating Nx from 22.0.0-rc.0 to 22.1.0-beta.0
2025-10-24 12:11:44 -04:00
Jason Jean 81fd8b4170 chore(maven): only run nx-maven-plugin:install for maven e2e tests (#33242)
## Current Behavior

Maven is installed as a global dependency for all e2e targets
(`e2e-local`, `e2e-ci--**/**`, and `e2e-macos-ci--**/*`), even when only
the Maven e2e tests need it.

## Expected Behavior

Maven should only be installed as a dependency for the Maven e2e tests
that actually use it, avoiding unnecessary installations for other e2e
test projects.

## Changes Made

- Removed `nx-maven-plugin:install` from the global e2e target defaults
in `nx.json`
- Added `nx-maven-plugin:install` as a specific dependency to the Maven
e2e project targets in `e2e/maven/project.json`

This optimization ensures Maven is only installed when needed, reducing
unnecessary build overhead for other e2e tests.
2025-10-24 11:39:20 -04:00
Colum Ferry 3047fbda9e fix(core): should find dockerfiles to suggest installing docker plugin (#33234)
## Current Behavior
`nx init` does not search for `Dockerfile` patterns to suggest adding
the `@nx/docker` plugin.

## Expected Behavior
`nx init` finds and suggests `@nx/docker` plugin

Fixes NXC-3319
2025-10-24 11:23:50 -04:00
Colum Ferry 09fb0b693a chore(repo): update codeowners for docker (#33240) 2025-10-24 15:45:13 +01:00
Leosvel Pérez Espinosa 6788fccbd6 fix(core): fix swapped arguments when resolving catalog references from the filesystem (#33237)
Fixes the order of the arguments in invocations to
`resolveCatalogReference` when resolving catalog references from the
filesystem (not using a `Tree`).
2025-10-24 13:52:58 +00:00
Leosvel Pérez Espinosa f1fe6c0e24 fix(misc): handle null exit codes from crashed child processes (#33163)
## Current Behavior

In some scenarios, when some processes terminate unexpectedly (e.g.
crashed due to OOM), the task runner will incorrectly determine their
exit code to be 0. This results in Nx storing the task results as a
success, which can cause cache hits with false positive successes.

## Expected Behavior

When processes terminate unexpectedly (e.g. crashed due to OOM), the
task runner should correctly determine their exit code from the signal,
and it should never be 0. The stored task result should not be marked as
successful.

## Related Issue(s)

Fixes #29204
2025-10-24 09:26:34 -04:00
Colum Ferry 54bd3c498f fix(docker): handle undefined options when creating graph (#33235)
## Current Behavior
When `@nx/docker` is registered via string only (`nxJson.plugins:
["@nx/docker"]`, project graph creation fails because we try to access
`options.buildTarget`.

## Expected Behavior
Handle undefined `options` gracefully, and still create the default
target.

## Related Issue(s)

Fixes NXC-3320
2025-10-24 09:13:08 -04:00
Craigory Coppola fa45d79e55 chore(repo): remove check commit (#33227)
check-commit is superceded by the pr title target
2025-10-23 22:51:23 +00:00
Jason Jean b1a33ee608 feat(core): update rust (#33220)
## Current Behavior
Dependencies are outdated and Rust tooling needs to be updated.

## Expected Behavior
Rust dependencies are updated to their latest compatible versions.

## Changes
- Updated Rust dependencies
- Rebased with latest `origin/master`
- Updated pnpm lock file

## Related Issue(s)
None
2025-10-23 18:45:00 -04:00
Craigory Coppola b9af6a74b8 docs(dotnet): add migration guide from @nx-dotnet/core (#33206)
## Current Behavior
No docs describing migration path

## Expected Behavior
Docs describing migration path

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

Fixes #

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Caleb Ukle <caleb@nrwl.io>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-23 18:20:14 -04:00
Craigory Coppola c4f1f53b70 chore(repo): mark dotnet e2e as parallel 1 (#33226)
## Current Behavior
.NET sometimes bails on a failed mutex in e2e

## Expected Behavior
it runs only 1 at a time

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

Fixes #
2025-10-23 17:27:22 -04:00
Craigory Coppola a4d9ad9c66 chore(gradle): format files (#33225) 2025-10-23 21:10:47 +00:00
Jack Hsu d3058a726f docs(core): update search filter on createnodes compat page (#33216)
This PR updates one filter from `Reference` to `References` to keep
consistency with our other pages.

Before (Both Reference and References show up):

<img width="137" height="206" alt="image"
src="https://github.com/user-attachments/assets/729379b6-0315-4b99-af90-fd96b3e96830"
/>


After (Just References, and every filter is plural):

<img width="736" height="535" alt="image"
src="https://github.com/user-attachments/assets/9c2ecbcd-67c4-4923-9d05-e2081b0e9dba"
/>

Closes DOC-309
2025-10-23 16:47:53 -04:00
Jack Hsu 97d38f75ee fix(nx-dev): add copy-docs back as a dep of serve (#33215)
It was removed when the scripts were cleaned up during next.js->astro
migration. Adding this back since blog posts need to be synced first
before serving.
2025-10-23 16:47:46 -04:00
Craigory Coppola d717414ec2 fix(core): prevent error message containing [object Object] for invalid {workspaceRoot} placement (#33203)
## Current Behavior

When project configuration errors occur due to invalid token usage
(e.g., `{workspaceRoot}` in the middle of a path), error messages don't
provide sufficient context about where the error occurred.

## Expected Behavior

Error messages should include:
- For project-level errors: the project and target context (e.g.,
"libs/my-app:build")
- For nx.json targetDefaults errors: the nx.json context (e.g.,
"nx.json[targetDefaults]:test")

This makes it much easier for users to locate and fix the configuration
issue.

## Changes

This PR adds comprehensive integration tests to verify the improved
error messaging:
- Test for project-level invalid token usage showing project:target
context
- Test for nx.json targetDefaults invalid token usage showing nx.json
context

Tests use mock plugins to simulate realistic scenarios where invalid
`{workspaceRoot}` token usage would occur, ensuring the error messages
contain the expected context information.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
2025-10-23 20:41:38 +00:00
Chau Tran b59fb033b9 docs(nx-cloud): add SCIM section for SAML Okta (#33222)
- [x] add SCIM for SAML okta
- [x] break up SAML Auth into Azure SAML Auth and Okta SAML Auth

---
Azure SAML Auth and Okta SAML Auth as cards under Single Tenant
<img width="777" height="649" alt="image"
src="https://github.com/user-attachments/assets/3353e804-ea03-468b-82e5-acf28a76bddd"
/>

---
Azure SAML Auth and Okta SAML Auth on sidebar
<img width="242" height="286" alt="image"
src="https://github.com/user-attachments/assets/27365e7f-82ba-4335-9f8d-45b4d61aa3a4"
/>

---
Okta SCIM docs ToC
<img width="1023" height="872" alt="image"
src="https://github.com/user-attachments/assets/9221b31f-004b-4026-9430-9ed12fa7d0dc"
/>
2025-10-23 15:27:45 -05:00
Caleb Ukle 4073537270 fix(nx-dev): update docs code blocks usage (#32998)
by default code blocks will get text as the lang if not set or the lang
is not supported
but we should be so I don't have to look at the warnings in the terminal
output 😅
also remove the frame=none since the team preferred to have the terminal
frame

Example of invalid codeblock messages

![wm_2025-10-15T11-26-05@2x](https://github.com/user-attachments/assets/33161287-3fa3-4897-a5dd-0de3a47b37fe)

Also added conformance rule for validating image pages for public and
src/assets/ directory

examples of incorrect absolute path ref from "public" folder and
incorrect absolute path:


![wm_2025-10-15T10-23-41@2x](https://github.com/user-attachments/assets/354800a4-6628-4236-87d9-2590cb56fe54)



fixes DOC-242
fixes DOC-259
2025-10-23 16:22:20 -04:00
Philip Fulcher 59cf495fe1 docs(nx-dev): add nx 22 release article (#33219) 2025-10-23 19:09:10 +00:00
Colum Ferry 0a8272d7e7 feat(docker): support inferring additional args for targets with interpolation support (#32892)
## Current Behavior
Currently, when configuring the `@nx/docker` plugin, we only set the
target name and a basic command.
The intention was that targetDefaults might be able to be used to
configure additional args, but this falls short in some places.


## Expected Behavior
Allow setting additional args when configuring the `@nx/docker` plugin
that supports interpolated values, similar to `versionSchemes`.

This will allow additional flexibility when setting up the docker build
command such as:

```json
{
  "plugin": "@nx/docker",
  "options": {
     "buildTarget": {
       "name": "docker:build",
       "args": ["-t {projectName}"]
     }
  }
}
```

This means that we can use `nx run-many -t docker:build` and it will
successfully add the name of the projects into the tag.

This is one example, other examples include being able to set individual
Docker Layer Caching where each registry needs a unique name.
2025-10-23 14:48:47 -04:00
Jason Jean 500a4c92ee fix(maven): use File.isAbsolute for cross-platform path detection (#33195)
## Current Behavior

The Maven plugin currently checks if a path is absolute by using
`outputFile.startsWith("/")`. This only works on Unix-like systems and
fails on Windows where absolute paths start with a drive letter (e.g.,
`C:\`).

## Expected Behavior

The Maven plugin should correctly identify absolute paths on all
platforms (Windows, macOS, Linux) using the platform-agnostic
`File.isAbsolute()` method.

## Related Issue(s)

<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

N/A - This is a proactive bug fix for cross-platform compatibility.

---

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-23 14:04:48 -04:00
Emilio Heinzmann b2ba8c2770 feat(release): support {versionActionsVersion} in docker version scheme (#33178) 2025-10-23 21:00:47 +04:00
Colum Ferry 87c8d49b7e fix(core): continue execution when cloud client is unavailable (#33214)
## Current Behavior
When Nx Cloud is used, but the Nx Cloud client is unavailable, an error
is thrown and commands are not run.

## Expected Behavior
When Nx Cloud is used, but the client is unavailable, continue execution
without Nx Cloud.

## Related Issue(s)

Fixes NXC-3175
2025-10-23 17:48:47 +01:00
Rares Matei 516db5c43d chore(repo): fix task flakiness (#33109)
<!-- 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
<!-- This is the behavior we have today -->

Tests either cause agents to run out of memory: 
<img width="956" height="358" alt="image"
src="https://github.com/user-attachments/assets/e55bae05-7757-46e7-88ed-158f72411195"
/>
<img width="1278" height="336" alt="image"
src="https://github.com/user-attachments/assets/40dc8dd6-4409-461e-b75a-5c1c36551da5"
/>

Or setup tasks fail due to network flakiness:
https://staging.nx.app/runs/J1qWVZA7K5



## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

A fully affected, cache busted task graph should run without any
failures.

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

Fixes #
2025-10-23 12:32:07 -04:00
MaxKless 44187bde41 fix(misc): add explanatory footer to ai agents prompts (#33182) 2025-10-23 18:08:39 +02:00
Craigory Coppola a8d6b0ad65 docs(dotnet): improve dotnet docs around option types (#33210)
This pull request updates the documentation for configuring .NET target
types in the `nx.json` file to provide clearer instructions and
examples. The changes make it easier to understand how to customize
target names and configurations for the `@nx/dotnet` plugin.

Improvements to configuration documentation:

* Added a section describing how each target type can be configured,
including renaming targets, customizing options, disabling targets, and
specifying additional properties.
* Updated the example configuration to show how to rename targets (e.g.,
"build" to "compile"), add configurations (e.g., production
optimization), set dependencies between targets, and disable targets
(e.g., disabling "pack").
* Clarified that targets are created with the configuration specified in
the `nx.json` `plugins` array, rather than just with custom names.
2025-10-23 11:55:59 -04:00
Colum Ferry 1002ad5198 fix(node): migrate to koa 3.0.3 (#33208)
Update `koa` to `3.0.3`
2025-10-23 16:10:45 +01:00
Jack Hsu b3c3e40490 docs(misc): update nx release documentation for v22 changes (#33189)
Changes:
- Update all Nx Release guides to show the config for v22 and prior
verisons
- Update `nx.json` reference page to show `releaseTag` property and what
they are prior to v22
- Add example showing all releaseTag options in v22 and < v22 (pattern,
requireSemver, strictPreid, preferDockerVersion, checkAllBranchesWhen)
- Update asides to use "Nx 22 Changes" instead of "Breaking Changes"
(properties deprecated, not breaking until v23)
- Fix `version.generatorOptions.updateDependents` →
`version.updateDependents` reference

Closes DOC-261

<img width="781" height="513" alt="image"
src="https://github.com/user-attachments/assets/3b8a13c4-e863-40da-87cb-ae5a6264bb9e"
/>

<img width="866" height="626" alt="image"
src="https://github.com/user-attachments/assets/e02fd179-80d7-42ea-993c-5da0ed793eaa"
/>

<img width="796" height="408" alt="image"
src="https://github.com/user-attachments/assets/14bb5c54-089c-4ed3-8774-731cbdaa37a5"
/>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-23 10:30:29 -04:00
James Henry ab82c7b1be docs(nx-dev): add guides for Release Groups and Update Dependents (#33200)
<!-- 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
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

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

Fixes #

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
2025-10-23 09:08:57 -04:00
James Henry 7c2f3511e2 docs(nx-dev): add dedicated guide for nx release programmatic API (#33198)
<!-- 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
<!-- This is the behavior we have today -->

The first-class programmatic API of nx release is only documented within
the manage releases introduction and is incomplete (`ReleaseClient` is
not covered at all).

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

The programmatic API has its own in depth guide, which is then
cross-referenced from the manage releases guide. `ReleaseClient` is now
documented including its new Nx 22 features.

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

Fixes #
2025-10-23 08:47:17 -04:00
Colum Ferry 2402ecb576 docs(release): update docs to use correct releaseTag object notation (#33202)
Update docs to match new API

---------

Co-authored-by: James Henry <james@henry.sc>
2025-10-23 13:37:49 +01:00
James Henry 3847528d44 chore(repo): remove unused typedoc-theme (#33196)
Deletes the unused typedoc-theme project from the root of the workspace
2025-10-23 08:15:29 -04:00
James Henry b92df85b97 chore(repo): clean up images (#33197) 2025-10-23 15:55:12 +04:00
Craigory Coppola 083b97255a docs(dotnet): refresh docs after adding run / watch config (#33190)
## Current Behavior
`run`/`watch` are not mentioned in docs

## Expected Behavior
`run`/`watch` docs are accurate

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

Fixes #

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-10-22 18:29:37 -04:00
Jason Jean b9a0f36d5f fix(maven): add support for unbound goals in plugin targets (#33191)
## Current Behavior

Maven plugin targets are only created for goals explicitly bound to
executions in the POM. Goals defined in a plugin but not bound to any
execution are not available as Nx targets.

## Expected Behavior

All available Maven goals should be accessible as Nx targets, including:
- Goals bound to executions (existing behavior)
- Unbound goals defined in the plugin (new behavior)

## Changes Made

1. **Added unbound goal support**: The `NxTargetFactory` now creates
targets for goals defined in a plugin but not bound to any execution.
These targets are created with the format `goalPrefix:goalName` without
an execution ID.

2. **Added continuous build tracking**: 
- Added `continuous` property to `NxTarget` data class to track whether
a goal supports continuous builds
- Updated `MojoAnalyzer` to detect continuous goals from the cache
configuration
   - All targets now properly propagate continuous mode information

3. **Code improvements**:
   - Improved formatting and indentation for consistency
- Made `execution` parameter optional in `createSimpleGoalTarget` to
support both bound and unbound goals
   - Updated command generation to work with or without execution IDs

## Related Issue(s)

This change enables better Maven goal discovery and execution in Nx
monorepos.
2025-10-22 18:16:50 -04:00
Zachary DeRose 4fcd1d22b2 fix(core): adding output error reason (#33159)
<!-- 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
<!-- This is the behavior we have today -->

When an invalid output exists we report:

```
 NX   The following outputs are invalid: 

 - foo.txt

Run `nx repair` to fix this.
```

Without specifying the reason, we tell to run `nx repair`.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

More feedback provided to the user as to the error with their output:

```
 NX   The following outputs are invalid: 

 - foo.txt
   ** Reason: Outputs must start with either "{workspaceRoot}/" or "{projectRoot}/".

Run `nx repair` to fix this.
```

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

Fixes #
2025-10-22 16:04:37 -04:00
Jack Hsu 681825e6be docs(dotnet): add experimental warning for @nx/dotnet (#33188)
Closes DOC-308
2025-10-22 14:36:17 -04:00
Jack Hsu 1c3434fc32 docs(misc): update GitLab project ID location in integration guide (#33186)
This PR updates the GitLab integration guide to reflect where `Copy
Project ID` is in the updated GitLab UI.
<img width="758" height="572" alt="image"
src="https://github.com/user-attachments/assets/ea400064-f3d4-4cd8-b5ba-a6b0bc884e81"
/>

## Related Issue(s)
Closes DOC-269
2025-10-22 12:32:45 -04:00
Jack Hsu ce2586aed8 docs(misc): fix bad line higlighting in docs (#33185)
This PR fixes some pages that don't use the proper markdoc syntax for
line lighting in code blocks. The `{% meta %}` tag is needed and it is
missing in some places.

Closes DOC-2790
2025-10-22 12:32:37 -04:00
James Henry 420091d9df fix(release): breaking change contents extraction (#33184) 2025-10-22 15:11:45 +00:00
Jason Jean cddb2ef2d0 fix(core): store reason when marking daemon as disabled (#33172)
## Current Behavior

When the daemon is disabled due to an error, the reason isn't captured,
making it harder to debug why the daemon was disabled.

## Expected Behavior

The error message/reason is now stored when marking the daemon as
disabled, allowing better visibility into what caused the daemon to be
disabled.

## Related Issue(s)
2025-10-22 10:40:36 -04:00
Andrew Ovens 28e681b99c fix(js): ensure node execute completes before exit (#32629)
Node tool executions (non-watch) were exiting before completing. This
change ensures they complete before exit.

closes #32385

<!-- 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
Node tool executions are not completing since #32356 

## Expected Behavior
Node tool executions complete before exit

## Related Issue(s)
#32385 

Fixes #32385
2025-10-22 15:01:23 +01:00
Colum Ferry c9d20c78f1 chore(repo): update daily canary releases schedule to 1 hour earlier (#33181)
Update canary release schedule to 1 hour earlier
2025-10-22 09:22:49 -04:00
Colum Ferry da88c80a7f fix(angular-rspack): bubble errors correctly (#33183)
## Current Behavior
When errors happen in earlier stages of compilation process, such as
processing global styles, these errors are not printed and the rspack
build process hangs at the Sealing phase.

## Expected Behavior
Ensure that errors that have occurred that would cause the process to
hang are printed and process exits correctly.

Part of this happens because the usual printing of errors happens in the
`afterDone` hook, which is never reached when the above occurs.

## Related Issue(s)

Fixes NXC-3268
2025-10-22 13:14:43 +01:00
Philip Fulcher 585a8ef1a9 docs(nx-dev): fixes for blog and webinar banner (#33179)
- **docs(nx-dev): update copy on webinar banner**
- **fix(nx-dev): handle missing profile links for blog authors**
2025-10-22 07:42:57 -04:00
MaxKless 03cde99faa chore(repo): drop unused and outdated nx-mcp hard dependency in package.json (#33180) 2025-10-22 13:04:23 +02:00
James Henry 8819dccb94 fix(release)!: better respect version plan file contents for changelog entries (#33166)
BREAKING CHANGE: config.conventionalCommitsConfig for `DefaultChangelogRenderer` is no longer nullable.
2025-10-22 09:27:35 +00:00
Jason Jean bbfd0a3c12 chore(repo): prevent readme templates from being published (#33177)
## Current Behavior
Readme template files are being published to npm with inconsistent
naming conventions.

## Expected Behavior
Readme template files should be excluded from npm publication and
consistently named as `readme-template.md`.

## Changes
- Renamed all readme template files to `readme-template.md` across
angular-rspack-compiler, angular-rspack, dotnet, and maven packages
- Updated .npmignore files to exclude readme-template.md from npm
publication
- Updated package.json build commands to reference the new
readme-template.md paths
- Removed `!README.md__tpl__` exceptions from package.json files array
entries
2025-10-21 23:11:24 -04:00
Caleb Ukle 3d8658cbcd docs(devkit): document the createNodes compat for Nx versions (#33102)
add new page for the createNodes api compat
add callouts to extending project graph and tooling plugin page

fixes DOC-255

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-10-21 19:08:34 -05:00
Caleb Ukle 8dacb26ea1 docs(core): correctly parse alias args with single dash (#33176)
@alberturria fixed this issue for the old docs as we migrated to astro,
so applied their change to the astro part of the docs as well. Original
PR: https://github.com/nrwl/nx/pull/33085
made sure to co-author alberturria as well

Thanks! 

![wm_2025-10-21T16-07-56@2x](https://github.com/user-attachments/assets/8bfb8a8c-d8eb-4892-8642-06c3c882e958)

Fixes #32723

Co-authored-by: alberturria <albertoherreravargas@gmail.com>
2025-10-21 23:32:09 +00:00
Colum Ferry 042915418c chore(repo): remove unused @rspack/plugin-minify from root (#33161)
Remove unused @rspack/plugin-minify from root package.json
2025-10-21 18:06:26 -04:00
Leosvel Pérez Espinosa c4b063d403 chore(repo): fix the pnpm caching in the main-macos job (#33162)
Fixes the pnpm caching setup for the `main-macos` job. It can currently
fail when the pnpm cache directory doesn't exist. We need to handle the
pnpm cache conditionally and separately from the node setup.
2025-10-21 21:21:55 +00:00
Jason Jean 10c64c804d chore(repo): update nx to 22.0.0-rc.0 (#33165)
Updating Nx from 22.0.0-beta.8 to 22.0.0-rc.0
2025-10-21 16:43:46 -04:00
Craigory Coppola 6934445fd9 fix(dotnet): fixup various issues + missing functionality (#33132)
…as testing projects<!-- 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
- Microsoft.Testing.Platform projects are not detected as having a test
target
- `serve` does not have an equivalent

## Expected Behavior
- Test projects are properly detected
- `serve` has been split into 2 targets:
  -  `watch`
  - `run`
  
The split of `serve` mirrors the`dotnet` cli in the same way that we
mirrored `vite` when adding `preview` and `dev` targets when we moved
with project crystal. `watch` can be used for a variety of cases, but
provides hot reload + run a 'la `dev` / `serve`. `run` is more of a fire
and forget target that starts up the app. Both targets would only really
be used in local dev.

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

Fixes #
…as testing projects

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-21 16:31:55 -04:00
7208 changed files with 222181 additions and 257105 deletions
+3
View File
@@ -1,3 +1,6 @@
[env]
JEMALLOC_SYS_WITH_MALLOC_CONF = "dirty_decay_ms:1000,muzzy_decay_ms:0"
[build]
target-dir = 'dist/target'
+13
View File
@@ -30,5 +30,18 @@
"enableAllProjectMcpServers": true,
"env": {
"BASH_MAX_TIMEOUT_MS": "1800000"
},
"extraKnownMarketplaces": {
"nx-claude-plugins": {
"source": {
"source": "github",
"repo": "nrwl/nx-ai-agents-config",
"ref": "experimental"
}
}
},
"enabledPlugins": {
"nx@nx-claude-plugins": true,
"polygraph@nx-claude-plugins": true
}
}
@@ -0,0 +1,301 @@
---
name: diagnose-sandbox-report
description: >
Diagnose Nx sandbox violations from a sandbox report. Use when asked to
"diagnose sandbox", "analyze sandbox report", "investigate sandbox violations",
"check violations", when given a sandbox report JSON file or URL to investigate,
or when the user pastes a staging.nx.app sandbox-report URL. Also trigger when
discussing unexpected reads/writes in Nx task execution. Guides structured
investigation of why tasks read/write undeclared files, determines root causes,
and recommends fixes.
argument-hint: '<sandbox-report.json or URL> [--filter <file|pattern|list>]'
allowed-tools: Bash, Read, Grep, Glob
---
# Diagnose Sandbox Report
## Overview
Sandbox violations occur when an Nx task reads files not declared as inputs or writes files not declared as outputs.
**Unexpected reads** are one of:
1. **Missing input** (most likely) — the process legitimately needs this file. Understand what the process does and why the access makes sense, then declare it as an input.
2. **Potential sandboxing gap** (last resort) — the access is irrelevant to correctness and should be filtered/ignored by the sandbox. Only conclude this after exhausting every possibility for it being a missing input.
**Unexpected writes** follow the same logic:
1. **Missing output** (most likely) — the process legitimately produces this file.
2. **Potential sandboxing gap** (last resort) — same as above.
The default assumption is that an unexpected access IS a missing declaration. The investigation's job is to understand WHY the process accesses the file — not to find reasons it shouldn't.
## Critical Rules
1. **NEVER read the sandbox report JSON directly** — these files are too large for the Read tool (50K+ tokens). Do NOT use `Read`, `cat`, `head`, `python3`, or `jq` on the raw report. All report parsing is handled by the script.
2. **ALWAYS run the context-gathering script as the very first step** — no manual parsing, no ad-hoc python/jq on the report file. The script does everything deterministically.
3. If the script fails, **report the error and stop**. Do not attempt manual parsing as a fallback.
4. **Identify the inferring plugin BEFORE proposing any fix** — check `inference.plugin` in the script output or run `jq '.targets.<target>.metadata' <detail-file>`. Fixing the wrong plugin wastes entire investigation rounds.
5. **Verify hypotheses empirically before committing to them** — see Principle 4 and the Phase 2 instrumentation guidance.
## Workflow
### Phase 0: Input
User provides one of:
- Path to a sandbox report JSON file
- A URL to a sandbox report — pass it directly to the script, it handles downloading
- A task ID + CIPE URL (fetch report via MCP if available)
- Inline violation data
If a task ID is provided but no report, ask the user for the report file.
**Filtering**: Most invocations will focus on specific files, not the entire report. The user may specify:
- A single file: `e2e.log`
- A comma-separated list: `apps/nx-cloud/e2e.log,apps/nx-cloud/build/client/assets/main.js`
- A glob pattern: `*.tsbuildinfo`, `apps/nx-cloud/build/**`
- A directory prefix: `apps/nx-cloud/build/client/assets`
When the user specifies files to focus on, pass them via `--filter` to the script. When they don't specify a filter and the report has many violations, summarize the groupings (by directory, extension) and ask which group(s) to investigate first rather than trying to investigate everything at once.
### Phase 1: Deterministic Pre-Processing
Run the context-gathering script **immediately** — this is the first tool call after reading the user's input.
Call it exactly as shown — do NOT append `2>&1` or `2>/dev/null` (the script manages its own stderr internally). Run in the **foreground** (no `run_in_background`) with a **3-minute timeout** — reports can be large and the script runs the task + multiple nx commands:
```bash
npx tsx ${CLAUDE_SKILL_DIR}/scripts/gather-sandbox-context.ts <report.json or URL> [--filter <pattern>] [--workspace <path>]
```
Pass `--filter` when the user wants to focus on specific files or patterns. The script filters violations before all downstream processing (grouping, validation, classification), so the output only contains relevant data.
The script produces two outputs:
**stdout** (~3-5KB compact brief) — everything needed to start investigating:
- `summary`: violation counts (total, filtered, confirmed vs undeclared)
- `undeclaredFiles`: the actual file paths that are true violations
- `grouping`: violations grouped by directory and extension
- `commands`: processes with violations (pid, cmd, executable, arguments, counts) — no full file lists
- `classificationSummary`: counts per category (cross-project, build artifacts, config files, etc.)
- `crossProjectDependencyCheck`: whether cross-project file owners are in the task's dependency chain
- `staleDeclarations`: grouped analysis of expectedInputsNotRead / expectedOutputsNotWritten
- `dependentTasksOutputFiles`: extracted from target inputs config and named inputs — shows what dep output globs are declared (critical for cross-project violations)
- `executorInfo`: executor name and resolved source path in `node_modules` — read this file to understand how the tool is invoked
- `checkSample`: results of `--check` on up to 5 undeclared files (catches false positives early)
- `inference` + `pluginRegistration`: plugin metadata
- `verificationCommands`: pre-built `--check` commands with the correct task ref
- `detailFile`: path to the full detail JSON
**detail file** (`/tmp/sandbox-diagnosis-detail-<project>-<target>.json`) — full data for drill-down. Structure:
- `processTree.processTree`: array of `{pid, cmd, parentPid}` entries
- `processTree.processPidToCmd`: `{ "pid": "command string" }` map
- `processTree.readsByPid`: `{ "pid": ["file1", "file2"] }` — violated reads grouped by PID
- `processTree.writesByPid`: `{ "pid": ["file1", "file2"] }` — violated writes grouped by PID
- `targetConfig`: full target configuration (executor, options, inputs, outputs, dependsOn)
- `projectConfig`: full project configuration
- `resolvedInputs`: `{ files: [...], depOutputs: [...], runtime: [...], environment: [...] }`
- `resolvedOutputs`: `{ outputPaths: [...], expandedOutputs: [...] }`
- `validation`: `{ reads: { confirmed: [...], undeclared: [...] }, writes: { ... } }`
- `classification`: `{ reads: { crossProject, buildArtifacts, configFiles, ... }, writes: { ... } }`
Read the brief output — it has everything to start. Use `jq` on the detail file only when you need to drill into specific sections. When querying the detail file, use the structure above — do not guess the schema. Do NOT use Python, ad-hoc scripts, or the Read tool on the detail file — only `jq`.
For reports with many violations, use `--filter` to narrow scope. When investigating without a filter, use the `grouping` data to identify patterns and prioritize — don't try to trace every file individually.
If `summary.undeclaredReads` and `summary.undeclaredWrites` are both 0, all violations were resolved by the script's validation against resolved inputs/outputs. Report this to the user — no further investigation needed.
The `commands` array pre-parses each process — use `executable` and `arguments` to identify the tool without re-parsing `cmd`. When many files share the same root cause, group them under one finding using a glob pattern or count (e.g., "88 `.d.ts` files matching `packages/nx/dist/**/*.d.ts`").
### Phase 2: Command Analysis — the core investigation
**This is the most important phase.** The goal is to determine with 100% certainty why each process reads or writes each violated file. Do not classify violations from file names or paths alone — trace the actual causal chain from command → config → file access.
#### Step 1: Understand the command
The brief's `commands` array pre-parses each process. Use the `executable` and `arguments` fields directly — don't re-parse `cmd`. Identify:
- The tool (from `executable`)
- The arguments (target files/dirs, config flags, extensions — from `arguments`)
- The working directory (from executor options or project root)
#### Step 2: Trace why the command accesses each violated file
For each violated file, establish the **exact causal chain** that leads the command to read or write it. The approach is the same regardless of tool:
1. Identify the tool's config file (usually in the project root or workspace root)
2. Read the config and trace file references: `includes`, `extends`, `presets`, entry points, plugins
3. Follow the reference chain until you can explain exactly why the violated file is accessed
Common causal patterns:
- **Config chain walk-up**: tool reads config, config extends another, chain reaches the violated file (e.g., tsconfig `extends`, eslint config chain, jest preset chain)
- **Directory traversal**: tool scans a directory for matching files and reads everything, including files it won't process (e.g., jest-haste-map scanning `.next/`, eslint reading `.d.ts` alongside `.ts`)
- **Dependency resolution**: tool resolves imports/requires and follows the dependency graph to files outside the project (e.g., esbuild/vite/webpack resolving workspace packages to their dist outputs)
- **Plugin/transformer loading**: tool loads plugins or transformers that read additional files (e.g., ts-jest loading tsconfig for TypeScript compilation)
For any tool, read its source code in `node_modules` to understand its file discovery behavior. Don't assume — trace the actual code.
**You must be able to explain the full path:** e.g., "eslint loads `.eslintrc.json` → configures `@typescript-eslint/parser` → parser resolves `parserOptions.project` → walks up to find `tsconfig.json` → reads it." If you can't trace the full path, keep investigating — do not guess.
**When theoretical analysis is inconclusive, verify empirically.** For difficult cases, instrument `node_modules` with interceptors to capture real stack traces. For example, patch `fs.readFileSync` in the tool's entry point to log stack traces when the violated file is accessed. A confirmed stack trace is worth more than multiple rounds of code reading.
#### Step 3: Confirm the violation with `--check`
**This step is mandatory — do not skip it.** The script already runs `--check` on a sample of up to 5 undeclared files (see `checkSample` in the brief). Review those results first — if the sample files are confirmed as inputs/outputs, the corresponding violations are false positives.
For files not in the sample, use the pre-generated commands from `verificationCommands` in the brief:
```bash
npx nx show target inputs <project>:<target> --check <violated-read-files>
npx nx show target outputs <project>:<target> --check <violated-write-files>
```
If the commands fail because output files don't exist (e.g., the script's task run timed out), run the task first with `verificationCommands.runTask`.
If `--check` shows the file IS already an input/output, the violation is a false positive from the script's static analysis. If it confirms the file is NOT an input/output, proceed to classification.
#### Step 4: Classify
With the causal chain established and the violation confirmed, classify into one of these categories:
1. **Missing input/output** (most common) — the process legitimately needs this file. Understand why:
- **Direct dependency** — the tool needs this file to do its job (e.g., tsc reads referenced tsconfigs, eslint loads config chain)
- **Transitive dependency** — a config file references another file that references this one (e.g., jest preset → resolver → module). Trace the full chain.
- **Directory traversal side effect** — the tool reads all files in a directory even if it only processes some (e.g., eslint reads `.d.ts` files while linting `.ts`). Still a legitimate access from the tool's perspective.
2. **Bad tool configuration** — the tool accesses a file it shouldn't because its scope is too broad. The fix is fixing the tool's config, NOT adding an input. Investigate:
- Is the command targeting too broad a directory? (e.g., `eslint .` instead of `eslint src/`)
- Is a config file missing ignore/exclude rules? (e.g., eslint processing a file type it should skip)
- Is a plugin inferring a target for a project that doesn't match? (e.g., eslint target on a non-JS project)
- Is an env var causing the tool to behave differently?
3. **Potential sandboxing gap** (last resort) — the access is genuinely irrelevant to correctness (PID files, temp sockets, dev server logs that no task consumes). Only conclude this after exhausting categories 1 and 2.
### Phase 3: Deep Investigation
For violations that aren't immediately obvious, investigate further:
#### If the target is inferred by a plugin
1. Identify which plugin from `inference.plugin` in the brief output, or `nx show project --json` metadata
2. Read the plugin's `createNodesV2` implementation to understand inference logic
3. Determine if this project should have this target at all
4. Check if the plugin has `include`/`exclude` patterns in `nx.json` that should filter this project
5. **Check for input override layers**`project.json`, `package.json`, or `nx.json` `targetDefaults` may override plugin-inferred inputs, rendering plugin-level fixes invisible. Check all three before concluding a plugin fix is sufficient.
#### If violations come from a subprocess
1. Trace the process tree: which parent spawned the subprocess?
2. Why does the subprocess exist? (dev server for e2e, worker thread, build tool subprocess)
3. What environment does the subprocess inherit? (env vars, cwd)
4. Does the subprocess access files in a different project's directory?
#### If violations involve config file reference chains
1. Read the config file (jest.config, tsconfig, .eslintrc)
2. Trace all file references: `preset`, `extends`, `references`, `setupFiles`, `resolver`, `moduleNameMapper`, `transform`, etc.
3. Recursively resolve references (preset → preset → files)
4. Determine which referenced files are not declared as task inputs
#### If violations involve dependency task outputs
1. Check `dependsOn` to understand task dependency chain
2. Check `dependentTasksOutputFiles` glob pattern — is it too narrow?
3. Compare the glob against actual file types the tool reads from dependencies (e.g., `**/*.d.ts` missing `.tsbuildinfo`)
#### Generalizability analysis
After diagnosing the root cause, determine scope:
1. Is this violation specific to this project, or does it affect all projects using this tool/plugin?
2. What conditions trigger it? (specific config, specific tool version, specific project structure)
3. Should the fix be per-project (declarative input) or systemic (plugin improvement)?
4. If the plugin can be made smarter to infer the correct inputs, that's preferable to manual declarations.
### Phase 4: Output
**You MUST present findings using the structured format below before proceeding to any implementation discussion.** Do not use free-form narrative — the structure ensures completeness and makes findings reviewable.
Present findings grouped by category:
```
=== Sandbox Violation Diagnosis: {project}:{target} ===
## Summary
Unexpected reads: N total → M validated as declared → K true violations
Unexpected writes: N total → M validated as declared → K true violations
## Findings
### [MISSING INPUT] {short description}
Files: {file list or pattern}
Process: PID {pid} — {command}
Why: {why the process legitimately needs this file}
Scope: {project-specific or affects all projects using this tool/plugin}
Fix: {where/how to add the input declaration — consider both declarative (add input) and systemic (improve plugin inference) options}
### [MISSING OUTPUT] {short description}
Files: {file list or pattern}
Process: PID {pid} — {command}
Why: {why the process produces this file}
Scope: {project-specific or affects all projects using this tool/plugin}
Fix: {where/how to add the output declaration}
### [BAD TOOL CONFIG] {short description}
Files: {file list or pattern}
Process: PID {pid} — {command}
Why: {why the tool accesses files it shouldn't — config too broad, missing ignore, etc.}
Fix: {specific tool config change}
### [POTENTIAL SANDBOXING GAP] {short description}
Files: {file list or pattern}
Process: PID {pid} — {command}
Why: {why this access is irrelevant to correctness}
Evidence: {proof that categories 1-2 were exhausted}
### [INVESTIGATE] {short description}
Files: {file list or pattern}
Notes: {what's known, what needs more info}
Question: {what to ask the user or team}
## Stale Declarations
expectedInputsNotRead: {count and details if relevant}
expectedOutputsNotWritten: {count and details if relevant}
## Verification Plan
For each fix, provide the exact commands to verify:
1. Run the task so output files exist on disk: `npx nx <target> <project> --skip-nx-cache`
2. Check each violation file is now an input: `npx nx show target <project>:<target> inputs --check <space-separated files>`
3. For plugin-level fixes: build the plugin, patch node_modules, then verify with steps 1-2
```
## Principles
1. **Missing declaration is the default.** Most unexpected accesses are legitimate — the process needs the file, it just wasn't declared. Start from this assumption and investigate to understand WHY the access happens.
2. **The command is the unit of analysis.** Don't classify files in isolation. Understand what the command does and whether each file access makes sense given that command's purpose.
3. **Trace the full chain.** Plugin inference → target config → executor → command → file access. The root cause is often several layers removed from the symptom.
4. **Empirical over theoretical.** When code analysis produces a hypothesis, verify it before acting. Instrument `node_modules`, capture stack traces, run with debug flags. Wrong theories waste entire investigation rounds.
5. **Be thorough.** Read plugin source code, config files, executor implementations. Don't guess based on file names alone.
6. **Potential sandboxing gaps are last resort.** Only conclude this after exhausting missing declaration and bad tool config. The access must be genuinely irrelevant to correctness.
7. **Verify claims about Nx behavior in source code.** Any assertion about how Nx works must be traced to the actual implementation. Do not reason from theory or assumptions.
8. **Prefer systemic fixes over per-project declarations.** If a plugin can be improved to infer correct inputs for all projects, that's better than adding manual input declarations to each project.
## Delegating to Subagents
When the investigation is complex and requires parallel research, you can delegate to subagents. Follow this pattern:
1. **Run the context-gathering script yourself first.** The brief output (~3-5KB) is the shared context all subagents need.
2. **Include the brief output in each subagent prompt** along with the specific question to investigate. Subagents should NOT run the script again or try to parse the raw report.
3. **Give subagents the detail file path** so they can `jq` specific sections (process tree, resolved inputs, etc.) without re-running the script.
4. **Each subagent should answer one focused question**, e.g., "Why does PID 12345 (eslint) read `tsconfig.base.json`? Trace the full causal chain from the eslint config."
5. **Subagents must still follow the skill principles** — trace full causal chains, verify empirically, use `--check`, don't guess from file names. Include these instructions in the subagent prompt.
6. **Synthesize subagent results yourself** using the structured Phase 4 output format. Do not delegate the final classification.
## Reference
For the sandbox report data model and field definitions, see `references/data-model.md`.
@@ -0,0 +1,92 @@
# Sandbox Report Data Model
## Raw Report Structure (JSON)
```typescript
interface SandboxReport {
taskId: string; // "project:target" or "project:target:configuration"
sandboxReportId: string;
inputs: string[]; // declared input patterns (globs or paths)
outputs: string[]; // declared output patterns
filesRead: FileAccessEntry[]; // all files actually read
filesWritten: FileAccessEntry[]; // all files actually written
unexpectedReads?: FileAccessEntry[]; // reads not matching any input pattern
unexpectedWrites?: FileAccessEntry[]; // writes not matching any output pattern
expectedInputsNotRead?: string[]; // declared inputs never accessed
expectedOutputsNotWritten?: string[]; // declared outputs never written
processTree?: ProcessTreeEntry[]; // process hierarchy with commands
}
interface FileAccessEntry {
path: string; // workspace-relative file path
pid: number; // process ID that accessed the file
}
interface ProcessTreeEntry {
pid: number;
cmd: string; // full command string
parentPid?: number; // parent process (absent for root)
}
```
## Violation Computation
Violations are computed by `findUnexpectedFiles()` using `minimatch`:
- A file is "unexpected" if it does NOT match any declared pattern
- Patterns without wildcards also match as directory prefixes (`pattern + '/'`)
- If `unexpectedReads`/`unexpectedWrites` are pre-computed in the report, those are used directly
## Nx CLI Commands for Context
### `nx show target <project:target> --json`
Returns: executor, command, options (merged with configuration), inputs (configured, not resolved), outputs, dependsOn, cache, parallelism, configurations, metadata.
### `nx show target inputs <project:target> --json`
Returns resolved input files (requires files to exist on disk — task must have run):
```json
{
"files": ["workspace-relative paths..."],
"runtime": ["node version checks..."],
"environment": ["ENV_VAR_NAMES..."],
"depOutputs": ["dependency output paths..."],
"external": ["external package names..."]
}
```
### `nx show target inputs <project:target> --check <files...>`
Validates specific files against declared inputs. Exit code 0 = match, 1 = no match.
Categories: `files`, `environment`, `runtime`, `external`, `depOutputs`.
Also detects directory matches (directory containing N input files).
### `nx show target outputs <project:target> --json`
Returns:
```json
{
"outputPaths": ["configured output paths..."],
"expandedOutputs": ["glob-expanded actual paths..."],
"unresolvedOutputs": ["{options.key} patterns that couldn't resolve..."]
}
```
### `nx show target outputs <project:target> --check <files...>`
Validates specific files against declared outputs. Same exit code behavior as inputs.
### `nx show project <project> --json`
Returns full project config. Key fields for sandbox analysis:
- `targets[name].metadata.plugin` — which plugin inferred the target
- `targets[name].metadata.technologies` — what tech the target uses
- `root` — project root directory
### `nx graph --view=tasks --targets=<target> --focus=<project> --print --file=stdout`
Returns task dependency graph with task IDs, dependencies, and roots.
@@ -0,0 +1,846 @@
#!/usr/bin/env npx tsx
/**
* gather-sandbox-context: Parse sandbox report + gather Nx task context
* Produces structured JSON for the diagnose-sandbox-report skill
*
* Usage: npx tsx gather-sandbox-context.ts <report.json or URL> [--filter <pattern>] [--workspace <path>]
*/
import { readFileSync, writeFileSync, existsSync } from 'fs';
import { resolve, basename, extname, dirname } from 'path';
import { execSync, execFileSync } from 'child_process';
import { minimatch } from 'minimatch';
// --- CLI argument parsing ---
interface Args {
reportFile: string;
filter: string | null;
workspaceRoot: string;
}
function parseArgs(): Args {
const args = process.argv.slice(2);
let reportFile = '';
let filter: string | null = null;
let workspaceRoot = process.cwd();
for (let i = 0; i < args.length; i++) {
switch (args[i]) {
case '--filter':
filter = args[++i];
break;
case '--workspace':
workspaceRoot = args[++i];
break;
case '--help':
case '-h':
console.error(
'Usage: gather-sandbox-context <report.json or URL> [--filter <pattern>] [--workspace <path>]'
);
process.exit(1);
default:
if (args[i].startsWith('-')) {
console.error(`Unknown option: ${args[i]}`);
process.exit(1);
}
reportFile = args[i];
}
}
if (!reportFile) {
console.error(
'Usage: gather-sandbox-context <report.json or URL> [--filter <pattern>] [--workspace <path>]'
);
process.exit(1);
}
return { reportFile, filter, workspaceRoot };
}
// --- Types ---
interface FileAccessEntry {
path: string;
pid: number;
}
interface ProcessTreeEntry {
pid: number;
cmd: string;
parentPid?: number;
}
interface SandboxReport {
taskId: string;
unexpectedReads?: FileAccessEntry[];
unexpectedWrites?: FileAccessEntry[];
expectedInputsNotRead?: string[];
expectedOutputsNotWritten?: string[];
filesRead?: FileAccessEntry[];
filesWritten?: FileAccessEntry[];
processTree?: ProcessTreeEntry[];
}
// --- Helpers ---
function downloadUrl(url: string): string {
const tmpPath = `/tmp/sandbox-report-${Date.now()}.json`;
try {
execFileSync('curl', ['-sL', '-o', tmpPath, url], { stdio: 'pipe' });
} catch {
console.error(`Error: Failed to download report from URL: ${url}`);
process.exit(1);
}
return tmpPath;
}
function runNxCommand(
args: string[],
workspaceRoot: string,
timeoutMs = 30000
): string | null {
try {
return execFileSync('npx', ['nx', ...args], {
cwd: workspaceRoot,
timeout: timeoutMs,
stdio: ['pipe', 'pipe', 'pipe'],
encoding: 'utf-8',
});
} catch {
return null;
}
}
function safeJsonParse<T>(str: string | null, fallback: T): T {
if (!str) return fallback;
try {
return JSON.parse(str);
} catch {
return fallback;
}
}
function filterEntries(
entries: FileAccessEntry[],
filterStr: string | null
): FileAccessEntry[] {
if (!filterStr) return entries;
const patterns = filterStr.split(',').map((p) => p.trim());
return entries.filter((entry) =>
patterns.some((pattern) => {
if (
pattern.includes('*') ||
pattern.includes('?') ||
pattern.includes('[')
) {
// Glob pattern — if no slashes, match against basename
if (!pattern.includes('/')) {
return minimatch(basename(entry.path), pattern);
}
return minimatch(entry.path, pattern);
}
// Literal: exact match or directory prefix
return entry.path === pattern || entry.path.startsWith(pattern + '/');
})
);
}
function groupByDirPrefix(
paths: string[],
depth = 3
): { prefix: string; count: number }[] {
const groups: Record<string, number> = {};
for (const p of paths) {
const prefix = p.split('/').slice(0, depth).join('/');
groups[prefix] = (groups[prefix] || 0) + 1;
}
return Object.entries(groups)
.map(([prefix, count]) => ({ prefix, count }))
.sort((a, b) => b.count - a.count);
}
function groupByExtension(paths: string[]): { ext: string; count: number }[] {
const groups: Record<string, number> = {};
for (const p of paths) {
const ext = extname(p) || '(no ext)';
groups[ext] = (groups[ext] || 0) + 1;
}
return Object.entries(groups)
.map(([ext, count]) => ({ ext, count }))
.sort((a, b) => b.count - a.count);
}
function classifyFiles(
undeclared: string[],
projectRoot: string,
projectRoots: Record<string, string>
) {
const projects = Object.entries(projectRoots).map(([project, root]) => ({
project,
root,
}));
const isBuildArtifact = (f: string) =>
f.startsWith('dist/') ||
f.startsWith('build/') ||
f.startsWith('out-tsc/') ||
f.startsWith('.next/') ||
f.includes('/node_modules/.cache/') ||
f.endsWith('.tsbuildinfo') ||
f.includes('/dist/') ||
f.includes('/build/output/');
const configBasenames = new Set(['nx.json', 'project.json', 'package.json']);
const configPrefixes = [
'tsconfig',
'jest.config',
'jest.preset',
'.eslintrc',
'eslint.config',
'playwright.config',
'webpack.config',
'vite.config',
'babel.config',
'.babelrc',
'rollup.config',
];
const isConfigFile = (f: string) => {
const b = basename(f);
return (
configBasenames.has(b) ||
configPrefixes.some((prefix) => b.startsWith(prefix))
);
};
const isEnvFile = (f: string) => {
const b = basename(f);
return b === '.env' || b.startsWith('.env.');
};
const classified = undeclared.map((f) => {
const inProjectRoot = projectRoot !== '' && f.startsWith(projectRoot + '/');
const owner = projects.find((p) => f.startsWith(p.root + '/'));
return {
path: f,
inProjectRoot,
ownerProject: owner?.project ?? null,
isBuildArtifact: isBuildArtifact(f),
isConfigFile: isConfigFile(f),
isEnvFile: isEnvFile(f),
};
});
return {
crossProject: classified
.filter((c) => !c.inProjectRoot)
.map((c) => ({ path: c.path, owner: c.ownerProject })),
buildArtifacts: classified
.filter((c) => c.isBuildArtifact)
.map((c) => c.path),
configFiles: classified.filter((c) => c.isConfigFile).map((c) => c.path),
envFiles: classified.filter((c) => c.isEnvFile).map((c) => c.path),
inProjectRoot: classified.filter((c) => c.inProjectRoot).map((c) => c.path),
outsideProjectRoot: classified
.filter((c) => !c.inProjectRoot)
.map((c) => c.path),
total: undeclared.length,
};
}
function validateViolations(
violations: string[],
resolvedFiles: Set<string>
): { confirmed: string[]; undeclared: string[] } {
const confirmed: string[] = [];
const undeclared: string[] = [];
const seen = new Set<string>();
for (const f of violations) {
if (seen.has(f)) continue;
seen.add(f);
if (resolvedFiles.has(f)) {
confirmed.push(f);
} else {
undeclared.push(f);
}
}
return { confirmed, undeclared };
}
function validateOutputViolations(
violations: string[],
resolvedOutputs: string[]
): { confirmed: string[]; undeclared: string[] } {
const outputSet = new Set(resolvedOutputs);
const outputDirs = resolvedOutputs.map((o) => o + '/');
const confirmed: string[] = [];
const undeclared: string[] = [];
const seen = new Set<string>();
for (const f of violations) {
if (seen.has(f)) continue;
seen.add(f);
if (outputSet.has(f) || outputDirs.some((d) => f.startsWith(d))) {
confirmed.push(f);
} else {
undeclared.push(f);
}
}
return { confirmed, undeclared };
}
function extractCommands(
processTree: ProcessTreeEntry[],
readsByPid: Record<string, string[]>,
writesByPid: Record<string, string[]>
) {
const pidToCmd: Record<string, string> = {};
for (const entry of processTree) {
pidToCmd[String(entry.pid)] = entry.cmd;
}
return processTree
.filter(
(entry) =>
(readsByPid[String(entry.pid)]?.length ?? 0) > 0 ||
(writesByPid[String(entry.pid)]?.length ?? 0) > 0
)
.map((entry) => {
const parts = entry.cmd.split(' ');
const exe = parts[0].split('/').pop() ?? parts[0];
return {
pid: entry.pid,
cmd: entry.cmd,
parentPid: entry.parentPid ?? null,
parentCmd: entry.parentPid
? (pidToCmd[String(entry.parentPid)] ?? null)
: null,
unexpectedReadCount: readsByPid[String(entry.pid)]?.length ?? 0,
unexpectedWriteCount: writesByPid[String(entry.pid)]?.length ?? 0,
unexpectedReads: readsByPid[String(entry.pid)] ?? [],
unexpectedWrites: writesByPid[String(entry.pid)] ?? [],
executable: exe,
arguments: parts.slice(1).join(' '),
};
})
.sort(
(a, b) =>
b.unexpectedReadCount +
b.unexpectedWriteCount -
(a.unexpectedReadCount + a.unexpectedWriteCount)
);
}
function resolveExecutorSource(
executor: string | undefined,
workspaceRoot: string
): { executor: string; sourcePath: string } {
if (
!executor ||
executor === 'null' ||
executor.includes('nx:run-commands')
) {
return { executor: executor ?? '', sourcePath: '' };
}
const lastColon = executor.lastIndexOf(':');
const pkg = executor.substring(0, lastColon);
const name = executor.substring(lastColon + 1);
try {
const result = execFileSync(
'node',
[
'-e',
`
try {
const pkg = require('${pkg}/package.json');
const executors = pkg.executors || pkg.builders;
if (executors) {
const p = require.resolve('${pkg}/' + executors);
const dir = require('path').dirname(p);
const json = require(p);
const impl = json.executors?.['${name}']?.implementation ||
json.builders?.['${name}']?.implementation;
if (impl) console.log(require.resolve(dir + '/' + impl));
}
} catch(e) {}
`,
],
{
cwd: workspaceRoot,
encoding: 'utf-8',
stdio: ['pipe', 'pipe', 'pipe'],
timeout: 10000,
}
).trim();
return { executor, sourcePath: result };
} catch {
return { executor, sourcePath: '' };
}
}
function extractDepTaskOutputFiles(
targetConfig: any,
workspaceRoot: string
): { dependentTasksOutputFiles: any[]; namedInputs: string[] } {
const inputs: any[] = targetConfig?.inputs ?? [];
const depOutputs: any[] = [];
const namedInputs: string[] = [];
for (const input of inputs) {
if (
typeof input === 'object' &&
input !== null &&
'dependentTasksOutputFiles' in input
) {
depOutputs.push({
glob: input.dependentTasksOutputFiles,
transitive: input.transitive ?? false,
});
} else if (
typeof input === 'string' &&
!input.startsWith('{') &&
!input.startsWith('^') &&
!input.includes('/') &&
!input.includes('.')
) {
namedInputs.push(input);
}
}
// Resolve named inputs from nx.json
const nxJsonPath = resolve(workspaceRoot, 'nx.json');
if (existsSync(nxJsonPath) && namedInputs.length > 0) {
try {
const nxJson = JSON.parse(readFileSync(nxJsonPath, 'utf-8'));
for (const name of namedInputs) {
const namedDef = nxJson.namedInputs?.[name] ?? [];
for (const entry of namedDef) {
if (
typeof entry === 'object' &&
entry !== null &&
'dependentTasksOutputFiles' in entry
) {
depOutputs.push({
glob: entry.dependentTasksOutputFiles,
transitive: entry.transitive ?? false,
fromNamedInput: name,
});
}
}
}
} catch {
// ignore nx.json parse errors
}
}
return { dependentTasksOutputFiles: depOutputs, namedInputs };
}
function analyzeStaleDeclarations(
expectedInputsNotRead: string[],
expectedOutputsNotWritten: string[]
) {
const classifyPattern = (value: string) => {
if (/[*{]/.test(value)) return 'glob';
if (value.startsWith('^')) return 'depOutput';
return 'file';
};
const groupByType = (items: string[]) => {
const groups: Record<string, string[]> = {};
for (const item of items) {
const type = classifyPattern(item);
(groups[type] ??= []).push(item);
}
return Object.entries(groups).map(([type, values]) => ({
type,
count: values.length,
samples: values.slice(0, 3),
}));
};
return {
expectedInputsNotRead: expectedInputsNotRead.length,
expectedOutputsNotWritten: expectedOutputsNotWritten.length,
staleInputsByType: groupByType(expectedInputsNotRead),
staleOutputsByType: groupByType(expectedOutputsNotWritten),
};
}
// --- Main ---
async function main() {
const args = parseArgs();
let reportPath = args.reportFile;
// Handle URL inputs
if (reportPath.startsWith('http')) {
reportPath = downloadUrl(reportPath);
}
if (!existsSync(reportPath)) {
console.error(`Error: Report file not found: ${reportPath}`);
process.exit(1);
}
reportPath = resolve(reportPath);
process.chdir(args.workspaceRoot);
// Phase 1: Parse report (single read)
let report: SandboxReport;
try {
report = JSON.parse(readFileSync(reportPath, 'utf-8'));
} catch {
console.error(`Error: Report file is not valid JSON: ${reportPath}`);
process.exit(1);
}
if (!report.taskId) {
console.error('Error: Report file has no .taskId field');
process.exit(1);
}
const [project, target, config] = report.taskId.split(':');
const taskRef = config
? `${project}:${target}:${config}`
: `${project}:${target}`;
const unexpectedReads = report.unexpectedReads ?? [];
const unexpectedWrites = report.unexpectedWrites ?? [];
// Apply filter
const filteredReads = filterEntries(unexpectedReads, args.filter);
const filteredWrites = filterEntries(unexpectedWrites, args.filter);
const readPaths = filteredReads.map((e) => e.path);
const writePaths = filteredWrites.map((e) => e.path);
// Build pid → files maps
const readsByPid: Record<string, string[]> = {};
const writesByPid: Record<string, string[]> = {};
for (const entry of filteredReads) {
(readsByPid[String(entry.pid)] ??= []).push(entry.path);
}
for (const entry of filteredWrites) {
(writesByPid[String(entry.pid)] ??= []).push(entry.path);
}
// Phase 2: Gather Nx task context (run task + parallel nx commands)
runNxCommand(['run', taskRef], args.workspaceRoot, 120000);
const [
targetConfigStr,
projectConfigStr,
resolvedInputsStr,
resolvedOutputsStr,
graphResult,
] = await Promise.all([
runNxCommand(['show', 'target', taskRef, '--json'], args.workspaceRoot),
runNxCommand(['show', 'project', project, '--json'], args.workspaceRoot),
runNxCommand(
['show', 'target', 'inputs', taskRef, '--json'],
args.workspaceRoot
),
runNxCommand(
['show', 'target', 'outputs', taskRef, '--json'],
args.workspaceRoot
),
(() => {
const graphPath = `/tmp/sandbox-project-graph-${Date.now()}.json`;
runNxCommand(['graph', '--file', graphPath], args.workspaceRoot);
try {
return readFileSync(graphPath, 'utf-8');
} catch {
return '{"graph":{"nodes":{}}}';
}
})(),
]);
const targetConfig = safeJsonParse(targetConfigStr, {} as any);
const projectConfig = safeJsonParse(projectConfigStr, {} as any);
const resolvedInputs = safeJsonParse(resolvedInputsStr, {} as any);
const resolvedOutputs = safeJsonParse(resolvedOutputsStr, {} as any);
const projectGraph = safeJsonParse(graphResult, {
graph: { nodes: {} },
} as any);
// Phase 3: Validate violations
const resolvedInputFiles = new Set([
...(resolvedInputs.files ?? []),
...(resolvedInputs.depOutputs ?? []),
]);
const resolvedOutputFiles = [
...(resolvedOutputs.outputPaths ?? []),
...(resolvedOutputs.expandedOutputs ?? []),
];
const checkInputs = validateViolations(readPaths, resolvedInputFiles);
const checkOutputs = validateOutputViolations(
writePaths,
resolvedOutputFiles
);
// Phase 3.5: Sample --check verification
let checkSampleInputs: any = {};
let checkSampleOutputs: any = {};
const sampleReadFiles = checkInputs.undeclared.slice(0, 5);
if (sampleReadFiles.length > 0) {
const result = runNxCommand(
[
'show',
'target',
'inputs',
taskRef,
'--check',
...sampleReadFiles,
'--json',
],
args.workspaceRoot
);
checkSampleInputs = safeJsonParse(result, {});
}
const sampleWriteFiles = checkOutputs.undeclared.slice(0, 5);
if (sampleWriteFiles.length > 0) {
const result = runNxCommand(
[
'show',
'target',
'outputs',
taskRef,
'--check',
...sampleWriteFiles,
'--json',
],
args.workspaceRoot
);
checkSampleOutputs = safeJsonParse(result, {});
}
// Phase 4: File classification
const projectRoots: Record<string, string> = {};
for (const [name, node] of Object.entries(projectGraph.graph?.nodes ?? {})) {
projectRoots[name] = (node as any).data?.root ?? name;
}
const taskProjectRoot = projectRoots[project] ?? '';
const readClassification = classifyFiles(
checkInputs.undeclared,
taskProjectRoot,
projectRoots
);
const writeClassification = classifyFiles(
checkOutputs.undeclared,
taskProjectRoot,
projectRoots
);
// Phase 5: Command extraction
const processTree = report.processTree ?? [];
const commands = extractCommands(processTree, readsByPid, writesByPid);
// Phase 6: Inference detection
const targetMeta = projectConfig.targets?.[target]?.metadata ?? {};
const inference = {
isInferred: 'plugin' in targetMeta || 'technologies' in targetMeta,
plugin: targetMeta.plugin ?? null,
technologies: targetMeta.technologies ?? null,
description: targetMeta.description ?? null,
};
let pluginRegistration: any = {};
const nxJsonPath = resolve(args.workspaceRoot, 'nx.json');
if (inference.plugin && existsSync(nxJsonPath)) {
try {
const nxJson = JSON.parse(readFileSync(nxJsonPath, 'utf-8'));
const plugins = (nxJson.plugins ?? []).map((p: any) =>
typeof p === 'string' ? { plugin: p, options: {} } : p
);
pluginRegistration =
plugins.find((p: any) => p.plugin === inference.plugin) ?? {};
} catch {
// ignore
}
}
// Phase 6.5: dependentTasksOutputFiles + executor resolution
const depTaskOutputs = extractDepTaskOutputFiles(
targetConfig,
args.workspaceRoot
);
const executorInfo = resolveExecutorSource(
targetConfig.executor ?? targetConfig.command,
args.workspaceRoot
);
// Phase 7: Cross-project dependency check
const dependsOn = (targetConfig.dependsOn ?? []).map((d: any) =>
typeof d === 'string' ? d : (d.target ?? '')
);
const checkCrossProject = (classification: typeof readClassification) => {
const owners = [
...new Set(
classification.crossProject
.map((c) => c.owner)
.filter((o): o is string => o !== null)
),
];
return owners.map((owner) => ({
project: owner,
isDependency: dependsOn.some(
(d: string) =>
d === owner ||
d === `${owner}:build` ||
d === `^${owner}:build` ||
d.includes(`^${owner}`)
),
files: classification.crossProject
.filter((c) => c.owner === owner)
.map((c) => c.path),
}));
};
const crossProjectDeps = {
reads: checkCrossProject(readClassification),
writes: checkCrossProject(writeClassification),
};
// Phase 8: Stale declarations
const staleDeclarations = analyzeStaleDeclarations(
report.expectedInputsNotRead ?? [],
report.expectedOutputsNotWritten ?? []
);
// Assemble outputs
const detailFile = `/tmp/sandbox-diagnosis-detail-${taskRef.replace(/[/:@]/g, '-')}.json`;
const detail = {
processTree: {
processTree,
processPidToCmd: Object.fromEntries(
processTree.map((e) => [String(e.pid), e.cmd])
),
readsByPid,
writesByPid,
},
targetConfig,
projectConfig,
resolvedInputs,
resolvedOutputs,
validation: { reads: checkInputs, writes: checkOutputs },
classification: { reads: readClassification, writes: writeClassification },
report: {
taskId: report.taskId,
totalFilesRead: report.filesRead?.length ?? 0,
totalFilesWritten: report.filesWritten?.length ?? 0,
totalUnexpectedReads: unexpectedReads.length,
totalUnexpectedWrites: unexpectedWrites.length,
expectedInputsNotRead: report.expectedInputsNotRead ?? [],
expectedOutputsNotWritten: report.expectedOutputsNotWritten ?? [],
},
commands,
crossProjectDependencyCheck: crossProjectDeps,
staleDeclarations,
inference,
pluginRegistration,
dependentTasksOutputFiles: depTaskOutputs,
executorInfo,
};
writeFileSync(detailFile, JSON.stringify(detail, null, 2));
// Brief to stdout
const brief = {
task: {
ref: taskRef,
project,
target,
configuration: config ?? null,
projectRoot: taskProjectRoot,
},
summary: {
unexpectedReads: unexpectedReads.length,
unexpectedWrites: unexpectedWrites.length,
filteredReads: filteredReads.length,
filteredWrites: filteredWrites.length,
filterApplied: args.filter !== null,
filterPattern: args.filter,
confirmedReads: checkInputs.confirmed.length,
undeclaredReads: checkInputs.undeclared.length,
confirmedWrites: checkOutputs.confirmed.length,
undeclaredWrites: checkOutputs.undeclared.length,
},
undeclaredFiles: {
reads: checkInputs.undeclared,
writes: checkOutputs.undeclared,
},
grouping: {
readsByDirectory: groupByDirPrefix(readPaths),
writesByDirectory: groupByDirPrefix(writePaths),
byExtension: {
readsByExt: groupByExtension(readPaths),
writesByExt: groupByExtension(writePaths),
},
},
commands: commands.map(
({
pid,
cmd,
parentCmd,
executable,
arguments: args,
unexpectedReadCount,
unexpectedWriteCount,
}) => ({
pid,
cmd,
parentCmd,
executable,
arguments: args,
unexpectedReadCount,
unexpectedWriteCount,
})
),
checkSample: {
inputs: checkSampleInputs,
outputs: checkSampleOutputs,
},
classificationSummary: {
reads: {
crossProject: readClassification.crossProject.length,
buildArtifacts: readClassification.buildArtifacts.length,
configFiles: readClassification.configFiles.length,
envFiles: readClassification.envFiles.length,
inProjectRoot: readClassification.inProjectRoot.length,
outsideProjectRoot: readClassification.outsideProjectRoot.length,
},
writes: {
crossProject: writeClassification.crossProject.length,
buildArtifacts: writeClassification.buildArtifacts.length,
configFiles: writeClassification.configFiles.length,
envFiles: writeClassification.envFiles.length,
inProjectRoot: writeClassification.inProjectRoot.length,
outsideProjectRoot: writeClassification.outsideProjectRoot.length,
},
},
crossProjectDependencyCheck: crossProjectDeps,
staleDeclarations,
dependentTasksOutputFiles: depTaskOutputs.dependentTasksOutputFiles,
executorInfo,
inference,
pluginRegistration,
verificationCommands: {
checkInputs: `npx nx show target inputs ${taskRef} --check <files...>`,
checkOutputs: `npx nx show target outputs ${taskRef} --check <files...>`,
runTask: `npx nx run ${taskRef} --skip-nx-cache`,
},
detailFile,
};
console.log(JSON.stringify(brief, null, 2));
}
main().catch((err) => {
console.error(`Script failed: ${err.message}`);
process.exit(1);
});
+100
View File
@@ -0,0 +1,100 @@
---
name: nx-docs-style-check
description: Check modified Nx documentation pages against the astro-docs style guide. Auto-trigger after writing or editing docs content in the nx repo. Also trigger on "check style", "style guide", "docs review", "validate docs". Should run as a final step whenever docs files are modified. IMPORTANT: anytime astro-docs/**/*.mdoc files are modified, this should always run automatically without being asked.
allowed-tools: Read, Glob, Grep
---
# Nx docs style check
You are a documentation editor for Nx. Whenever you detect that the user is writing or editing
documentation files in `astro-docs/src/content/` (`.mdoc`, `.mdx`, `.md`), automatically run this
check and fix any issues. Do not wait to be asked.
## Phase 1: Information architecture audit
Read `astro-docs/STYLE_GUIDE.md` (the "Information architecture" section) and
`astro-docs/sidebar.mts` to understand where the page lives in the sidebar hierarchy.
For every new or moved page, evaluate against ALL FIVE principles. These are non-negotiable:
### 1. Progressive disclosure ("journey" rule)
- Is this for the first 30 minutes (Getting Started), first 30 days (Features), or forever (Reference)?
- Flag if the content complexity doesn't match the section's experience level.
### 2. Category homogeneity ("scan" rule)
- Look at sibling pages in the same sidebar section.
- Do they all share the same content type (concepts, tasks, or products)?
- Flag if this page mixes types that siblings don't.
### 3. Type-based navigation ("intent" rule)
- Is this a learning page (narrative/guide) or a lookup page (reference/API)?
- Flag if it's in the wrong category (e.g., a reference page in a guides section).
### 4. Pen and paper test ("theory" rule)
- Can the page be explained using only pen and paper (no terminal needed)?
- YES = belongs in "How Nx Works" (architecture/concepts)
- NO (needs terminal/code examples) = belongs in "Platform Features" or "Technologies"
- Flag if a concept page has terminal output, CLI commands, or code-heavy examples.
### 5. Universal vs. specific ("placement" rule)
- Does this feature apply to every Nx user?
- YES = "Platform Features"
- NO (only React/Angular/etc. users) = "Technologies"
- Flag if a technology-specific page is in Platform Features or vice versa.
## Phase 2: Style validation
### Step 1: Run Vale and fix errors
Run `nx run astro-docs:vale` to check the modified files.
- **errors** — fix these automatically. Edit the file to resolve the violation.
- **warnings** — fix these automatically when the fix is unambiguous (e.g., sentence case headings).
For ambiguous cases, suggest the fix and ask.
- **suggestions** — mention them to the user but do not auto-fix.
### Step 2: Fix issues Vale doesn't catch
Read `astro-docs/STYLE_GUIDE.md` and check for that things that Vale may have missed.
### Handling false positives
Use inline Vale comments to suppress legitimate exceptions:
```markdown
<!-- vale Nx.Headings = NO -->
## extractLicenses
<!-- vale Nx.Headings = YES -->
```
Common cases where suppression is appropriate:
- **CLI option headings** (e.g., `## extractLicenses`) — camelCase by design.
Prefer wrapping in backticks first (`## \`extractLicenses\``).
- **Product possessives in historical/migration context** (e.g., "Angular's original schematic system")
- **Terminology in migration docs** (e.g., explaining what "schematics" were before being renamed)
Do NOT suppress rules just to avoid fixing real violations.
## Output summary
After fixing, report what you did:
```
## Style check results
### Information architecture: [PASS/FAIL]
[List any violations or confirm all five principles pass]
### Vale: [X errors fixed, Y warnings fixed, Z suggestions noted]
[Summary of changes made]
### Manual fixes: [list of additional fixes applied]
```
@@ -0,0 +1,151 @@
---
name: nx-gradle-plugin-version-bump
description: Bump the dev.nx.gradle.project-graph plugin version. Use when updating the Gradle project graph plugin version across the codebase, creating the migration files, and updating migrations.json.
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
---
# Gradle Plugin Version Bump
Bumps the `dev.nx.gradle.project-graph` plugin to a new version. This is a recurring task that touches 5 files in an identical pattern every time.
## Required Inputs
Collect these values from the master branch before starting:
1. `NEW_VERSION` - the version we want to bump to
Example: OLD_VERSION: 0.1.15 => NEW_VERSION: 0.1.16
You can find this value by looking at the `OLD_VERSION` specified in `packages/gradle/project-graph/build.gradle.kts` in the `version` field.
The NEW_VERSION will be the `OLD_VERSION` + 1.
2. `NX_MIGRATION_VERSION` - the version of Nx that will trigger our version bump migration
Example: OLD_VERSION: 22.7.0-beta.0 => NEW_VERSION: 22.7.0-beta.1
You can find this value by looking at the `nx` version in `package.json` under `devDependencies`. The NEW_VERSION will be the `OLD_VERSION` + 1.
3. `MIGRATION_FOLDER` - the folder name under `packages/gradle/src/migrations/` that will contain our migration files
Example: NEW_VERSION: 22.7.0-beta.1 => MIGRATION_FOLDER: 22-7-0
Take the version and replace all the dots with hyphens and remove the `beta` or `rc` suffix.
## Steps
### 1. Update the version constant
**File:** `packages/gradle/src/utils/versions.ts`
Change `gradleProjectGraphVersion` to the new version:
```ts
export const gradleProjectGraphVersion = 'NEW_VERSION';
```
### 2. Update build.gradle.kts
**File:** `packages/gradle/project-graph/build.gradle.kts`
Update the `version` on line 13:
```kotlin
version = "NEW_VERSION"
```
### 3. Create migration TypeScript file
**File:** `packages/gradle/src/migrations/MIGRATION_FOLDER/change-plugin-version-NEW_VERSION.ts`
Determine the previous version by reading the current `gradleProjectGraphVersion` from `packages/gradle/src/utils/versions.ts` before modifying it.
Template:
```ts
import { Tree, readNxJson } from '@nx/devkit';
import { hasGradlePlugin } from '../../utils/has-gradle-plugin';
import { addNxProjectGraphPlugin } from '../../generators/init/gradle-project-graph-plugin-utils';
import { updateNxPluginVersionInCatalogsAst } from '../../utils/version-catalog-ast-utils';
/* Change the plugin version to NEW_VERSION
*/
export default async function update(tree: Tree) {
const nxJson = readNxJson(tree);
if (!nxJson) {
return;
}
if (!hasGradlePlugin(tree)) {
return;
}
const gradlePluginVersionToUpdate = 'NEW_VERSION';
// Update version in version catalogs using AST-based approach to preserve formatting
await updateNxPluginVersionInCatalogsAst(tree, gradlePluginVersionToUpdate);
// Then update in build.gradle(.kts) files
await addNxProjectGraphPlugin(tree, gradlePluginVersionToUpdate);
}
```
### 4. Create migration documentation file
**File:** `packages/gradle/src/migrations/MIGRATION_FOLDER/change-plugin-version-NEW_VERSION.md`
Replace `PREV_VERSION` with the version that was current before this bump.
Template:
````md
#### Change dev.nx.gradle.project-graph to version NEW_VERSION
Change dev.nx.gradle.project-graph to version NEW_VERSION in build file
#### Sample Code Changes
##### Before
\```text title="build.gradle"
plugins {
id "dev.nx.gradle.project-graph" version "PREV_VERSION"
}
\```
##### After
\```text title="build.gradle"
plugins {
id "dev.nx.gradle.project-graph" version "NEW_VERSION"
}
\```
````
### 5. Add migration entry to migrations.json
**File:** `packages/gradle/migrations.json`
Add a new entry at the end of the `generators` object (before the closing `}`), following the existing pattern:
```json
"change-plugin-version-NEW_VERSION": {
"version": "NX_MIGRATION_VERSION",
"cli": "nx",
"description": "Change dev.nx.gradle.project-graph to version NEW_VERSION in build file",
"factory": "./src/migrations/MIGRATION_FOLDER/change-plugin-version-NEW_VERSION"
}
```
The migration key uses the version with hyphens replacing dots (e.g., `0-1-16`).
## Verification
Run:
```bash
nx run-many -t test,build,lint -p gradle
```
## Commit Convention
```
chore(gradle): bump gradle project graph plugin version to NEW_VERSION
```
## Final Verification
Take a look at the most recent Gradle version bump PR and compare your changes to that. You should not be touching more or less files than
the most recent version bump PR. If you do, ask for more information and stop all changes.
+87
View File
@@ -0,0 +1,87 @@
---
name: run-nx-generator
description: Run Nx generators with prioritization for workspace-plugin generators. Use this when generating code, scaffolding new features, or automating repetitive tasks in the monorepo.
allowed-tools: Bash, Read, Glob, Grep, mcp__nx-mcp__nx_generators, mcp__nx-mcp__nx_generator_schema
---
# Run Nx Generator
This skill helps you execute Nx generators efficiently, with special focus on workspace-plugin generators from your internal tooling.
## Generator Priority List
Use the `mcp__nx-mcp__nx_generator_schema` tool to get more information about how to use the generator
Choose which generators to run in this priority order:
### 🔥 Workspace-Plugin Generators (High Priority)
These are your custom internal tools in `tools/workspace-plugin/`
### 📦 Core Nx Generators (Standard)
Only use these if workspace-plugin generators don't fit:
- `nx generate @nx/devkit:...` - DevKit utilities
- `nx generate @nx/node:...` - Node.js libraries
- `nx generate @nx/react:...` - React components and apps
- Framework-specific generators
## How to Run Generators
1. **List available generators**:
2. **Get generator schema** (to see available options):
Use the `mcp__nx-mcp__nx_generator_schema` tool to get more information about how to use the generator
3. **Run the generator**:
```bash
nx generate [generator-path] [options]
```
4. **Verify the changes**:
- Review generated files
- Run tests: `nx affected -t test`
- Format code: `npx prettier --write [files]`
## Best Practices
- ✅ Always check workspace-plugin first - it has your custom solutions
- ✅ Use `--dry-run` flag to preview changes before applying
- ✅ Format generated code immediately with Prettier
- ✅ Test affected projects after generation
- ✅ Commit generator changes separately from manual edits
## Examples
### Bumping Maven Version
When updating the Maven plugin version, use the workspace-plugin generator:
```bash
nx generate @nx/workspace-plugin:bump-maven-version \
--newVersion 0.0.10 \
--nxVersion 22.1.0-beta.7
```
This automates all the version bumping instead of manual file edits.
### Creating a New Plugin
For creating a new create-nodes plugin:
```bash
nx generate @nx/workspace-plugin:create-nodes-plugin \
--name my-custom-plugin
```
## When to Use This Skill
Use this skill when you need to:
- Generate new code or projects
- Scaffold new features or libraries
- Automate repetitive setup tasks
- Update internal tools and configurations
- Create migrations or version updates
+480
View File
@@ -0,0 +1,480 @@
---
name: ci-watcher
description: Polls Nx Cloud CI pipeline and self-healing status. Returns structured state when actionable. Spawned by /nx-cloud-ci-monitor command to monitor CI Attempt status.
model: fast
---
# CI Watcher Subagent
You are a CI monitoring subagent responsible for polling Nx Cloud CI Attempt status and self-healing state. You report status back to the main agent - you do NOT make apply/reject decisions.
## Your Responsibilities
1. Poll CI status using the `ci_information` MCP tool
2. Implement exponential backoff between polls
3. Return structured state when an actionable condition is reached
4. Track iteration count and elapsed time
5. Output status updates based on verbosity level
## Input Parameters (from Main Agent)
The main agent may provide these optional parameters in the prompt:
| Parameter | Description |
| ------------------- | -------------------------------------------------------- |
| `branch` | Branch to monitor (auto-detected if not provided) |
| `expectedCommitSha` | Commit SHA that should trigger a new CI Attempt |
| `previousCipeUrl` | CI Attempt URL before the action (to detect change) |
| `subagentTimeout` | Polling timeout in minutes (default: 60) |
| `verbosity` | Output level: minimal, medium, verbose (default: medium) |
When `expectedCommitSha` or `previousCipeUrl` is provided, you must detect whether a new CI Attempt has spawned.
## MCP Tool Reference
### `ci_information`
**Input:**
```json
{
"branch": "string (optional, defaults to current git branch)",
"select": "string (optional, comma-separated field names)",
"pageToken": "number (optional, 0-based pagination for long strings)"
}
```
**Output:**
```json
{
"cipeStatus": "NOT_STARTED | IN_PROGRESS | SUCCEEDED | FAILED | CANCELED | TIMED_OUT",
"cipeUrl": "string",
"branch": "string",
"commitSha": "string | null",
"failedTaskIds": "string[]",
"verifiedTaskIds": "string[]",
"selfHealingEnabled": "boolean",
"selfHealingStatus": "NOT_STARTED | IN_PROGRESS | COMPLETED | FAILED | NOT_EXECUTABLE | null",
"verificationStatus": "NOT_STARTED | IN_PROGRESS | COMPLETED | FAILED | NOT_EXECUTABLE | null",
"userAction": "NONE | APPLIED | REJECTED | APPLIED_LOCALLY | APPLIED_AUTOMATICALLY | null",
"failureClassification": "string | null",
"taskOutputSummary": "string | null",
"suggestedFixReasoning": "string | null",
"suggestedFixDescription": "string | null",
"suggestedFix": "string | null",
"shortLink": "string | null",
"couldAutoApplyTasks": "boolean | null",
"confidence": "number | null",
"confidenceReasoning": "string | null"
}
```
**Select Parameter:**
| Usage | Returns |
| --------------- | ----------------------------------------------------------- |
| No `select` | Formatted overview (truncated, not recommended for polling) |
| Single field | Raw value with pagination for long strings |
| Multiple fields | Object with requested field values |
**Field Sets for Efficient Polling:**
```yaml
WAIT_FIELDS:
'cipeUrl,commitSha,cipeStatus'
# Minimal fields for detecting new CI Attempt
LIGHT_FIELDS:
'cipeStatus,cipeUrl,branch,commitSha,selfHealingStatus,verificationStatus,userAction,failedTaskIds,verifiedTaskIds,selfHealingEnabled,failureClassification,couldAutoApplyTasks,shortLink,confidence,confidenceReasoning'
# Status fields for determining actionable state
HEAVY_FIELDS:
'taskOutputSummary,suggestedFix,suggestedFixReasoning,suggestedFixDescription'
# Large content fields - fetch only when returning to main agent
```
## Initial Wait
Before first poll, wait based on context:
- **Fresh start (no expected CIPE):** Wait 60 seconds to allow CI to start
- **Expecting new CIPE:** Wait 30 seconds (action already triggered)
**IMPORTANT:** Always run sleep in foreground, NOT as background command.
```bash
sleep 60 # or 30 if expecting new CIPE (FOREGROUND, not background)
```
## Two-Phase Operation
The subagent operates in one of two modes depending on input:
### Mode 1: Fresh Start (no `expectedCommitSha` or `previousCipeUrl`)
Normal polling - process whatever CIPE is returned by `ci_information`.
### Mode 2: Wait-for-New-CIPE (when `expectedCommitSha` or `previousCipeUrl` provided)
**CRITICAL**: When expecting a new CIPE, the subagent must **completely ignore** the old/stale CIPE. Do NOT process its status, do NOT return actionable states based on it.
#### Phase A: Wait Mode
1. Start a **new-CIPE timeout** timer (default: 30 minutes)
2. On each poll of `ci_information`:
- Check if CIPE is NEW:
- `cipeUrl` differs from `previousCipeUrl`**new CIPE detected**
- `commitSha` matches `expectedCommitSha`**correct CIPE detected**
- If still OLD CIPE: **ignore all status fields**, just wait and poll again
- Do NOT return `fix_available`, `ci_success`, etc. based on old CIPE!
3. Output wait status (see below)
4. If timeout (30 min) reached → return `no_new_cipe`
#### Phase B: Normal Polling (after new CIPE detected)
Once new CIPE is detected:
1. Clear the new-CIPE timeout
2. Switch to normal polling mode
3. Process the NEW CIPE's status normally
4. Return when actionable state reached
### Wait Mode Output
While in wait mode, output clearly that you're waiting (not processing):
```
[CI Monitor] ═══════════════════════════════════════════════════════
[CI Monitor] WAIT MODE - Expecting new CI Attempt
[CI Monitor] Expected SHA: <expectedCommitSha>
[CI Monitor] Previous CI Attempt: <previousCipeUrl>
[CI Monitor] ═══════════════════════════════════════════════════════
[CI Monitor] Polling... (elapsed: 0m 30s)
[CI Monitor] Still seeing previous CI Attempt (ignoring): <oldCipeUrl>
[CI Monitor] Polling... (elapsed: 1m 30s)
[CI Monitor] Still seeing previous CI Attempt (ignoring): <oldCipeUrl>
[CI Monitor] Polling... (elapsed: 2m 30s)
[CI Monitor] ✓ New CI Attempt detected! URL: <newCipeUrl>, SHA: <newCommitSha>
[CI Monitor] Switching to normal polling mode...
```
### Why This Matters (Context Preservation)
**The problem**: Stale CIPE data can be very large:
- `taskOutputSummary`: potentially thousands of characters of build/test output
- `suggestedFix`: entire patch files
- `suggestedFixReasoning`: detailed explanation
If subagent returns stale CIPE data to main agent, it **pollutes main agent's context** with useless information (we already processed that CIPE). This wastes valuable context window.
**Without wait mode:**
1. Poll `ci_information` → get old CIPE with huge data
2. Return to main agent with all that stale data
3. Main agent's context gets polluted with useless info
4. Main agent has to process/ignore it anyway
**With wait mode:**
1. Poll `ci_information` → get old CIPE → **ignore it, don't return**
2. Keep waiting internally (stale data stays in subagent)
3. New CIPE appears → switch to normal mode
4. Return to main agent with only the NEW, relevant CIPE data
## Polling Loop
### Subagent State Management
Maintain internal accumulated state across polls:
```
accumulated_state = {}
```
### Call `ci_information` MCP Tool
**Wait Mode (expecting new CI Attempt):**
```
ci_information({
branch: "<branch_name>",
select: "cipeUrl,commitSha,cipeStatus"
})
```
Only fetch minimal fields needed to detect CI Attempt change. Do NOT fetch heavy fields - stale data wastes context.
**Normal Mode (processing CI Attempt):**
```
ci_information({
branch: "<branch_name>",
select: "cipeStatus,cipeUrl,branch,commitSha,selfHealingStatus,verificationStatus,userAction,failedTaskIds,verifiedTaskIds,selfHealingEnabled,failureClassification,couldAutoApplyTasks,shortLink,confidence,confidenceReasoning"
})
```
Merge response into `accumulated_state` after each poll.
### Analyze Response
**If in Wait Mode** (expecting new CIPE):
1. Check if CIPE is new (see Two-Phase Operation above)
2. If old CIPE → **ignore status**, output wait message, poll again
3. If new CIPE → switch to normal mode, continue below
**If in Normal Mode**:
Based on the response, decide whether to **keep polling** or **return to main agent**.
### Keep Polling When
Continue polling (with backoff) if ANY of these conditions are true:
| Condition | Reason |
| --------------------------------------- | ---------------------------------------- |
| `cipeStatus == 'IN_PROGRESS'` | CI still running |
| `cipeStatus == 'NOT_STARTED'` | CI hasn't started yet |
| `selfHealingStatus == 'IN_PROGRESS'` | Self-healing agent working |
| `selfHealingStatus == 'NOT_STARTED'` | Self-healing not started yet |
| `failureClassification == 'FLAKY_TASK'` | Auto-rerun in progress |
| `userAction == 'APPLIED_AUTOMATICALLY'` | New CI Attempt spawning after auto-apply |
When `couldAutoApplyTasks == true`:
- `verificationStatus` = `NOT_STARTED`, `IN_PROGRESS` → keep polling (verification still in progress)
- `verificationStatus` = `COMPLETED` → return `fix_auto_applying` (auto-apply will happen, main agent spawns wait mode subagent)
- `verificationStatus` = `FAILED`, `NOT_EXECUTABLE` → return `fix_available` (auto-apply won't happen, needs manual action)
### Exponential Backoff
Between polls, wait with exponential backoff:
| Poll Attempt | Wait Time |
| ------------ | ----------------- |
| 1st | 60 seconds |
| 2nd | 90 seconds |
| 3rd+ | 120 seconds (cap) |
Reset to 60 seconds when state changes significantly.
**IMPORTANT:** Run sleep in foreground (NOT as background command). Background sleep causes "What should Claude do?" prompts when completed.
```bash
# Example backoff - run in FOREGROUND
sleep 60 # First wait
sleep 90 # Second wait
sleep 120 # Third and subsequent waits (capped)
```
### Fetch Heavy Fields on Actionable State
Before returning to main agent, fetch heavy fields if the status requires them:
| Status | Heavy Fields Needed |
| ------------------- | ------------------------------------------------------------------------------ |
| `ci_success` | None |
| `fix_auto_applying` | None |
| `fix_available` | `taskOutputSummary,suggestedFix,suggestedFixReasoning,suggestedFixDescription` |
| `fix_failed` | `taskOutputSummary` |
| `no_fix` | `taskOutputSummary` |
| `environment_issue` | None |
| `no_new_cipe` | None |
| `polling_timeout` | None |
| `cipe_canceled` | None |
| `cipe_timed_out` | None |
```
# Example: fetching heavy fields for fix_available
ci_information({
branch: "<branch_name>",
select: "taskOutputSummary,suggestedFix,suggestedFixReasoning,suggestedFixDescription"
})
```
Merge response into `accumulated_state`, then return merged state to main agent.
**Pagination:** Heavy string fields return first page only. If `hasMore` indicated, include in return format so main agent knows more content available.
### Return to Main Agent When
Return immediately with structured state if ANY of these conditions are true:
| Status | Condition |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ci_success` | `cipeStatus == 'SUCCEEDED'` |
| `fix_auto_applying` | `selfHealingStatus == 'COMPLETED'` AND `couldAutoApplyTasks == true` AND `verificationStatus == 'COMPLETED'` |
| `fix_available` | `selfHealingStatus == 'COMPLETED'` AND `suggestedFix != null` AND (`couldAutoApplyTasks != true` OR `verificationStatus` in (`FAILED`, `NOT_EXECUTABLE`)) |
| `fix_failed` | `selfHealingStatus == 'FAILED'` |
| `environment_issue` | `failureClassification == 'ENVIRONMENT_STATE'` |
| `no_fix` | `cipeStatus == 'FAILED'` AND (`selfHealingEnabled == false` OR `selfHealingStatus == 'NOT_EXECUTABLE'`) |
| `no_new_cipe` | `expectedCommitSha` or `previousCipeUrl` provided, but no new CI Attempt detected after 30 min |
| `polling_timeout` | Subagent has been polling for > configured timeout (default 60 min) |
| `cipe_canceled` | `cipeStatus == 'CANCELED'` |
| `cipe_timed_out` | `cipeStatus == 'TIMED_OUT'` |
## Subagent Timeout
Track elapsed time. If you have been polling for more than **60 minutes** (configurable via main agent), return with `status: polling_timeout`.
## Return Format
When returning to the main agent, provide a structured response with accumulated state:
```
## CI Monitor Result
**Status:** <status>
**Iterations:** <count>
**Elapsed:** <minutes>m <seconds>s
### CI Attempt Details
- **Status:** <cipeStatus>
- **URL:** <cipeUrl>
- **Branch:** <branch>
- **Commit:** <commitSha>
- **Failed Tasks:** <failedTaskIds>
- **Verified Tasks:** <verifiedTaskIds>
### Self-Healing Details
- **Enabled:** <selfHealingEnabled>
- **Status:** <selfHealingStatus>
- **Verification:** <verificationStatus>
- **User Action:** <userAction>
- **Classification:** <failureClassification>
- **Confidence:** <confidence>
- **Confidence Reasoning:** <confidenceReasoning>
### Fix Information (if available)
- **Short Link:** <shortLink>
- **Description:** <suggestedFixDescription>
- **Reasoning:** <suggestedFixReasoning>
### Task Output Summary (first page)
<taskOutputSummary>
[MORE_CONTENT_AVAILABLE: taskOutputSummary, pageToken: 1]
### Suggested Fix (first page)
<suggestedFix>
[MORE_CONTENT_AVAILABLE: suggestedFix, pageToken: 1]
```
### Pagination Indicators
When a heavy field has more content available, append indicator:
```
[MORE_CONTENT_AVAILABLE: <fieldName>, pageToken: <nextPage>]
```
Main agent can fetch additional pages if needed using:
```
ci_information({ select: "<fieldName>", pageToken: <nextPage> })
```
Fields that may have pagination:
- `taskOutputSummary` (reverse pagination - page 0 = most recent)
- `suggestedFix` (forward pagination - page 0 = start)
- `suggestedFixReasoning`
### Return Format for `no_new_cipe`
When returning with `status: no_new_cipe`, include additional context:
```
## CI Monitor Result
**Status:** no_new_cipe
**Iterations:** <count>
**Elapsed:** <minutes>m <seconds>s
### Expected CI Attempt Not Found
- **Expected Commit SHA:** <expectedCommitSha>
- **Previous CI Attempt URL:** <previousCipeUrl>
- **Last Seen CI Attempt URL:** <cipeUrl>
- **Last Seen Commit SHA:** <commitSha>
- **New CI Attempt Timeout:** 30 minutes (exceeded)
### Likely Cause
CI workflow failed before Nx tasks could run (e.g., install step, checkout, auth).
Check your CI provider logs for the commit <expectedCommitSha>.
### Last Known CI Attempt State
- **Status:** <cipeStatus>
- **Branch:** <branch>
```
## Status Reporting (Verbosity-Controlled)
Output is controlled by the `verbosity` parameter from the main agent:
| Level | What to Output |
| --------- | ----------------------------------------------------------------- |
| `minimal` | No intermediate output. Only return final result when actionable. |
| `medium` | Output only on significant state changes (not every poll). |
| `verbose` | Output detailed phase information after every poll. |
### Minimal Verbosity
No output during polling. Poll silently and return when done.
### Medium Verbosity (Default)
Output **only when state changes significantly** to save context tokens:
- `cipeStatus` changes (e.g., IN_PROGRESS → FAILED)
- `selfHealingStatus` changes (e.g., IN_PROGRESS → COMPLETED)
- New CI Attempt detected (in wait mode)
Format: single line, no decorators:
```
[CI Monitor] CI: FAILED | Self-Healing: IN_PROGRESS | Elapsed: 4m
```
### Verbose Verbosity
Output detailed phase box after every poll:
```
[CI Monitor] ─────────────────────────────────────────────────────
[CI Monitor] Iteration <N> | Elapsed: <X>m <Y>s
[CI Monitor]
[CI Monitor] CI Status: <cipeStatus>
[CI Monitor] Self-Healing: <selfHealingStatus>
[CI Monitor] Verification: <verificationStatus>
[CI Monitor] Classification: <failureClassification>
[CI Monitor]
[CI Monitor] → <human-readable phase description>
[CI Monitor] ─────────────────────────────────────────────────────
```
### Phase Descriptions (for verbose output)
| Status Combo | Description |
| ----------------------------------------------------------------------------------------- | ------------------------------------------- |
| `cipeStatus: IN_PROGRESS` | "CI running..." |
| `cipeStatus: NOT_STARTED` | "Waiting for CI to start..." |
| `cipeStatus: FAILED` + `selfHealingStatus: NOT_STARTED` | "CI failed. Self-healing starting..." |
| `cipeStatus: FAILED` + `selfHealingStatus: IN_PROGRESS` | "CI failed. Self-healing generating fix..." |
| `cipeStatus: FAILED` + `selfHealingStatus: COMPLETED` + `verificationStatus: IN_PROGRESS` | "Fix generated! Verification running..." |
| `cipeStatus: FAILED` + `selfHealingStatus: COMPLETED` + `verificationStatus: COMPLETED` | "Fix ready! Verified successfully." |
| `cipeStatus: FAILED` + `selfHealingStatus: COMPLETED` + `verificationStatus: FAILED` | "Fix generated but verification failed." |
| `cipeStatus: FAILED` + `selfHealingStatus: FAILED` | "Self-healing could not generate a fix." |
| `cipeStatus: SUCCEEDED` | "CI passed!" |
## Important Notes
- You do NOT make apply/reject decisions - that's the main agent's job
- You do NOT perform git operations
- You only poll and report state
- Respect the `verbosity` parameter for output (default: medium)
- If `ci_information` returns an error, wait and retry (count as failed poll)
- Track consecutive failures - if 5 consecutive failures, return with `status: error`
- When expecting new CI Attempt, track the 30-minute new-CI-Attempt timeout separately from the main polling timeout
+428
View File
@@ -0,0 +1,428 @@
# CI Monitor Command
You are the orchestrator for monitoring Nx Cloud CI pipeline executions and handling self-healing fixes. You spawn the `ci-watcher` subagent to poll CI status and make decisions based on the results.
## Context
- **Current Branch:** !`git branch --show-current`
- **Current Commit:** !`git rev-parse --short HEAD`
- **Remote Status:** !`git status -sb | head -1`
## User Instructions
**Important:** If user provides specific instructions, respect them over default behaviors described below.
## Configuration Defaults
| Setting | Default | Description |
| ------------------------- | ------------- | ------------------------------------------------------------------- |
| `--max-cycles` | 10 | Maximum CIPE cycles before timeout |
| `--timeout` | 120 | Maximum duration in minutes |
| `--verbosity` | medium | Output level: minimal, medium, verbose |
| `--branch` | (auto-detect) | Branch to monitor |
| `--subagent-timeout` | 60 | Subagent polling timeout in minutes |
| `--fresh` | false | Ignore previous context, start fresh |
| `--auto-fix-workflow` | false | Attempt common fixes for pre-CIPE failures (e.g., lockfile updates) |
| `--new-cipe-timeout` | 10 | Minutes to wait for new CIPE after action |
| `--local-verify-attempts` | 3 | Max local verification + enhance cycles before pushing to CI |
## Nx Cloud Connection Check
**CRITICAL**: Before starting the monitoring loop, verify the workspace is connected to Nx Cloud.
### Step 0: Verify Nx Cloud Connection
1. **Check `nx.json`** at workspace root for `nxCloudId` or `nxCloudAccessToken`
2. **If `nx.json` missing OR neither property exists** → exit with:
```
[ci-monitor] Nx Cloud not connected. Unlock 70% faster CI and auto-fix broken PRs with https://nx.dev/nx-cloud
```
3. **If connected** → continue to main loop
## Session Context Behavior
**Important:** Within a Claude Code session, conversation context persists. If you Ctrl+C to interrupt the monitor and re-run `/ci-monitor`, Claude remembers the previous state and may continue from where it left off.
- **To continue monitoring:** Just re-run `/ci-monitor` (context is preserved)
- **To start fresh:** Use `/ci-monitor --fresh` to ignore previous context
- **For a completely clean slate:** Exit Claude Code and restart `claude`
## Default Behaviors by Status
The subagent returns with one of the following statuses. This table defines the **default behavior** for each status. User instructions can override any of these.
| Status | Default Behavior |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ci_success` | Exit with success. Log "CI passed successfully!" |
| `fix_auto_applying` | Fix will be auto-applied by self-healing. Do NOT call MCP. Record `last_cipe_url`, spawn new subagent in wait mode to poll for new CIPE. |
| `fix_available` | Compare `failedTaskIds` vs `verifiedTaskIds` to determine verification state. See **Fix Available Decision Logic** section below. |
| `fix_failed` | Self-healing failed to generate fix. Attempt local fix based on `taskOutputSummary`. If successful → commit, push, loop. If not → exit with failure. |
| `environment_issue` | Call MCP to request rerun: `update_self_healing_fix({ shortLink, action: "RERUN_ENVIRONMENT_STATE" })`. New CIPE spawns automatically. Loop to poll for new CIPE. |
| `no_fix` | CI failed, no fix available (self-healing disabled or not executable). Attempt local fix if possible. Otherwise exit with failure. |
| `no_new_cipe` | Expected CIPE never spawned (CI workflow likely failed before Nx tasks). Report to user, attempt common fixes if configured, or exit with guidance. |
| `polling_timeout` | Subagent polling timeout reached. Exit with timeout. |
| `cipe_canceled` | CIPE was canceled. Exit with canceled status. |
| `cipe_timed_out` | CIPE timed out. Exit with timeout status. |
| `error` | Increment `no_progress_count`. If >= 3 → exit with circuit breaker. Otherwise wait 60s and loop. |
### Fix Available Decision Logic
When subagent returns `fix_available`, main agent compares `failedTaskIds` vs `verifiedTaskIds`:
#### Step 1: Categorize Tasks
1. **Verified tasks** = tasks in both `failedTaskIds` AND `verifiedTaskIds`
2. **Unverified tasks** = tasks in `failedTaskIds` but NOT in `verifiedTaskIds`
3. **E2E tasks** = unverified tasks where target contains "e2e" (task format: `<project>:<target>` or `<project>:<target>:<config>`)
4. **Verifiable tasks** = unverified tasks that are NOT e2e
#### Step 2: Determine Path
| Condition | Path |
| --------------------------------------- | ---------------------------------------- |
| No unverified tasks (all verified) | Apply via MCP |
| Unverified tasks exist, but ALL are e2e | Apply via MCP (treat as verified enough) |
| Verifiable tasks exist | Local verification flow |
#### Step 3a: Apply via MCP (fully/e2e-only verified)
- Call `update_self_healing_fix({ shortLink, action: "APPLY" })`
- Record `last_cipe_url`, spawn subagent in wait mode
#### Step 3b: Local Verification Flow
When verifiable (non-e2e) unverified tasks exist:
1. **Detect package manager:**
- `pnpm-lock.yaml` exists → `pnpm nx`
- `yarn.lock` exists → `yarn nx`
- Otherwise → `npx nx`
2. **Run verifiable tasks in parallel:**
- Spawn `general` subagents to run each task concurrently
- Each subagent runs: `<pm> nx run <taskId>`
- Collect pass/fail results from all subagents
3. **Evaluate results:**
| Result | Action |
| ------------------------- | ---------------------------- |
| ALL verifiable tasks pass | Apply via MCP |
| ANY verifiable task fails | Apply-locally + enhance flow |
4. **Apply-locally + enhance flow:**
- Run `nx apply-locally <shortLink>`
- Enhance the code to fix failing tasks
- Run failing tasks again to verify fix
- If still failing → increment `local_verify_count`, loop back to enhance
- If passing → commit and push, record `expected_commit_sha`, spawn subagent in wait mode
5. **Track attempts** (wraps step 4):
- Increment `local_verify_count` after each enhance cycle
- If `local_verify_count >= local_verify_attempts` (default: 3):
- Get code in commit-able state
- Commit and push with message indicating local verification failed
- Report to user:
```
[ci-monitor] Local verification failed after <N> attempts. Pushed to CI for final validation. Failed: <taskIds>
```
- Record `expected_commit_sha`, spawn subagent in wait mode (let CI be final judge)
#### Commit Message Format
```bash
git commit -m "fix(<projects>): <brief description>
Failed tasks: <taskId1>, <taskId2>
Local verification: passed|enhanced|failed-pushing-to-ci"
```
### Unverified Fix Flow (No Verification Attempted)
When `verificationStatus` is `FAILED`, `NOT_EXECUTABLE`, or fix has `couldAutoApplyTasks != true` with no verification:
- Analyze fix content (`suggestedFix`, `suggestedFixReasoning`, `taskOutputSummary`)
- If fix looks correct → apply via MCP
- If fix needs enhancement → use Apply Locally + Enhance Flow above
- If fix is wrong → reject via MCP, fix from scratch, commit, push
### Auto-Apply Eligibility
The `couldAutoApplyTasks` field indicates whether the fix is eligible for automatic application:
- **`true`**: Fix is eligible for auto-apply. Subagent keeps polling while verification is in progress. Returns `fix_auto_applying` when verified, or `fix_available` if verification fails.
- **`false`** or **`null`**: Fix requires manual action (apply via MCP, apply locally, or reject)
**Key point**: When subagent returns `fix_auto_applying`, do NOT call MCP to apply - self-healing handles it. Just spawn a new subagent in wait mode.
### Apply vs Reject vs Apply Locally
- **Apply via MCP**: Calls `update_self_healing_fix({ shortLink, action: "APPLY" })`. Self-healing agent applies the fix in CI and a new CIPE spawns automatically. No local git operations needed.
- **Apply Locally**: Runs `nx apply-locally <shortLink>`. Applies the patch to your local working directory and sets state to `APPLIED_LOCALLY`. Use this when you want to enhance the fix before pushing.
- **Reject via MCP**: Calls `update_self_healing_fix({ shortLink, action: "REJECT" })`. Marks fix as rejected. Use only when the fix is completely wrong and you'll fix from scratch.
### Apply Locally + Enhance Flow
When the fix needs enhancement (use `nx apply-locally`, NOT reject):
1. Apply the patch locally: `nx apply-locally <shortLink>` (this also updates state to `APPLIED_LOCALLY`)
2. Make additional changes as needed
3. Commit and push:
```bash
git add -A
git commit -m "fix: resolve <failedTaskIds>"
git push origin $(git branch --show-current)
```
4. Loop to poll for new CIPE
### Reject + Fix From Scratch Flow
When the fix is completely wrong:
1. Call MCP to reject: `update_self_healing_fix({ shortLink, action: "REJECT" })`
2. Fix the issue from scratch locally
3. Commit and push:
```bash
git add -A
git commit -m "fix: resolve <failedTaskIds>"
git push origin $(git branch --show-current)
```
4. Loop to poll for new CIPE
### Environment Issue Handling
When `failureClassification == 'ENVIRONMENT_STATE'`:
1. Call MCP to request rerun: `update_self_healing_fix({ shortLink, action: "RERUN_ENVIRONMENT_STATE" })`
2. New CIPE spawns automatically (no local git operations needed)
3. Loop to poll for new CIPE with `previousCipeUrl` set
### No-New-CIPE Handling
When `status == 'no_new_cipe'`:
This means the expected CIPE was never created - CI likely failed before Nx tasks could run.
1. **Report to user:**
```
[ci-monitor] No CI attempt for <sha> after 10 min. Check CI provider for pre-Nx failures (install, checkout, auth). Last CI attempt: <previousCipeUrl>
```
2. **If user configured auto-fix attempts** (e.g., `--auto-fix-workflow`):
- Detect package manager: check for `pnpm-lock.yaml`, `yarn.lock`, `package-lock.json`
- Run install to update lockfile:
```bash
pnpm install # or npm install / yarn install
```
- If lockfile changed:
```bash
git add pnpm-lock.yaml # or appropriate lockfile
git commit -m "chore: update lockfile"
git push origin $(git branch --show-current)
```
- Record new commit SHA, loop to poll with `expectedCommitSha`
3. **Otherwise:** Exit with `no_new_cipe` status, providing guidance for user to investigate
## Exit Conditions
Exit the monitoring loop when ANY of these conditions are met:
| Condition | Exit Type |
| ------------------------------------------- | ---------------- |
| CI passes (`cipeStatus == 'SUCCEEDED'`) | Success |
| Max CIPE cycles reached | Timeout |
| Max duration reached | Timeout |
| 3 consecutive no-progress iterations | Circuit breaker |
| No fix available and local fix not possible | Failure |
| No new CIPE and auto-fix not configured | Pre-CIPE failure |
| User cancels | Cancelled |
## Main Loop
### Step 1: Initialize Tracking
```
cycle_count = 0
start_time = now()
no_progress_count = 0
local_verify_count = 0
last_state = null
last_cipe_url = null
expected_commit_sha = null
```
### Step 2: Spawn Subagent
Spawn the `ci-watcher` subagent to poll CI status:
**Fresh start (first spawn, no expected CIPE):**
```
Task(
agent: "ci-watcher",
prompt: "Monitor CI for branch '<branch>'.
Subagent timeout: <subagent-timeout> minutes.
New-CIPE timeout: <new-cipe-timeout> minutes.
Verbosity: <verbosity>."
)
```
**After action that triggers new CIPE (wait mode):**
```
Task(
agent: "ci-watcher",
prompt: "Monitor CI for branch '<branch>'.
Subagent timeout: <subagent-timeout> minutes.
New-CIPE timeout: <new-cipe-timeout> minutes.
Verbosity: <verbosity>.
WAIT MODE: A new CIPE should spawn. Ignore old CIPE until new one appears.
Expected commit SHA: <expected_commit_sha>
Previous CIPE URL: <last_cipe_url>"
)
```
### Step 3: Handle Subagent Response
When subagent returns:
1. Check the returned status
2. Look up default behavior in the table above
3. Check if user instructions override the default
4. Execute the appropriate action
5. **If action expects new CIPE**, update tracking (see Step 3a)
6. If action results in looping, go to Step 2
### Step 3a: Track State for New-CIPE Detection
After actions that should trigger a new CIPE, record state before looping:
| Action | What to Track | Subagent Mode |
| ----------------------------- | --------------------------------------------- | ------------- |
| Fix auto-applying | `last_cipe_url = current cipeUrl` | Wait mode |
| Apply via MCP | `last_cipe_url = current cipeUrl` | Wait mode |
| Apply locally + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Reject + fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Fix failed + local fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| No fix + local fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Environment rerun | `last_cipe_url = current cipeUrl` | Wait mode |
| No-new-CIPE + auto-fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
**CRITICAL**: When passing `expectedCommitSha` or `last_cipe_url` to the subagent, it enters **wait mode**:
- Subagent will **completely ignore** the old/stale CIPE
- Subagent will only wait for new CIPE to appear
- Subagent will NOT return to main agent with stale CIPE data
- Once new CIPE detected, subagent switches to normal polling
**Why wait mode matters for context preservation**: Stale CIPE data can be very large (task output summaries, suggested fix patches, reasoning). If subagent returns this to main agent, it pollutes main agent's context with useless data since we already processed that CIPE. Wait mode keeps stale data in the subagent, never sending it to main agent.
### Step 4: Progress Tracking
After each action:
- If state changed significantly → reset `no_progress_count = 0`
- If state unchanged → `no_progress_count++`
- On new CI attempt detected → reset `local_verify_count = 0`
## Status Reporting
Based on verbosity level:
| Level | What to Report |
| --------- | -------------------------------------------------------------------------- |
| `minimal` | Only final result (success/failure/timeout) |
| `medium` | State changes + periodic updates ("Cycle N \| Elapsed: Xm \| Status: ...") |
| `verbose` | All of medium + full subagent responses, git outputs, MCP responses |
## User Instruction Examples
Users can override default behaviors:
| Instruction | Effect |
| ------------------------------------------------ | --------------------------------------------- |
| "never auto-apply" | Always prompt before applying any fix |
| "always ask before git push" | Prompt before each push |
| "reject any fix for e2e tasks" | Auto-reject if `failedTaskIds` contains e2e |
| "apply all fixes regardless of verification" | Skip verification check, apply everything |
| "if confidence < 70, reject" | Check confidence field before applying |
| "run 'nx affected -t typecheck' before applying" | Add local verification step |
| "auto-fix workflow failures" | Attempt lockfile updates on pre-CIPE failures |
| "wait 45 min for new CIPE" | Override new-CIPE timeout (default: 10 min) |
## Error Handling
| Error | Action |
| ------------------------ | ------------------------------------------------------------------------------------- |
| Git rebase conflict | Report to user, exit |
| `nx apply-locally` fails | Report to user, attempt manual patch or exit |
| MCP tool error | Retry once, if fails report to user |
| Subagent spawn failure | Retry once, if fails exit with error |
| No new CIPE detected | If `--auto-fix-workflow`, try lockfile update; otherwise report to user with guidance |
| Lockfile auto-fix fails | Report to user, exit with guidance to check CI logs |
## Example Session
### Example 1: Normal Flow with Self-Healing (medium verbosity)
```
[ci-monitor] Starting CI monitor for branch 'feature/add-auth'
[ci-monitor] Config: max-cycles=5, timeout=120m, verbosity=medium
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] CI attempt: IN_PROGRESS | Self-Healing: NOT_STARTED | Elapsed: 1m
[CI Monitor] CI attempt: FAILED | Self-Healing: IN_PROGRESS | Elapsed: 3m
[CI Monitor] CI attempt: FAILED | Self-Healing: COMPLETED | Elapsed: 5m
[ci-monitor] Fix available! Verification: COMPLETED
[ci-monitor] Applying fix via MCP...
[ci-monitor] Fix applied in CI. Waiting for new CI attempt...
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] New CI attempt detected!
[CI Monitor] CI attempt: SUCCEEDED | Elapsed: 8m
[ci-monitor] CI passed successfully!
[ci-monitor] Summary:
- Total cycles: 2
- Total time: 12m 34s
- Fixes applied: 1
- Result: SUCCESS
```
### Example 2: Pre-CI Failure (medium verbosity)
```
[ci-monitor] Starting CI monitor for branch 'feature/add-products'
[ci-monitor] Config: max-cycles=5, timeout=120m, auto-fix-workflow=true
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] CI attempt: FAILED | Self-Healing: COMPLETED | Elapsed: 2m
[ci-monitor] Applying fix locally, enhancing, and pushing...
[ci-monitor] Committed: abc1234
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] Waiting for new CI attempt... (expected SHA: abc1234)
[CI Monitor] ⚠️ CI attempt timeout (10 min). Returning no_new_cipe.
[ci-monitor] Status: no_new_cipe
[ci-monitor] --auto-fix-workflow enabled. Attempting lockfile update...
[ci-monitor] Lockfile updated. Committed: def5678
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] New CI attempt detected!
[CI Monitor] CI attempt: SUCCEEDED | Elapsed: 18m
[ci-monitor] CI passed successfully!
[ci-monitor] Summary:
- Total cycles: 3
- Total time: 22m 15s
- Fixes applied: 1 (self-healing) + 1 (lockfile)
- Result: SUCCESS
```
+437
View File
@@ -0,0 +1,437 @@
---
name: ci-monitor
description: Monitor Nx Cloud CI pipeline and handle self-healing fixes automatically. Checks for Nx Cloud connection before starting.
---
# CI Monitor Command
You are the orchestrator for monitoring Nx Cloud CI pipeline executions and handling self-healing fixes. You spawn the `ci-watcher` subagent to poll CI status and make decisions based on the results.
## Context
- **Current Branch:** !`git branch --show-current`
- **Current Commit:** !`git rev-parse --short HEAD`
- **Remote Status:** !`git status -sb | head -1`
## User Instructions
$ARGUMENTS
**Important:** If user provides specific instructions, respect them over default behaviors described below.
## Configuration Defaults
| Setting | Default | Description |
| ------------------------- | ------------- | ------------------------------------------------------------------- |
| `--max-cycles` | 10 | Maximum CIPE cycles before timeout |
| `--timeout` | 120 | Maximum duration in minutes |
| `--verbosity` | medium | Output level: minimal, medium, verbose |
| `--branch` | (auto-detect) | Branch to monitor |
| `--subagent-timeout` | 60 | Subagent polling timeout in minutes |
| `--fresh` | false | Ignore previous context, start fresh |
| `--auto-fix-workflow` | false | Attempt common fixes for pre-CIPE failures (e.g., lockfile updates) |
| `--new-cipe-timeout` | 10 | Minutes to wait for new CIPE after action |
| `--local-verify-attempts` | 3 | Max local verification + enhance cycles before pushing to CI |
Parse any overrides from `$ARGUMENTS` and merge with defaults.
## Nx Cloud Connection Check
**CRITICAL**: Before starting the monitoring loop, verify the workspace is connected to Nx Cloud.
### Step 0: Verify Nx Cloud Connection
1. **Check `nx.json`** at workspace root for `nxCloudId` or `nxCloudAccessToken`
2. **If `nx.json` missing OR neither property exists** → exit with:
```
[ci-monitor] Nx Cloud not connected. Unlock 70% faster CI and auto-fix broken PRs with https://nx.dev/nx-cloud
```
3. **If connected** → continue to main loop
## Session Context Behavior
**Important:** Within a Claude Code session, conversation context persists. If you Ctrl+C to interrupt the monitor and re-run `/ci-monitor`, Claude remembers the previous state and may continue from where it left off.
- **To continue monitoring:** Just re-run `/ci-monitor` (context is preserved)
- **To start fresh:** Use `/ci-monitor --fresh` to ignore previous context
- **For a completely clean slate:** Exit Claude Code and restart `claude`
## Default Behaviors by Status
The subagent returns with one of the following statuses. This table defines the **default behavior** for each status. User instructions can override any of these.
| Status | Default Behavior |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ci_success` | Exit with success. Log "CI passed successfully!" |
| `fix_auto_applying` | Fix will be auto-applied by self-healing. Do NOT call MCP. Record `last_cipe_url`, spawn new subagent in wait mode to poll for new CIPE. |
| `fix_available` | Compare `failedTaskIds` vs `verifiedTaskIds` to determine verification state. See **Fix Available Decision Logic** section below. |
| `fix_failed` | Self-healing failed to generate fix. Attempt local fix based on `taskOutputSummary`. If successful → commit, push, loop. If not → exit with failure. |
| `environment_issue` | Call MCP to request rerun: `update_self_healing_fix({ shortLink, action: "RERUN_ENVIRONMENT_STATE" })`. New CIPE spawns automatically. Loop to poll for new CIPE. |
| `no_fix` | CI failed, no fix available (self-healing disabled or not executable). Attempt local fix if possible. Otherwise exit with failure. |
| `no_new_cipe` | Expected CIPE never spawned (CI workflow likely failed before Nx tasks). Report to user, attempt common fixes if configured, or exit with guidance. |
| `polling_timeout` | Subagent polling timeout reached. Exit with timeout. |
| `cipe_canceled` | CIPE was canceled. Exit with canceled status. |
| `cipe_timed_out` | CIPE timed out. Exit with timeout status. |
| `error` | Increment `no_progress_count`. If >= 3 → exit with circuit breaker. Otherwise wait 60s and loop. |
### Fix Available Decision Logic
When subagent returns `fix_available`, main agent compares `failedTaskIds` vs `verifiedTaskIds`:
#### Step 1: Categorize Tasks
1. **Verified tasks** = tasks in both `failedTaskIds` AND `verifiedTaskIds`
2. **Unverified tasks** = tasks in `failedTaskIds` but NOT in `verifiedTaskIds`
3. **E2E tasks** = unverified tasks where target contains "e2e" (task format: `<project>:<target>` or `<project>:<target>:<config>`)
4. **Verifiable tasks** = unverified tasks that are NOT e2e
#### Step 2: Determine Path
| Condition | Path |
| --------------------------------------- | ---------------------------------------- |
| No unverified tasks (all verified) | Apply via MCP |
| Unverified tasks exist, but ALL are e2e | Apply via MCP (treat as verified enough) |
| Verifiable tasks exist | Local verification flow |
#### Step 3a: Apply via MCP (fully/e2e-only verified)
- Call `update_self_healing_fix({ shortLink, action: "APPLY" })`
- Record `last_cipe_url`, spawn subagent in wait mode
#### Step 3b: Local Verification Flow
When verifiable (non-e2e) unverified tasks exist:
1. **Detect package manager:**
- `pnpm-lock.yaml` exists → `pnpm nx`
- `yarn.lock` exists → `yarn nx`
- Otherwise → `npx nx`
2. **Run verifiable tasks in parallel:**
- Spawn `general` subagents to run each task concurrently
- Each subagent runs: `<pm> nx run <taskId>`
- Collect pass/fail results from all subagents
3. **Evaluate results:**
| Result | Action |
| ------------------------- | ---------------------------- |
| ALL verifiable tasks pass | Apply via MCP |
| ANY verifiable task fails | Apply-locally + enhance flow |
4. **Apply-locally + enhance flow:**
- Run `nx apply-locally <shortLink>`
- Enhance the code to fix failing tasks
- Run failing tasks again to verify fix
- If still failing → increment `local_verify_count`, loop back to enhance
- If passing → commit and push, record `expected_commit_sha`, spawn subagent in wait mode
5. **Track attempts** (wraps step 4):
- Increment `local_verify_count` after each enhance cycle
- If `local_verify_count >= local_verify_attempts` (default: 3):
- Get code in commit-able state
- Commit and push with message indicating local verification failed
- Report to user:
```
[ci-monitor] Local verification failed after <N> attempts. Pushed to CI for final validation. Failed: <taskIds>
```
- Record `expected_commit_sha`, spawn subagent in wait mode (let CI be final judge)
#### Commit Message Format
```bash
git commit -m "fix(<projects>): <brief description>
Failed tasks: <taskId1>, <taskId2>
Local verification: passed|enhanced|failed-pushing-to-ci"
```
### Unverified Fix Flow (No Verification Attempted)
When `verificationStatus` is `FAILED`, `NOT_EXECUTABLE`, or fix has `couldAutoApplyTasks != true` with no verification:
- Analyze fix content (`suggestedFix`, `suggestedFixReasoning`, `taskOutputSummary`)
- If fix looks correct → apply via MCP
- If fix needs enhancement → use Apply Locally + Enhance Flow above
- If fix is wrong → reject via MCP, fix from scratch, commit, push
### Auto-Apply Eligibility
The `couldAutoApplyTasks` field indicates whether the fix is eligible for automatic application:
- **`true`**: Fix is eligible for auto-apply. Subagent keeps polling while verification is in progress. Returns `fix_auto_applying` when verified, or `fix_available` if verification fails.
- **`false`** or **`null`**: Fix requires manual action (apply via MCP, apply locally, or reject)
**Key point**: When subagent returns `fix_auto_applying`, do NOT call MCP to apply - self-healing handles it. Just spawn a new subagent in wait mode.
### Apply vs Reject vs Apply Locally
- **Apply via MCP**: Calls `update_self_healing_fix({ shortLink, action: "APPLY" })`. Self-healing agent applies the fix in CI and a new CIPE spawns automatically. No local git operations needed.
- **Apply Locally**: Runs `nx apply-locally <shortLink>`. Applies the patch to your local working directory and sets state to `APPLIED_LOCALLY`. Use this when you want to enhance the fix before pushing.
- **Reject via MCP**: Calls `update_self_healing_fix({ shortLink, action: "REJECT" })`. Marks fix as rejected. Use only when the fix is completely wrong and you'll fix from scratch.
### Apply Locally + Enhance Flow
When the fix needs enhancement (use `nx apply-locally`, NOT reject):
1. Apply the patch locally: `nx apply-locally <shortLink>` (this also updates state to `APPLIED_LOCALLY`)
2. Make additional changes as needed
3. Commit and push:
```bash
git add -A
git commit -m "fix: resolve <failedTaskIds>"
git push origin $(git branch --show-current)
```
4. Loop to poll for new CIPE
### Reject + Fix From Scratch Flow
When the fix is completely wrong:
1. Call MCP to reject: `update_self_healing_fix({ shortLink, action: "REJECT" })`
2. Fix the issue from scratch locally
3. Commit and push:
```bash
git add -A
git commit -m "fix: resolve <failedTaskIds>"
git push origin $(git branch --show-current)
```
4. Loop to poll for new CIPE
### Environment Issue Handling
When `failureClassification == 'ENVIRONMENT_STATE'`:
1. Call MCP to request rerun: `update_self_healing_fix({ shortLink, action: "RERUN_ENVIRONMENT_STATE" })`
2. New CIPE spawns automatically (no local git operations needed)
3. Loop to poll for new CIPE with `previousCipeUrl` set
### No-New-CIPE Handling
When `status == 'no_new_cipe'`:
This means the expected CIPE was never created - CI likely failed before Nx tasks could run.
1. **Report to user:**
```
[ci-monitor] No CI attempt for <sha> after 10 min. Check CI provider for pre-Nx failures (install, checkout, auth). Last CI attempt: <previousCipeUrl>
```
2. **If user configured auto-fix attempts** (e.g., `--auto-fix-workflow`):
- Detect package manager: check for `pnpm-lock.yaml`, `yarn.lock`, `package-lock.json`
- Run install to update lockfile:
```bash
pnpm install # or npm install / yarn install
```
- If lockfile changed:
```bash
git add pnpm-lock.yaml # or appropriate lockfile
git commit -m "chore: update lockfile"
git push origin $(git branch --show-current)
```
- Record new commit SHA, loop to poll with `expectedCommitSha`
3. **Otherwise:** Exit with `no_new_cipe` status, providing guidance for user to investigate
## Exit Conditions
Exit the monitoring loop when ANY of these conditions are met:
| Condition | Exit Type |
| ------------------------------------------- | ---------------- |
| CI passes (`cipeStatus == 'SUCCEEDED'`) | Success |
| Max CIPE cycles reached | Timeout |
| Max duration reached | Timeout |
| 3 consecutive no-progress iterations | Circuit breaker |
| No fix available and local fix not possible | Failure |
| No new CIPE and auto-fix not configured | Pre-CIPE failure |
| User cancels | Cancelled |
## Main Loop
### Step 1: Initialize Tracking
```
cycle_count = 0
start_time = now()
no_progress_count = 0
local_verify_count = 0
last_state = null
last_cipe_url = null
expected_commit_sha = null
```
### Step 2: Spawn Subagent
Spawn the `ci-watcher` subagent to poll CI status:
**Fresh start (first spawn, no expected CIPE):**
```
Task(
agent: "ci-watcher",
prompt: "Monitor CI for branch '<branch>'.
Subagent timeout: <subagent-timeout> minutes.
New-CIPE timeout: <new-cipe-timeout> minutes.
Verbosity: <verbosity>."
)
```
**After action that triggers new CIPE (wait mode):**
```
Task(
agent: "ci-watcher",
prompt: "Monitor CI for branch '<branch>'.
Subagent timeout: <subagent-timeout> minutes.
New-CIPE timeout: <new-cipe-timeout> minutes.
Verbosity: <verbosity>.
WAIT MODE: A new CIPE should spawn. Ignore old CIPE until new one appears.
Expected commit SHA: <expected_commit_sha>
Previous CIPE URL: <last_cipe_url>"
)
```
### Step 3: Handle Subagent Response
When subagent returns:
1. Check the returned status
2. Look up default behavior in the table above
3. Check if user instructions override the default
4. Execute the appropriate action
5. **If action expects new CIPE**, update tracking (see Step 3a)
6. If action results in looping, go to Step 2
### Step 3a: Track State for New-CIPE Detection
After actions that should trigger a new CIPE, record state before looping:
| Action | What to Track | Subagent Mode |
| ----------------------------- | --------------------------------------------- | ------------- |
| Fix auto-applying | `last_cipe_url = current cipeUrl` | Wait mode |
| Apply via MCP | `last_cipe_url = current cipeUrl` | Wait mode |
| Apply locally + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Reject + fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Fix failed + local fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| No fix + local fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Environment rerun | `last_cipe_url = current cipeUrl` | Wait mode |
| No-new-CIPE + auto-fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
**CRITICAL**: When passing `expectedCommitSha` or `last_cipe_url` to the subagent, it enters **wait mode**:
- Subagent will **completely ignore** the old/stale CIPE
- Subagent will only wait for new CIPE to appear
- Subagent will NOT return to main agent with stale CIPE data
- Once new CIPE detected, subagent switches to normal polling
**Why wait mode matters for context preservation**: Stale CIPE data can be very large (task output summaries, suggested fix patches, reasoning). If subagent returns this to main agent, it pollutes main agent's context with useless data since we already processed that CIPE. Wait mode keeps stale data in the subagent, never sending it to main agent.
### Step 4: Progress Tracking
After each action:
- If state changed significantly → reset `no_progress_count = 0`
- If state unchanged → `no_progress_count++`
- On new CI attempt detected → reset `local_verify_count = 0`
## Status Reporting
Based on verbosity level:
| Level | What to Report |
| --------- | -------------------------------------------------------------------------- |
| `minimal` | Only final result (success/failure/timeout) |
| `medium` | State changes + periodic updates ("Cycle N \| Elapsed: Xm \| Status: ...") |
| `verbose` | All of medium + full subagent responses, git outputs, MCP responses |
## User Instruction Examples
Users can override default behaviors:
| Instruction | Effect |
| ------------------------------------------------ | --------------------------------------------- |
| "never auto-apply" | Always prompt before applying any fix |
| "always ask before git push" | Prompt before each push |
| "reject any fix for e2e tasks" | Auto-reject if `failedTaskIds` contains e2e |
| "apply all fixes regardless of verification" | Skip verification check, apply everything |
| "if confidence < 70, reject" | Check confidence field before applying |
| "run 'nx affected -t typecheck' before applying" | Add local verification step |
| "auto-fix workflow failures" | Attempt lockfile updates on pre-CIPE failures |
| "wait 45 min for new CIPE" | Override new-CIPE timeout (default: 10 min) |
## Error Handling
| Error | Action |
| ------------------------ | ------------------------------------------------------------------------------------- |
| Git rebase conflict | Report to user, exit |
| `nx apply-locally` fails | Report to user, attempt manual patch or exit |
| MCP tool error | Retry once, if fails report to user |
| Subagent spawn failure | Retry once, if fails exit with error |
| No new CIPE detected | If `--auto-fix-workflow`, try lockfile update; otherwise report to user with guidance |
| Lockfile auto-fix fails | Report to user, exit with guidance to check CI logs |
## Example Session
### Example 1: Normal Flow with Self-Healing (medium verbosity)
```
[ci-monitor] Starting CI monitor for branch 'feature/add-auth'
[ci-monitor] Config: max-cycles=5, timeout=120m, verbosity=medium
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] CI attempt: IN_PROGRESS | Self-Healing: NOT_STARTED | Elapsed: 1m
[CI Monitor] CI attempt: FAILED | Self-Healing: IN_PROGRESS | Elapsed: 3m
[CI Monitor] CI attempt: FAILED | Self-Healing: COMPLETED | Elapsed: 5m
[ci-monitor] Fix available! Verification: COMPLETED
[ci-monitor] Applying fix via MCP...
[ci-monitor] Fix applied in CI. Waiting for new CI attempt...
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] New CI attempt detected!
[CI Monitor] CI attempt: SUCCEEDED | Elapsed: 8m
[ci-monitor] CI passed successfully!
[ci-monitor] Summary:
- Total cycles: 2
- Total time: 12m 34s
- Fixes applied: 1
- Result: SUCCESS
```
### Example 2: Pre-CI Failure (medium verbosity)
```
[ci-monitor] Starting CI monitor for branch 'feature/add-products'
[ci-monitor] Config: max-cycles=5, timeout=120m, auto-fix-workflow=true
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] CI attempt: FAILED | Self-Healing: COMPLETED | Elapsed: 2m
[ci-monitor] Applying fix locally, enhancing, and pushing...
[ci-monitor] Committed: abc1234
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] Waiting for new CI attempt... (expected SHA: abc1234)
[CI Monitor] ⚠️ CI attempt timeout (10 min). Returning no_new_cipe.
[ci-monitor] Status: no_new_cipe
[ci-monitor] --auto-fix-workflow enabled. Attempting lockfile update...
[ci-monitor] Lockfile updated. Committed: def5678
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] New CI attempt detected!
[CI Monitor] CI attempt: SUCCEEDED | Elapsed: 18m
[ci-monitor] CI passed successfully!
[ci-monitor] Summary:
- Total cycles: 3
- Total time: 22m 15s
- Fixes applied: 1 (self-healing) + 1 (lockfile)
- Result: SUCCESS
```
+228
View File
@@ -0,0 +1,228 @@
---
name: nx-generate
description: Generate code using nx generators. USE WHEN scaffolding code or transforming existing code - for example creating libraries or applications, or anything else that is boilerplate code or automates repetitive tasks. ALWAYS use this first when generating code with Nx instead of calling MCP tools or running nx generate immediately.
---
# Run Nx Generator
Nx generators are powerful tools that scaffold projects, make automated code migrations or automate repetitive tasks in a monorepo. They ensure consistency across the codebase and reduce boilerplate work.
This skill applies when the user wants to:
- Create new projects like libraries or applications
- Scaffold features or boilerplate code
- Run workspace-specific or custom generators
- Do anything else that an nx generator exists for
## Generator Discovery Flow
### Step 1: List Available Generators
Use the Nx CLI to discover available generators:
- List all generators for a plugin: `npx nx list @nx/react`
- View available plugins: `npx nx list`
This includes:
- Plugin generators (e.g., `@nx/react:library`, `@nx/js:library`)
- Local workspace generators (defined in the repo's own plugins)
### Step 2: Match Generator to User Request
Based on the user's request, identify which generator(s) could fulfill their needs. Consider:
- What artifact type they want to create (library, application, etc.)
- Which framework or technology stack is relevant
- Whether they mentioned specific generator names
**IMPORTANT**: When both a local workspace generator and an external plugin generator could satisfy the request, **always prefer the local workspace generator**. Local generators are customized for the specific repo's patterns and conventions.
It's possible that the user request is something that no Nx generator exists for whatsoever. In this case, you can stop using this skill and try to help the user another way. HOWEVER, the burden of proof for this is high. Before aborting, carefully consider each and every generator that's available. Look into details for any that could be related in any way before making this decision.
## Pre-Execution Checklist
Before running any generator, complete these steps:
### 1. Fetch Generator Schema
Use the `--help` flag to understand all available options:
```bash
npx nx g @nx/react:library --help
```
Pay attention to:
- Required options that must be provided
- Optional options that may be relevant to the user's request
- Default values that might need to be overridden
### 2. Read Generator Source Code
Understanding what the generator actually does helps you:
- Know what files will be created/modified
- Understand any side effects (updating configs, installing deps, etc.)
- Identify options that might not be obvious from the schema
To find generator source code:
- For plugin generators: Use `node -e "console.log(require.resolve('@nx/<plugin>/generators.json'));"` to find the generators.json, then locate the source from there
- If that fails, read directly from `node_modules/<plugin>/generators.json`
- For local generators: They are typically in `tools/generators/` or a local plugin directory. You can search the repo for the generator name to find it.
### 2.5 Reevaluate if the generator is right
Once you have built up an understanding of what the selected generator does, reconsider: Is this the right generator to service the user request?
If not, it's okay to go back to the Generator Discovery Flow and select a different generator before proceeding. If you do, make sure to go through the entire pre-execution checklist once more.
### 3. Understand Repo Context
Before generating, examine the target area of the codebase:
- Look at similar existing artifacts (other libraries, applications, etc.)
- Identify patterns and conventions used in the repo
- Note naming conventions, file structures, and configuration patterns
- Try to match these patterns when configuring the generator
For example, if similar libraries are using a specific test runner, build tool or linter, try to match that if possible.
If projects or other artifacts are organized with a specific naming convention, try to match it.
### 4. Validate Required Options
Ensure all required options have values:
- Map the user's request to generator options
- Infer values from context where possible
- Ask the user for any critical missing information
## Execution
Keep in mind that you might have to prefix things with npx/pnpx/yarn if the user doesn't have nx installed globally.
Many generators will behave differently based on where they are executed. For example, first-party nx library generators use the cwd to determine the directory that the library should be placed in. This is highly important.
### Consider Dry-Run (Optional)
Running with `--dry-run` first is strongly encouraged but not mandatory. Use your judgment:
- For complex generators or unfamiliar territory: do a dry-run first
- For simple, well-understood generators: may proceed directly
- Dry-run shows file names and created/deleted/modified markers, but not content
- There are cases where a generator does not support dry-run (for example if it had to install an npm package) - in that case --dry-run might fail. Don't be discouraged but simply move on to running the generator for real and iterating from there.
### Running the Generator
Execute the generator with:
```bash
nx generate <generator-name> <options> --no-interactive
```
**CRITICAL**: Always include `--no-interactive` to prevent prompts that would hang the execution.
Example:
```bash
nx generate @nx/react:library --name=my-utils --no-interactive
```
### Handling Generator Failures
If the generator fails:
1. **Diagnose the error** - Read the error message carefully
2. **Identify the cause** - Missing options, invalid values, conflicts, etc.
3. **Attempt automatic fix** - Adjust options or resolve conflicts
4. **Retry** - Run the generator again with corrected options
Common failure reasons:
- Missing required options
- Invalid option values
- Conflicting with existing files
- Missing dependencies
- Generator doesn't support certain flag combinations
## Post-Generation
### 1. Modify Generated Code (If Needed)
Generators provide a starting point, but the output may need adjustment to match the user's specific requirements:
- Add or modify functionality as requested
- Adjust imports, exports, or configurations
- Integrate with existing code patterns in the repo
### 2. Format Code
Run formatting on all generated/modified files:
```bash
nx format --fix
```
Languages other than javascript/typescript might need other formatting invocations too.
### 3. Run Verification
Verify that the generated code works correctly. What this looks like will vary depending on the type of generator and the targets available.
If the generator created a new project, run its targets directly
Use your best judgement to determine what needs to be verified.
Example:
```bash
nx lint <new-project>
nx test <new-project>
nx build <new-project>
```
### 4. Handle Verification Failures
When verification fails:
**If scope is manageable** (a few lint errors, minor type issues):
- Fix the issues
- Re-run verification to confirm
**If issues are extensive** (many errors, complex problems):
- Attempt simple, obvious fixes first
- If still failing, escalate to the user with:
- Description of what was generated
- What verification is failing
- What you've attempted to fix
- Remaining issues that need user input
## Error Handling
### Generator Failures
- Check the error message for specific causes
- Verify all required options are provided
- Check for conflicts with existing files
- Ensure the generator name and options are correct
### Missing Options
- Consult the generator schema for required fields
- Infer values from context when reasonable
- Ask the user for values that cannot be inferred
## Key Principles
1. **Local generators first** - Always prefer workspace/local generators over external plugin generators when both could work
2. **Understand before running** - Read both the schema AND the source code to fully understand what will happen
3. **No prompts** - Always use `--no-interactive` to prevent hanging
4. **Generators are starting points** - Modify the output as needed to fully satisfy the user's requirements
5. **Verify changes work** - Don't just generate; ensure the code builds, lints, and tests pass
6. **Be proactive about fixes** - Don't just report errors; attempt to resolve them automatically when possible
7. **Match repo patterns** - Study existing similar code in the repo and match its conventions
+9
View File
@@ -0,0 +1,9 @@
---
name: nx-plugins
description: Find and add Nx plugins. USE WHEN user wants to discover available plugins, install a new plugin, or add support for a specific framework or technology to the workspace.
---
## Finding and Installing new plugins
- List plugins: `pnpm nx list`
- Install plugins `pnpm nx add <plugin>`. Example: `pnpm nx add @nx/react`.
+58
View File
@@ -0,0 +1,58 @@
---
name: nx-run-tasks
description: Helps with running tasks in an Nx workspace. USE WHEN the user wants to execute build, test, lint, serve, or run any other tasks defined in the workspace.
---
You can run tasks with Nx in the following way.
Keep in mind that you might have to prefix things with npx/pnpx/yarn if the user doesn't have nx installed globally. Look at the package.json or lockfile to determine which package manager is in use.
For more details on any command, run it with `--help` (e.g. `nx run-many --help`, `nx affected --help`).
## Understand which tasks can be run
You can check those via `nx show project <projectname> --json`, for example `nx show project myapp --json`. It contains a `targets` section which has information about targets that can be run. You can also just look at the `package.json` scripts or `project.json` targets, but you might miss out on inferred tasks by Nx plugins.
## Run a single task
```
nx run <project>:<task>
```
where `project` is the project name defined in `package.json` or `project.json` (if present).
## Run multiple tasks
```
nx run-many -t build test lint typecheck
```
You can pass a `-p` flag to filter to specific projects, otherwise it runs on all projects. You can also use `--exclude` to exclude projects, and `--parallel` to control the number of parallel processes (default is 3).
Examples:
- `nx run-many -t test -p proj1 proj2` — test specific projects
- `nx run-many -t test --projects=*-app --exclude=excluded-app` — test projects matching a pattern
- `nx run-many -t test --projects=tag:api-*` — test projects by tag
## Run tasks for affected projects
Use `nx affected` to only run tasks on projects that have been changed and projects that depend on changed projects. This is especially useful in CI and for large workspaces.
```
nx affected -t build test lint
```
By default it compares against the base branch. You can customize this:
- `nx affected -t test --base=main --head=HEAD` — compare against a specific base and head
- `nx affected -t test --files=libs/mylib/src/index.ts` — specify changed files directly
## Useful flags
These flags work with `run`, `run-many`, and `affected`:
- `--skipNxCache` — rerun tasks even when results are cached
- `--verbose` — print additional information such as stack traces
- `--nxBail` — stop execution after the first failed task
- `--configuration=<name>` — use a specific configuration (e.g. `production`)
+186
View File
@@ -0,0 +1,186 @@
---
name: nx-workspace
description: "Explore and understand Nx workspaces. USE WHEN answering any questions about the nx workspace, the projects in it or tasks to run. EXAMPLES: 'What projects are in this workspace?', 'How is project X configured?', 'What targets can I run?', 'What's affected by my changes?', 'Which projects depend on library Y?', or any questions about Nx workspace structure, project configuration, or available tasks."
---
# Nx Workspace Exploration
This skill provides read-only exploration of Nx workspaces. Use it to understand workspace structure, project configuration, available targets, and dependencies.
Keep in mind that you might have to prefix commands with `npx`/`pnpx`/`yarn` if nx isn't installed globally. Check the lockfile to determine the package manager in use.
## Listing Projects
Use `nx show projects` to list projects in the workspace.
```bash
# List all projects
nx show projects
# Filter by pattern (glob)
nx show projects --projects "apps/*"
nx show projects --projects "shared-*"
# Filter by project type
nx show projects --type app
nx show projects --type lib
nx show projects --type e2e
# Filter by target (projects that have a specific target)
nx show projects --withTarget build
nx show projects --withTarget e2e
# Find affected projects (changed since base branch)
nx show projects --affected
nx show projects --affected --base=main
nx show projects --affected --type app
# Combine filters
nx show projects --type lib --withTarget test
nx show projects --affected --exclude="*-e2e"
# Output as JSON
nx show projects --json
```
## Project Configuration
Use `nx show project <name> --json` to get the full resolved configuration for a project.
**Important**: Do NOT read `project.json` directly - it only contains partial configuration. The `nx show project` command returns the full resolved config including inferred targets from plugins.
You can read the full project schema at `node_modules/nx/schemas/project-schema.json` to understand nx project configuration options.
```bash
# Get full project configuration
nx show project my-app --json
# Extract specific parts from the JSON
nx show project my-app --json | jq '.targets'
nx show project my-app --json | jq '.targets.build'
nx show project my-app --json | jq '.targets | keys'
# Check project metadata
nx show project my-app --json | jq '{name, root, sourceRoot, projectType, tags}'
```
## Target Information
Targets define what tasks can be run on a project.
```bash
# List all targets for a project
nx show project my-app --json | jq '.targets | keys'
# Get full target configuration
nx show project my-app --json | jq '.targets.build'
# Check target executor/command
nx show project my-app --json | jq '.targets.build.executor'
nx show project my-app --json | jq '.targets.build.command'
# View target options
nx show project my-app --json | jq '.targets.build.options'
# Check target inputs/outputs (for caching)
nx show project my-app --json | jq '.targets.build.inputs'
nx show project my-app --json | jq '.targets.build.outputs'
# Find projects with a specific target
nx show projects --withTarget serve
nx show projects --withTarget e2e
```
## Workspace Configuration
Read `nx.json` directly for workspace-level configuration.
You can read the full project schema at `node_modules/nx/schemas/nx-schema.json` to understand nx project configuration options.
```bash
# Read the full nx.json
cat nx.json
# Or use jq for specific sections
cat nx.json | jq '.targetDefaults'
cat nx.json | jq '.namedInputs'
cat nx.json | jq '.plugins'
cat nx.json | jq '.generators'
```
Key nx.json sections:
- `targetDefaults` - Default configuration applied to all targets of a given name
- `namedInputs` - Reusable input definitions for caching
- `plugins` - Nx plugins and their configuration
- ...and much more, read the schema or nx.json for details
## Affected Projects
Find projects affected by changes in the current branch.
```bash
# Affected since base branch (auto-detected)
nx show projects --affected
# Affected with explicit base
nx show projects --affected --base=main
nx show projects --affected --base=origin/main
# Affected between two commits
nx show projects --affected --base=abc123 --head=def456
# Affected apps only
nx show projects --affected --type app
# Affected excluding e2e projects
nx show projects --affected --exclude="*-e2e"
# Affected by uncommitted changes
nx show projects --affected --uncommitted
# Affected by untracked files
nx show projects --affected --untracked
```
## Common Exploration Patterns
### "What's in this workspace?"
```bash
nx show projects
nx show projects --type app
nx show projects --type lib
```
### "How do I build/test/lint project X?"
```bash
nx show project X --json | jq '.targets | keys'
nx show project X --json | jq '.targets.build'
```
### "What depends on library Y?"
```bash
# Find projects that may depend on Y by searching for imports
# (Nx doesn't have a direct "dependents" command via CLI)
grep -r "from '@myorg/Y'" --include="*.ts" --include="*.tsx" apps/ libs/
```
### "What configuration options are available?"
```bash
cat node_modules/nx/schemas/nx-schema.json | jq '.properties | keys'
cat node_modules/nx/schemas/project-schema.json | jq '.properties | keys'
```
### "Why is project X affected?"
```bash
# Check what files changed
git diff --name-only main
# See which project owns those files
nx show project X --json | jq '.root'
```
+4 -4
View File
@@ -8,11 +8,11 @@
// Try a more recent distribution, if your are having build issues related to GLIBC version
// Here we use 'bookworm', which is based on `Debian-12`, which comes with `GLIBC v2.36`
// (Nx tools currenlty requires `GLIBC v2.33` or higher)
"image": "mcr.microsoft.com/devcontainers/typescript-node:20-bookworm",
// Note: Using base debian image instead of typescript-node since mise will manage all tools
"image": "mcr.microsoft.com/devcontainers/base:bookworm",
"features": {
"ghcr.io/devcontainers/features/rust:1": {}
},
// All tools (Node, Java, Rust, Dotnet) are managed by mise via mise.toml
"features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// 4211 = nx graph port
+23 -5
View File
@@ -1,12 +1,30 @@
#!/bin/sh
#!/bin/bash
# Update the underlying (Debian) OS, to make sure we have the latest security patches and libraries like 'GLIBC'
# Update the underlying (Debian) OS, to make sure we have the latest security patches and libraries like 'GLIBC'
echo "⚙️ Updating the underlying OS..."
sudo apt-get update && sudo apt-get -y upgrade
# Uninstall globally installed PNPM (required version will be reinstalled through corepack)
echo "❌ Uninstalling globally installed PNPM..."
npm uninstall -g pnpm
# Install mise for managing development tools (Node, Java, Rust, Dotnet)
echo "⚙️ Installing mise..."
curl https://mise.run | sh
# Add mise to PATH
export PATH="$HOME/.local/bin:$PATH"
# Trust the mise.toml configuration file
echo "⚙️ Trusting mise.toml configuration..."
mise trust
# Install all tools from mise.toml (node, java, rust, dotnet)
echo "⚙️ Installing tools via mise (node, java, rust, dotnet)..."
mise install
# Activate mise to make tools available in current shell
eval "$(mise activate bash)"
# Add mise activation to bashrc for future shell sessions
echo "⚙️ Configuring mise activation in shell..."
echo 'eval "$(~/.local/bin/mise activate bash)"' >> ~/.bashrc
# Prevent corepack from prompting user before downloading PNPM
export COREPACK_ENABLE_DOWNLOAD_PROMPT=0
+19 -2
View File
@@ -4,7 +4,7 @@
"env": {
"node": true
},
"ignorePatterns": ["**/*.ts", "**/test-output"],
"ignorePatterns": ["**/*.ts", "**/test-output", "**/dist"],
"plugins": ["@typescript-eslint", "@nx"],
"extends": ["plugin:storybook/recommended"],
"rules": {
@@ -76,7 +76,8 @@
]
}
],
"@nx/workspace/valid-command-object": "error"
"@nx/workspace/valid-command-object": "error",
"@nx/workspace/require-windows-hide": "error"
}
},
{
@@ -96,6 +97,22 @@
"rules": {
"@angular-eslint/prefer-standalone": "off"
}
},
{
"files": [
"*.spec.ts",
"*.spec.tsx",
"*.spec.js",
"*.spec.jsx",
"*.test.ts",
"*.test.tsx",
"*.test.js",
"*.test.jsx"
],
"plugins": ["jest"],
"rules": {
"jest/no-disabled-tests": "warn"
}
}
]
}
+438
View File
@@ -0,0 +1,438 @@
description = "Monitor Nx Cloud CI pipeline and handle self-healing fixes automatically. Checks for Nx Cloud connection before starting."
prompt = """
# CI Monitor Command
You are the orchestrator for monitoring Nx Cloud CI pipeline executions and handling self-healing fixes. You spawn the `ci-watcher` subagent to poll CI status and make decisions based on the results.
## Context
- **Current Branch:** !`git branch --show-current`
- **Current Commit:** !`git rev-parse --short HEAD`
- **Remote Status:** !`git status -sb | head -1`
## User Instructions
{{args}}
**Important:** If user provides specific instructions, respect them over default behaviors described below.
## Configuration Defaults
| Setting | Default | Description |
| ------------------------- | ------------- | ------------------------------------------------------------------- |
| `--max-cycles` | 10 | Maximum CIPE cycles before timeout |
| `--timeout` | 120 | Maximum duration in minutes |
| `--verbosity` | medium | Output level: minimal, medium, verbose |
| `--branch` | (auto-detect) | Branch to monitor |
| `--subagent-timeout` | 60 | Subagent polling timeout in minutes |
| `--fresh` | false | Ignore previous context, start fresh |
| `--auto-fix-workflow` | false | Attempt common fixes for pre-CIPE failures (e.g., lockfile updates) |
| `--new-cipe-timeout` | 10 | Minutes to wait for new CIPE after action |
| `--local-verify-attempts` | 3 | Max local verification + enhance cycles before pushing to CI |
Parse any overrides from `{{args}}` and merge with defaults.
## Nx Cloud Connection Check
**CRITICAL**: Before starting the monitoring loop, verify the workspace is connected to Nx Cloud.
### Step 0: Verify Nx Cloud Connection
1. **Check `nx.json`** at workspace root for `nxCloudId` or `nxCloudAccessToken`
2. **If `nx.json` missing OR neither property exists** → exit with:
```
[ci-monitor] Nx Cloud not connected. Unlock 70% faster CI and auto-fix broken PRs with https://nx.dev/nx-cloud
```
3. **If connected** → continue to main loop
## Session Context Behavior
**Important:** Within a Claude Code session, conversation context persists. If you Ctrl+C to interrupt the monitor and re-run `/ci-monitor`, Claude remembers the previous state and may continue from where it left off.
- **To continue monitoring:** Just re-run `/ci-monitor` (context is preserved)
- **To start fresh:** Use `/ci-monitor --fresh` to ignore previous context
- **For a completely clean slate:** Exit Claude Code and restart `claude`
## Default Behaviors by Status
The subagent returns with one of the following statuses. This table defines the **default behavior** for each status. User instructions can override any of these.
| Status | Default Behavior |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ci_success` | Exit with success. Log "CI passed successfully!" |
| `fix_auto_applying` | Fix will be auto-applied by self-healing. Do NOT call MCP. Record `last_cipe_url`, spawn new subagent in wait mode to poll for new CIPE. |
| `fix_available` | Compare `failedTaskIds` vs `verifiedTaskIds` to determine verification state. See **Fix Available Decision Logic** section below. |
| `fix_failed` | Self-healing failed to generate fix. Attempt local fix based on `taskOutputSummary`. If successful → commit, push, loop. If not → exit with failure. |
| `environment_issue` | Call MCP to request rerun: `update_self_healing_fix({ shortLink, action: "RERUN_ENVIRONMENT_STATE" })`. New CIPE spawns automatically. Loop to poll for new CIPE. |
| `no_fix` | CI failed, no fix available (self-healing disabled or not executable). Attempt local fix if possible. Otherwise exit with failure. |
| `no_new_cipe` | Expected CIPE never spawned (CI workflow likely failed before Nx tasks). Report to user, attempt common fixes if configured, or exit with guidance. |
| `polling_timeout` | Subagent polling timeout reached. Exit with timeout. |
| `cipe_canceled` | CIPE was canceled. Exit with canceled status. |
| `cipe_timed_out` | CIPE timed out. Exit with timeout status. |
| `error` | Increment `no_progress_count`. If >= 3 → exit with circuit breaker. Otherwise wait 60s and loop. |
### Fix Available Decision Logic
When subagent returns `fix_available`, main agent compares `failedTaskIds` vs `verifiedTaskIds`:
#### Step 1: Categorize Tasks
1. **Verified tasks** = tasks in both `failedTaskIds` AND `verifiedTaskIds`
2. **Unverified tasks** = tasks in `failedTaskIds` but NOT in `verifiedTaskIds`
3. **E2E tasks** = unverified tasks where target contains "e2e" (task format: `<project>:<target>` or `<project>:<target>:<config>`)
4. **Verifiable tasks** = unverified tasks that are NOT e2e
#### Step 2: Determine Path
| Condition | Path |
| --------------------------------------- | ---------------------------------------- |
| No unverified tasks (all verified) | Apply via MCP |
| Unverified tasks exist, but ALL are e2e | Apply via MCP (treat as verified enough) |
| Verifiable tasks exist | Local verification flow |
#### Step 3a: Apply via MCP (fully/e2e-only verified)
- Call `update_self_healing_fix({ shortLink, action: "APPLY" })`
- Record `last_cipe_url`, spawn subagent in wait mode
#### Step 3b: Local Verification Flow
When verifiable (non-e2e) unverified tasks exist:
1. **Detect package manager:**
- `pnpm-lock.yaml` exists → `pnpm nx`
- `yarn.lock` exists → `yarn nx`
- Otherwise → `npx nx`
2. **Run verifiable tasks in parallel:**
- Spawn `general` subagents to run each task concurrently
- Each subagent runs: `<pm> nx run <taskId>`
- Collect pass/fail results from all subagents
3. **Evaluate results:**
| Result | Action |
| ------------------------- | ---------------------------- |
| ALL verifiable tasks pass | Apply via MCP |
| ANY verifiable task fails | Apply-locally + enhance flow |
4. **Apply-locally + enhance flow:**
- Run `nx apply-locally <shortLink>`
- Enhance the code to fix failing tasks
- Run failing tasks again to verify fix
- If still failing → increment `local_verify_count`, loop back to enhance
- If passing → commit and push, record `expected_commit_sha`, spawn subagent in wait mode
5. **Track attempts** (wraps step 4):
- Increment `local_verify_count` after each enhance cycle
- If `local_verify_count >= local_verify_attempts` (default: 3):
- Get code in commit-able state
- Commit and push with message indicating local verification failed
- Report to user:
```
[ci-monitor] Local verification failed after <N> attempts. Pushed to CI for final validation. Failed: <taskIds>
```
- Record `expected_commit_sha`, spawn subagent in wait mode (let CI be final judge)
#### Commit Message Format
```bash
git commit -m "fix(<projects>): <brief description>
Failed tasks: <taskId1>, <taskId2>
Local verification: passed|enhanced|failed-pushing-to-ci"
```
### Unverified Fix Flow (No Verification Attempted)
When `verificationStatus` is `FAILED`, `NOT_EXECUTABLE`, or fix has `couldAutoApplyTasks != true` with no verification:
- Analyze fix content (`suggestedFix`, `suggestedFixReasoning`, `taskOutputSummary`)
- If fix looks correct → apply via MCP
- If fix needs enhancement → use Apply Locally + Enhance Flow above
- If fix is wrong → reject via MCP, fix from scratch, commit, push
### Auto-Apply Eligibility
The `couldAutoApplyTasks` field indicates whether the fix is eligible for automatic application:
- **`true`**: Fix is eligible for auto-apply. Subagent keeps polling while verification is in progress. Returns `fix_auto_applying` when verified, or `fix_available` if verification fails.
- **`false`** or **`null`**: Fix requires manual action (apply via MCP, apply locally, or reject)
**Key point**: When subagent returns `fix_auto_applying`, do NOT call MCP to apply - self-healing handles it. Just spawn a new subagent in wait mode.
### Apply vs Reject vs Apply Locally
- **Apply via MCP**: Calls `update_self_healing_fix({ shortLink, action: "APPLY" })`. Self-healing agent applies the fix in CI and a new CIPE spawns automatically. No local git operations needed.
- **Apply Locally**: Runs `nx apply-locally <shortLink>`. Applies the patch to your local working directory and sets state to `APPLIED_LOCALLY`. Use this when you want to enhance the fix before pushing.
- **Reject via MCP**: Calls `update_self_healing_fix({ shortLink, action: "REJECT" })`. Marks fix as rejected. Use only when the fix is completely wrong and you'll fix from scratch.
### Apply Locally + Enhance Flow
When the fix needs enhancement (use `nx apply-locally`, NOT reject):
1. Apply the patch locally: `nx apply-locally <shortLink>` (this also updates state to `APPLIED_LOCALLY`)
2. Make additional changes as needed
3. Commit and push:
```bash
git add -A
git commit -m "fix: resolve <failedTaskIds>"
git push origin $(git branch --show-current)
```
4. Loop to poll for new CIPE
### Reject + Fix From Scratch Flow
When the fix is completely wrong:
1. Call MCP to reject: `update_self_healing_fix({ shortLink, action: "REJECT" })`
2. Fix the issue from scratch locally
3. Commit and push:
```bash
git add -A
git commit -m "fix: resolve <failedTaskIds>"
git push origin $(git branch --show-current)
```
4. Loop to poll for new CIPE
### Environment Issue Handling
When `failureClassification == 'ENVIRONMENT_STATE'`:
1. Call MCP to request rerun: `update_self_healing_fix({ shortLink, action: "RERUN_ENVIRONMENT_STATE" })`
2. New CIPE spawns automatically (no local git operations needed)
3. Loop to poll for new CIPE with `previousCipeUrl` set
### No-New-CIPE Handling
When `status == 'no_new_cipe'`:
This means the expected CIPE was never created - CI likely failed before Nx tasks could run.
1. **Report to user:**
```
[ci-monitor] No CI attempt for <sha> after 10 min. Check CI provider for pre-Nx failures (install, checkout, auth). Last CI attempt: <previousCipeUrl>
```
2. **If user configured auto-fix attempts** (e.g., `--auto-fix-workflow`):
- Detect package manager: check for `pnpm-lock.yaml`, `yarn.lock`, `package-lock.json`
- Run install to update lockfile:
```bash
pnpm install # or npm install / yarn install
```
- If lockfile changed:
```bash
git add pnpm-lock.yaml # or appropriate lockfile
git commit -m "chore: update lockfile"
git push origin $(git branch --show-current)
```
- Record new commit SHA, loop to poll with `expectedCommitSha`
3. **Otherwise:** Exit with `no_new_cipe` status, providing guidance for user to investigate
## Exit Conditions
Exit the monitoring loop when ANY of these conditions are met:
| Condition | Exit Type |
| ------------------------------------------- | ---------------- |
| CI passes (`cipeStatus == 'SUCCEEDED'`) | Success |
| Max CIPE cycles reached | Timeout |
| Max duration reached | Timeout |
| 3 consecutive no-progress iterations | Circuit breaker |
| No fix available and local fix not possible | Failure |
| No new CIPE and auto-fix not configured | Pre-CIPE failure |
| User cancels | Cancelled |
## Main Loop
### Step 1: Initialize Tracking
```
cycle_count = 0
start_time = now()
no_progress_count = 0
local_verify_count = 0
last_state = null
last_cipe_url = null
expected_commit_sha = null
```
### Step 2: Spawn Subagent
Spawn the `ci-watcher` subagent to poll CI status:
**Fresh start (first spawn, no expected CIPE):**
```
Task(
agent: "ci-watcher",
prompt: "Monitor CI for branch '<branch>'.
Subagent timeout: <subagent-timeout> minutes.
New-CIPE timeout: <new-cipe-timeout> minutes.
Verbosity: <verbosity>."
)
```
**After action that triggers new CIPE (wait mode):**
```
Task(
agent: "ci-watcher",
prompt: "Monitor CI for branch '<branch>'.
Subagent timeout: <subagent-timeout> minutes.
New-CIPE timeout: <new-cipe-timeout> minutes.
Verbosity: <verbosity>.
WAIT MODE: A new CIPE should spawn. Ignore old CIPE until new one appears.
Expected commit SHA: <expected_commit_sha>
Previous CIPE URL: <last_cipe_url>"
)
```
### Step 3: Handle Subagent Response
When subagent returns:
1. Check the returned status
2. Look up default behavior in the table above
3. Check if user instructions override the default
4. Execute the appropriate action
5. **If action expects new CIPE**, update tracking (see Step 3a)
6. If action results in looping, go to Step 2
### Step 3a: Track State for New-CIPE Detection
After actions that should trigger a new CIPE, record state before looping:
| Action | What to Track | Subagent Mode |
| ----------------------------- | --------------------------------------------- | ------------- |
| Fix auto-applying | `last_cipe_url = current cipeUrl` | Wait mode |
| Apply via MCP | `last_cipe_url = current cipeUrl` | Wait mode |
| Apply locally + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Reject + fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Fix failed + local fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| No fix + local fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Environment rerun | `last_cipe_url = current cipeUrl` | Wait mode |
| No-new-CIPE + auto-fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
**CRITICAL**: When passing `expectedCommitSha` or `last_cipe_url` to the subagent, it enters **wait mode**:
- Subagent will **completely ignore** the old/stale CIPE
- Subagent will only wait for new CIPE to appear
- Subagent will NOT return to main agent with stale CIPE data
- Once new CIPE detected, subagent switches to normal polling
**Why wait mode matters for context preservation**: Stale CIPE data can be very large (task output summaries, suggested fix patches, reasoning). If subagent returns this to main agent, it pollutes main agent's context with useless data since we already processed that CIPE. Wait mode keeps stale data in the subagent, never sending it to main agent.
### Step 4: Progress Tracking
After each action:
- If state changed significantly → reset `no_progress_count = 0`
- If state unchanged → `no_progress_count++`
- On new CI attempt detected → reset `local_verify_count = 0`
## Status Reporting
Based on verbosity level:
| Level | What to Report |
| --------- | -------------------------------------------------------------------------- |
| `minimal` | Only final result (success/failure/timeout) |
| `medium` | State changes + periodic updates ("Cycle N \\| Elapsed: Xm \\| Status: ...") |
| `verbose` | All of medium + full subagent responses, git outputs, MCP responses |
## User Instruction Examples
Users can override default behaviors:
| Instruction | Effect |
| ------------------------------------------------ | --------------------------------------------- |
| "never auto-apply" | Always prompt before applying any fix |
| "always ask before git push" | Prompt before each push |
| "reject any fix for e2e tasks" | Auto-reject if `failedTaskIds` contains e2e |
| "apply all fixes regardless of verification" | Skip verification check, apply everything |
| "if confidence < 70, reject" | Check confidence field before applying |
| "run 'nx affected -t typecheck' before applying" | Add local verification step |
| "auto-fix workflow failures" | Attempt lockfile updates on pre-CIPE failures |
| "wait 45 min for new CIPE" | Override new-CIPE timeout (default: 10 min) |
## Error Handling
| Error | Action |
| ------------------------ | ------------------------------------------------------------------------------------- |
| Git rebase conflict | Report to user, exit |
| `nx apply-locally` fails | Report to user, attempt manual patch or exit |
| MCP tool error | Retry once, if fails report to user |
| Subagent spawn failure | Retry once, if fails exit with error |
| No new CIPE detected | If `--auto-fix-workflow`, try lockfile update; otherwise report to user with guidance |
| Lockfile auto-fix fails | Report to user, exit with guidance to check CI logs |
## Example Session
### Example 1: Normal Flow with Self-Healing (medium verbosity)
```
[ci-monitor] Starting CI monitor for branch 'feature/add-auth'
[ci-monitor] Config: max-cycles=5, timeout=120m, verbosity=medium
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] CI attempt: IN_PROGRESS | Self-Healing: NOT_STARTED | Elapsed: 1m
[CI Monitor] CI attempt: FAILED | Self-Healing: IN_PROGRESS | Elapsed: 3m
[CI Monitor] CI attempt: FAILED | Self-Healing: COMPLETED | Elapsed: 5m
[ci-monitor] Fix available! Verification: COMPLETED
[ci-monitor] Applying fix via MCP...
[ci-monitor] Fix applied in CI. Waiting for new CI attempt...
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] New CI attempt detected!
[CI Monitor] CI attempt: SUCCEEDED | Elapsed: 8m
[ci-monitor] CI passed successfully!
[ci-monitor] Summary:
- Total cycles: 2
- Total time: 12m 34s
- Fixes applied: 1
- Result: SUCCESS
```
### Example 2: Pre-CI Failure (medium verbosity)
```
[ci-monitor] Starting CI monitor for branch 'feature/add-products'
[ci-monitor] Config: max-cycles=5, timeout=120m, auto-fix-workflow=true
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] CI attempt: FAILED | Self-Healing: COMPLETED | Elapsed: 2m
[ci-monitor] Applying fix locally, enhancing, and pushing...
[ci-monitor] Committed: abc1234
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] Waiting for new CI attempt... (expected SHA: abc1234)
[CI Monitor] ⚠️ CI attempt timeout (10 min). Returning no_new_cipe.
[ci-monitor] Status: no_new_cipe
[ci-monitor] --auto-fix-workflow enabled. Attempting lockfile update...
[ci-monitor] Lockfile updated. Committed: def5678
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] New CI attempt detected!
[CI Monitor] CI attempt: SUCCEEDED | Elapsed: 18m
[ci-monitor] CI passed successfully!
[ci-monitor] Summary:
- Total cycles: 3
- Total time: 22m 15s
- Fixes applied: 1 (self-healing) + 1 (lockfile)
- Result: SUCCESS
```"""
+437
View File
@@ -0,0 +1,437 @@
---
name: ci-monitor
description: Monitor Nx Cloud CI pipeline and handle self-healing fixes automatically. Checks for Nx Cloud connection before starting.
---
# CI Monitor Command
You are the orchestrator for monitoring Nx Cloud CI pipeline executions and handling self-healing fixes. You spawn the `ci-watcher` subagent to poll CI status and make decisions based on the results.
## Context
- **Current Branch:** !`git branch --show-current`
- **Current Commit:** !`git rev-parse --short HEAD`
- **Remote Status:** !`git status -sb | head -1`
## User Instructions
$ARGUMENTS
**Important:** If user provides specific instructions, respect them over default behaviors described below.
## Configuration Defaults
| Setting | Default | Description |
| ------------------------- | ------------- | ------------------------------------------------------------------- |
| `--max-cycles` | 10 | Maximum CIPE cycles before timeout |
| `--timeout` | 120 | Maximum duration in minutes |
| `--verbosity` | medium | Output level: minimal, medium, verbose |
| `--branch` | (auto-detect) | Branch to monitor |
| `--subagent-timeout` | 60 | Subagent polling timeout in minutes |
| `--fresh` | false | Ignore previous context, start fresh |
| `--auto-fix-workflow` | false | Attempt common fixes for pre-CIPE failures (e.g., lockfile updates) |
| `--new-cipe-timeout` | 10 | Minutes to wait for new CIPE after action |
| `--local-verify-attempts` | 3 | Max local verification + enhance cycles before pushing to CI |
Parse any overrides from `$ARGUMENTS` and merge with defaults.
## Nx Cloud Connection Check
**CRITICAL**: Before starting the monitoring loop, verify the workspace is connected to Nx Cloud.
### Step 0: Verify Nx Cloud Connection
1. **Check `nx.json`** at workspace root for `nxCloudId` or `nxCloudAccessToken`
2. **If `nx.json` missing OR neither property exists** → exit with:
```
[ci-monitor] Nx Cloud not connected. Unlock 70% faster CI and auto-fix broken PRs with https://nx.dev/nx-cloud
```
3. **If connected** → continue to main loop
## Session Context Behavior
**Important:** Within a Claude Code session, conversation context persists. If you Ctrl+C to interrupt the monitor and re-run `/ci-monitor`, Claude remembers the previous state and may continue from where it left off.
- **To continue monitoring:** Just re-run `/ci-monitor` (context is preserved)
- **To start fresh:** Use `/ci-monitor --fresh` to ignore previous context
- **For a completely clean slate:** Exit Claude Code and restart `claude`
## Default Behaviors by Status
The subagent returns with one of the following statuses. This table defines the **default behavior** for each status. User instructions can override any of these.
| Status | Default Behavior |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ci_success` | Exit with success. Log "CI passed successfully!" |
| `fix_auto_applying` | Fix will be auto-applied by self-healing. Do NOT call MCP. Record `last_cipe_url`, spawn new subagent in wait mode to poll for new CIPE. |
| `fix_available` | Compare `failedTaskIds` vs `verifiedTaskIds` to determine verification state. See **Fix Available Decision Logic** section below. |
| `fix_failed` | Self-healing failed to generate fix. Attempt local fix based on `taskOutputSummary`. If successful → commit, push, loop. If not → exit with failure. |
| `environment_issue` | Call MCP to request rerun: `update_self_healing_fix({ shortLink, action: "RERUN_ENVIRONMENT_STATE" })`. New CIPE spawns automatically. Loop to poll for new CIPE. |
| `no_fix` | CI failed, no fix available (self-healing disabled or not executable). Attempt local fix if possible. Otherwise exit with failure. |
| `no_new_cipe` | Expected CIPE never spawned (CI workflow likely failed before Nx tasks). Report to user, attempt common fixes if configured, or exit with guidance. |
| `polling_timeout` | Subagent polling timeout reached. Exit with timeout. |
| `cipe_canceled` | CIPE was canceled. Exit with canceled status. |
| `cipe_timed_out` | CIPE timed out. Exit with timeout status. |
| `error` | Increment `no_progress_count`. If >= 3 → exit with circuit breaker. Otherwise wait 60s and loop. |
### Fix Available Decision Logic
When subagent returns `fix_available`, main agent compares `failedTaskIds` vs `verifiedTaskIds`:
#### Step 1: Categorize Tasks
1. **Verified tasks** = tasks in both `failedTaskIds` AND `verifiedTaskIds`
2. **Unverified tasks** = tasks in `failedTaskIds` but NOT in `verifiedTaskIds`
3. **E2E tasks** = unverified tasks where target contains "e2e" (task format: `<project>:<target>` or `<project>:<target>:<config>`)
4. **Verifiable tasks** = unverified tasks that are NOT e2e
#### Step 2: Determine Path
| Condition | Path |
| --------------------------------------- | ---------------------------------------- |
| No unverified tasks (all verified) | Apply via MCP |
| Unverified tasks exist, but ALL are e2e | Apply via MCP (treat as verified enough) |
| Verifiable tasks exist | Local verification flow |
#### Step 3a: Apply via MCP (fully/e2e-only verified)
- Call `update_self_healing_fix({ shortLink, action: "APPLY" })`
- Record `last_cipe_url`, spawn subagent in wait mode
#### Step 3b: Local Verification Flow
When verifiable (non-e2e) unverified tasks exist:
1. **Detect package manager:**
- `pnpm-lock.yaml` exists → `pnpm nx`
- `yarn.lock` exists → `yarn nx`
- Otherwise → `npx nx`
2. **Run verifiable tasks in parallel:**
- Spawn `general` subagents to run each task concurrently
- Each subagent runs: `<pm> nx run <taskId>`
- Collect pass/fail results from all subagents
3. **Evaluate results:**
| Result | Action |
| ------------------------- | ---------------------------- |
| ALL verifiable tasks pass | Apply via MCP |
| ANY verifiable task fails | Apply-locally + enhance flow |
4. **Apply-locally + enhance flow:**
- Run `nx apply-locally <shortLink>`
- Enhance the code to fix failing tasks
- Run failing tasks again to verify fix
- If still failing → increment `local_verify_count`, loop back to enhance
- If passing → commit and push, record `expected_commit_sha`, spawn subagent in wait mode
5. **Track attempts** (wraps step 4):
- Increment `local_verify_count` after each enhance cycle
- If `local_verify_count >= local_verify_attempts` (default: 3):
- Get code in commit-able state
- Commit and push with message indicating local verification failed
- Report to user:
```
[ci-monitor] Local verification failed after <N> attempts. Pushed to CI for final validation. Failed: <taskIds>
```
- Record `expected_commit_sha`, spawn subagent in wait mode (let CI be final judge)
#### Commit Message Format
```bash
git commit -m "fix(<projects>): <brief description>
Failed tasks: <taskId1>, <taskId2>
Local verification: passed|enhanced|failed-pushing-to-ci"
```
### Unverified Fix Flow (No Verification Attempted)
When `verificationStatus` is `FAILED`, `NOT_EXECUTABLE`, or fix has `couldAutoApplyTasks != true` with no verification:
- Analyze fix content (`suggestedFix`, `suggestedFixReasoning`, `taskOutputSummary`)
- If fix looks correct → apply via MCP
- If fix needs enhancement → use Apply Locally + Enhance Flow above
- If fix is wrong → reject via MCP, fix from scratch, commit, push
### Auto-Apply Eligibility
The `couldAutoApplyTasks` field indicates whether the fix is eligible for automatic application:
- **`true`**: Fix is eligible for auto-apply. Subagent keeps polling while verification is in progress. Returns `fix_auto_applying` when verified, or `fix_available` if verification fails.
- **`false`** or **`null`**: Fix requires manual action (apply via MCP, apply locally, or reject)
**Key point**: When subagent returns `fix_auto_applying`, do NOT call MCP to apply - self-healing handles it. Just spawn a new subagent in wait mode.
### Apply vs Reject vs Apply Locally
- **Apply via MCP**: Calls `update_self_healing_fix({ shortLink, action: "APPLY" })`. Self-healing agent applies the fix in CI and a new CIPE spawns automatically. No local git operations needed.
- **Apply Locally**: Runs `nx apply-locally <shortLink>`. Applies the patch to your local working directory and sets state to `APPLIED_LOCALLY`. Use this when you want to enhance the fix before pushing.
- **Reject via MCP**: Calls `update_self_healing_fix({ shortLink, action: "REJECT" })`. Marks fix as rejected. Use only when the fix is completely wrong and you'll fix from scratch.
### Apply Locally + Enhance Flow
When the fix needs enhancement (use `nx apply-locally`, NOT reject):
1. Apply the patch locally: `nx apply-locally <shortLink>` (this also updates state to `APPLIED_LOCALLY`)
2. Make additional changes as needed
3. Commit and push:
```bash
git add -A
git commit -m "fix: resolve <failedTaskIds>"
git push origin $(git branch --show-current)
```
4. Loop to poll for new CIPE
### Reject + Fix From Scratch Flow
When the fix is completely wrong:
1. Call MCP to reject: `update_self_healing_fix({ shortLink, action: "REJECT" })`
2. Fix the issue from scratch locally
3. Commit and push:
```bash
git add -A
git commit -m "fix: resolve <failedTaskIds>"
git push origin $(git branch --show-current)
```
4. Loop to poll for new CIPE
### Environment Issue Handling
When `failureClassification == 'ENVIRONMENT_STATE'`:
1. Call MCP to request rerun: `update_self_healing_fix({ shortLink, action: "RERUN_ENVIRONMENT_STATE" })`
2. New CIPE spawns automatically (no local git operations needed)
3. Loop to poll for new CIPE with `previousCipeUrl` set
### No-New-CIPE Handling
When `status == 'no_new_cipe'`:
This means the expected CIPE was never created - CI likely failed before Nx tasks could run.
1. **Report to user:**
```
[ci-monitor] No CI attempt for <sha> after 10 min. Check CI provider for pre-Nx failures (install, checkout, auth). Last CI attempt: <previousCipeUrl>
```
2. **If user configured auto-fix attempts** (e.g., `--auto-fix-workflow`):
- Detect package manager: check for `pnpm-lock.yaml`, `yarn.lock`, `package-lock.json`
- Run install to update lockfile:
```bash
pnpm install # or npm install / yarn install
```
- If lockfile changed:
```bash
git add pnpm-lock.yaml # or appropriate lockfile
git commit -m "chore: update lockfile"
git push origin $(git branch --show-current)
```
- Record new commit SHA, loop to poll with `expectedCommitSha`
3. **Otherwise:** Exit with `no_new_cipe` status, providing guidance for user to investigate
## Exit Conditions
Exit the monitoring loop when ANY of these conditions are met:
| Condition | Exit Type |
| ------------------------------------------- | ---------------- |
| CI passes (`cipeStatus == 'SUCCEEDED'`) | Success |
| Max CIPE cycles reached | Timeout |
| Max duration reached | Timeout |
| 3 consecutive no-progress iterations | Circuit breaker |
| No fix available and local fix not possible | Failure |
| No new CIPE and auto-fix not configured | Pre-CIPE failure |
| User cancels | Cancelled |
## Main Loop
### Step 1: Initialize Tracking
```
cycle_count = 0
start_time = now()
no_progress_count = 0
local_verify_count = 0
last_state = null
last_cipe_url = null
expected_commit_sha = null
```
### Step 2: Spawn Subagent
Spawn the `ci-watcher` subagent to poll CI status:
**Fresh start (first spawn, no expected CIPE):**
```
Task(
agent: "ci-watcher",
prompt: "Monitor CI for branch '<branch>'.
Subagent timeout: <subagent-timeout> minutes.
New-CIPE timeout: <new-cipe-timeout> minutes.
Verbosity: <verbosity>."
)
```
**After action that triggers new CIPE (wait mode):**
```
Task(
agent: "ci-watcher",
prompt: "Monitor CI for branch '<branch>'.
Subagent timeout: <subagent-timeout> minutes.
New-CIPE timeout: <new-cipe-timeout> minutes.
Verbosity: <verbosity>.
WAIT MODE: A new CIPE should spawn. Ignore old CIPE until new one appears.
Expected commit SHA: <expected_commit_sha>
Previous CIPE URL: <last_cipe_url>"
)
```
### Step 3: Handle Subagent Response
When subagent returns:
1. Check the returned status
2. Look up default behavior in the table above
3. Check if user instructions override the default
4. Execute the appropriate action
5. **If action expects new CIPE**, update tracking (see Step 3a)
6. If action results in looping, go to Step 2
### Step 3a: Track State for New-CIPE Detection
After actions that should trigger a new CIPE, record state before looping:
| Action | What to Track | Subagent Mode |
| ----------------------------- | --------------------------------------------- | ------------- |
| Fix auto-applying | `last_cipe_url = current cipeUrl` | Wait mode |
| Apply via MCP | `last_cipe_url = current cipeUrl` | Wait mode |
| Apply locally + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Reject + fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Fix failed + local fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| No fix + local fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Environment rerun | `last_cipe_url = current cipeUrl` | Wait mode |
| No-new-CIPE + auto-fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
**CRITICAL**: When passing `expectedCommitSha` or `last_cipe_url` to the subagent, it enters **wait mode**:
- Subagent will **completely ignore** the old/stale CIPE
- Subagent will only wait for new CIPE to appear
- Subagent will NOT return to main agent with stale CIPE data
- Once new CIPE detected, subagent switches to normal polling
**Why wait mode matters for context preservation**: Stale CIPE data can be very large (task output summaries, suggested fix patches, reasoning). If subagent returns this to main agent, it pollutes main agent's context with useless data since we already processed that CIPE. Wait mode keeps stale data in the subagent, never sending it to main agent.
### Step 4: Progress Tracking
After each action:
- If state changed significantly → reset `no_progress_count = 0`
- If state unchanged → `no_progress_count++`
- On new CI attempt detected → reset `local_verify_count = 0`
## Status Reporting
Based on verbosity level:
| Level | What to Report |
| --------- | -------------------------------------------------------------------------- |
| `minimal` | Only final result (success/failure/timeout) |
| `medium` | State changes + periodic updates ("Cycle N \| Elapsed: Xm \| Status: ...") |
| `verbose` | All of medium + full subagent responses, git outputs, MCP responses |
## User Instruction Examples
Users can override default behaviors:
| Instruction | Effect |
| ------------------------------------------------ | --------------------------------------------- |
| "never auto-apply" | Always prompt before applying any fix |
| "always ask before git push" | Prompt before each push |
| "reject any fix for e2e tasks" | Auto-reject if `failedTaskIds` contains e2e |
| "apply all fixes regardless of verification" | Skip verification check, apply everything |
| "if confidence < 70, reject" | Check confidence field before applying |
| "run 'nx affected -t typecheck' before applying" | Add local verification step |
| "auto-fix workflow failures" | Attempt lockfile updates on pre-CIPE failures |
| "wait 45 min for new CIPE" | Override new-CIPE timeout (default: 10 min) |
## Error Handling
| Error | Action |
| ------------------------ | ------------------------------------------------------------------------------------- |
| Git rebase conflict | Report to user, exit |
| `nx apply-locally` fails | Report to user, attempt manual patch or exit |
| MCP tool error | Retry once, if fails report to user |
| Subagent spawn failure | Retry once, if fails exit with error |
| No new CIPE detected | If `--auto-fix-workflow`, try lockfile update; otherwise report to user with guidance |
| Lockfile auto-fix fails | Report to user, exit with guidance to check CI logs |
## Example Session
### Example 1: Normal Flow with Self-Healing (medium verbosity)
```
[ci-monitor] Starting CI monitor for branch 'feature/add-auth'
[ci-monitor] Config: max-cycles=5, timeout=120m, verbosity=medium
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] CI attempt: IN_PROGRESS | Self-Healing: NOT_STARTED | Elapsed: 1m
[CI Monitor] CI attempt: FAILED | Self-Healing: IN_PROGRESS | Elapsed: 3m
[CI Monitor] CI attempt: FAILED | Self-Healing: COMPLETED | Elapsed: 5m
[ci-monitor] Fix available! Verification: COMPLETED
[ci-monitor] Applying fix via MCP...
[ci-monitor] Fix applied in CI. Waiting for new CI attempt...
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] New CI attempt detected!
[CI Monitor] CI attempt: SUCCEEDED | Elapsed: 8m
[ci-monitor] CI passed successfully!
[ci-monitor] Summary:
- Total cycles: 2
- Total time: 12m 34s
- Fixes applied: 1
- Result: SUCCESS
```
### Example 2: Pre-CI Failure (medium verbosity)
```
[ci-monitor] Starting CI monitor for branch 'feature/add-products'
[ci-monitor] Config: max-cycles=5, timeout=120m, auto-fix-workflow=true
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] CI attempt: FAILED | Self-Healing: COMPLETED | Elapsed: 2m
[ci-monitor] Applying fix locally, enhancing, and pushing...
[ci-monitor] Committed: abc1234
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] Waiting for new CI attempt... (expected SHA: abc1234)
[CI Monitor] ⚠️ CI attempt timeout (10 min). Returning no_new_cipe.
[ci-monitor] Status: no_new_cipe
[ci-monitor] --auto-fix-workflow enabled. Attempting lockfile update...
[ci-monitor] Lockfile updated. Committed: def5678
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] New CI attempt detected!
[CI Monitor] CI attempt: SUCCEEDED | Elapsed: 18m
[ci-monitor] CI passed successfully!
[ci-monitor] Summary:
- Total cycles: 3
- Total time: 22m 15s
- Fixes applied: 1 (self-healing) + 1 (lockfile)
- Result: SUCCESS
```
+228
View File
@@ -0,0 +1,228 @@
---
name: nx-generate
description: Generate code using nx generators. USE WHEN scaffolding code or transforming existing code - for example creating libraries or applications, or anything else that is boilerplate code or automates repetitive tasks. ALWAYS use this first when generating code with Nx instead of calling MCP tools or running nx generate immediately.
---
# Run Nx Generator
Nx generators are powerful tools that scaffold projects, make automated code migrations or automate repetitive tasks in a monorepo. They ensure consistency across the codebase and reduce boilerplate work.
This skill applies when the user wants to:
- Create new projects like libraries or applications
- Scaffold features or boilerplate code
- Run workspace-specific or custom generators
- Do anything else that an nx generator exists for
## Generator Discovery Flow
### Step 1: List Available Generators
Use the Nx CLI to discover available generators:
- List all generators for a plugin: `npx nx list @nx/react`
- View available plugins: `npx nx list`
This includes:
- Plugin generators (e.g., `@nx/react:library`, `@nx/js:library`)
- Local workspace generators (defined in the repo's own plugins)
### Step 2: Match Generator to User Request
Based on the user's request, identify which generator(s) could fulfill their needs. Consider:
- What artifact type they want to create (library, application, etc.)
- Which framework or technology stack is relevant
- Whether they mentioned specific generator names
**IMPORTANT**: When both a local workspace generator and an external plugin generator could satisfy the request, **always prefer the local workspace generator**. Local generators are customized for the specific repo's patterns and conventions.
It's possible that the user request is something that no Nx generator exists for whatsoever. In this case, you can stop using this skill and try to help the user another way. HOWEVER, the burden of proof for this is high. Before aborting, carefully consider each and every generator that's available. Look into details for any that could be related in any way before making this decision.
## Pre-Execution Checklist
Before running any generator, complete these steps:
### 1. Fetch Generator Schema
Use the `--help` flag to understand all available options:
```bash
npx nx g @nx/react:library --help
```
Pay attention to:
- Required options that must be provided
- Optional options that may be relevant to the user's request
- Default values that might need to be overridden
### 2. Read Generator Source Code
Understanding what the generator actually does helps you:
- Know what files will be created/modified
- Understand any side effects (updating configs, installing deps, etc.)
- Identify options that might not be obvious from the schema
To find generator source code:
- For plugin generators: Use `node -e "console.log(require.resolve('@nx/<plugin>/generators.json'));"` to find the generators.json, then locate the source from there
- If that fails, read directly from `node_modules/<plugin>/generators.json`
- For local generators: They are typically in `tools/generators/` or a local plugin directory. You can search the repo for the generator name to find it.
### 2.5 Reevaluate if the generator is right
Once you have built up an understanding of what the selected generator does, reconsider: Is this the right generator to service the user request?
If not, it's okay to go back to the Generator Discovery Flow and select a different generator before proceeding. If you do, make sure to go through the entire pre-execution checklist once more.
### 3. Understand Repo Context
Before generating, examine the target area of the codebase:
- Look at similar existing artifacts (other libraries, applications, etc.)
- Identify patterns and conventions used in the repo
- Note naming conventions, file structures, and configuration patterns
- Try to match these patterns when configuring the generator
For example, if similar libraries are using a specific test runner, build tool or linter, try to match that if possible.
If projects or other artifacts are organized with a specific naming convention, try to match it.
### 4. Validate Required Options
Ensure all required options have values:
- Map the user's request to generator options
- Infer values from context where possible
- Ask the user for any critical missing information
## Execution
Keep in mind that you might have to prefix things with npx/pnpx/yarn if the user doesn't have nx installed globally.
Many generators will behave differently based on where they are executed. For example, first-party nx library generators use the cwd to determine the directory that the library should be placed in. This is highly important.
### Consider Dry-Run (Optional)
Running with `--dry-run` first is strongly encouraged but not mandatory. Use your judgment:
- For complex generators or unfamiliar territory: do a dry-run first
- For simple, well-understood generators: may proceed directly
- Dry-run shows file names and created/deleted/modified markers, but not content
- There are cases where a generator does not support dry-run (for example if it had to install an npm package) - in that case --dry-run might fail. Don't be discouraged but simply move on to running the generator for real and iterating from there.
### Running the Generator
Execute the generator with:
```bash
nx generate <generator-name> <options> --no-interactive
```
**CRITICAL**: Always include `--no-interactive` to prevent prompts that would hang the execution.
Example:
```bash
nx generate @nx/react:library --name=my-utils --no-interactive
```
### Handling Generator Failures
If the generator fails:
1. **Diagnose the error** - Read the error message carefully
2. **Identify the cause** - Missing options, invalid values, conflicts, etc.
3. **Attempt automatic fix** - Adjust options or resolve conflicts
4. **Retry** - Run the generator again with corrected options
Common failure reasons:
- Missing required options
- Invalid option values
- Conflicting with existing files
- Missing dependencies
- Generator doesn't support certain flag combinations
## Post-Generation
### 1. Modify Generated Code (If Needed)
Generators provide a starting point, but the output may need adjustment to match the user's specific requirements:
- Add or modify functionality as requested
- Adjust imports, exports, or configurations
- Integrate with existing code patterns in the repo
### 2. Format Code
Run formatting on all generated/modified files:
```bash
nx format --fix
```
Languages other than javascript/typescript might need other formatting invocations too.
### 3. Run Verification
Verify that the generated code works correctly. What this looks like will vary depending on the type of generator and the targets available.
If the generator created a new project, run its targets directly
Use your best judgement to determine what needs to be verified.
Example:
```bash
nx lint <new-project>
nx test <new-project>
nx build <new-project>
```
### 4. Handle Verification Failures
When verification fails:
**If scope is manageable** (a few lint errors, minor type issues):
- Fix the issues
- Re-run verification to confirm
**If issues are extensive** (many errors, complex problems):
- Attempt simple, obvious fixes first
- If still failing, escalate to the user with:
- Description of what was generated
- What verification is failing
- What you've attempted to fix
- Remaining issues that need user input
## Error Handling
### Generator Failures
- Check the error message for specific causes
- Verify all required options are provided
- Check for conflicts with existing files
- Ensure the generator name and options are correct
### Missing Options
- Consult the generator schema for required fields
- Infer values from context when reasonable
- Ask the user for values that cannot be inferred
## Key Principles
1. **Local generators first** - Always prefer workspace/local generators over external plugin generators when both could work
2. **Understand before running** - Read both the schema AND the source code to fully understand what will happen
3. **No prompts** - Always use `--no-interactive` to prevent hanging
4. **Generators are starting points** - Modify the output as needed to fully satisfy the user's requirements
5. **Verify changes work** - Don't just generate; ensure the code builds, lints, and tests pass
6. **Be proactive about fixes** - Don't just report errors; attempt to resolve them automatically when possible
7. **Match repo patterns** - Study existing similar code in the repo and match its conventions
+9
View File
@@ -0,0 +1,9 @@
---
name: nx-plugins
description: Find and add Nx plugins. USE WHEN user wants to discover available plugins, install a new plugin, or add support for a specific framework or technology to the workspace.
---
## Finding and Installing new plugins
- List plugins: `pnpm nx list`
- Install plugins `pnpm nx add <plugin>`. Example: `pnpm nx add @nx/react`.
+58
View File
@@ -0,0 +1,58 @@
---
name: nx-run-tasks
description: Helps with running tasks in an Nx workspace. USE WHEN the user wants to execute build, test, lint, serve, or run any other tasks defined in the workspace.
---
You can run tasks with Nx in the following way.
Keep in mind that you might have to prefix things with npx/pnpx/yarn if the user doesn't have nx installed globally. Look at the package.json or lockfile to determine which package manager is in use.
For more details on any command, run it with `--help` (e.g. `nx run-many --help`, `nx affected --help`).
## Understand which tasks can be run
You can check those via `nx show project <projectname> --json`, for example `nx show project myapp --json`. It contains a `targets` section which has information about targets that can be run. You can also just look at the `package.json` scripts or `project.json` targets, but you might miss out on inferred tasks by Nx plugins.
## Run a single task
```
nx run <project>:<task>
```
where `project` is the project name defined in `package.json` or `project.json` (if present).
## Run multiple tasks
```
nx run-many -t build test lint typecheck
```
You can pass a `-p` flag to filter to specific projects, otherwise it runs on all projects. You can also use `--exclude` to exclude projects, and `--parallel` to control the number of parallel processes (default is 3).
Examples:
- `nx run-many -t test -p proj1 proj2` — test specific projects
- `nx run-many -t test --projects=*-app --exclude=excluded-app` — test projects matching a pattern
- `nx run-many -t test --projects=tag:api-*` — test projects by tag
## Run tasks for affected projects
Use `nx affected` to only run tasks on projects that have been changed and projects that depend on changed projects. This is especially useful in CI and for large workspaces.
```
nx affected -t build test lint
```
By default it compares against the base branch. You can customize this:
- `nx affected -t test --base=main --head=HEAD` — compare against a specific base and head
- `nx affected -t test --files=libs/mylib/src/index.ts` — specify changed files directly
## Useful flags
These flags work with `run`, `run-many`, and `affected`:
- `--skipNxCache` — rerun tasks even when results are cached
- `--verbose` — print additional information such as stack traces
- `--nxBail` — stop execution after the first failed task
- `--configuration=<name>` — use a specific configuration (e.g. `production`)
+186
View File
@@ -0,0 +1,186 @@
---
name: nx-workspace
description: "Explore and understand Nx workspaces. USE WHEN answering any questions about the nx workspace, the projects in it or tasks to run. EXAMPLES: 'What projects are in this workspace?', 'How is project X configured?', 'What targets can I run?', 'What's affected by my changes?', 'Which projects depend on library Y?', or any questions about Nx workspace structure, project configuration, or available tasks."
---
# Nx Workspace Exploration
This skill provides read-only exploration of Nx workspaces. Use it to understand workspace structure, project configuration, available targets, and dependencies.
Keep in mind that you might have to prefix commands with `npx`/`pnpx`/`yarn` if nx isn't installed globally. Check the lockfile to determine the package manager in use.
## Listing Projects
Use `nx show projects` to list projects in the workspace.
```bash
# List all projects
nx show projects
# Filter by pattern (glob)
nx show projects --projects "apps/*"
nx show projects --projects "shared-*"
# Filter by project type
nx show projects --type app
nx show projects --type lib
nx show projects --type e2e
# Filter by target (projects that have a specific target)
nx show projects --withTarget build
nx show projects --withTarget e2e
# Find affected projects (changed since base branch)
nx show projects --affected
nx show projects --affected --base=main
nx show projects --affected --type app
# Combine filters
nx show projects --type lib --withTarget test
nx show projects --affected --exclude="*-e2e"
# Output as JSON
nx show projects --json
```
## Project Configuration
Use `nx show project <name> --json` to get the full resolved configuration for a project.
**Important**: Do NOT read `project.json` directly - it only contains partial configuration. The `nx show project` command returns the full resolved config including inferred targets from plugins.
You can read the full project schema at `node_modules/nx/schemas/project-schema.json` to understand nx project configuration options.
```bash
# Get full project configuration
nx show project my-app --json
# Extract specific parts from the JSON
nx show project my-app --json | jq '.targets'
nx show project my-app --json | jq '.targets.build'
nx show project my-app --json | jq '.targets | keys'
# Check project metadata
nx show project my-app --json | jq '{name, root, sourceRoot, projectType, tags}'
```
## Target Information
Targets define what tasks can be run on a project.
```bash
# List all targets for a project
nx show project my-app --json | jq '.targets | keys'
# Get full target configuration
nx show project my-app --json | jq '.targets.build'
# Check target executor/command
nx show project my-app --json | jq '.targets.build.executor'
nx show project my-app --json | jq '.targets.build.command'
# View target options
nx show project my-app --json | jq '.targets.build.options'
# Check target inputs/outputs (for caching)
nx show project my-app --json | jq '.targets.build.inputs'
nx show project my-app --json | jq '.targets.build.outputs'
# Find projects with a specific target
nx show projects --withTarget serve
nx show projects --withTarget e2e
```
## Workspace Configuration
Read `nx.json` directly for workspace-level configuration.
You can read the full project schema at `node_modules/nx/schemas/nx-schema.json` to understand nx project configuration options.
```bash
# Read the full nx.json
cat nx.json
# Or use jq for specific sections
cat nx.json | jq '.targetDefaults'
cat nx.json | jq '.namedInputs'
cat nx.json | jq '.plugins'
cat nx.json | jq '.generators'
```
Key nx.json sections:
- `targetDefaults` - Default configuration applied to all targets of a given name
- `namedInputs` - Reusable input definitions for caching
- `plugins` - Nx plugins and their configuration
- ...and much more, read the schema or nx.json for details
## Affected Projects
Find projects affected by changes in the current branch.
```bash
# Affected since base branch (auto-detected)
nx show projects --affected
# Affected with explicit base
nx show projects --affected --base=main
nx show projects --affected --base=origin/main
# Affected between two commits
nx show projects --affected --base=abc123 --head=def456
# Affected apps only
nx show projects --affected --type app
# Affected excluding e2e projects
nx show projects --affected --exclude="*-e2e"
# Affected by uncommitted changes
nx show projects --affected --uncommitted
# Affected by untracked files
nx show projects --affected --untracked
```
## Common Exploration Patterns
### "What's in this workspace?"
```bash
nx show projects
nx show projects --type app
nx show projects --type lib
```
### "How do I build/test/lint project X?"
```bash
nx show project X --json | jq '.targets | keys'
nx show project X --json | jq '.targets.build'
```
### "What depends on library Y?"
```bash
# Find projects that may depend on Y by searching for imports
# (Nx doesn't have a direct "dependents" command via CLI)
grep -r "from '@myorg/Y'" --include="*.ts" --include="*.tsx" apps/ libs/
```
### "What configuration options are available?"
```bash
cat node_modules/nx/schemas/nx-schema.json | jq '.properties | keys'
cat node_modules/nx/schemas/project-schema.json | jq '.properties | keys'
```
### "Why is project X affected?"
```bash
# Check what files changed
git diff --name-only main
# See which project owns those files
nx show project X --json | jq '.root'
```
+478
View File
@@ -0,0 +1,478 @@
---
description: Polls Nx Cloud CI pipeline and self-healing status. Returns structured state when actionable. Spawned by /nx-cloud-ci-monitor command to monitor CI Attempt status.
---
# CI Watcher Subagent
You are a CI monitoring subagent responsible for polling Nx Cloud CI Attempt status and self-healing state. You report status back to the main agent - you do NOT make apply/reject decisions.
## Your Responsibilities
1. Poll CI status using the `ci_information` MCP tool
2. Implement exponential backoff between polls
3. Return structured state when an actionable condition is reached
4. Track iteration count and elapsed time
5. Output status updates based on verbosity level
## Input Parameters (from Main Agent)
The main agent may provide these optional parameters in the prompt:
| Parameter | Description |
| ------------------- | -------------------------------------------------------- |
| `branch` | Branch to monitor (auto-detected if not provided) |
| `expectedCommitSha` | Commit SHA that should trigger a new CI Attempt |
| `previousCipeUrl` | CI Attempt URL before the action (to detect change) |
| `subagentTimeout` | Polling timeout in minutes (default: 60) |
| `verbosity` | Output level: minimal, medium, verbose (default: medium) |
When `expectedCommitSha` or `previousCipeUrl` is provided, you must detect whether a new CI Attempt has spawned.
## MCP Tool Reference
### `ci_information`
**Input:**
```json
{
"branch": "string (optional, defaults to current git branch)",
"select": "string (optional, comma-separated field names)",
"pageToken": "number (optional, 0-based pagination for long strings)"
}
```
**Output:**
```json
{
"cipeStatus": "NOT_STARTED | IN_PROGRESS | SUCCEEDED | FAILED | CANCELED | TIMED_OUT",
"cipeUrl": "string",
"branch": "string",
"commitSha": "string | null",
"failedTaskIds": "string[]",
"verifiedTaskIds": "string[]",
"selfHealingEnabled": "boolean",
"selfHealingStatus": "NOT_STARTED | IN_PROGRESS | COMPLETED | FAILED | NOT_EXECUTABLE | null",
"verificationStatus": "NOT_STARTED | IN_PROGRESS | COMPLETED | FAILED | NOT_EXECUTABLE | null",
"userAction": "NONE | APPLIED | REJECTED | APPLIED_LOCALLY | APPLIED_AUTOMATICALLY | null",
"failureClassification": "string | null",
"taskOutputSummary": "string | null",
"suggestedFixReasoning": "string | null",
"suggestedFixDescription": "string | null",
"suggestedFix": "string | null",
"shortLink": "string | null",
"couldAutoApplyTasks": "boolean | null",
"confidence": "number | null",
"confidenceReasoning": "string | null"
}
```
**Select Parameter:**
| Usage | Returns |
| --------------- | ----------------------------------------------------------- |
| No `select` | Formatted overview (truncated, not recommended for polling) |
| Single field | Raw value with pagination for long strings |
| Multiple fields | Object with requested field values |
**Field Sets for Efficient Polling:**
```yaml
WAIT_FIELDS:
'cipeUrl,commitSha,cipeStatus'
# Minimal fields for detecting new CI Attempt
LIGHT_FIELDS:
'cipeStatus,cipeUrl,branch,commitSha,selfHealingStatus,verificationStatus,userAction,failedTaskIds,verifiedTaskIds,selfHealingEnabled,failureClassification,couldAutoApplyTasks,shortLink,confidence,confidenceReasoning'
# Status fields for determining actionable state
HEAVY_FIELDS:
'taskOutputSummary,suggestedFix,suggestedFixReasoning,suggestedFixDescription'
# Large content fields - fetch only when returning to main agent
```
## Initial Wait
Before first poll, wait based on context:
- **Fresh start (no expected CIPE):** Wait 60 seconds to allow CI to start
- **Expecting new CIPE:** Wait 30 seconds (action already triggered)
**IMPORTANT:** Always run sleep in foreground, NOT as background command.
```bash
sleep 60 # or 30 if expecting new CIPE (FOREGROUND, not background)
```
## Two-Phase Operation
The subagent operates in one of two modes depending on input:
### Mode 1: Fresh Start (no `expectedCommitSha` or `previousCipeUrl`)
Normal polling - process whatever CIPE is returned by `ci_information`.
### Mode 2: Wait-for-New-CIPE (when `expectedCommitSha` or `previousCipeUrl` provided)
**CRITICAL**: When expecting a new CIPE, the subagent must **completely ignore** the old/stale CIPE. Do NOT process its status, do NOT return actionable states based on it.
#### Phase A: Wait Mode
1. Start a **new-CIPE timeout** timer (default: 30 minutes)
2. On each poll of `ci_information`:
- Check if CIPE is NEW:
- `cipeUrl` differs from `previousCipeUrl`**new CIPE detected**
- `commitSha` matches `expectedCommitSha`**correct CIPE detected**
- If still OLD CIPE: **ignore all status fields**, just wait and poll again
- Do NOT return `fix_available`, `ci_success`, etc. based on old CIPE!
3. Output wait status (see below)
4. If timeout (30 min) reached → return `no_new_cipe`
#### Phase B: Normal Polling (after new CIPE detected)
Once new CIPE is detected:
1. Clear the new-CIPE timeout
2. Switch to normal polling mode
3. Process the NEW CIPE's status normally
4. Return when actionable state reached
### Wait Mode Output
While in wait mode, output clearly that you're waiting (not processing):
```
[CI Monitor] ═══════════════════════════════════════════════════════
[CI Monitor] WAIT MODE - Expecting new CI Attempt
[CI Monitor] Expected SHA: <expectedCommitSha>
[CI Monitor] Previous CI Attempt: <previousCipeUrl>
[CI Monitor] ═══════════════════════════════════════════════════════
[CI Monitor] Polling... (elapsed: 0m 30s)
[CI Monitor] Still seeing previous CI Attempt (ignoring): <oldCipeUrl>
[CI Monitor] Polling... (elapsed: 1m 30s)
[CI Monitor] Still seeing previous CI Attempt (ignoring): <oldCipeUrl>
[CI Monitor] Polling... (elapsed: 2m 30s)
[CI Monitor] ✓ New CI Attempt detected! URL: <newCipeUrl>, SHA: <newCommitSha>
[CI Monitor] Switching to normal polling mode...
```
### Why This Matters (Context Preservation)
**The problem**: Stale CIPE data can be very large:
- `taskOutputSummary`: potentially thousands of characters of build/test output
- `suggestedFix`: entire patch files
- `suggestedFixReasoning`: detailed explanation
If subagent returns stale CIPE data to main agent, it **pollutes main agent's context** with useless information (we already processed that CIPE). This wastes valuable context window.
**Without wait mode:**
1. Poll `ci_information` → get old CIPE with huge data
2. Return to main agent with all that stale data
3. Main agent's context gets polluted with useless info
4. Main agent has to process/ignore it anyway
**With wait mode:**
1. Poll `ci_information` → get old CIPE → **ignore it, don't return**
2. Keep waiting internally (stale data stays in subagent)
3. New CIPE appears → switch to normal mode
4. Return to main agent with only the NEW, relevant CIPE data
## Polling Loop
### Subagent State Management
Maintain internal accumulated state across polls:
```
accumulated_state = {}
```
### Call `ci_information` MCP Tool
**Wait Mode (expecting new CI Attempt):**
```
ci_information({
branch: "<branch_name>",
select: "cipeUrl,commitSha,cipeStatus"
})
```
Only fetch minimal fields needed to detect CI Attempt change. Do NOT fetch heavy fields - stale data wastes context.
**Normal Mode (processing CI Attempt):**
```
ci_information({
branch: "<branch_name>",
select: "cipeStatus,cipeUrl,branch,commitSha,selfHealingStatus,verificationStatus,userAction,failedTaskIds,verifiedTaskIds,selfHealingEnabled,failureClassification,couldAutoApplyTasks,shortLink,confidence,confidenceReasoning"
})
```
Merge response into `accumulated_state` after each poll.
### Analyze Response
**If in Wait Mode** (expecting new CIPE):
1. Check if CIPE is new (see Two-Phase Operation above)
2. If old CIPE → **ignore status**, output wait message, poll again
3. If new CIPE → switch to normal mode, continue below
**If in Normal Mode**:
Based on the response, decide whether to **keep polling** or **return to main agent**.
### Keep Polling When
Continue polling (with backoff) if ANY of these conditions are true:
| Condition | Reason |
| --------------------------------------- | ---------------------------------------- |
| `cipeStatus == 'IN_PROGRESS'` | CI still running |
| `cipeStatus == 'NOT_STARTED'` | CI hasn't started yet |
| `selfHealingStatus == 'IN_PROGRESS'` | Self-healing agent working |
| `selfHealingStatus == 'NOT_STARTED'` | Self-healing not started yet |
| `failureClassification == 'FLAKY_TASK'` | Auto-rerun in progress |
| `userAction == 'APPLIED_AUTOMATICALLY'` | New CI Attempt spawning after auto-apply |
When `couldAutoApplyTasks == true`:
- `verificationStatus` = `NOT_STARTED`, `IN_PROGRESS` → keep polling (verification still in progress)
- `verificationStatus` = `COMPLETED` → return `fix_auto_applying` (auto-apply will happen, main agent spawns wait mode subagent)
- `verificationStatus` = `FAILED`, `NOT_EXECUTABLE` → return `fix_available` (auto-apply won't happen, needs manual action)
### Exponential Backoff
Between polls, wait with exponential backoff:
| Poll Attempt | Wait Time |
| ------------ | ----------------- |
| 1st | 60 seconds |
| 2nd | 90 seconds |
| 3rd+ | 120 seconds (cap) |
Reset to 60 seconds when state changes significantly.
**IMPORTANT:** Run sleep in foreground (NOT as background command). Background sleep causes "What should Claude do?" prompts when completed.
```bash
# Example backoff - run in FOREGROUND
sleep 60 # First wait
sleep 90 # Second wait
sleep 120 # Third and subsequent waits (capped)
```
### Fetch Heavy Fields on Actionable State
Before returning to main agent, fetch heavy fields if the status requires them:
| Status | Heavy Fields Needed |
| ------------------- | ------------------------------------------------------------------------------ |
| `ci_success` | None |
| `fix_auto_applying` | None |
| `fix_available` | `taskOutputSummary,suggestedFix,suggestedFixReasoning,suggestedFixDescription` |
| `fix_failed` | `taskOutputSummary` |
| `no_fix` | `taskOutputSummary` |
| `environment_issue` | None |
| `no_new_cipe` | None |
| `polling_timeout` | None |
| `cipe_canceled` | None |
| `cipe_timed_out` | None |
```
# Example: fetching heavy fields for fix_available
ci_information({
branch: "<branch_name>",
select: "taskOutputSummary,suggestedFix,suggestedFixReasoning,suggestedFixDescription"
})
```
Merge response into `accumulated_state`, then return merged state to main agent.
**Pagination:** Heavy string fields return first page only. If `hasMore` indicated, include in return format so main agent knows more content available.
### Return to Main Agent When
Return immediately with structured state if ANY of these conditions are true:
| Status | Condition |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ci_success` | `cipeStatus == 'SUCCEEDED'` |
| `fix_auto_applying` | `selfHealingStatus == 'COMPLETED'` AND `couldAutoApplyTasks == true` AND `verificationStatus == 'COMPLETED'` |
| `fix_available` | `selfHealingStatus == 'COMPLETED'` AND `suggestedFix != null` AND (`couldAutoApplyTasks != true` OR `verificationStatus` in (`FAILED`, `NOT_EXECUTABLE`)) |
| `fix_failed` | `selfHealingStatus == 'FAILED'` |
| `environment_issue` | `failureClassification == 'ENVIRONMENT_STATE'` |
| `no_fix` | `cipeStatus == 'FAILED'` AND (`selfHealingEnabled == false` OR `selfHealingStatus == 'NOT_EXECUTABLE'`) |
| `no_new_cipe` | `expectedCommitSha` or `previousCipeUrl` provided, but no new CI Attempt detected after 30 min |
| `polling_timeout` | Subagent has been polling for > configured timeout (default 60 min) |
| `cipe_canceled` | `cipeStatus == 'CANCELED'` |
| `cipe_timed_out` | `cipeStatus == 'TIMED_OUT'` |
## Subagent Timeout
Track elapsed time. If you have been polling for more than **60 minutes** (configurable via main agent), return with `status: polling_timeout`.
## Return Format
When returning to the main agent, provide a structured response with accumulated state:
```
## CI Monitor Result
**Status:** <status>
**Iterations:** <count>
**Elapsed:** <minutes>m <seconds>s
### CI Attempt Details
- **Status:** <cipeStatus>
- **URL:** <cipeUrl>
- **Branch:** <branch>
- **Commit:** <commitSha>
- **Failed Tasks:** <failedTaskIds>
- **Verified Tasks:** <verifiedTaskIds>
### Self-Healing Details
- **Enabled:** <selfHealingEnabled>
- **Status:** <selfHealingStatus>
- **Verification:** <verificationStatus>
- **User Action:** <userAction>
- **Classification:** <failureClassification>
- **Confidence:** <confidence>
- **Confidence Reasoning:** <confidenceReasoning>
### Fix Information (if available)
- **Short Link:** <shortLink>
- **Description:** <suggestedFixDescription>
- **Reasoning:** <suggestedFixReasoning>
### Task Output Summary (first page)
<taskOutputSummary>
[MORE_CONTENT_AVAILABLE: taskOutputSummary, pageToken: 1]
### Suggested Fix (first page)
<suggestedFix>
[MORE_CONTENT_AVAILABLE: suggestedFix, pageToken: 1]
```
### Pagination Indicators
When a heavy field has more content available, append indicator:
```
[MORE_CONTENT_AVAILABLE: <fieldName>, pageToken: <nextPage>]
```
Main agent can fetch additional pages if needed using:
```
ci_information({ select: "<fieldName>", pageToken: <nextPage> })
```
Fields that may have pagination:
- `taskOutputSummary` (reverse pagination - page 0 = most recent)
- `suggestedFix` (forward pagination - page 0 = start)
- `suggestedFixReasoning`
### Return Format for `no_new_cipe`
When returning with `status: no_new_cipe`, include additional context:
```
## CI Monitor Result
**Status:** no_new_cipe
**Iterations:** <count>
**Elapsed:** <minutes>m <seconds>s
### Expected CI Attempt Not Found
- **Expected Commit SHA:** <expectedCommitSha>
- **Previous CI Attempt URL:** <previousCipeUrl>
- **Last Seen CI Attempt URL:** <cipeUrl>
- **Last Seen Commit SHA:** <commitSha>
- **New CI Attempt Timeout:** 30 minutes (exceeded)
### Likely Cause
CI workflow failed before Nx tasks could run (e.g., install step, checkout, auth).
Check your CI provider logs for the commit <expectedCommitSha>.
### Last Known CI Attempt State
- **Status:** <cipeStatus>
- **Branch:** <branch>
```
## Status Reporting (Verbosity-Controlled)
Output is controlled by the `verbosity` parameter from the main agent:
| Level | What to Output |
| --------- | ----------------------------------------------------------------- |
| `minimal` | No intermediate output. Only return final result when actionable. |
| `medium` | Output only on significant state changes (not every poll). |
| `verbose` | Output detailed phase information after every poll. |
### Minimal Verbosity
No output during polling. Poll silently and return when done.
### Medium Verbosity (Default)
Output **only when state changes significantly** to save context tokens:
- `cipeStatus` changes (e.g., IN_PROGRESS → FAILED)
- `selfHealingStatus` changes (e.g., IN_PROGRESS → COMPLETED)
- New CI Attempt detected (in wait mode)
Format: single line, no decorators:
```
[CI Monitor] CI: FAILED | Self-Healing: IN_PROGRESS | Elapsed: 4m
```
### Verbose Verbosity
Output detailed phase box after every poll:
```
[CI Monitor] ─────────────────────────────────────────────────────
[CI Monitor] Iteration <N> | Elapsed: <X>m <Y>s
[CI Monitor]
[CI Monitor] CI Status: <cipeStatus>
[CI Monitor] Self-Healing: <selfHealingStatus>
[CI Monitor] Verification: <verificationStatus>
[CI Monitor] Classification: <failureClassification>
[CI Monitor]
[CI Monitor] → <human-readable phase description>
[CI Monitor] ─────────────────────────────────────────────────────
```
### Phase Descriptions (for verbose output)
| Status Combo | Description |
| ----------------------------------------------------------------------------------------- | ------------------------------------------- |
| `cipeStatus: IN_PROGRESS` | "CI running..." |
| `cipeStatus: NOT_STARTED` | "Waiting for CI to start..." |
| `cipeStatus: FAILED` + `selfHealingStatus: NOT_STARTED` | "CI failed. Self-healing starting..." |
| `cipeStatus: FAILED` + `selfHealingStatus: IN_PROGRESS` | "CI failed. Self-healing generating fix..." |
| `cipeStatus: FAILED` + `selfHealingStatus: COMPLETED` + `verificationStatus: IN_PROGRESS` | "Fix generated! Verification running..." |
| `cipeStatus: FAILED` + `selfHealingStatus: COMPLETED` + `verificationStatus: COMPLETED` | "Fix ready! Verified successfully." |
| `cipeStatus: FAILED` + `selfHealingStatus: COMPLETED` + `verificationStatus: FAILED` | "Fix generated but verification failed." |
| `cipeStatus: FAILED` + `selfHealingStatus: FAILED` | "Self-healing could not generate a fix." |
| `cipeStatus: SUCCEEDED` | "CI passed!" |
## Important Notes
- You do NOT make apply/reject decisions - that's the main agent's job
- You do NOT perform git operations
- You only poll and report state
- Respect the `verbosity` parameter for output (default: medium)
- If `ci_information` returns an error, wait and retry (count as failed poll)
- Track consecutive failures - if 5 consecutive failures, return with `status: error`
- When expecting new CI Attempt, track the 30-minute new-CI-Attempt timeout separately from the main polling timeout
+18
View File
@@ -0,0 +1,18 @@
# This configuration is here to prevent false positive alerts for __fixtures__.
# We are intentionally disabling the PR opening feature.
version: 2
updates:
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'weekly'
open-pull-requests-limit: 0
exclude-paths:
- '**/__fixtures__/**'
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'weekly'
open-pull-requests-limit: 0
+437
View File
@@ -0,0 +1,437 @@
---
description: Monitor Nx Cloud CI pipeline and handle self-healing fixes automatically. Checks for Nx Cloud connection before starting.
argument-hint: '[instructions] [--max-cycles N] [--timeout MINUTES] [--verbosity minimal|medium|verbose] [--branch BRANCH] [--fresh] [--auto-fix-workflow] [--new-cipe-timeout MINUTES]'
---
# CI Monitor Command
You are the orchestrator for monitoring Nx Cloud CI pipeline executions and handling self-healing fixes. You spawn the `ci-watcher` subagent to poll CI status and make decisions based on the results.
## Context
- **Current Branch:** !`git branch --show-current`
- **Current Commit:** !`git rev-parse --short HEAD`
- **Remote Status:** !`git status -sb | head -1`
## User Instructions
${input:args}
**Important:** If user provides specific instructions, respect them over default behaviors described below.
## Configuration Defaults
| Setting | Default | Description |
| ------------------------- | ------------- | ------------------------------------------------------------------- |
| `--max-cycles` | 10 | Maximum CIPE cycles before timeout |
| `--timeout` | 120 | Maximum duration in minutes |
| `--verbosity` | medium | Output level: minimal, medium, verbose |
| `--branch` | (auto-detect) | Branch to monitor |
| `--subagent-timeout` | 60 | Subagent polling timeout in minutes |
| `--fresh` | false | Ignore previous context, start fresh |
| `--auto-fix-workflow` | false | Attempt common fixes for pre-CIPE failures (e.g., lockfile updates) |
| `--new-cipe-timeout` | 10 | Minutes to wait for new CIPE after action |
| `--local-verify-attempts` | 3 | Max local verification + enhance cycles before pushing to CI |
Parse any overrides from `${input:args}` and merge with defaults.
## Nx Cloud Connection Check
**CRITICAL**: Before starting the monitoring loop, verify the workspace is connected to Nx Cloud.
### Step 0: Verify Nx Cloud Connection
1. **Check `nx.json`** at workspace root for `nxCloudId` or `nxCloudAccessToken`
2. **If `nx.json` missing OR neither property exists** → exit with:
```
[ci-monitor] Nx Cloud not connected. Unlock 70% faster CI and auto-fix broken PRs with https://nx.dev/nx-cloud
```
3. **If connected** → continue to main loop
## Session Context Behavior
**Important:** Within a Claude Code session, conversation context persists. If you Ctrl+C to interrupt the monitor and re-run `/ci-monitor`, Claude remembers the previous state and may continue from where it left off.
- **To continue monitoring:** Just re-run `/ci-monitor` (context is preserved)
- **To start fresh:** Use `/ci-monitor --fresh` to ignore previous context
- **For a completely clean slate:** Exit Claude Code and restart `claude`
## Default Behaviors by Status
The subagent returns with one of the following statuses. This table defines the **default behavior** for each status. User instructions can override any of these.
| Status | Default Behavior |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ci_success` | Exit with success. Log "CI passed successfully!" |
| `fix_auto_applying` | Fix will be auto-applied by self-healing. Do NOT call MCP. Record `last_cipe_url`, spawn new subagent in wait mode to poll for new CIPE. |
| `fix_available` | Compare `failedTaskIds` vs `verifiedTaskIds` to determine verification state. See **Fix Available Decision Logic** section below. |
| `fix_failed` | Self-healing failed to generate fix. Attempt local fix based on `taskOutputSummary`. If successful → commit, push, loop. If not → exit with failure. |
| `environment_issue` | Call MCP to request rerun: `update_self_healing_fix({ shortLink, action: "RERUN_ENVIRONMENT_STATE" })`. New CIPE spawns automatically. Loop to poll for new CIPE. |
| `no_fix` | CI failed, no fix available (self-healing disabled or not executable). Attempt local fix if possible. Otherwise exit with failure. |
| `no_new_cipe` | Expected CIPE never spawned (CI workflow likely failed before Nx tasks). Report to user, attempt common fixes if configured, or exit with guidance. |
| `polling_timeout` | Subagent polling timeout reached. Exit with timeout. |
| `cipe_canceled` | CIPE was canceled. Exit with canceled status. |
| `cipe_timed_out` | CIPE timed out. Exit with timeout status. |
| `error` | Increment `no_progress_count`. If >= 3 → exit with circuit breaker. Otherwise wait 60s and loop. |
### Fix Available Decision Logic
When subagent returns `fix_available`, main agent compares `failedTaskIds` vs `verifiedTaskIds`:
#### Step 1: Categorize Tasks
1. **Verified tasks** = tasks in both `failedTaskIds` AND `verifiedTaskIds`
2. **Unverified tasks** = tasks in `failedTaskIds` but NOT in `verifiedTaskIds`
3. **E2E tasks** = unverified tasks where target contains "e2e" (task format: `<project>:<target>` or `<project>:<target>:<config>`)
4. **Verifiable tasks** = unverified tasks that are NOT e2e
#### Step 2: Determine Path
| Condition | Path |
| --------------------------------------- | ---------------------------------------- |
| No unverified tasks (all verified) | Apply via MCP |
| Unverified tasks exist, but ALL are e2e | Apply via MCP (treat as verified enough) |
| Verifiable tasks exist | Local verification flow |
#### Step 3a: Apply via MCP (fully/e2e-only verified)
- Call `update_self_healing_fix({ shortLink, action: "APPLY" })`
- Record `last_cipe_url`, spawn subagent in wait mode
#### Step 3b: Local Verification Flow
When verifiable (non-e2e) unverified tasks exist:
1. **Detect package manager:**
- `pnpm-lock.yaml` exists → `pnpm nx`
- `yarn.lock` exists → `yarn nx`
- Otherwise → `npx nx`
2. **Run verifiable tasks in parallel:**
- Spawn `general` subagents to run each task concurrently
- Each subagent runs: `<pm> nx run <taskId>`
- Collect pass/fail results from all subagents
3. **Evaluate results:**
| Result | Action |
| ------------------------- | ---------------------------- |
| ALL verifiable tasks pass | Apply via MCP |
| ANY verifiable task fails | Apply-locally + enhance flow |
4. **Apply-locally + enhance flow:**
- Run `nx apply-locally <shortLink>`
- Enhance the code to fix failing tasks
- Run failing tasks again to verify fix
- If still failing → increment `local_verify_count`, loop back to enhance
- If passing → commit and push, record `expected_commit_sha`, spawn subagent in wait mode
5. **Track attempts** (wraps step 4):
- Increment `local_verify_count` after each enhance cycle
- If `local_verify_count >= local_verify_attempts` (default: 3):
- Get code in commit-able state
- Commit and push with message indicating local verification failed
- Report to user:
```
[ci-monitor] Local verification failed after <N> attempts. Pushed to CI for final validation. Failed: <taskIds>
```
- Record `expected_commit_sha`, spawn subagent in wait mode (let CI be final judge)
#### Commit Message Format
```bash
git commit -m "fix(<projects>): <brief description>
Failed tasks: <taskId1>, <taskId2>
Local verification: passed|enhanced|failed-pushing-to-ci"
```
### Unverified Fix Flow (No Verification Attempted)
When `verificationStatus` is `FAILED`, `NOT_EXECUTABLE`, or fix has `couldAutoApplyTasks != true` with no verification:
- Analyze fix content (`suggestedFix`, `suggestedFixReasoning`, `taskOutputSummary`)
- If fix looks correct → apply via MCP
- If fix needs enhancement → use Apply Locally + Enhance Flow above
- If fix is wrong → reject via MCP, fix from scratch, commit, push
### Auto-Apply Eligibility
The `couldAutoApplyTasks` field indicates whether the fix is eligible for automatic application:
- **`true`**: Fix is eligible for auto-apply. Subagent keeps polling while verification is in progress. Returns `fix_auto_applying` when verified, or `fix_available` if verification fails.
- **`false`** or **`null`**: Fix requires manual action (apply via MCP, apply locally, or reject)
**Key point**: When subagent returns `fix_auto_applying`, do NOT call MCP to apply - self-healing handles it. Just spawn a new subagent in wait mode.
### Apply vs Reject vs Apply Locally
- **Apply via MCP**: Calls `update_self_healing_fix({ shortLink, action: "APPLY" })`. Self-healing agent applies the fix in CI and a new CIPE spawns automatically. No local git operations needed.
- **Apply Locally**: Runs `nx apply-locally <shortLink>`. Applies the patch to your local working directory and sets state to `APPLIED_LOCALLY`. Use this when you want to enhance the fix before pushing.
- **Reject via MCP**: Calls `update_self_healing_fix({ shortLink, action: "REJECT" })`. Marks fix as rejected. Use only when the fix is completely wrong and you'll fix from scratch.
### Apply Locally + Enhance Flow
When the fix needs enhancement (use `nx apply-locally`, NOT reject):
1. Apply the patch locally: `nx apply-locally <shortLink>` (this also updates state to `APPLIED_LOCALLY`)
2. Make additional changes as needed
3. Commit and push:
```bash
git add -A
git commit -m "fix: resolve <failedTaskIds>"
git push origin $(git branch --show-current)
```
4. Loop to poll for new CIPE
### Reject + Fix From Scratch Flow
When the fix is completely wrong:
1. Call MCP to reject: `update_self_healing_fix({ shortLink, action: "REJECT" })`
2. Fix the issue from scratch locally
3. Commit and push:
```bash
git add -A
git commit -m "fix: resolve <failedTaskIds>"
git push origin $(git branch --show-current)
```
4. Loop to poll for new CIPE
### Environment Issue Handling
When `failureClassification == 'ENVIRONMENT_STATE'`:
1. Call MCP to request rerun: `update_self_healing_fix({ shortLink, action: "RERUN_ENVIRONMENT_STATE" })`
2. New CIPE spawns automatically (no local git operations needed)
3. Loop to poll for new CIPE with `previousCipeUrl` set
### No-New-CIPE Handling
When `status == 'no_new_cipe'`:
This means the expected CIPE was never created - CI likely failed before Nx tasks could run.
1. **Report to user:**
```
[ci-monitor] No CI attempt for <sha> after 10 min. Check CI provider for pre-Nx failures (install, checkout, auth). Last CI attempt: <previousCipeUrl>
```
2. **If user configured auto-fix attempts** (e.g., `--auto-fix-workflow`):
- Detect package manager: check for `pnpm-lock.yaml`, `yarn.lock`, `package-lock.json`
- Run install to update lockfile:
```bash
pnpm install # or npm install / yarn install
```
- If lockfile changed:
```bash
git add pnpm-lock.yaml # or appropriate lockfile
git commit -m "chore: update lockfile"
git push origin $(git branch --show-current)
```
- Record new commit SHA, loop to poll with `expectedCommitSha`
3. **Otherwise:** Exit with `no_new_cipe` status, providing guidance for user to investigate
## Exit Conditions
Exit the monitoring loop when ANY of these conditions are met:
| Condition | Exit Type |
| ------------------------------------------- | ---------------- |
| CI passes (`cipeStatus == 'SUCCEEDED'`) | Success |
| Max CIPE cycles reached | Timeout |
| Max duration reached | Timeout |
| 3 consecutive no-progress iterations | Circuit breaker |
| No fix available and local fix not possible | Failure |
| No new CIPE and auto-fix not configured | Pre-CIPE failure |
| User cancels | Cancelled |
## Main Loop
### Step 1: Initialize Tracking
```
cycle_count = 0
start_time = now()
no_progress_count = 0
local_verify_count = 0
last_state = null
last_cipe_url = null
expected_commit_sha = null
```
### Step 2: Spawn Subagent
Spawn the `ci-watcher` subagent to poll CI status:
**Fresh start (first spawn, no expected CIPE):**
```
Task(
agent: "ci-watcher",
prompt: "Monitor CI for branch '<branch>'.
Subagent timeout: <subagent-timeout> minutes.
New-CIPE timeout: <new-cipe-timeout> minutes.
Verbosity: <verbosity>."
)
```
**After action that triggers new CIPE (wait mode):**
```
Task(
agent: "ci-watcher",
prompt: "Monitor CI for branch '<branch>'.
Subagent timeout: <subagent-timeout> minutes.
New-CIPE timeout: <new-cipe-timeout> minutes.
Verbosity: <verbosity>.
WAIT MODE: A new CIPE should spawn. Ignore old CIPE until new one appears.
Expected commit SHA: <expected_commit_sha>
Previous CIPE URL: <last_cipe_url>"
)
```
### Step 3: Handle Subagent Response
When subagent returns:
1. Check the returned status
2. Look up default behavior in the table above
3. Check if user instructions override the default
4. Execute the appropriate action
5. **If action expects new CIPE**, update tracking (see Step 3a)
6. If action results in looping, go to Step 2
### Step 3a: Track State for New-CIPE Detection
After actions that should trigger a new CIPE, record state before looping:
| Action | What to Track | Subagent Mode |
| ----------------------------- | --------------------------------------------- | ------------- |
| Fix auto-applying | `last_cipe_url = current cipeUrl` | Wait mode |
| Apply via MCP | `last_cipe_url = current cipeUrl` | Wait mode |
| Apply locally + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Reject + fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Fix failed + local fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| No fix + local fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Environment rerun | `last_cipe_url = current cipeUrl` | Wait mode |
| No-new-CIPE + auto-fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
**CRITICAL**: When passing `expectedCommitSha` or `last_cipe_url` to the subagent, it enters **wait mode**:
- Subagent will **completely ignore** the old/stale CIPE
- Subagent will only wait for new CIPE to appear
- Subagent will NOT return to main agent with stale CIPE data
- Once new CIPE detected, subagent switches to normal polling
**Why wait mode matters for context preservation**: Stale CIPE data can be very large (task output summaries, suggested fix patches, reasoning). If subagent returns this to main agent, it pollutes main agent's context with useless data since we already processed that CIPE. Wait mode keeps stale data in the subagent, never sending it to main agent.
### Step 4: Progress Tracking
After each action:
- If state changed significantly → reset `no_progress_count = 0`
- If state unchanged → `no_progress_count++`
- On new CI attempt detected → reset `local_verify_count = 0`
## Status Reporting
Based on verbosity level:
| Level | What to Report |
| --------- | -------------------------------------------------------------------------- |
| `minimal` | Only final result (success/failure/timeout) |
| `medium` | State changes + periodic updates ("Cycle N \| Elapsed: Xm \| Status: ...") |
| `verbose` | All of medium + full subagent responses, git outputs, MCP responses |
## User Instruction Examples
Users can override default behaviors:
| Instruction | Effect |
| ------------------------------------------------ | --------------------------------------------- |
| "never auto-apply" | Always prompt before applying any fix |
| "always ask before git push" | Prompt before each push |
| "reject any fix for e2e tasks" | Auto-reject if `failedTaskIds` contains e2e |
| "apply all fixes regardless of verification" | Skip verification check, apply everything |
| "if confidence < 70, reject" | Check confidence field before applying |
| "run 'nx affected -t typecheck' before applying" | Add local verification step |
| "auto-fix workflow failures" | Attempt lockfile updates on pre-CIPE failures |
| "wait 45 min for new CIPE" | Override new-CIPE timeout (default: 10 min) |
## Error Handling
| Error | Action |
| ------------------------ | ------------------------------------------------------------------------------------- |
| Git rebase conflict | Report to user, exit |
| `nx apply-locally` fails | Report to user, attempt manual patch or exit |
| MCP tool error | Retry once, if fails report to user |
| Subagent spawn failure | Retry once, if fails exit with error |
| No new CIPE detected | If `--auto-fix-workflow`, try lockfile update; otherwise report to user with guidance |
| Lockfile auto-fix fails | Report to user, exit with guidance to check CI logs |
## Example Session
### Example 1: Normal Flow with Self-Healing (medium verbosity)
```
[ci-monitor] Starting CI monitor for branch 'feature/add-auth'
[ci-monitor] Config: max-cycles=5, timeout=120m, verbosity=medium
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] CI attempt: IN_PROGRESS | Self-Healing: NOT_STARTED | Elapsed: 1m
[CI Monitor] CI attempt: FAILED | Self-Healing: IN_PROGRESS | Elapsed: 3m
[CI Monitor] CI attempt: FAILED | Self-Healing: COMPLETED | Elapsed: 5m
[ci-monitor] Fix available! Verification: COMPLETED
[ci-monitor] Applying fix via MCP...
[ci-monitor] Fix applied in CI. Waiting for new CI attempt...
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] New CI attempt detected!
[CI Monitor] CI attempt: SUCCEEDED | Elapsed: 8m
[ci-monitor] CI passed successfully!
[ci-monitor] Summary:
- Total cycles: 2
- Total time: 12m 34s
- Fixes applied: 1
- Result: SUCCESS
```
### Example 2: Pre-CI Failure (medium verbosity)
```
[ci-monitor] Starting CI monitor for branch 'feature/add-products'
[ci-monitor] Config: max-cycles=5, timeout=120m, auto-fix-workflow=true
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] CI attempt: FAILED | Self-Healing: COMPLETED | Elapsed: 2m
[ci-monitor] Applying fix locally, enhancing, and pushing...
[ci-monitor] Committed: abc1234
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] Waiting for new CI attempt... (expected SHA: abc1234)
[CI Monitor] ⚠️ CI attempt timeout (10 min). Returning no_new_cipe.
[ci-monitor] Status: no_new_cipe
[ci-monitor] --auto-fix-workflow enabled. Attempting lockfile update...
[ci-monitor] Lockfile updated. Committed: def5678
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] New CI attempt detected!
[CI Monitor] CI attempt: SUCCEEDED | Elapsed: 18m
[ci-monitor] CI passed successfully!
[ci-monitor] Summary:
- Total cycles: 3
- Total time: 22m 15s
- Fixes applied: 1 (self-healing) + 1 (lockfile)
- Result: SUCCESS
```
+437
View File
@@ -0,0 +1,437 @@
---
name: ci-monitor
description: Monitor Nx Cloud CI pipeline and handle self-healing fixes automatically. Checks for Nx Cloud connection before starting.
---
# CI Monitor Command
You are the orchestrator for monitoring Nx Cloud CI pipeline executions and handling self-healing fixes. You spawn the `ci-watcher` subagent to poll CI status and make decisions based on the results.
## Context
- **Current Branch:** !`git branch --show-current`
- **Current Commit:** !`git rev-parse --short HEAD`
- **Remote Status:** !`git status -sb | head -1`
## User Instructions
$ARGUMENTS
**Important:** If user provides specific instructions, respect them over default behaviors described below.
## Configuration Defaults
| Setting | Default | Description |
| ------------------------- | ------------- | ------------------------------------------------------------------- |
| `--max-cycles` | 10 | Maximum CIPE cycles before timeout |
| `--timeout` | 120 | Maximum duration in minutes |
| `--verbosity` | medium | Output level: minimal, medium, verbose |
| `--branch` | (auto-detect) | Branch to monitor |
| `--subagent-timeout` | 60 | Subagent polling timeout in minutes |
| `--fresh` | false | Ignore previous context, start fresh |
| `--auto-fix-workflow` | false | Attempt common fixes for pre-CIPE failures (e.g., lockfile updates) |
| `--new-cipe-timeout` | 10 | Minutes to wait for new CIPE after action |
| `--local-verify-attempts` | 3 | Max local verification + enhance cycles before pushing to CI |
Parse any overrides from `$ARGUMENTS` and merge with defaults.
## Nx Cloud Connection Check
**CRITICAL**: Before starting the monitoring loop, verify the workspace is connected to Nx Cloud.
### Step 0: Verify Nx Cloud Connection
1. **Check `nx.json`** at workspace root for `nxCloudId` or `nxCloudAccessToken`
2. **If `nx.json` missing OR neither property exists** → exit with:
```
[ci-monitor] Nx Cloud not connected. Unlock 70% faster CI and auto-fix broken PRs with https://nx.dev/nx-cloud
```
3. **If connected** → continue to main loop
## Session Context Behavior
**Important:** Within a Claude Code session, conversation context persists. If you Ctrl+C to interrupt the monitor and re-run `/ci-monitor`, Claude remembers the previous state and may continue from where it left off.
- **To continue monitoring:** Just re-run `/ci-monitor` (context is preserved)
- **To start fresh:** Use `/ci-monitor --fresh` to ignore previous context
- **For a completely clean slate:** Exit Claude Code and restart `claude`
## Default Behaviors by Status
The subagent returns with one of the following statuses. This table defines the **default behavior** for each status. User instructions can override any of these.
| Status | Default Behavior |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ci_success` | Exit with success. Log "CI passed successfully!" |
| `fix_auto_applying` | Fix will be auto-applied by self-healing. Do NOT call MCP. Record `last_cipe_url`, spawn new subagent in wait mode to poll for new CIPE. |
| `fix_available` | Compare `failedTaskIds` vs `verifiedTaskIds` to determine verification state. See **Fix Available Decision Logic** section below. |
| `fix_failed` | Self-healing failed to generate fix. Attempt local fix based on `taskOutputSummary`. If successful → commit, push, loop. If not → exit with failure. |
| `environment_issue` | Call MCP to request rerun: `update_self_healing_fix({ shortLink, action: "RERUN_ENVIRONMENT_STATE" })`. New CIPE spawns automatically. Loop to poll for new CIPE. |
| `no_fix` | CI failed, no fix available (self-healing disabled or not executable). Attempt local fix if possible. Otherwise exit with failure. |
| `no_new_cipe` | Expected CIPE never spawned (CI workflow likely failed before Nx tasks). Report to user, attempt common fixes if configured, or exit with guidance. |
| `polling_timeout` | Subagent polling timeout reached. Exit with timeout. |
| `cipe_canceled` | CIPE was canceled. Exit with canceled status. |
| `cipe_timed_out` | CIPE timed out. Exit with timeout status. |
| `error` | Increment `no_progress_count`. If >= 3 → exit with circuit breaker. Otherwise wait 60s and loop. |
### Fix Available Decision Logic
When subagent returns `fix_available`, main agent compares `failedTaskIds` vs `verifiedTaskIds`:
#### Step 1: Categorize Tasks
1. **Verified tasks** = tasks in both `failedTaskIds` AND `verifiedTaskIds`
2. **Unverified tasks** = tasks in `failedTaskIds` but NOT in `verifiedTaskIds`
3. **E2E tasks** = unverified tasks where target contains "e2e" (task format: `<project>:<target>` or `<project>:<target>:<config>`)
4. **Verifiable tasks** = unverified tasks that are NOT e2e
#### Step 2: Determine Path
| Condition | Path |
| --------------------------------------- | ---------------------------------------- |
| No unverified tasks (all verified) | Apply via MCP |
| Unverified tasks exist, but ALL are e2e | Apply via MCP (treat as verified enough) |
| Verifiable tasks exist | Local verification flow |
#### Step 3a: Apply via MCP (fully/e2e-only verified)
- Call `update_self_healing_fix({ shortLink, action: "APPLY" })`
- Record `last_cipe_url`, spawn subagent in wait mode
#### Step 3b: Local Verification Flow
When verifiable (non-e2e) unverified tasks exist:
1. **Detect package manager:**
- `pnpm-lock.yaml` exists → `pnpm nx`
- `yarn.lock` exists → `yarn nx`
- Otherwise → `npx nx`
2. **Run verifiable tasks in parallel:**
- Spawn `general` subagents to run each task concurrently
- Each subagent runs: `<pm> nx run <taskId>`
- Collect pass/fail results from all subagents
3. **Evaluate results:**
| Result | Action |
| ------------------------- | ---------------------------- |
| ALL verifiable tasks pass | Apply via MCP |
| ANY verifiable task fails | Apply-locally + enhance flow |
4. **Apply-locally + enhance flow:**
- Run `nx apply-locally <shortLink>`
- Enhance the code to fix failing tasks
- Run failing tasks again to verify fix
- If still failing → increment `local_verify_count`, loop back to enhance
- If passing → commit and push, record `expected_commit_sha`, spawn subagent in wait mode
5. **Track attempts** (wraps step 4):
- Increment `local_verify_count` after each enhance cycle
- If `local_verify_count >= local_verify_attempts` (default: 3):
- Get code in commit-able state
- Commit and push with message indicating local verification failed
- Report to user:
```
[ci-monitor] Local verification failed after <N> attempts. Pushed to CI for final validation. Failed: <taskIds>
```
- Record `expected_commit_sha`, spawn subagent in wait mode (let CI be final judge)
#### Commit Message Format
```bash
git commit -m "fix(<projects>): <brief description>
Failed tasks: <taskId1>, <taskId2>
Local verification: passed|enhanced|failed-pushing-to-ci"
```
### Unverified Fix Flow (No Verification Attempted)
When `verificationStatus` is `FAILED`, `NOT_EXECUTABLE`, or fix has `couldAutoApplyTasks != true` with no verification:
- Analyze fix content (`suggestedFix`, `suggestedFixReasoning`, `taskOutputSummary`)
- If fix looks correct → apply via MCP
- If fix needs enhancement → use Apply Locally + Enhance Flow above
- If fix is wrong → reject via MCP, fix from scratch, commit, push
### Auto-Apply Eligibility
The `couldAutoApplyTasks` field indicates whether the fix is eligible for automatic application:
- **`true`**: Fix is eligible for auto-apply. Subagent keeps polling while verification is in progress. Returns `fix_auto_applying` when verified, or `fix_available` if verification fails.
- **`false`** or **`null`**: Fix requires manual action (apply via MCP, apply locally, or reject)
**Key point**: When subagent returns `fix_auto_applying`, do NOT call MCP to apply - self-healing handles it. Just spawn a new subagent in wait mode.
### Apply vs Reject vs Apply Locally
- **Apply via MCP**: Calls `update_self_healing_fix({ shortLink, action: "APPLY" })`. Self-healing agent applies the fix in CI and a new CIPE spawns automatically. No local git operations needed.
- **Apply Locally**: Runs `nx apply-locally <shortLink>`. Applies the patch to your local working directory and sets state to `APPLIED_LOCALLY`. Use this when you want to enhance the fix before pushing.
- **Reject via MCP**: Calls `update_self_healing_fix({ shortLink, action: "REJECT" })`. Marks fix as rejected. Use only when the fix is completely wrong and you'll fix from scratch.
### Apply Locally + Enhance Flow
When the fix needs enhancement (use `nx apply-locally`, NOT reject):
1. Apply the patch locally: `nx apply-locally <shortLink>` (this also updates state to `APPLIED_LOCALLY`)
2. Make additional changes as needed
3. Commit and push:
```bash
git add -A
git commit -m "fix: resolve <failedTaskIds>"
git push origin $(git branch --show-current)
```
4. Loop to poll for new CIPE
### Reject + Fix From Scratch Flow
When the fix is completely wrong:
1. Call MCP to reject: `update_self_healing_fix({ shortLink, action: "REJECT" })`
2. Fix the issue from scratch locally
3. Commit and push:
```bash
git add -A
git commit -m "fix: resolve <failedTaskIds>"
git push origin $(git branch --show-current)
```
4. Loop to poll for new CIPE
### Environment Issue Handling
When `failureClassification == 'ENVIRONMENT_STATE'`:
1. Call MCP to request rerun: `update_self_healing_fix({ shortLink, action: "RERUN_ENVIRONMENT_STATE" })`
2. New CIPE spawns automatically (no local git operations needed)
3. Loop to poll for new CIPE with `previousCipeUrl` set
### No-New-CIPE Handling
When `status == 'no_new_cipe'`:
This means the expected CIPE was never created - CI likely failed before Nx tasks could run.
1. **Report to user:**
```
[ci-monitor] No CI attempt for <sha> after 10 min. Check CI provider for pre-Nx failures (install, checkout, auth). Last CI attempt: <previousCipeUrl>
```
2. **If user configured auto-fix attempts** (e.g., `--auto-fix-workflow`):
- Detect package manager: check for `pnpm-lock.yaml`, `yarn.lock`, `package-lock.json`
- Run install to update lockfile:
```bash
pnpm install # or npm install / yarn install
```
- If lockfile changed:
```bash
git add pnpm-lock.yaml # or appropriate lockfile
git commit -m "chore: update lockfile"
git push origin $(git branch --show-current)
```
- Record new commit SHA, loop to poll with `expectedCommitSha`
3. **Otherwise:** Exit with `no_new_cipe` status, providing guidance for user to investigate
## Exit Conditions
Exit the monitoring loop when ANY of these conditions are met:
| Condition | Exit Type |
| ------------------------------------------- | ---------------- |
| CI passes (`cipeStatus == 'SUCCEEDED'`) | Success |
| Max CIPE cycles reached | Timeout |
| Max duration reached | Timeout |
| 3 consecutive no-progress iterations | Circuit breaker |
| No fix available and local fix not possible | Failure |
| No new CIPE and auto-fix not configured | Pre-CIPE failure |
| User cancels | Cancelled |
## Main Loop
### Step 1: Initialize Tracking
```
cycle_count = 0
start_time = now()
no_progress_count = 0
local_verify_count = 0
last_state = null
last_cipe_url = null
expected_commit_sha = null
```
### Step 2: Spawn Subagent
Spawn the `ci-watcher` subagent to poll CI status:
**Fresh start (first spawn, no expected CIPE):**
```
Task(
agent: "ci-watcher",
prompt: "Monitor CI for branch '<branch>'.
Subagent timeout: <subagent-timeout> minutes.
New-CIPE timeout: <new-cipe-timeout> minutes.
Verbosity: <verbosity>."
)
```
**After action that triggers new CIPE (wait mode):**
```
Task(
agent: "ci-watcher",
prompt: "Monitor CI for branch '<branch>'.
Subagent timeout: <subagent-timeout> minutes.
New-CIPE timeout: <new-cipe-timeout> minutes.
Verbosity: <verbosity>.
WAIT MODE: A new CIPE should spawn. Ignore old CIPE until new one appears.
Expected commit SHA: <expected_commit_sha>
Previous CIPE URL: <last_cipe_url>"
)
```
### Step 3: Handle Subagent Response
When subagent returns:
1. Check the returned status
2. Look up default behavior in the table above
3. Check if user instructions override the default
4. Execute the appropriate action
5. **If action expects new CIPE**, update tracking (see Step 3a)
6. If action results in looping, go to Step 2
### Step 3a: Track State for New-CIPE Detection
After actions that should trigger a new CIPE, record state before looping:
| Action | What to Track | Subagent Mode |
| ----------------------------- | --------------------------------------------- | ------------- |
| Fix auto-applying | `last_cipe_url = current cipeUrl` | Wait mode |
| Apply via MCP | `last_cipe_url = current cipeUrl` | Wait mode |
| Apply locally + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Reject + fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Fix failed + local fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| No fix + local fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Environment rerun | `last_cipe_url = current cipeUrl` | Wait mode |
| No-new-CIPE + auto-fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
**CRITICAL**: When passing `expectedCommitSha` or `last_cipe_url` to the subagent, it enters **wait mode**:
- Subagent will **completely ignore** the old/stale CIPE
- Subagent will only wait for new CIPE to appear
- Subagent will NOT return to main agent with stale CIPE data
- Once new CIPE detected, subagent switches to normal polling
**Why wait mode matters for context preservation**: Stale CIPE data can be very large (task output summaries, suggested fix patches, reasoning). If subagent returns this to main agent, it pollutes main agent's context with useless data since we already processed that CIPE. Wait mode keeps stale data in the subagent, never sending it to main agent.
### Step 4: Progress Tracking
After each action:
- If state changed significantly → reset `no_progress_count = 0`
- If state unchanged → `no_progress_count++`
- On new CI attempt detected → reset `local_verify_count = 0`
## Status Reporting
Based on verbosity level:
| Level | What to Report |
| --------- | -------------------------------------------------------------------------- |
| `minimal` | Only final result (success/failure/timeout) |
| `medium` | State changes + periodic updates ("Cycle N \| Elapsed: Xm \| Status: ...") |
| `verbose` | All of medium + full subagent responses, git outputs, MCP responses |
## User Instruction Examples
Users can override default behaviors:
| Instruction | Effect |
| ------------------------------------------------ | --------------------------------------------- |
| "never auto-apply" | Always prompt before applying any fix |
| "always ask before git push" | Prompt before each push |
| "reject any fix for e2e tasks" | Auto-reject if `failedTaskIds` contains e2e |
| "apply all fixes regardless of verification" | Skip verification check, apply everything |
| "if confidence < 70, reject" | Check confidence field before applying |
| "run 'nx affected -t typecheck' before applying" | Add local verification step |
| "auto-fix workflow failures" | Attempt lockfile updates on pre-CIPE failures |
| "wait 45 min for new CIPE" | Override new-CIPE timeout (default: 10 min) |
## Error Handling
| Error | Action |
| ------------------------ | ------------------------------------------------------------------------------------- |
| Git rebase conflict | Report to user, exit |
| `nx apply-locally` fails | Report to user, attempt manual patch or exit |
| MCP tool error | Retry once, if fails report to user |
| Subagent spawn failure | Retry once, if fails exit with error |
| No new CIPE detected | If `--auto-fix-workflow`, try lockfile update; otherwise report to user with guidance |
| Lockfile auto-fix fails | Report to user, exit with guidance to check CI logs |
## Example Session
### Example 1: Normal Flow with Self-Healing (medium verbosity)
```
[ci-monitor] Starting CI monitor for branch 'feature/add-auth'
[ci-monitor] Config: max-cycles=5, timeout=120m, verbosity=medium
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] CI attempt: IN_PROGRESS | Self-Healing: NOT_STARTED | Elapsed: 1m
[CI Monitor] CI attempt: FAILED | Self-Healing: IN_PROGRESS | Elapsed: 3m
[CI Monitor] CI attempt: FAILED | Self-Healing: COMPLETED | Elapsed: 5m
[ci-monitor] Fix available! Verification: COMPLETED
[ci-monitor] Applying fix via MCP...
[ci-monitor] Fix applied in CI. Waiting for new CI attempt...
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] New CI attempt detected!
[CI Monitor] CI attempt: SUCCEEDED | Elapsed: 8m
[ci-monitor] CI passed successfully!
[ci-monitor] Summary:
- Total cycles: 2
- Total time: 12m 34s
- Fixes applied: 1
- Result: SUCCESS
```
### Example 2: Pre-CI Failure (medium verbosity)
```
[ci-monitor] Starting CI monitor for branch 'feature/add-products'
[ci-monitor] Config: max-cycles=5, timeout=120m, auto-fix-workflow=true
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] CI attempt: FAILED | Self-Healing: COMPLETED | Elapsed: 2m
[ci-monitor] Applying fix locally, enhancing, and pushing...
[ci-monitor] Committed: abc1234
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] Waiting for new CI attempt... (expected SHA: abc1234)
[CI Monitor] ⚠️ CI attempt timeout (10 min). Returning no_new_cipe.
[ci-monitor] Status: no_new_cipe
[ci-monitor] --auto-fix-workflow enabled. Attempting lockfile update...
[ci-monitor] Lockfile updated. Committed: def5678
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] New CI attempt detected!
[CI Monitor] CI attempt: SUCCEEDED | Elapsed: 18m
[ci-monitor] CI passed successfully!
[ci-monitor] Summary:
- Total cycles: 3
- Total time: 22m 15s
- Fixes applied: 1 (self-healing) + 1 (lockfile)
- Result: SUCCESS
```
+228
View File
@@ -0,0 +1,228 @@
---
name: nx-generate
description: Generate code using nx generators. USE WHEN scaffolding code or transforming existing code - for example creating libraries or applications, or anything else that is boilerplate code or automates repetitive tasks. ALWAYS use this first when generating code with Nx instead of calling MCP tools or running nx generate immediately.
---
# Run Nx Generator
Nx generators are powerful tools that scaffold projects, make automated code migrations or automate repetitive tasks in a monorepo. They ensure consistency across the codebase and reduce boilerplate work.
This skill applies when the user wants to:
- Create new projects like libraries or applications
- Scaffold features or boilerplate code
- Run workspace-specific or custom generators
- Do anything else that an nx generator exists for
## Generator Discovery Flow
### Step 1: List Available Generators
Use the Nx CLI to discover available generators:
- List all generators for a plugin: `npx nx list @nx/react`
- View available plugins: `npx nx list`
This includes:
- Plugin generators (e.g., `@nx/react:library`, `@nx/js:library`)
- Local workspace generators (defined in the repo's own plugins)
### Step 2: Match Generator to User Request
Based on the user's request, identify which generator(s) could fulfill their needs. Consider:
- What artifact type they want to create (library, application, etc.)
- Which framework or technology stack is relevant
- Whether they mentioned specific generator names
**IMPORTANT**: When both a local workspace generator and an external plugin generator could satisfy the request, **always prefer the local workspace generator**. Local generators are customized for the specific repo's patterns and conventions.
It's possible that the user request is something that no Nx generator exists for whatsoever. In this case, you can stop using this skill and try to help the user another way. HOWEVER, the burden of proof for this is high. Before aborting, carefully consider each and every generator that's available. Look into details for any that could be related in any way before making this decision.
## Pre-Execution Checklist
Before running any generator, complete these steps:
### 1. Fetch Generator Schema
Use the `--help` flag to understand all available options:
```bash
npx nx g @nx/react:library --help
```
Pay attention to:
- Required options that must be provided
- Optional options that may be relevant to the user's request
- Default values that might need to be overridden
### 2. Read Generator Source Code
Understanding what the generator actually does helps you:
- Know what files will be created/modified
- Understand any side effects (updating configs, installing deps, etc.)
- Identify options that might not be obvious from the schema
To find generator source code:
- For plugin generators: Use `node -e "console.log(require.resolve('@nx/<plugin>/generators.json'));"` to find the generators.json, then locate the source from there
- If that fails, read directly from `node_modules/<plugin>/generators.json`
- For local generators: They are typically in `tools/generators/` or a local plugin directory. You can search the repo for the generator name to find it.
### 2.5 Reevaluate if the generator is right
Once you have built up an understanding of what the selected generator does, reconsider: Is this the right generator to service the user request?
If not, it's okay to go back to the Generator Discovery Flow and select a different generator before proceeding. If you do, make sure to go through the entire pre-execution checklist once more.
### 3. Understand Repo Context
Before generating, examine the target area of the codebase:
- Look at similar existing artifacts (other libraries, applications, etc.)
- Identify patterns and conventions used in the repo
- Note naming conventions, file structures, and configuration patterns
- Try to match these patterns when configuring the generator
For example, if similar libraries are using a specific test runner, build tool or linter, try to match that if possible.
If projects or other artifacts are organized with a specific naming convention, try to match it.
### 4. Validate Required Options
Ensure all required options have values:
- Map the user's request to generator options
- Infer values from context where possible
- Ask the user for any critical missing information
## Execution
Keep in mind that you might have to prefix things with npx/pnpx/yarn if the user doesn't have nx installed globally.
Many generators will behave differently based on where they are executed. For example, first-party nx library generators use the cwd to determine the directory that the library should be placed in. This is highly important.
### Consider Dry-Run (Optional)
Running with `--dry-run` first is strongly encouraged but not mandatory. Use your judgment:
- For complex generators or unfamiliar territory: do a dry-run first
- For simple, well-understood generators: may proceed directly
- Dry-run shows file names and created/deleted/modified markers, but not content
- There are cases where a generator does not support dry-run (for example if it had to install an npm package) - in that case --dry-run might fail. Don't be discouraged but simply move on to running the generator for real and iterating from there.
### Running the Generator
Execute the generator with:
```bash
nx generate <generator-name> <options> --no-interactive
```
**CRITICAL**: Always include `--no-interactive` to prevent prompts that would hang the execution.
Example:
```bash
nx generate @nx/react:library --name=my-utils --no-interactive
```
### Handling Generator Failures
If the generator fails:
1. **Diagnose the error** - Read the error message carefully
2. **Identify the cause** - Missing options, invalid values, conflicts, etc.
3. **Attempt automatic fix** - Adjust options or resolve conflicts
4. **Retry** - Run the generator again with corrected options
Common failure reasons:
- Missing required options
- Invalid option values
- Conflicting with existing files
- Missing dependencies
- Generator doesn't support certain flag combinations
## Post-Generation
### 1. Modify Generated Code (If Needed)
Generators provide a starting point, but the output may need adjustment to match the user's specific requirements:
- Add or modify functionality as requested
- Adjust imports, exports, or configurations
- Integrate with existing code patterns in the repo
### 2. Format Code
Run formatting on all generated/modified files:
```bash
nx format --fix
```
Languages other than javascript/typescript might need other formatting invocations too.
### 3. Run Verification
Verify that the generated code works correctly. What this looks like will vary depending on the type of generator and the targets available.
If the generator created a new project, run its targets directly
Use your best judgement to determine what needs to be verified.
Example:
```bash
nx lint <new-project>
nx test <new-project>
nx build <new-project>
```
### 4. Handle Verification Failures
When verification fails:
**If scope is manageable** (a few lint errors, minor type issues):
- Fix the issues
- Re-run verification to confirm
**If issues are extensive** (many errors, complex problems):
- Attempt simple, obvious fixes first
- If still failing, escalate to the user with:
- Description of what was generated
- What verification is failing
- What you've attempted to fix
- Remaining issues that need user input
## Error Handling
### Generator Failures
- Check the error message for specific causes
- Verify all required options are provided
- Check for conflicts with existing files
- Ensure the generator name and options are correct
### Missing Options
- Consult the generator schema for required fields
- Infer values from context when reasonable
- Ask the user for values that cannot be inferred
## Key Principles
1. **Local generators first** - Always prefer workspace/local generators over external plugin generators when both could work
2. **Understand before running** - Read both the schema AND the source code to fully understand what will happen
3. **No prompts** - Always use `--no-interactive` to prevent hanging
4. **Generators are starting points** - Modify the output as needed to fully satisfy the user's requirements
5. **Verify changes work** - Don't just generate; ensure the code builds, lints, and tests pass
6. **Be proactive about fixes** - Don't just report errors; attempt to resolve them automatically when possible
7. **Match repo patterns** - Study existing similar code in the repo and match its conventions
+9
View File
@@ -0,0 +1,9 @@
---
name: nx-plugins
description: Find and add Nx plugins. USE WHEN user wants to discover available plugins, install a new plugin, or add support for a specific framework or technology to the workspace.
---
## Finding and Installing new plugins
- List plugins: `pnpm nx list`
- Install plugins `pnpm nx add <plugin>`. Example: `pnpm nx add @nx/react`.
+58
View File
@@ -0,0 +1,58 @@
---
name: nx-run-tasks
description: Helps with running tasks in an Nx workspace. USE WHEN the user wants to execute build, test, lint, serve, or run any other tasks defined in the workspace.
---
You can run tasks with Nx in the following way.
Keep in mind that you might have to prefix things with npx/pnpx/yarn if the user doesn't have nx installed globally. Look at the package.json or lockfile to determine which package manager is in use.
For more details on any command, run it with `--help` (e.g. `nx run-many --help`, `nx affected --help`).
## Understand which tasks can be run
You can check those via `nx show project <projectname> --json`, for example `nx show project myapp --json`. It contains a `targets` section which has information about targets that can be run. You can also just look at the `package.json` scripts or `project.json` targets, but you might miss out on inferred tasks by Nx plugins.
## Run a single task
```
nx run <project>:<task>
```
where `project` is the project name defined in `package.json` or `project.json` (if present).
## Run multiple tasks
```
nx run-many -t build test lint typecheck
```
You can pass a `-p` flag to filter to specific projects, otherwise it runs on all projects. You can also use `--exclude` to exclude projects, and `--parallel` to control the number of parallel processes (default is 3).
Examples:
- `nx run-many -t test -p proj1 proj2` — test specific projects
- `nx run-many -t test --projects=*-app --exclude=excluded-app` — test projects matching a pattern
- `nx run-many -t test --projects=tag:api-*` — test projects by tag
## Run tasks for affected projects
Use `nx affected` to only run tasks on projects that have been changed and projects that depend on changed projects. This is especially useful in CI and for large workspaces.
```
nx affected -t build test lint
```
By default it compares against the base branch. You can customize this:
- `nx affected -t test --base=main --head=HEAD` — compare against a specific base and head
- `nx affected -t test --files=libs/mylib/src/index.ts` — specify changed files directly
## Useful flags
These flags work with `run`, `run-many`, and `affected`:
- `--skipNxCache` — rerun tasks even when results are cached
- `--verbose` — print additional information such as stack traces
- `--nxBail` — stop execution after the first failed task
- `--configuration=<name>` — use a specific configuration (e.g. `production`)
+186
View File
@@ -0,0 +1,186 @@
---
name: nx-workspace
description: "Explore and understand Nx workspaces. USE WHEN answering any questions about the nx workspace, the projects in it or tasks to run. EXAMPLES: 'What projects are in this workspace?', 'How is project X configured?', 'What targets can I run?', 'What's affected by my changes?', 'Which projects depend on library Y?', or any questions about Nx workspace structure, project configuration, or available tasks."
---
# Nx Workspace Exploration
This skill provides read-only exploration of Nx workspaces. Use it to understand workspace structure, project configuration, available targets, and dependencies.
Keep in mind that you might have to prefix commands with `npx`/`pnpx`/`yarn` if nx isn't installed globally. Check the lockfile to determine the package manager in use.
## Listing Projects
Use `nx show projects` to list projects in the workspace.
```bash
# List all projects
nx show projects
# Filter by pattern (glob)
nx show projects --projects "apps/*"
nx show projects --projects "shared-*"
# Filter by project type
nx show projects --type app
nx show projects --type lib
nx show projects --type e2e
# Filter by target (projects that have a specific target)
nx show projects --withTarget build
nx show projects --withTarget e2e
# Find affected projects (changed since base branch)
nx show projects --affected
nx show projects --affected --base=main
nx show projects --affected --type app
# Combine filters
nx show projects --type lib --withTarget test
nx show projects --affected --exclude="*-e2e"
# Output as JSON
nx show projects --json
```
## Project Configuration
Use `nx show project <name> --json` to get the full resolved configuration for a project.
**Important**: Do NOT read `project.json` directly - it only contains partial configuration. The `nx show project` command returns the full resolved config including inferred targets from plugins.
You can read the full project schema at `node_modules/nx/schemas/project-schema.json` to understand nx project configuration options.
```bash
# Get full project configuration
nx show project my-app --json
# Extract specific parts from the JSON
nx show project my-app --json | jq '.targets'
nx show project my-app --json | jq '.targets.build'
nx show project my-app --json | jq '.targets | keys'
# Check project metadata
nx show project my-app --json | jq '{name, root, sourceRoot, projectType, tags}'
```
## Target Information
Targets define what tasks can be run on a project.
```bash
# List all targets for a project
nx show project my-app --json | jq '.targets | keys'
# Get full target configuration
nx show project my-app --json | jq '.targets.build'
# Check target executor/command
nx show project my-app --json | jq '.targets.build.executor'
nx show project my-app --json | jq '.targets.build.command'
# View target options
nx show project my-app --json | jq '.targets.build.options'
# Check target inputs/outputs (for caching)
nx show project my-app --json | jq '.targets.build.inputs'
nx show project my-app --json | jq '.targets.build.outputs'
# Find projects with a specific target
nx show projects --withTarget serve
nx show projects --withTarget e2e
```
## Workspace Configuration
Read `nx.json` directly for workspace-level configuration.
You can read the full project schema at `node_modules/nx/schemas/nx-schema.json` to understand nx project configuration options.
```bash
# Read the full nx.json
cat nx.json
# Or use jq for specific sections
cat nx.json | jq '.targetDefaults'
cat nx.json | jq '.namedInputs'
cat nx.json | jq '.plugins'
cat nx.json | jq '.generators'
```
Key nx.json sections:
- `targetDefaults` - Default configuration applied to all targets of a given name
- `namedInputs` - Reusable input definitions for caching
- `plugins` - Nx plugins and their configuration
- ...and much more, read the schema or nx.json for details
## Affected Projects
Find projects affected by changes in the current branch.
```bash
# Affected since base branch (auto-detected)
nx show projects --affected
# Affected with explicit base
nx show projects --affected --base=main
nx show projects --affected --base=origin/main
# Affected between two commits
nx show projects --affected --base=abc123 --head=def456
# Affected apps only
nx show projects --affected --type app
# Affected excluding e2e projects
nx show projects --affected --exclude="*-e2e"
# Affected by uncommitted changes
nx show projects --affected --uncommitted
# Affected by untracked files
nx show projects --affected --untracked
```
## Common Exploration Patterns
### "What's in this workspace?"
```bash
nx show projects
nx show projects --type app
nx show projects --type lib
```
### "How do I build/test/lint project X?"
```bash
nx show project X --json | jq '.targets | keys'
nx show project X --json | jq '.targets.build'
```
### "What depends on library Y?"
```bash
# Find projects that may depend on Y by searching for imports
# (Nx doesn't have a direct "dependents" command via CLI)
grep -r "from '@myorg/Y'" --include="*.ts" --include="*.tsx" apps/ libs/
```
### "What configuration options are available?"
```bash
cat node_modules/nx/schemas/nx-schema.json | jq '.properties | keys'
cat node_modules/nx/schemas/project-schema.json | jq '.properties | keys'
```
### "Why is project X affected?"
```bash
# Check what files changed
git diff --name-only main
# See which project owns those files
nx show project X --json | jq '.root'
```
+92
View File
@@ -0,0 +1,92 @@
name: Banner Content Monitor
on:
schedule:
- cron: '*/15 * * * *'
workflow_dispatch: # Allow manual trigger
permissions: {}
env:
BANNER_URL: ${{ vars.BANNER_URL }}
jobs:
check-and-deploy:
if: ${{ github.repository_owner == 'nrwl' }}
runs-on: ubuntu-latest
steps:
- name: Fetch banner content and compute hash
id: banner
run: |
if [ -z "$BANNER_URL" ]; then
echo "BANNER_URL is not set"
exit 1
fi
# Fetch content and compute hash
CONTENT_HASH=$(curl -sf "$BANNER_URL" | sha256sum | cut -d' ' -f1)
if [ -z "$CONTENT_HASH" ]; then
echo "Failed to fetch banner content"
exit 1
fi
echo "current_hash=$CONTENT_HASH" >> $GITHUB_OUTPUT
echo "Current banner hash: $CONTENT_HASH"
- name: Restore cached hash
id: cache
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.0.3
with:
path: .banner-hash
key: banner-content-hash-
restore-keys: |
banner-content-hash-
- name: Compare hashes
id: compare
run: |
CURRENT_HASH="${{ steps.banner.outputs.current_hash }}"
if [ -f .banner-hash ]; then
CACHED_HASH=$(cat .banner-hash)
echo "Cached hash: $CACHED_HASH"
else
CACHED_HASH=""
echo "No cached hash found"
fi
if [ "$CURRENT_HASH" != "$CACHED_HASH" ]; then
echo "changed=true" >> $GITHUB_OUTPUT
echo "Banner content has changed!"
else
echo "changed=false" >> $GITHUB_OUTPUT
echo "Banner content unchanged"
fi
- name: Trigger Netlify deploys
if: steps.compare.outputs.changed == 'true'
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
run: |
npm install -g netlify-cli
echo "Triggering nx-docs deploy..."
netlify deploy --trigger --prod -s nx-docs
echo "Triggering nx-dev deploy..."
netlify deploy --trigger --prod -s nx-dev
echo "Both deploys triggered successfully"
- name: Save new hash to cache
if: steps.compare.outputs.changed == 'true'
run: |
echo "${{ steps.banner.outputs.current_hash }}" > .banner-hash
- name: Update cache
if: steps.compare.outputs.changed == 'true'
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.0.3
with:
path: .banner-hash
key: banner-content-hash-${{ github.run_id }}
+56 -53
View File
@@ -11,12 +11,14 @@ on:
env:
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
NX_CLOUD_ENABLE_METRICS_COLLECTION: 'true'
PNPM_HOME: ~/.pnpm
jobs:
main-linux:
runs-on: ubuntu-latest
env:
NX_BATCH_MODE: 'true'
NX_E2E_CI_CACHE_KEY: e2e-github-linux
NX_DAEMON: 'true'
NX_PERF_LOGGING: 'false'
@@ -26,8 +28,9 @@ jobs:
NX_CI_EXECUTION_ENV: 'linux'
NX_CLOUD_NO_TIMEOUTS: 'true'
NX_ALLOW_NON_CACHEABLE_DTE: 'true'
NX_CLOUD_USE_NEW_TASK_APIS: 'true'
NX_CLOUD_USE_NEW_STREAM_OUTPUT: 'true'
NX_CLOUD_EXPERIMENTAL_POLLING: 'true'
NX_CLOUD_CONTINUOUS_ASSIGNMENT: 'false'
NX_CLOUD_VERBOSE_LOGGING: 'true'
steps:
- name: Checkout
@@ -36,78 +39,69 @@ jobs:
fetch-depth: 0
filter: tree:0
- name: Set verbose logging from debug mode
if: runner.debug == '1'
run: echo "NX_VERBOSE_LOGGING=true" >> "$GITHUB_ENV"
- name: Fetch Master
run: git fetch origin master:master
if: ${{ github.event_name == 'pull_request' }}
- name: Set SHAs
uses: nrwl/nx-set-shas@1859e66a83ac9be0dceecbd9a023702e27ac47f4 # v4.3.3
uses: nrwl/nx-set-shas@310288c04d90696f9f1bc27c5e3caea6642b53d4 # v5.0.0
with:
main-branch-name: 'master'
- name: Start CI Run
run: npx nx-cloud@next start-ci-run --fix-tasks="!*check-commit*" --auto-apply-fixes="*format:check*,*sync:check*,*conformance:check*,*format-native*,*lint-native*,*lint*,*astro-docs:validate-links*" --distribute-on="./.nx/workflows/dynamic-changesets.yaml" --stop-agents-after="e2e"
run: npx nx-cloud@next start-ci-run --distribute-on="./.nx/workflows/dynamic-changesets.yaml" --stop-agents-after="e2e"
- name: Install dependencies
- name: Setup dev tools with mise
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
- name: Enable corepack and install pnpm
run: |
sudo apt-get update
sudo apt-get install -y ca-certificates lsof libvips-dev libglib2.0-dev libgirepository1.0-dev
corepack enable
corepack prepare --activate
- name: Install Chrome
uses: browser-actions/setup-chrome@2dbff04819ebbfd5c974947148805a825b8a07fd # v2.1.0
- name: Get pnpm store directory
id: pnpm-cache
run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
name: Install pnpm
- name: Cache pnpm store
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
version: 10.11.1
run_install: false
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: 20
cache: 'pnpm'
- name: Install Rust
uses: actions-rust-lang/setup-rust-toolchain@ac90e63697ac2784f4ecfe2964e1a285c304003a # v1
with:
rustflags: ''
- name: Setup Java
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
distribution: temurin
java-version: 17
cache: maven
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Setup Gradle
uses: gradle/actions/setup-gradle@48b5f213c81028ace310571dc5ec0fbbca0b2947 # v4.4.3
- name: Install project dependencies
run: |
pnpm install --frozen-lockfile
pnpm playwright install --with-deps
run: pnpm install --frozen-lockfile
- name: Nx Report
run:
run:
pnpm nx report
- name: Run Checks/Lint/Test/Build
run: |
pids=()
pnpm nx-cloud record -- nx format:check &
pnpm nx record -- nx format:check &
pids+=($!)
pnpm nx-cloud record -- nx sync:check
pnpm nx record -- nx sync:check
pids+=($!)
pnpm nx-cloud record -- nx-cloud conformance:check
pnpm nx build workspace-plugin && pnpm nx record -- pnpm nx-cloud conformance:check
pids+=($!)
pnpm nx run-many -t check-imports check-commit check-lock-files check-codeowners --parallel=1 --no-dte &
pnpm nx run-many -t check-imports check-lock-files check-codeowners --parallel=1 --no-dte &
pids+=($!)
pnpm nx affected --targets=lint,test,test-kt,build,e2e,e2e-ci,format-native,lint-native &
pnpm nx affected --targets=lint,test,build,e2e,e2e-ci,format-native,lint-native,gradle:build-ci,vale,run &
pids+=($!)
for pid in "${pids[@]}"; do
@@ -115,7 +109,7 @@ jobs:
done
timeout-minutes: 100
- name: Fix CI
run: pnpm nx-cloud fix-ci
run: pnpm nx fix-ci
if: failure()
main-macos:
@@ -145,23 +139,24 @@ jobs:
fetch-depth: 0
filter: tree:0
- name: Set verbose logging from debug mode
if: runner.debug == '1'
run: echo "NX_VERBOSE_LOGGING=true" >> "$GITHUB_ENV"
- name: Fetch Master
run: git fetch origin master:master
if: ${{ github.event_name == 'pull_request' }}
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
name: Install pnpm
with:
version: 10.11.1
run_install: false
- name: Setup dev tools with mise
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: 20
cache: 'pnpm'
- name: Enable corepack and install pnpm
run: |
corepack enable
corepack prepare --activate
- name: Set SHAs
uses: nrwl/nx-set-shas@1859e66a83ac9be0dceecbd9a023702e27ac47f4 # v4.3.3
uses: nrwl/nx-set-shas@310288c04d90696f9f1bc27c5e3caea6642b53d4 # v5.0.0
with:
main-branch-name: 'master'
@@ -294,11 +289,19 @@ jobs:
~/Library/Caches/Homebrew
key: nrwl-nx-homebrew-packages
- name: Install Rust
- name: Get pnpm store directory
if: steps.check-changes.outputs.has_changes == 'true'
uses: actions-rust-lang/setup-rust-toolchain@ac90e63697ac2784f4ecfe2964e1a285c304003a # v1
id: pnpm-cache-macos
run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
- name: Cache pnpm store
if: steps.check-changes.outputs.has_changes == 'true'
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
rustflags: ''
path: ${{ steps.pnpm-cache-macos.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install project dependencies
if: steps.check-changes.outputs.has_changes == 'true'
+10
View File
@@ -51,6 +51,8 @@ jobs:
build-mode: none
- language: rust
build-mode: none
- language: csharp
build-mode: autobuild
# CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
@@ -63,6 +65,14 @@ jobs:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Language Tooling
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
- name: Enable corepack and install pnpm
run: |
corepack enable
corepack prepare --activate
# Add any setup steps before running the `github/codeql-action/init` action.
# This includes steps like installing compilers or runtimes (`actions/setup-node`
# or others). This is typically only required for manual builds.
+10
View File
@@ -46,6 +46,8 @@ jobs:
build-mode: none
- language: rust
build-mode: none
- language: csharp
build-mode: autobuild
# CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
@@ -58,6 +60,14 @@ jobs:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Language Tooling
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
- name: Enable corepack and install pnpm
run: |
corepack enable
corepack prepare --activate
# Add any setup steps before running the `github/codeql-action/init` action.
# This includes steps like installing compilers or runtimes (`actions/setup-node`
# or others). This is typically only required for manual builds.
+30 -51
View File
@@ -20,6 +20,8 @@ jobs:
if: ${{ github.repository_owner == 'nrwl' }}
runs-on: ${{ matrix.os }}
timeout-minutes: 20
env:
NODE_VERSION: ${{ matrix.node_version }}
strategy:
matrix:
os:
@@ -28,19 +30,20 @@ jobs:
# - windows-latest Windows fails to build gradle wrapper which always runs when we build nx.
## https://staging.nx.app/runs/LgD4vxGn8w?utm_source=pull-request&utm_medium=comment
node_version:
# TODO(v23): remove node 20 - EOL April 2026
- 20
- 22
# - 23
- 24
exclude:
# run just node v20 on macos and windows
# run just node v24 on macos and windows
- os: macos-latest
node_version: 20
- os: macos-latest
node_version: 22
# - os: macos-latest
# node_version: 23
# - os: windows-latest TODO (emily): Windows fails to build gradle wrapper which always runs when we build nx. Re-enable when we fix this.
# node_version: 22
# - os: windows-latest TODO (emily): Windows fails to build gradle wrapper which always runs when we build nx. Re-enable when we fix this.
# node_version: 23
# - os: windows-latest TODO(Jack): Windows fails to build gradle wrapper which always runs when we build nx. Re-enable when we fix this.
# node_version: 20
# - os: windows-latest TODO (Jack): Windows fails to build gradle wrapper which always runs when we build nx. Re-enable when we fix this.
# node_version: 22
name: Cache install (${{ matrix.os }}, node v${{ matrix.node_version }})
steps:
@@ -50,17 +53,14 @@ jobs:
fetch-depth: 0
filter: tree:0
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
name: Install pnpm
with:
version: 10.11.1
run_install: false
- name: Setup dev tools with mise
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
- name: Set node
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: ${{ matrix.node_version }}
cache: 'pnpm'
- name: Enable corepack and install pnpm
run: |
npm install -g corepack@latest
corepack enable
corepack prepare --activate
- name: Get pnpm store directory
id: pnpm-cache
@@ -138,6 +138,8 @@ jobs:
contents: read
runs-on: ${{ matrix.os }}
timeout-minutes: 200 # <- cap each job to 200 minutes
env:
NODE_VERSION: ${{ matrix.node_version }}
strategy:
matrix: ${{fromJson(needs.prepare-matrix.outputs.matrix)}} # Load matrix from previous job
fail-fast: false
@@ -153,39 +155,14 @@ jobs:
- name: Prepare dir for output
run: mkdir -p outputs
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
name: Install pnpm
with:
version: 10.11.1
run_install: false
- name: Setup dev tools with mise
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
- name: Use Node.js ${{ matrix.node_version }}
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: ${{ matrix.node_version }}
cache: 'pnpm'
- name: Install Rust
if: ${{ matrix.os != 'windows-latest' }}
- name: Enable corepack and install pnpm
run: |
curl --proto '=https' --tlsv1.3 https://sh.rustup.rs -sSf | sh -s -- -y
source "$HOME/.cargo/env"
rustup toolchain install 1.70.0
- name: Load Cargo Env
if: ${{ matrix.os != 'windows-latest' }}
run: echo "PATH=$HOME/.cargo/bin:$PATH" >> $GITHUB_ENV
- name: Setup .NET 9
uses: actions/setup-dotnet@d4c94342e560b34958eacfc5d055d21461ed1c5d # v5.0.0
with:
dotnet-version: '9.0.x'
- name: Install bun
if: ${{ matrix.os != 'windows-latest' }}
uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2.0.2
with:
bun-version: latest
npm install -g corepack@latest
corepack enable
corepack prepare --activate
- name: Install packages
run: |
@@ -420,7 +397,7 @@ jobs:
if: ${{ always() && github.repository_owner == 'nrwl' && github.event_name != 'workflow_dispatch' }}
runs-on: ubuntu-latest
needs: e2e
timeout-minutes: 10
timeout-minutes: 15
outputs:
message: ${{ steps.process-json.outputs.slack_message }}
proj_duration: ${{ steps.process-json.outputs.slack_proj_duration }}
@@ -448,8 +425,10 @@ jobs:
combined=$(jq -sc . outputs/*/matrix.json)
echo "combined=$combined" >> $GITHUB_OUTPUT
- name: Process results with TypeScript script
- name: Process results and collect failure details
id: process-json
env:
GH_TOKEN: ${{ github.token }}
run: |
echo '${{ steps.combine-json.outputs.combined }}' | npx tsx .github/workflows/nightly/process-result.ts
+3 -3
View File
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: ['20.19.0']
node-version: ['24']
steps:
- name: Checkout
@@ -19,14 +19,14 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: '20.19.0'
node-version: '24'
package-manager-cache: false
- name: Install pnpm
uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
id: pnpm-install
with:
version: 10.11.1
version: 10.28.2
run_install: false
- name: Get pnpm store directory
+4 -5
View File
@@ -20,12 +20,12 @@ jobs:
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
with:
version: 10.11.1
version: 10.28.2
- name: Use Node.js ${{ matrix.node_version }}
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: '20.19.0'
node-version: '24'
cache: 'pnpm'
- name: Cache node_modules
@@ -64,7 +64,6 @@ jobs:
id: slack
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
with:
webhook: ${{ secrets.SLACK_ISSUES_REPORT_URL }}
webhook-type: incoming-webhook
payload: ${{ steps.collect.outputs.SLACK_MESSAGE }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_ISSUES_REPORT_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
+2 -1
View File
@@ -17,9 +17,10 @@ jobs:
if: ${{ github.repository_owner == 'nrwl' }}
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@7de207be1d3ce97a9abe6ff1306222982d1ca9f9 # v5.0.1
- uses: dessant/lock-threads@6548363a2d763e3a4a3a0dc04ca4a10481d8e536 # v6.0.0
id: lockthreads
with:
process-only: 'issues, prs'
github-token: ${{ github.token }}
issue-inactive-days: "30" # Lock issues after 30 days of being closed
pr-inactive-days: "5" # Lock closed PRs after 5 days. This ensures that issues that stem from a PR are opened as issues, rather than comments on the recently merged PR.
@@ -0,0 +1,674 @@
import { exec } from 'child_process';
import { execSync } from 'child_process';
const MAX_CONCURRENCY = 8;
interface MatrixResult {
project: string;
codeowners: string;
node_version: number | string;
package_manager: string;
os: string;
os_name: string;
os_timeout: number;
is_golden?: boolean;
status: 'success' | 'failure' | 'cancelled';
duration: number;
}
interface Streak {
consecutive_failures: number;
failing_since: string | null;
last_passing: string | null;
}
interface HistoryEntry {
date: string;
failed: string[];
}
interface ErrorDate {
testFile: string;
startDate: string;
days: number;
}
const REPO = process.env.GITHUB_REPOSITORY || 'nrwl/nx';
const RUN_ID = process.env.GITHUB_RUN_ID || '0';
function gh(args: string): string {
try {
return execSync(`gh ${args}`, {
encoding: 'utf-8',
timeout: 60_000,
maxBuffer: 10 * 1024 * 1024,
stdio: ['pipe', 'pipe', 'pipe'],
}).trim();
} catch {
return '';
}
}
function ghAsync(args: string): Promise<string> {
return new Promise((resolve) => {
exec(
`gh ${args}`,
{ encoding: 'utf-8', timeout: 60_000, maxBuffer: 10 * 1024 * 1024 },
(err, stdout) => resolve(err ? '' : (stdout || '').trim())
);
});
}
async function ghParallel<T>(
items: T[],
fn: (item: T) => string,
concurrency = MAX_CONCURRENCY
): Promise<Map<T, string>> {
const results = new Map<T, string>();
const queue = [...items];
async function worker() {
while (queue.length > 0) {
const item = queue.shift()!;
results.set(item, await ghAsync(fn(item)));
}
}
await Promise.all(
Array.from({ length: Math.min(concurrency, items.length) }, () => worker())
);
return results;
}
function extractJestBlocks(raw: string): string {
const lines = raw
.replace(/^\d{4}-\d{2}-\d{2}T[\d:.]+Z /gm, '')
.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '')
.split('\n');
const blocks: string[] = [];
let capturing = false;
for (const line of lines) {
if (line.startsWith(' FAIL ')) capturing = true;
if (capturing) blocks.push(line);
if (line.startsWith('Ran all test suites')) capturing = false;
}
return blocks.slice(0, 50).join('\n');
}
function extractTestFiles(block: string): string[] {
const matches = block.match(/FAIL\s+\S+\s+(src\/[^\s]+\.test\.ts)/g) || [];
return [...new Set(matches.map((m) => m.replace(/FAIL\s+\S+\s+/, '')))];
}
// Extract a normalized error signature for a test file from a Jest block.
// Used to distinguish different root causes for the same test file across runs.
function extractErrorSignature(block: string, testFile: string): string {
const lines = block.split('\n');
let afterBullet = false;
let inFile = false;
for (const l of lines) {
if (l.includes('FAIL') && l.includes(testFile)) { inFile = true; continue; }
if (inFile && /●/.test(l)) { afterBullet = true; continue; }
if (!inFile || !afterBullet) continue;
const trimmed = l.trim();
if (!trimmed) continue;
// Skip generic "Command failed" and warnings — find the actual error
if (/^Command failed:|^warning /i.test(trimmed)) continue;
// Normalize dynamic parts
return trimmed
.replace(/\/tmp\/[^\s]+/g, '<tmpdir>')
.replace(/\/Users\/[^\s]+/g, '<path>')
.replace(/\/home\/[^\s]+/g, '<path>')
.replace(/[a-z]+\d{5,}/gi, '<id>')
.replace(/\d{4}-\d{2}-\d{2}T[\d:._Z-]+/g, '<ts>')
.replace(/\d+\.\d+\.\d+/g, '<ver>')
.trim();
}
return '';
}
// Extract signatures for all test files in a block
function extractSignatures(
block: string,
testFiles: string[]
): Map<string, string> {
const sigs = new Map<string, string>();
for (const tf of testFiles) {
sigs.set(tf, extractErrorSignature(block, tf));
}
return sigs;
}
function extractBlockForFile(fullBlock: string, testFile: string): string {
const lines = fullBlock.split('\n');
const result: string[] = [];
let capturing = false;
for (const line of lines) {
if (line.includes('FAIL') && line.includes(testFile)) capturing = true;
else if (capturing && line.match(/^ FAIL /)) capturing = false;
if (capturing) result.push(line);
}
return result.slice(0, 20).join('\n');
}
export interface JobLink {
combo: string;
url: string;
}
export interface FailureDetailsResult {
report: string;
goldenJobLinks: Map<string, JobLink[]>; // project -> [{combo, url}]
}
/**
* Collects detailed failure information for golden projects.
* Called by process-result.ts when golden failures exist.
* Returns Slack mrkdwn report + job links for the summary section.
*/
export async function collectFailureDetails(
combined: MatrixResult[],
failedGoldenProjectNames: string[]
): Promise<FailureDetailsResult> {
const projectNames = failedGoldenProjectNames;
if (projectNames.length === 0) {
return { report: '', goldenJobLinks: new Map() };
}
// Group failures by project for combo info
const failuresByProject = new Map<string, MatrixResult[]>();
for (const r of combined) {
if (r.is_golden && (r.status === 'failure' || r.status === 'cancelled')) {
if (!failuresByProject.has(r.project))
failuresByProject.set(r.project, []);
failuresByProject.get(r.project)!.push(r);
}
}
// Step 1: 30-day failure history
const histRunsRaw = gh(
`run list --workflow=e2e-matrix.yml --repo ${REPO} --limit 40 --json databaseId,createdAt,event --jq '[.[] | select(.event == "schedule" and .databaseId != ${RUN_ID})] | .[0:30]'`
);
const histRuns: Array<{ databaseId: number; createdAt: string }> =
histRunsRaw ? JSON.parse(histRunsRaw) : [];
const histResults = await ghParallel(
histRuns.map((r) => r.databaseId),
(rid) =>
`run view ${rid} --repo ${REPO} --json jobs --jq '[.jobs[] | select(.conclusion == "failure") | .name | split(" ") | last] | unique'`
);
const history: HistoryEntry[] = histRuns.map((run) => {
const raw = histResults.get(run.databaseId) || '[]';
try {
return { date: run.createdAt, failed: JSON.parse(raw) };
} catch {
return { date: run.createdAt, failed: [] };
}
});
// Compute streaks
const streaks = new Map<string, Streak>();
for (const project of projectNames) {
let streak = 0,
firstSeen: string | null = null,
lastPassing: string | null = null,
broken = false;
for (const entry of history) {
if (broken) break;
if (entry.failed.includes(project)) {
streak++;
firstSeen = entry.date;
} else {
broken = true;
lastPassing = entry.date;
}
}
streaks.set(project, {
consecutive_failures: streak,
failing_since: firstSeen ? firstSeen.split('T')[0] : null,
last_passing: lastPassing ? lastPassing.split('T')[0] : null,
});
}
// Step 2: Fetch failure logs (one per OS/PM combo per project)
const failedJobsRaw = gh(
`run view ${RUN_ID} --repo ${REPO} --json jobs --jq '[.jobs[] | select(.conclusion == "failure") | {id: .databaseId, name: .name, project: (.name | split(" ") | last), combo: (.name | split(" ")[0])}]'`
);
const failedJobs: Array<{
id: number;
name: string;
project: string;
combo: string;
}> = failedJobsRaw ? JSON.parse(failedJobsRaw) : [];
const jobsToFetch: Array<{ id: number; project: string }> = [];
for (const project of projectNames) {
const seen = new Set<string>();
for (const job of failedJobs.filter((j) => j.project === project)) {
const key = job.combo.split('/').slice(0, 2).join('/');
if (!seen.has(key)) {
seen.add(key);
jobsToFetch.push({ id: job.id, project: job.project });
}
}
}
const logResults = await ghParallel(
jobsToFetch,
(job) => `api repos/${REPO}/actions/jobs/${job.id}/logs`
);
// Keep per-combo logs separate AND a merged block per project
interface ComboLog {
combo: string;
block: string;
testFiles: string[];
signatures: Map<string, string>; // testFile -> error signature
}
const projectComboLogs = new Map<string, ComboLog[]>();
const projectLogs = new Map<string, string>(); // merged block for backwards compat
for (const [job, raw] of logResults) {
if (!raw) continue;
const cleaned = raw
.replace(/^\d{4}-\d{2}-\d{2}T[\d:.]+Z /gm, '')
.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
const block = extractJestBlocks(raw);
const testFiles = extractTestFiles(cleaned);
const sigs = extractSignatures(cleaned, testFiles);
const combo =
failedJobs.find((j) => j.id === job.id)?.combo || 'unknown';
if (!projectComboLogs.has(job.project))
projectComboLogs.set(job.project, []);
projectComboLogs.get(job.project)!.push({
combo,
block,
testFiles,
signatures: sigs,
});
projectLogs.set(
job.project,
(projectLogs.get(job.project) || '') + '\n' + block
);
}
// Step 3: Build distinct failures per project — each (testFile, signature, combos) is a "failure"
interface DistinctFailure {
testFile: string;
signature: string;
combos: string[];
block: string; // the Jest block from the first combo that has this signature
}
const projectDistinctFailures = new Map<string, DistinctFailure[]>();
for (const project of projectNames) {
const comboLogs = projectComboLogs.get(project) || [];
const seen = new Map<string, DistinctFailure>(); // "testFile|signature" -> failure
for (const cl of comboLogs) {
for (const tf of cl.testFiles) {
const sig = cl.signatures.get(tf) || '';
const key = `${tf}|${sig}`;
if (seen.has(key)) {
seen.get(key)!.combos.push(cl.combo);
} else {
seen.set(key, {
testFile: tf,
signature: sig,
combos: [cl.combo],
block: extractBlockForFile(cl.block, tf),
});
}
}
}
projectDistinctFailures.set(project, [...seen.values()]);
}
// Step 3b: Validate each distinct failure against the first-failing run
interface FailureValidation {
status: 'new' | 'confirmed' | 'different' | 'unknown';
startDate?: string;
days?: number;
}
// Key: "project|testFile|signature"
const failureValidations = new Map<string, FailureValidation>();
for (const project of projectNames) {
const streak = streaks.get(project)!;
const failures = projectDistinctFailures.get(project) || [];
if (streak.consecutive_failures <= 1 || !streak.failing_since) {
for (const f of failures) {
failureValidations.set(`${project}|${f.testFile}|${f.signature}`, {
status: 'new',
startDate: streak.failing_since || undefined,
days: streak.consecutive_failures || 1,
});
}
continue;
}
// Fetch first-failing run's signatures across all combos
const firstRun = histRuns.find(
(r) => r.createdAt.split('T')[0] === streak.failing_since
);
if (!firstRun) {
for (const f of failures) {
failureValidations.set(`${project}|${f.testFile}|${f.signature}`, {
status: 'unknown',
});
}
continue;
}
const firstJobIdsRaw = gh(
`run view ${firstRun.databaseId} --repo ${REPO} --json jobs --jq '[.jobs[] | select(.conclusion == "failure" and (.name | split(" ") | last) == "${project}")] | group_by(.name | split("/")[0:2] | join("/")) | map(.[0].databaseId) | .[]'`
);
const firstJobIds = firstJobIdsRaw
.split('\n')
.filter((id) => id && id !== 'null');
// Collect ALL signatures from the first run
const firstRunSigs = new Set<string>(); // "testFile|signature"
for (const jobId of firstJobIds) {
const log = gh(`api repos/${REPO}/actions/jobs/${jobId}/logs`);
if (!log) continue;
const cleanedLog = log
.replace(/^\d{4}-\d{2}-\d{2}T[\d:.]+Z /gm, '')
.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
const files = extractTestFiles(cleanedLog);
for (const f of files) {
const sig = extractErrorSignature(cleanedLog, f);
firstRunSigs.add(`${f}|${sig}`);
}
}
// Validate each current failure
for (const f of failures) {
const key = `${f.testFile}|${f.signature}`;
const fullKey = `${project}|${key}`;
if (firstRunSigs.has(key)) {
failureValidations.set(fullKey, {
status: 'confirmed',
startDate: streak.failing_since!,
days: streak.consecutive_failures,
});
} else {
failureValidations.set(fullKey, {
status: 'different',
});
}
}
}
// Step 4: Binary search for start date of each "different" failure
for (const project of projectNames) {
const streak = streaks.get(project)!;
const failures = projectDistinctFailures.get(project) || [];
const different = failures.filter((f) => {
const v = failureValidations.get(
`${project}|${f.testFile}|${f.signature}`
);
return v?.status === 'different';
});
if (!different.length) continue;
const projRunIds = histRuns
.slice(0, streak.consecutive_failures)
.map((r) => r.databaseId);
if (projRunIds.length <= 1) continue;
for (const failure of different) {
const targetSig = failure.signature;
if (!targetSig) continue;
function runHasSignature(runId: number): boolean {
const jobIdsRaw = gh(
`run view ${runId} --repo ${REPO} --json jobs --jq '[.jobs[] | select(.conclusion == "failure" and (.name | split(" ") | last) == "${project}")] | group_by(.name | split("/")[0:2] | join("/")) | map(.[0].databaseId) | .[]'`
);
for (const jid of jobIdsRaw.split('\n').filter(Boolean)) {
const log = gh(`api repos/${REPO}/actions/jobs/${jid}/logs`);
if (!log) continue;
const cleaned = log
.replace(/^\d{4}-\d{2}-\d{2}T[\d:.]+Z /gm, '')
.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
const sig = extractErrorSignature(cleaned, failure.testFile);
if (sig === targetSig) return true;
}
return false;
}
let low = 0,
high = projRunIds.length - 1;
// Check oldest run
const fullKey = `${project}|${failure.testFile}|${failure.signature}`;
const oldestHas = runHasSignature(projRunIds[high]);
if (oldestHas) {
const run = histRuns.find((r) => r.databaseId === projRunIds[high]);
failureValidations.set(fullKey, {
status: 'different',
startDate: run?.createdAt.split('T')[0] || 'unknown',
days: projRunIds.length,
});
continue;
}
// Binary search
while (high - low > 1) {
const mid = Math.floor((low + high) / 2);
if (runHasSignature(projRunIds[mid])) low = mid;
else high = mid;
}
const foundRun = histRuns.find((r) => r.databaseId === projRunIds[low]);
failureValidations.set(fullKey, {
status: 'different',
startDate: foundRun?.createdAt.split('T')[0] || 'unknown',
days: low + 1,
});
}
}
// Step 5: Recent commits
let commitCount = 0;
if (histRuns[0]?.createdAt) {
try {
const commits = execSync(
`git log origin/master --after="${histRuns[0].createdAt}" --format="%h" --no-merges 2>/dev/null | head -30`,
{ encoding: 'utf-8', timeout: 10_000 }
).trim();
commitCount = commits ? commits.split('\n').length : 0;
} catch {
/* git not available */
}
}
// Step 6: Format report
const lines: string[] = ['', '🔍 *Failure Details*', ''];
const sorted = [...projectNames].sort((a, b) => {
const sa = streaks.get(a)?.consecutive_failures || 0;
const sb = streaks.get(b)?.consecutive_failures || 0;
return (
sa - sb ||
(failuresByProject.get(b)?.length || 0) -
(failuresByProject.get(a)?.length || 0)
);
});
for (const project of sorted) {
const streak = streaks.get(project)!;
const projResults = failuresByProject.get(project) || [];
const distinctFailures = projectDistinctFailures.get(project) || [];
const block = projectLogs.get(project) || '';
const pms = [...new Set(projResults.map((r) => r.package_manager))];
const pattern =
pms.length === 1
? `${pms[0]}-only`
: pms.length >= 3
? 'all PMs'
: pms.join('+');
const since = streak.failing_since || 'today (new)';
const lastPass = streak.last_passing || '—';
const uniqueCombos = [
...new Set(
failedJobs.filter((j) => j.project === project).map((j) => j.combo)
),
];
lines.push('———————————————————————————');
lines.push(`*${project}* — ${projResults.length} combos (${pattern})`);
lines.push(
`Project failing since ${since} | Last fully passing: ${lastPass}`
);
lines.push('');
if (distinctFailures.length > 0) {
for (const failure of distinctFailures) {
const fullKey = `${project}|${failure.testFile}|${failure.signature}`;
const val = failureValidations.get(fullKey);
let errorDate = since;
let errorDays: number | string = streak.consecutive_failures || 1;
let label = '';
if (val?.startDate) {
errorDate = val.startDate;
errorDays = val.days || 1;
}
if (val?.status === 'different') {
label = ' ⚠️ error changed mid-streak';
}
if (errorDays === 1 || errorDays === '1') {
label = ' 🆕 NEW';
}
const comboStr = failure.combos.join(', ');
lines.push(
`📋 \`${failure.testFile}\` (${comboStr}) — failing since ${errorDate} (${errorDays} ${errorDays === 1 || errorDays === '1' ? 'day' : 'days'})${label}`
);
if (failure.block) {
lines.push('```');
lines.push(failure.block);
lines.push('```');
}
}
const summaryMatch = block.match(/^Test Suites:.*$/m);
if (summaryMatch) lines.push(`_${summaryMatch[0]}_`);
} else {
// No Jest blocks — find which step failed and extract its error output
const firstJob = failedJobs.find((j) => j.project === project);
if (firstJob) {
// Get the failed step name from the jobs API
const stepsRaw = gh(
`run view ${RUN_ID} --repo ${REPO} --json jobs --jq '[.jobs[] | select(.databaseId == ${firstJob.id})][0].steps[] | select(.conclusion == "failure") | .name'`
);
const failedStep = stepsRaw || 'unknown step';
// Get the log and extract error lines
const raw = gh(`api repos/${REPO}/actions/jobs/${firstJob.id}/logs`);
const cleaned = raw
.split('\n')
.map((l) => l.replace(/^\d{4}-\d{2}-\d{2}T[\d:.]+Z /, ''))
.map((l) => l.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, ''));
// Extract the failed Nx task output block (❌ > nx run <task> ... until next ##[group] or NX summary)
const failedTaskBlock: string[] = [];
let capturingTask = false;
for (const l of cleaned) {
if (/❌.*> nx run /i.test(l)) {
capturingTask = true;
failedTaskBlock.push(l);
continue;
}
if (capturingTask) {
if (/^##\[group\]|NX.*Running target/i.test(l) || failedTaskBlock.length >= 15) {
capturingTask = false;
} else {
failedTaskBlock.push(l);
}
}
}
// Extract the Nx failure summary block ("Running target...failed" + "Failed tasks:" + task list)
const nxFailureBlock: string[] = [];
let capturingNx = false;
for (const l of cleaned) {
if (/NX.*Running target.*failed/i.test(l)) capturingNx = true;
if (capturingNx) {
nxFailureBlock.push(l);
if (/^Hint:/i.test(l.trim()) || nxFailureBlock.length >= 10) {
capturingNx = false;
}
}
}
// Fallback: if no Nx blocks or task blocks found, extract generic error lines
let fallbackErrors: string[] = [];
if (nxFailureBlock.length === 0 && failedTaskBlock.length === 0) {
fallbackErrors = cleaned.filter((l) => {
const t = l.trim();
if (t.length < 10) return false;
if (/warning|warn\b|deprecated|orphan|Node\.js 20|FORCE_JAVASCRIPT|\* \[new branch\]|\* \[new tag\]/i.test(t)) return false;
return (
/error TS\d+:|^Error:|^\s*error\b[:\s]|ERR!|ERESOLVE|##\[error\]/i.test(t) ||
/Cannot find module|ENOENT|EACCES|permission denied/i.test(t) ||
/Segmentation fault|killed|OOM|out of memory/i.test(t) ||
/command not found|No such file or directory/i.test(t) ||
/Process completed with exit code [^0]/i.test(t)
);
}).slice(0, 5);
}
// Combine: Nx summary first, then task output, then fallback errors
const relevantErrors = [
...nxFailureBlock,
...(failedTaskBlock.length > 0 ? ['', ...failedTaskBlock] : []),
...(fallbackErrors.length > 0 ? ['', ...fallbackErrors] : []),
];
lines.push(`⚠️ Tests did not run — failed at step: *${failedStep}*`);
if (relevantErrors.length > 0) {
lines.push('```');
lines.push(relevantErrors.join('\n'));
lines.push('```');
}
lines.push(`Failing combos: ${uniqueCombos.join(', ')}`);
} else {
lines.push('⏱️ No job data available');
}
}
lines.push('');
}
if (commitCount > 0) {
lines.push(`_${commitCount} commits since last nightly_`);
}
// Build job links for the summary section
const runUrl = `https://github.com/${REPO}/actions/runs/${RUN_ID}`;
const goldenJobLinks = new Map<string, JobLink[]>();
for (const project of projectNames) {
const projectJobs = failedJobs.filter((j) => j.project === project);
goldenJobLinks.set(
project,
projectJobs.map((j) => ({
combo: j.combo,
url: `${runUrl}/job/${j.id}`,
}))
);
}
return { report: lines.join('\n'), goldenJobLinks };
}
+8 -4
View File
@@ -67,6 +67,7 @@ const matrixData: MatrixData = {
{ name: 'e2e-storybook', codeowners: 'S04SVQ8H0G5' },
{ name: 'e2e-nuxt', codeowners: 'S04SJ6PL98X' }
],
// TODO(v23): remove node 20 - EOL April 2026
nodeTLS: 20,
setup: [
{
@@ -74,12 +75,15 @@ const matrixData: MatrixData = {
os_name: 'Linux',
os_timeout: 60,
package_managers: ['npm', 'pnpm', 'yarn'],
node_versions: ['20.19.0', '22.12.0'],
node_versions: ['20.19.0', '22.13.0', '24.0.0'],
excluded: ['e2e-detox', 'e2e-react-native', 'e2e-expo']
},
{ os: 'macos-latest', os_name: 'MacOS', os_timeout: 90, package_managers: ['npm'], node_versions: ['20.19.0'] }
// TODO (emily): Fix Windows support as gradle fails when running nx build https://staging.nx.app/runs/LgD4vxGn8w?utm_source=pull-request&utm_medium=comment
// { os: 'windows-latest', os_name: 'WinOS', os_timeout: 180, package_managers: ['npm'], node_versions: ['20.19.0'], excluded: ['e2e-detox', 'e2e-react-native', 'e2e-expo'] }
// Docker is not supported on ARM-based macOS runners (no nested virtualization)
// See: https://github.com/docker/setup-docker-action and https://github.com/douglascamata/setup-docker-macos-action
// We may want to look into adding intel only for this docker case, at least until vm-in-vm works on latest macos
{ os: 'macos-latest', os_name: 'MacOS', os_timeout: 90, package_managers: ['npm'], node_versions: ['24.0.0'], excluded: ['e2e-docker'] }
// TODO (Jack): Fix Windows support as gradle fails when running nx build https://staging.nx.app/runs/LgD4vxGn8w?utm_source=pull-request&utm_medium=comment
// { os: 'windows-latest', os_name: 'WinOS', os_timeout: 180, package_managers: ['npm'], node_versions: ['24.0.0'], excluded: ['e2e-detox', 'e2e-react-native', 'e2e-expo'] }
]
};
+63 -31
View File
@@ -1,5 +1,6 @@
import * as fs from 'fs';
import { MatrixItem } from './process-matrix';
import { collectFailureDetails, JobLink } from './analyze-failures';
interface MatrixResult extends MatrixItem {
status: 'success' | 'failure' | 'cancelled';
@@ -52,42 +53,31 @@ function processResults(combined: MatrixResult[]): ProcessedResults {
const otherFailingCount = uniqueFailedOtherProjects.size;
result += `\n🌟 *Golden Projects*`;
result += `\n✅ Passing: ${goldenPassingCount}`;
result += `\n❌ Failing: ${goldenFailingCount}`;
result += `\n✅ Passing: ${goldenPassingCount} | ❌ Failing: ${goldenFailingCount}`;
if (failedGoldenProjects.length > 0) {
result += `\n\n🚨 *Failed Golden Projects*\n\`\`\``;
result += `\n| Failed project |`;
result += `\n|--------------------------------|`;
let lastProject: string | undefined;
result += `\n\n🚨 *Failed Golden Projects*`;
// Project names listed here — combo links added later by main() with job data
const seenProjects = new Set<string>();
failedGoldenProjects.forEach(matrix => {
const project = matrix.project !== lastProject ? matrix.project : '';
if (project) {
result += `\n| ${project.padEnd(30)} |`;
lastProject = matrix.project;
if (!seenProjects.has(matrix.project)) {
seenProjects.add(matrix.project);
result += `\n\n*${matrix.project}*`;
// Placeholder — main() will replace with linked combos
result += `\n {{COMBOS:${matrix.project}}}`;
}
});
result += `\n\`\`\``;
}
result += `\n\n🔧 *Other Projects*`;
result += `\n✅ Passing: ${otherPassingCount}`;
result += `\n❌ Failing: ${otherFailingCount}`;
// Failed Other Projects Table (if any)
if (failedRegularProjects.length > 0) {
result += `\n\n⚠️ *Failed Other Projects*\n\`\`\``;
result += `\n| Failed project |`;
result += `\n|--------------------------------|`;
let lastProject: string | undefined;
failedRegularProjects.forEach(matrix => {
const project = matrix.project !== lastProject ? matrix.project : '';
if (project) {
result += `\n| ${project.padEnd(30)} |`;
lastProject = matrix.project;
}
if (otherFailingCount > 0) {
const otherProjectCounts = new Map<string, number>();
failedRegularProjects.forEach(m => {
otherProjectCounts.set(m.project, (otherProjectCounts.get(m.project) || 0) + 1);
});
result += `\n\`\`\``;
const otherSummary = [...otherProjectCounts.entries()]
.map(([p, c]) => `${p} (${c})`)
.join(', ');
result += `\n\n⚠️ *Failed Other Projects:* ${otherSummary}`;
}
if (failedProjects.length === 0) {
@@ -180,7 +170,7 @@ function setOutput(key: string, value: string) {
}
}
try {
async function main() {
const combinedInput = process.argv[2]
? process.argv[2]
: fs.readFileSync(0, 'utf-8').trim();
@@ -188,10 +178,52 @@ try {
const combined: MatrixResult[] = JSON.parse(combinedInput);
const results = processResults(combined);
// Collect detailed failure info if golden failures exist
if (results.has_golden_failures === 'true') {
try {
const failedProjects = [
...new Set(
combined
.filter((c) => c.is_golden && (c.status === 'failure' || c.status === 'cancelled'))
.map((c) => c.project)
),
];
const { report, goldenJobLinks } = await collectFailureDetails(combined, failedProjects);
// Replace combo placeholders in the summary with linked combos
for (const [project, links] of goldenJobLinks) {
const placeholder = `{{COMBOS:${project}}}`;
const linkedCombos =
links.length > 0
? links.map((l) => ` · <${l.url}|${l.combo}>`).join('\n')
: ' (no job data)';
results.slack_message = results.slack_message.replace(
placeholder,
linkedCombos
);
}
// Remove any unreplaced placeholders (if collectFailureDetails didn't have data for a project)
results.slack_message = results.slack_message.replace(
/ \{\{COMBOS:[^}]+\}\}/g,
' (no job data)'
);
if (report) {
results.slack_message += '\n\n' + report;
}
} catch (e) {
console.error('Failed to collect failure details (brief report will still be posted):', e);
results.slack_message += '\n\n⚠️ _Failed to collect detailed failure information_';
}
}
Object.entries(results).forEach(([key, value]) => {
setOutput(key, value);
});
} catch (error) {
}
main().catch((error) => {
console.error('Error processing results:', error);
process.exit(1);
}
});
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
with:
version: 10.11.1 # Aligned with root package.json (pnpm/action-setup will helpfully error if out of sync)
version: 10.28.2 # Aligned with root package.json (pnpm/action-setup will helpfully error if out of sync)
- name: Run a security audit
run: pnpm dlx audit-ci --critical --report-type summary
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: 20
node-version: 24
package-manager-cache: false
- name: Validate PR title
+97 -49
View File
@@ -3,7 +3,7 @@ name: publish
on:
# Automated schedule - canary releases from master
schedule:
- cron: "0 20 * * 1-5" # Monday - Friday, at 20:00 UTC (8pm UTC)
- cron: "0 19 * * 1-5" # Monday - Friday, at 19:00 UTC (7pm UTC)
# Manual trigger - PR releases or dry-runs (based on workflow inputs)
workflow_dispatch:
inputs:
@@ -22,7 +22,8 @@ env:
NX_RUN_GROUP: ${{ github.run_id }}-${{ github.run_attempt }}
CYPRESS_INSTALL_BINARY: 0
NODE_VERSION: 22.16.0
PNPM_VERSION: 10.11.1 # Aligned with root package.json (pnpm/action-setup will helpfully error if out of sync)
PNPM_VERSION: 10.28.2 # Aligned with root package.json (pnpm/action-setup will helpfully error if out of sync)
NX_GRADLE_PROJECT_GRAPH_TIMEOUT: 600
jobs:
# We first need to determine the version we are releasing, and if we need a custom repo or ref to use for the git checkout in subsequent steps.
@@ -120,10 +121,10 @@ jobs:
fail-fast: false
matrix:
settings:
- host: macos-13
- host: macos-latest
target: x86_64-apple-darwin
setup: |-
rustup target add aarch64-apple-darwin
rustup target add x86_64-apple-darwin
build: |
pnpm nx run-many --target=build-native -- --target=x86_64-apple-darwin
- host: windows-latest
@@ -174,7 +175,7 @@ jobs:
bash -c "
set -e
echo 'https://dl-cdn.alpinelinux.org/alpine/edge/community' >> /etc/apk/repositories
apk add --no-cache curl xz openjdk21
apk add --no-cache curl xz openjdk21 build-base lld
# Set up Java 21
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk
@@ -194,12 +195,16 @@ jobs:
npm i -g pnpm@${PNPM_VERSION} --force
pnpm --version
# Help clang find GCC runtime (crtbeginS.o, libgcc) and use lld for jemalloc build
GCC_DIR=\$(dirname \$(find /usr/lib/gcc -name crtbeginS.o | head -1))
export CFLAGS=\"\${CFLAGS} -fuse-ld=lld --gcc-install-dir=\${GCC_DIR}\"
# Install deps and run native build
pnpm install --frozen-lockfile
rustup target add x86_64-unknown-linux-musl
pnpm nx run-many --verbose --target=build-native -- --target=x86_64-unknown-linux-musl
"
- host: macos-13
- host: macos-latest
target: aarch64-apple-darwin
setup: |-
rustup target add aarch64-apple-darwin
@@ -230,6 +235,9 @@ jobs:
node --version
npm --version
# Help clang find GCC runtime (crtbeginS.o, libgcc) and use lld for jemalloc build
export CFLAGS="${CFLAGS} -fuse-ld=lld --gcc-toolchain=/usr/aarch64-unknown-linux-gnu"
npm i -g pnpm@${PNPM_VERSION} --force
pnpm --version
@@ -260,7 +268,7 @@ jobs:
bash -c "
set -e
echo 'https://dl-cdn.alpinelinux.org/alpine/edge/community' >> /etc/apk/repositories
apk add --no-cache curl xz openjdk21
apk add --no-cache curl xz openjdk21 build-base lld
# Set up Java 21
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk
@@ -280,6 +288,10 @@ jobs:
npm i -g pnpm@${PNPM_VERSION} --force
pnpm --version
# Help clang find GCC runtime (crtbeginS.o, libgcc) and use lld for jemalloc build
GCC_DIR=\$(dirname \$(find /aarch64-linux-musl-cross/lib/gcc -name crtbeginS.o | head -1))
export CFLAGS=\"\${CFLAGS} -fuse-ld=lld --gcc-install-dir=\${GCC_DIR}\"
# Install deps and run native build
pnpm install --frozen-lockfile
rustup target add aarch64-unknown-linux-musl
@@ -303,24 +315,19 @@ jobs:
repository: ${{ needs.resolve-required-data.outputs.repo || github.repository }}
ref: ${{ needs.resolve-required-data.outputs.ref || github.ref }}
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
with:
version: ${{ env.PNPM_VERSION }}
- name: Set verbose logging from debug mode
if: runner.debug == '1'
run: echo "NX_VERBOSE_LOGGING=true" >> "$GITHUB_ENV"
- name: Setup node
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
- name: Setup dev tools with mise
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
if: ${{ !matrix.settings.docker }}
with:
node-version: ${{ env.NODE_VERSION }}
check-latest: true
cache: 'pnpm'
- name: Install
uses: actions-rust-lang/setup-rust-toolchain@ac90e63697ac2784f4ecfe2964e1a285c304003a # v1
- name: Enable corepack and install pnpm
if: ${{ !matrix.settings.docker }}
with:
target: ${{ matrix.settings.target }}
rustflags: ''
run: |
corepack enable
corepack prepare --activate
- name: Cache cargo
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
@@ -363,12 +370,26 @@ jobs:
architecture: x86
- name: Build in docker
uses: addnab/docker-run-action@4f65fabd2431ebc8d299f8e5a018d79a769ae185 # v3
if: ${{ matrix.settings.docker }}
with:
image: ${{ matrix.settings.docker }}
options: --user 0:0 -v ${{ github.workspace }}/.cargo-cache/git/db:/usr/local/cargo/git/db -v ${{ github.workspace }}/.cargo/registry/cache:/usr/local/cargo/registry/cache -v ${{ github.workspace }}/.cargo/registry/index:/usr/local/cargo/registry/index -v ${{ github.workspace }}:/build -w /build
run: ${{ matrix.settings.build }}
shell: bash
env:
BUILD_SCRIPT: ${{ matrix.settings.build }}
run: |
SCRIPT_FILE=$(mktemp)
echo "$BUILD_SCRIPT" > "$SCRIPT_FILE"
docker run --rm \
--user 0:0 \
-e PNPM_VERSION \
-e NX_GRADLE_PROJECT_GRAPH_TIMEOUT \
-e NX_VERBOSE_LOGGING \
-v ${{ github.workspace }}/.cargo-cache/git/db:/usr/local/cargo/git/db \
-v ${{ github.workspace }}/.cargo/registry/cache:/usr/local/cargo/registry/cache \
-v ${{ github.workspace }}/.cargo/registry/index:/usr/local/cargo/registry/index \
-v ${{ github.workspace }}:/build \
-v "$SCRIPT_FILE:/build-script.sh" \
-w /build \
${{ matrix.settings.docker }} \
bash /build-script.sh
- name: Build
run: ${{ matrix.settings.build }}
@@ -405,21 +426,19 @@ jobs:
NX_PREFER_TS_NODE: true
PLAYWRIGHT_BROWSERS_PATH: 0
NODE_VERSION: 22.16.0
NX_GRADLE_DISABLE: 'true'
NODE_OPTIONS: '--max-old-space-size=4096'
with:
operating_system: freebsd
version: '14.0'
architecture: x86-64
environment_variables: DEBUG RUSTUP_IO_THREADS CI NX_PREFER_TS_NODE PLAYWRIGHT_BROWSERS_PATH NODE_VERSION
environment_variables: DEBUG RUSTUP_IO_THREADS CI NX_PREFER_TS_NODE PLAYWRIGHT_BROWSERS_PATH NODE_VERSION NX_GRADLE_DISABLE NODE_OPTIONS
shell: bash
run: |
env
whoami
sudo pkg install -y -f node libnghttp2 www/npm git openjdk17
sudo npm install --location=global --ignore-scripts pnpm@10.11.1
# Set up Java 17
export JAVA_HOME=/usr/local/openjdk17
export PATH="$JAVA_HOME/bin:$PATH"
java --version
sudo pkg install -y -f node libnghttp2 www/npm git ca_root_nss
sudo npm install --location=global --ignore-scripts pnpm@10.28.2
curl https://sh.rustup.rs -sSf --output rustup.sh
sh rustup.sh -y --profile minimal --default-toolchain stable
source "$HOME/.cargo/env"
@@ -475,17 +494,46 @@ jobs:
pnpm store prune || true
rm -rf ~/.npm || true
rm -rf ~/.pnpm-store || true
# Remove Rust build artifacts if any
rm -rf ~/.cargo/registry || true
rm -rf ~/.cargo/git || true
# Clean Rust extras but keep registry/git (needed for cargo to resolve deps)
rm -rf ~/.rustup/toolchains/*/share || true
# Remove other development tool caches
rm -rf ~/.cache/* || true
# Remove unnecessary workspace directories
rm -rf docs astro-docs nx-dev || true
echo "Checking disk space after cleanup"
df -h
# Disable core dumps - OOM'd Node processes write multi-GB core files that fill the disk
ulimit -c 0
echo "Building FreeBSD bindings"
pnpm nx run-many --verbose --outputStyle stream --target=build-native -- --target=x86_64-unknown-freebsd
BUILD_EXIT=0
pnpm nx run-many --verbose --outputStyle stream --target=build-native -- --target=x86_64-unknown-freebsd || BUILD_EXIT=$?
echo "=== Disk usage after build ==="
df -h
if [ "$BUILD_EXIT" -ne 0 ]; then
echo "Build failed with exit code $BUILD_EXIT"
echo "=== Disk usage by top-level directories ==="
du -sh /* 2>/dev/null | sort -rh | head -20
echo "=== Disk usage in home directory ==="
du -sh ~/* 2>/dev/null | sort -rh | head -20
echo "=== Disk usage in workspace ==="
du -sh /home/runner/work/nx/nx/* 2>/dev/null | sort -rh | head -20
echo "=== Disk usage in .nx ==="
du -sh /home/runner/work/nx/nx/.nx/* 2>/dev/null | sort -rh | head -20
echo "=== Disk usage in cargo/rustup ==="
du -sh ~/.cargo/* ~/.rustup/* 2>/dev/null | sort -rh | head -20
echo "=== Core dumps ==="
find / -name "*.core" -o -name "core.*" -o -name "core" 2>/dev/null | head -10
exit $BUILD_EXIT
fi
echo "Build succeeded"
echo "Cleaning up"
pnpm nx reset
rm -rf node_modules
@@ -523,18 +571,18 @@ jobs:
repository: ${{ needs.resolve-required-data.outputs.repo || github.repository }}
ref: ${{ needs.resolve-required-data.outputs.ref || github.ref }}
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
with:
version: ${{ env.PNPM_VERSION }}
- name: Set verbose logging from debug mode
if: runner.debug == '1'
run: echo "NX_VERBOSE_LOGGING=true" >> "$GITHUB_ENV"
- name: Setup dev tools with mise
uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3
- name: Enable corepack and install pnpm
run: |
corepack enable
corepack prepare --activate
- name: Setup node
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: ${{ env.NODE_VERSION }}
registry-url: 'https://registry.npmjs.org'
check-latest: true
cache: 'pnpm'
- name: Use npm 11.5.2
run: npm install -g npm@11.5.2
@@ -554,13 +602,13 @@ jobs:
run: |
wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-23/wasi-sdk-23.0-x86_64-linux.tar.gz
tar -xvf wasi-sdk-23.0-x86_64-linux.tar.gz
rustup toolchain install nightly-2025-05-09
pnpm build:wasm
- name: Publish
env:
VERSION: ${{ needs.resolve-required-data.outputs.version }}
DRY_RUN: ${{ needs.resolve-required-data.outputs.dry_run_flag }}
PUBLISH_BRANCH: ${{ needs.resolve-required-data.outputs.publish_branch }}
NX_VERBOSE_LOGGING: true
run: |
echo ""
# Create and check out the publish branch
+27 -5
View File
@@ -25,7 +25,14 @@ jest.debug.config.js
/nx-dev/nx-dev/public/documentation
/nx-dev/nx-dev/public/tutorials
/nx-dev/nx-dev/public/images/open-graph
**/tests/temp-db
/nx-dev/nx-dev/public/robots.txt
/nx-dev/nx-dev/public/sitemap-0.xml
/nx-dev/nx-dev/public/sitemap.xml
# Banner JSON files are generated during static builds
/nx-dev/nx-dev/lib/banner.json
/astro-docs/src/content/banner.json
**/tests/temp-db*
# Issues scraper creates these files, stored by github's cache
/scripts/issues-scraper/cached
@@ -63,10 +70,11 @@ out
.rustup/
target
.flattened-pom.xml
dependency-reduced-pom.xml
*.wasm
/wasi-sdk*
vite.config.*.timestamp*
*.config.timestamp*
storybook-static
@@ -75,10 +83,10 @@ storybook-static
.kotlin
.claude/settings.local.json
.claude/scheduled_tasks.lock
CLAUDE.local.md
.cursor/rules/nx-rules.mdc
.cursor/mcp.json
.github/instructions/nx.instructions.md
# Added by Claude Task Master
# Logs
@@ -110,7 +118,8 @@ node_modules/
# Upstream docs local configuration (machine-specific)
.upstreamdocs.local.json
astro-docs/.netlify
# Netlify build artifacts
.netlify
coverage
@@ -123,6 +132,7 @@ packages/angular-rspack/README.md
packages/angular-rspack-compiler/README.md
packages/dotnet/README.md
packages/maven/README.md
packages/nx/README.md
test-output
test-results
@@ -133,3 +143,15 @@ test-results
# .NET build output
/packages/dotnet/analyzer/bin
/packages/dotnet/analyzer/obj
/*.deb
.nx/polygraph
.claude/worktrees
.nx/self-healing
# Nx Typings Output
packages/nx/**/*.d.ts
!packages/nx/src/utils/perf-hooks.d.ts
!packages/nx/src/ai/set-up-ai-agents/schema.d.ts
!packages/nx/src/native/index.d.ts
e2e/**/*.d.ts
e2e/**/*.d.ts.map
+1
View File
@@ -0,0 +1 @@
NX_USE_V8_SERIALIZER=false
-9
View File
@@ -1,9 +0,0 @@
{
"mcpServers": {
"nx-mcp": {
"type": "stdio",
"command": "npx",
"args": ["nx", "mcp"]
}
}
}
+1 -1
View File
@@ -1,3 +1,3 @@
wrapperVersion=3.3.4
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/4.0.0-rc-5/apache-maven-4.0.0-rc-5-bin.zip
+3
View File
@@ -0,0 +1,3 @@
{
"experimentalPolygraph": true
}
+77 -176
View File
@@ -1,184 +1,85 @@
common-env-vars: &common-env-vars
GIT_AUTHOR_EMAIL: test@test.com
GIT_AUTHOR_NAME: Test
GIT_COMMITTER_EMAIL: test@test.com
GIT_COMMITTER_NAME: Test
SELECTED_PM: 'pnpm'
NX_NATIVE_LOGGING: 'nx::native::db'
# These are need for build and link validation for next.js and astro apps
NEXT_PUBLIC_ASTRO_URL: 'https://master--nx-docs.netlify.app'
NX_DEV_URL: 'https://canary.nx.dev'
common-init-steps: &common-init-steps
- name: Checkout
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'
- name: Cache restore
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
inputs:
key: 'pnpm-lock.yaml'
paths: ~/.local/share/pnpm/store
base-branch: 'master'
# reads mise.toml and installs toolchains needed for repo
- name: Setup toolchains
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-mise/main.yaml'
- name: Verify toolchain versions
script: |
echo "mise: $(mise --version)"
echo "node: $(node --version)"
echo "pnpm: $(pnpm --version)"
echo "bun: $(bun --version)"
echo "rust: $(rustc --version) - $(cargo --version)"
echo "dotnet: $(dotnet --version)"
echo "java: $(javac --version)"
- name: Install system deps
script: |
# archive.ubuntu.com periodically serves a Packages.gz that doesn't
# match its own InRelease metadata while the canonical mirror is
# mid-sync, breaking apt-get update across all agents at once.
# Azure's mirror has a better SLA and is what GitHub Actions runners use.
sudo sed -i 's|http://archive.ubuntu.com/ubuntu|http://azure.archive.ubuntu.com/ubuntu|g; s|http://security.ubuntu.com/ubuntu|http://azure.archive.ubuntu.com/ubuntu|g' /etc/apt/sources.list
sudo apt-get update
sudo apt-get install -y ca-certificates lsof libvips-dev libglib2.0-dev libgirepository1.0-dev zip unzip
- name: Pnpm Install from lockfile
script: |
pnpm install --frozen-lockfile
- name: Install browsers
script: |
pnpm exec cypress install
pnpm exec playwright install --with-deps
- name: Install rust deps
script: |
cargo fetch
- name: Install hyperfine
script: |
cargo install hyperfine
- name: Setup gradle
script: |
./gradlew wrapper
./gradlew --version
- name: Configure git metadata (needed for lerna smoke tests)
script: |
git config --global user.email test@test.com
git config --global user.name "Test Test"
launch-templates:
linux-large:
resource-class: 'docker_linux_amd64/large'
image: 'us-east1-docker.pkg.dev/nxcloudoperations/nx-cloud/nx-agents-base-images:ubuntu22.04-node20.19-v1'
env:
GIT_AUTHOR_EMAIL: test@test.com
GIT_AUTHOR_NAME: Test
GIT_COMMITTER_EMAIL: test@test.com
GIT_COMMITTER_NAME: Test
SELECTED_PM: 'pnpm'
NX_NATIVE_LOGGING: 'nx::native::db'
# These are need for build and link validation for next.js and astro apps
NEXT_PUBLIC_ASTRO_URL: 'https://master--nx-docs.netlify.app'
NX_DEV_URL: 'https://canary.nx.dev'
init-steps:
- name: Checkout
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'
- name: Check Node Version
script: node --version
- name: Cache restore
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
inputs:
key: 'pnpm-lock.yaml'
paths: .pnpm-store
base-branch: 'master'
- name: Install zip and unzip
script: sudo apt-get -yqq install zip unzip
- name: Install bun
script: |
curl -fsSL https://bun.sh/install | bash
echo "BUN_INSTALL=$HOME/.bun" >> $NX_CLOUD_ENV
echo "PATH=$HOME/.bun/bin:$PATH" >> $NX_CLOUD_ENV
- name: Check bun
script: |
bun --version
- name: Install e2e deps
script: |
sudo apt-get update
sudo apt-get install -y ca-certificates lsof libvips-dev libglib2.0-dev libgirepository1.0-dev
- name: Pnpm Install from lockfile
script: |
pnpm install --frozen-lockfile
- name: Install Browsers
script: |
pnpm exec cypress install
pnpm exec playwright install --with-deps
- name: Install Rust
script: |
curl --proto '=https' --tlsv1.3 https://sh.rustup.rs -sSf | sh -s -- -y
source "$HOME/.cargo/env"
rustup toolchain install 1.70.0
- name: Configure git metadata (needed for lerna smoke tests)
script: |
git config --global user.email test@test.com
git config --global user.name "Test Test"
- name: Load Cargo Env
script: echo "PATH=$HOME/.cargo/bin:$PATH" >> $NX_CLOUD_ENV
- name: Install Rust Dependencies
script: |
cargo fetch
- name: Setup Java 21
script: |
sudo apt update
sudo apt install -y openjdk-21-jdk
sudo update-alternatives --set java /usr/lib/jvm/java-21-openjdk-amd64/bin/java
java -version
- name: Setup Gradle
script: |
./gradlew wrapper
./gradlew --version
- name: Setup .NET 9
script: |
wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt-get update
sudo apt-get install -y dotnet-sdk-9.0
dotnet --version
env: *common-env-vars
init-steps: *common-init-steps
linux-extra-large:
resource-class: 'docker_linux_amd64/extra_large'
image: 'us-east1-docker.pkg.dev/nxcloudoperations/nx-cloud/nx-agents-base-images:ubuntu22.04-node20.19-v1'
env:
GIT_AUTHOR_EMAIL: test@test.com
GIT_AUTHOR_NAME: Test
GIT_COMMITTER_EMAIL: test@test.com
GIT_COMMITTER_NAME: Test
SELECTED_PM: 'pnpm'
NX_NATIVE_LOGGING: 'nx::native::db'
# These are need for build and link validation for next.js and astro apps
NEXT_PUBLIC_ASTRO_URL: 'https://master--nx-docs.netlify.app'
NX_DEV_URL: 'https://canary.nx.dev'
init-steps:
- name: Checkout
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'
- name: Check Node Version
script: node --version
- name: Cache restore
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
inputs:
key: 'pnpm-lock.yaml'
paths: .pnpm-store
base-branch: 'master'
- name: Install zip and unzip
script: sudo apt-get -yqq install zip unzip
- name: Install bun
script: |
curl -fsSL https://bun.sh/install | bash
echo "BUN_INSTALL=$HOME/.bun" >> $NX_CLOUD_ENV
echo "PATH=$HOME/.bun/bin:$PATH" >> $NX_CLOUD_ENV
- name: Check bun
script: |
bun --version
- name: Install e2e deps
script: |
sudo apt-get update
sudo apt-get install -y ca-certificates lsof libvips-dev libglib2.0-dev libgirepository1.0-dev
- name: Pnpm Install from lockfile
script: |
pnpm install --frozen-lockfile
- name: Install Browsers
script: |
pnpm exec cypress install
pnpm exec playwright install --with-deps
- name: Install Rust
script: |
curl --proto '=https' --tlsv1.3 https://sh.rustup.rs -sSf | sh -s -- -y
source "$HOME/.cargo/env"
rustup toolchain install 1.70.0
- name: Configure git metadata (needed for lerna smoke tests)
script: |
git config --global user.email test@test.com
git config --global user.name "Test Test"
- name: Load Cargo Env
script: echo "PATH=$HOME/.cargo/bin:$PATH" >> $NX_CLOUD_ENV
- name: Install Rust Dependencies
script: |
cargo fetch
- name: Setup Java 21
script: |
sudo apt update
sudo apt install -y openjdk-21-jdk
sudo update-alternatives --set java /usr/lib/jvm/java-21-openjdk-amd64/bin/java
java -version
- name: Setup Gradle
script: |
./gradlew wrapper
./gradlew --version
- name: Setup .NET 9
script: |
wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt-get update
sudo apt-get install -y dotnet-sdk-9.0
dotnet --version
env: *common-env-vars
init-steps: *common-init-steps
+65 -7
View File
@@ -1,28 +1,70 @@
distribute-on:
default: auto linux-large, 3 linux-extra-large
extra-small-changeset: 6 linux-large, 3 linux-extra-large
small-changeset: 6 linux-large, 4 linux-extra-large
medium-changeset: 6 linux-large, 5 linux-extra-large
large-changeset: 6 linux-large, 6 linux-extra-large
extra-large-changeset: 8 linux-large, 8 linux-extra-large
assignment-rules:
- projects:
- e2e-gradle
- e2e-release
- e2e-angular
- e2e-react
targets:
- e2e-ci**
run-on:
- agent: linux-extra-large
parallelism: 1
- projects:
- e2e-next
- e2e-plugin
targets:
- e2e-ci**
run-on:
- agent: linux-extra-large
parallelism: 2
- projects:
- e2e-angular
- e2e-node
- e2e-react
targets:
- e2e-ci**
run-on:
- agent: linux-extra-large
parallelism: 1
- projects:
- nx
- workspace
- remix
- nx-maven-plugin
targets:
- install
- test
run-on:
- agent: linux-large
parallelism: 1
- agent: linux-extra-large
parallelism: 1
- projects:
- e2e-release
- e2e-nuxt
- e2e-web
- e2e-eslint
- e2e-remix
- e2e-cypress
- e2e-docker
- e2e-js
- e2e-nx
- e2e-nx-init
- nx-maven-plugin
- e2e-dotnet
- e2e-workspace-create
- e2e-rollup
targets:
- e2e-ci**
- install
run-on:
- agent: linux-large
parallelism: 1
- agent: linux-extra-large
parallelism: 1
parallelism: 2
# All other e2e tests can run in parallel
- targets:
@@ -33,9 +75,16 @@ assignment-rules:
- agent: linux-extra-large
parallelism: 3
- targets:
- bench:*
run-on:
- agent: linux-large
parallelism: 1
# These projects should not need to be isolated.
- projects:
- nx-dev
- astro-docs
targets:
- build*
run-on:
@@ -58,6 +107,15 @@ assignment-rules:
- agent: linux-extra-large
parallelism: 6
# TODO(altan): remove when scheduling issue resolved
- projects:
- nx-dev
targets:
- prebuild-banner
run-on:
- agent: linux-extra-large
parallelism: 6
- targets:
- "*"
run-on:
+21
View File
@@ -0,0 +1,21 @@
exclude-reads:
- packages/nx/src/native/*.node
- 'dist/target/**'
exclude-writes:
- '**/.swc/**'
- 'dist/target/**'
task-exclusions:
- target: lint
exclude-reads:
- '**/dist/**/*.json'
# TODO: populate-local-registry-storage is doing too much — it reads all build
# outputs and writes version-bumped packages across the entire workspace during
# nx-release. We're reworking this task to have more focused I/O and will fix
# the inputs/outputs properly after that.
- project: '@nx/nx-source'
target: populate-local-registry-storage
exclude-reads:
- '**'
exclude-writes:
- '**'
+1
View File
@@ -1,3 +1,4 @@
benchmarks/packages
nx-dev/**/jest.config.js
.next
_files
+479
View File
@@ -0,0 +1,479 @@
---
description: Polls Nx Cloud CI pipeline and self-healing status. Returns structured state when actionable. Spawned by /nx-cloud-ci-monitor command to monitor CI Attempt status.
mode: subagent
---
# CI Watcher Subagent
You are a CI monitoring subagent responsible for polling Nx Cloud CI Attempt status and self-healing state. You report status back to the main agent - you do NOT make apply/reject decisions.
## Your Responsibilities
1. Poll CI status using the `ci_information` MCP tool
2. Implement exponential backoff between polls
3. Return structured state when an actionable condition is reached
4. Track iteration count and elapsed time
5. Output status updates based on verbosity level
## Input Parameters (from Main Agent)
The main agent may provide these optional parameters in the prompt:
| Parameter | Description |
| ------------------- | -------------------------------------------------------- |
| `branch` | Branch to monitor (auto-detected if not provided) |
| `expectedCommitSha` | Commit SHA that should trigger a new CI Attempt |
| `previousCipeUrl` | CI Attempt URL before the action (to detect change) |
| `subagentTimeout` | Polling timeout in minutes (default: 60) |
| `verbosity` | Output level: minimal, medium, verbose (default: medium) |
When `expectedCommitSha` or `previousCipeUrl` is provided, you must detect whether a new CI Attempt has spawned.
## MCP Tool Reference
### `ci_information`
**Input:**
```json
{
"branch": "string (optional, defaults to current git branch)",
"select": "string (optional, comma-separated field names)",
"pageToken": "number (optional, 0-based pagination for long strings)"
}
```
**Output:**
```json
{
"cipeStatus": "NOT_STARTED | IN_PROGRESS | SUCCEEDED | FAILED | CANCELED | TIMED_OUT",
"cipeUrl": "string",
"branch": "string",
"commitSha": "string | null",
"failedTaskIds": "string[]",
"verifiedTaskIds": "string[]",
"selfHealingEnabled": "boolean",
"selfHealingStatus": "NOT_STARTED | IN_PROGRESS | COMPLETED | FAILED | NOT_EXECUTABLE | null",
"verificationStatus": "NOT_STARTED | IN_PROGRESS | COMPLETED | FAILED | NOT_EXECUTABLE | null",
"userAction": "NONE | APPLIED | REJECTED | APPLIED_LOCALLY | APPLIED_AUTOMATICALLY | null",
"failureClassification": "string | null",
"taskOutputSummary": "string | null",
"suggestedFixReasoning": "string | null",
"suggestedFixDescription": "string | null",
"suggestedFix": "string | null",
"shortLink": "string | null",
"couldAutoApplyTasks": "boolean | null",
"confidence": "number | null",
"confidenceReasoning": "string | null"
}
```
**Select Parameter:**
| Usage | Returns |
| --------------- | ----------------------------------------------------------- |
| No `select` | Formatted overview (truncated, not recommended for polling) |
| Single field | Raw value with pagination for long strings |
| Multiple fields | Object with requested field values |
**Field Sets for Efficient Polling:**
```yaml
WAIT_FIELDS:
'cipeUrl,commitSha,cipeStatus'
# Minimal fields for detecting new CI Attempt
LIGHT_FIELDS:
'cipeStatus,cipeUrl,branch,commitSha,selfHealingStatus,verificationStatus,userAction,failedTaskIds,verifiedTaskIds,selfHealingEnabled,failureClassification,couldAutoApplyTasks,shortLink,confidence,confidenceReasoning'
# Status fields for determining actionable state
HEAVY_FIELDS:
'taskOutputSummary,suggestedFix,suggestedFixReasoning,suggestedFixDescription'
# Large content fields - fetch only when returning to main agent
```
## Initial Wait
Before first poll, wait based on context:
- **Fresh start (no expected CIPE):** Wait 60 seconds to allow CI to start
- **Expecting new CIPE:** Wait 30 seconds (action already triggered)
**IMPORTANT:** Always run sleep in foreground, NOT as background command.
```bash
sleep 60 # or 30 if expecting new CIPE (FOREGROUND, not background)
```
## Two-Phase Operation
The subagent operates in one of two modes depending on input:
### Mode 1: Fresh Start (no `expectedCommitSha` or `previousCipeUrl`)
Normal polling - process whatever CIPE is returned by `ci_information`.
### Mode 2: Wait-for-New-CIPE (when `expectedCommitSha` or `previousCipeUrl` provided)
**CRITICAL**: When expecting a new CIPE, the subagent must **completely ignore** the old/stale CIPE. Do NOT process its status, do NOT return actionable states based on it.
#### Phase A: Wait Mode
1. Start a **new-CIPE timeout** timer (default: 30 minutes)
2. On each poll of `ci_information`:
- Check if CIPE is NEW:
- `cipeUrl` differs from `previousCipeUrl`**new CIPE detected**
- `commitSha` matches `expectedCommitSha`**correct CIPE detected**
- If still OLD CIPE: **ignore all status fields**, just wait and poll again
- Do NOT return `fix_available`, `ci_success`, etc. based on old CIPE!
3. Output wait status (see below)
4. If timeout (30 min) reached → return `no_new_cipe`
#### Phase B: Normal Polling (after new CIPE detected)
Once new CIPE is detected:
1. Clear the new-CIPE timeout
2. Switch to normal polling mode
3. Process the NEW CIPE's status normally
4. Return when actionable state reached
### Wait Mode Output
While in wait mode, output clearly that you're waiting (not processing):
```
[CI Monitor] ═══════════════════════════════════════════════════════
[CI Monitor] WAIT MODE - Expecting new CI Attempt
[CI Monitor] Expected SHA: <expectedCommitSha>
[CI Monitor] Previous CI Attempt: <previousCipeUrl>
[CI Monitor] ═══════════════════════════════════════════════════════
[CI Monitor] Polling... (elapsed: 0m 30s)
[CI Monitor] Still seeing previous CI Attempt (ignoring): <oldCipeUrl>
[CI Monitor] Polling... (elapsed: 1m 30s)
[CI Monitor] Still seeing previous CI Attempt (ignoring): <oldCipeUrl>
[CI Monitor] Polling... (elapsed: 2m 30s)
[CI Monitor] ✓ New CI Attempt detected! URL: <newCipeUrl>, SHA: <newCommitSha>
[CI Monitor] Switching to normal polling mode...
```
### Why This Matters (Context Preservation)
**The problem**: Stale CIPE data can be very large:
- `taskOutputSummary`: potentially thousands of characters of build/test output
- `suggestedFix`: entire patch files
- `suggestedFixReasoning`: detailed explanation
If subagent returns stale CIPE data to main agent, it **pollutes main agent's context** with useless information (we already processed that CIPE). This wastes valuable context window.
**Without wait mode:**
1. Poll `ci_information` → get old CIPE with huge data
2. Return to main agent with all that stale data
3. Main agent's context gets polluted with useless info
4. Main agent has to process/ignore it anyway
**With wait mode:**
1. Poll `ci_information` → get old CIPE → **ignore it, don't return**
2. Keep waiting internally (stale data stays in subagent)
3. New CIPE appears → switch to normal mode
4. Return to main agent with only the NEW, relevant CIPE data
## Polling Loop
### Subagent State Management
Maintain internal accumulated state across polls:
```
accumulated_state = {}
```
### Call `ci_information` MCP Tool
**Wait Mode (expecting new CI Attempt):**
```
ci_information({
branch: "<branch_name>",
select: "cipeUrl,commitSha,cipeStatus"
})
```
Only fetch minimal fields needed to detect CI Attempt change. Do NOT fetch heavy fields - stale data wastes context.
**Normal Mode (processing CI Attempt):**
```
ci_information({
branch: "<branch_name>",
select: "cipeStatus,cipeUrl,branch,commitSha,selfHealingStatus,verificationStatus,userAction,failedTaskIds,verifiedTaskIds,selfHealingEnabled,failureClassification,couldAutoApplyTasks,shortLink,confidence,confidenceReasoning"
})
```
Merge response into `accumulated_state` after each poll.
### Analyze Response
**If in Wait Mode** (expecting new CIPE):
1. Check if CIPE is new (see Two-Phase Operation above)
2. If old CIPE → **ignore status**, output wait message, poll again
3. If new CIPE → switch to normal mode, continue below
**If in Normal Mode**:
Based on the response, decide whether to **keep polling** or **return to main agent**.
### Keep Polling When
Continue polling (with backoff) if ANY of these conditions are true:
| Condition | Reason |
| --------------------------------------- | ---------------------------------------- |
| `cipeStatus == 'IN_PROGRESS'` | CI still running |
| `cipeStatus == 'NOT_STARTED'` | CI hasn't started yet |
| `selfHealingStatus == 'IN_PROGRESS'` | Self-healing agent working |
| `selfHealingStatus == 'NOT_STARTED'` | Self-healing not started yet |
| `failureClassification == 'FLAKY_TASK'` | Auto-rerun in progress |
| `userAction == 'APPLIED_AUTOMATICALLY'` | New CI Attempt spawning after auto-apply |
When `couldAutoApplyTasks == true`:
- `verificationStatus` = `NOT_STARTED`, `IN_PROGRESS` → keep polling (verification still in progress)
- `verificationStatus` = `COMPLETED` → return `fix_auto_applying` (auto-apply will happen, main agent spawns wait mode subagent)
- `verificationStatus` = `FAILED`, `NOT_EXECUTABLE` → return `fix_available` (auto-apply won't happen, needs manual action)
### Exponential Backoff
Between polls, wait with exponential backoff:
| Poll Attempt | Wait Time |
| ------------ | ----------------- |
| 1st | 60 seconds |
| 2nd | 90 seconds |
| 3rd+ | 120 seconds (cap) |
Reset to 60 seconds when state changes significantly.
**IMPORTANT:** Run sleep in foreground (NOT as background command). Background sleep causes "What should Claude do?" prompts when completed.
```bash
# Example backoff - run in FOREGROUND
sleep 60 # First wait
sleep 90 # Second wait
sleep 120 # Third and subsequent waits (capped)
```
### Fetch Heavy Fields on Actionable State
Before returning to main agent, fetch heavy fields if the status requires them:
| Status | Heavy Fields Needed |
| ------------------- | ------------------------------------------------------------------------------ |
| `ci_success` | None |
| `fix_auto_applying` | None |
| `fix_available` | `taskOutputSummary,suggestedFix,suggestedFixReasoning,suggestedFixDescription` |
| `fix_failed` | `taskOutputSummary` |
| `no_fix` | `taskOutputSummary` |
| `environment_issue` | None |
| `no_new_cipe` | None |
| `polling_timeout` | None |
| `cipe_canceled` | None |
| `cipe_timed_out` | None |
```
# Example: fetching heavy fields for fix_available
ci_information({
branch: "<branch_name>",
select: "taskOutputSummary,suggestedFix,suggestedFixReasoning,suggestedFixDescription"
})
```
Merge response into `accumulated_state`, then return merged state to main agent.
**Pagination:** Heavy string fields return first page only. If `hasMore` indicated, include in return format so main agent knows more content available.
### Return to Main Agent When
Return immediately with structured state if ANY of these conditions are true:
| Status | Condition |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ci_success` | `cipeStatus == 'SUCCEEDED'` |
| `fix_auto_applying` | `selfHealingStatus == 'COMPLETED'` AND `couldAutoApplyTasks == true` AND `verificationStatus == 'COMPLETED'` |
| `fix_available` | `selfHealingStatus == 'COMPLETED'` AND `suggestedFix != null` AND (`couldAutoApplyTasks != true` OR `verificationStatus` in (`FAILED`, `NOT_EXECUTABLE`)) |
| `fix_failed` | `selfHealingStatus == 'FAILED'` |
| `environment_issue` | `failureClassification == 'ENVIRONMENT_STATE'` |
| `no_fix` | `cipeStatus == 'FAILED'` AND (`selfHealingEnabled == false` OR `selfHealingStatus == 'NOT_EXECUTABLE'`) |
| `no_new_cipe` | `expectedCommitSha` or `previousCipeUrl` provided, but no new CI Attempt detected after 30 min |
| `polling_timeout` | Subagent has been polling for > configured timeout (default 60 min) |
| `cipe_canceled` | `cipeStatus == 'CANCELED'` |
| `cipe_timed_out` | `cipeStatus == 'TIMED_OUT'` |
## Subagent Timeout
Track elapsed time. If you have been polling for more than **60 minutes** (configurable via main agent), return with `status: polling_timeout`.
## Return Format
When returning to the main agent, provide a structured response with accumulated state:
```
## CI Monitor Result
**Status:** <status>
**Iterations:** <count>
**Elapsed:** <minutes>m <seconds>s
### CI Attempt Details
- **Status:** <cipeStatus>
- **URL:** <cipeUrl>
- **Branch:** <branch>
- **Commit:** <commitSha>
- **Failed Tasks:** <failedTaskIds>
- **Verified Tasks:** <verifiedTaskIds>
### Self-Healing Details
- **Enabled:** <selfHealingEnabled>
- **Status:** <selfHealingStatus>
- **Verification:** <verificationStatus>
- **User Action:** <userAction>
- **Classification:** <failureClassification>
- **Confidence:** <confidence>
- **Confidence Reasoning:** <confidenceReasoning>
### Fix Information (if available)
- **Short Link:** <shortLink>
- **Description:** <suggestedFixDescription>
- **Reasoning:** <suggestedFixReasoning>
### Task Output Summary (first page)
<taskOutputSummary>
[MORE_CONTENT_AVAILABLE: taskOutputSummary, pageToken: 1]
### Suggested Fix (first page)
<suggestedFix>
[MORE_CONTENT_AVAILABLE: suggestedFix, pageToken: 1]
```
### Pagination Indicators
When a heavy field has more content available, append indicator:
```
[MORE_CONTENT_AVAILABLE: <fieldName>, pageToken: <nextPage>]
```
Main agent can fetch additional pages if needed using:
```
ci_information({ select: "<fieldName>", pageToken: <nextPage> })
```
Fields that may have pagination:
- `taskOutputSummary` (reverse pagination - page 0 = most recent)
- `suggestedFix` (forward pagination - page 0 = start)
- `suggestedFixReasoning`
### Return Format for `no_new_cipe`
When returning with `status: no_new_cipe`, include additional context:
```
## CI Monitor Result
**Status:** no_new_cipe
**Iterations:** <count>
**Elapsed:** <minutes>m <seconds>s
### Expected CI Attempt Not Found
- **Expected Commit SHA:** <expectedCommitSha>
- **Previous CI Attempt URL:** <previousCipeUrl>
- **Last Seen CI Attempt URL:** <cipeUrl>
- **Last Seen Commit SHA:** <commitSha>
- **New CI Attempt Timeout:** 30 minutes (exceeded)
### Likely Cause
CI workflow failed before Nx tasks could run (e.g., install step, checkout, auth).
Check your CI provider logs for the commit <expectedCommitSha>.
### Last Known CI Attempt State
- **Status:** <cipeStatus>
- **Branch:** <branch>
```
## Status Reporting (Verbosity-Controlled)
Output is controlled by the `verbosity` parameter from the main agent:
| Level | What to Output |
| --------- | ----------------------------------------------------------------- |
| `minimal` | No intermediate output. Only return final result when actionable. |
| `medium` | Output only on significant state changes (not every poll). |
| `verbose` | Output detailed phase information after every poll. |
### Minimal Verbosity
No output during polling. Poll silently and return when done.
### Medium Verbosity (Default)
Output **only when state changes significantly** to save context tokens:
- `cipeStatus` changes (e.g., IN_PROGRESS → FAILED)
- `selfHealingStatus` changes (e.g., IN_PROGRESS → COMPLETED)
- New CI Attempt detected (in wait mode)
Format: single line, no decorators:
```
[CI Monitor] CI: FAILED | Self-Healing: IN_PROGRESS | Elapsed: 4m
```
### Verbose Verbosity
Output detailed phase box after every poll:
```
[CI Monitor] ─────────────────────────────────────────────────────
[CI Monitor] Iteration <N> | Elapsed: <X>m <Y>s
[CI Monitor]
[CI Monitor] CI Status: <cipeStatus>
[CI Monitor] Self-Healing: <selfHealingStatus>
[CI Monitor] Verification: <verificationStatus>
[CI Monitor] Classification: <failureClassification>
[CI Monitor]
[CI Monitor] → <human-readable phase description>
[CI Monitor] ─────────────────────────────────────────────────────
```
### Phase Descriptions (for verbose output)
| Status Combo | Description |
| ----------------------------------------------------------------------------------------- | ------------------------------------------- |
| `cipeStatus: IN_PROGRESS` | "CI running..." |
| `cipeStatus: NOT_STARTED` | "Waiting for CI to start..." |
| `cipeStatus: FAILED` + `selfHealingStatus: NOT_STARTED` | "CI failed. Self-healing starting..." |
| `cipeStatus: FAILED` + `selfHealingStatus: IN_PROGRESS` | "CI failed. Self-healing generating fix..." |
| `cipeStatus: FAILED` + `selfHealingStatus: COMPLETED` + `verificationStatus: IN_PROGRESS` | "Fix generated! Verification running..." |
| `cipeStatus: FAILED` + `selfHealingStatus: COMPLETED` + `verificationStatus: COMPLETED` | "Fix ready! Verified successfully." |
| `cipeStatus: FAILED` + `selfHealingStatus: COMPLETED` + `verificationStatus: FAILED` | "Fix generated but verification failed." |
| `cipeStatus: FAILED` + `selfHealingStatus: FAILED` | "Self-healing could not generate a fix." |
| `cipeStatus: SUCCEEDED` | "CI passed!" |
## Important Notes
- You do NOT make apply/reject decisions - that's the main agent's job
- You do NOT perform git operations
- You only poll and report state
- Respect the `verbosity` parameter for output (default: medium)
- If `ci_information` returns an error, wait and retry (count as failed poll)
- Track consecutive failures - if 5 consecutive failures, return with `status: error`
- When expecting new CI Attempt, track the 30-minute new-CI-Attempt timeout separately from the main polling timeout
+437
View File
@@ -0,0 +1,437 @@
---
description: Monitor Nx Cloud CI pipeline and handle self-healing fixes automatically. Checks for Nx Cloud connection before starting.
argument-hint: '[instructions] [--max-cycles N] [--timeout MINUTES] [--verbosity minimal|medium|verbose] [--branch BRANCH] [--fresh] [--auto-fix-workflow] [--new-cipe-timeout MINUTES]'
---
# CI Monitor Command
You are the orchestrator for monitoring Nx Cloud CI pipeline executions and handling self-healing fixes. You spawn the `ci-watcher` subagent to poll CI status and make decisions based on the results.
## Context
- **Current Branch:** !`git branch --show-current`
- **Current Commit:** !`git rev-parse --short HEAD`
- **Remote Status:** !`git status -sb | head -1`
## User Instructions
$ARGUMENTS
**Important:** If user provides specific instructions, respect them over default behaviors described below.
## Configuration Defaults
| Setting | Default | Description |
| ------------------------- | ------------- | ------------------------------------------------------------------- |
| `--max-cycles` | 10 | Maximum CIPE cycles before timeout |
| `--timeout` | 120 | Maximum duration in minutes |
| `--verbosity` | medium | Output level: minimal, medium, verbose |
| `--branch` | (auto-detect) | Branch to monitor |
| `--subagent-timeout` | 60 | Subagent polling timeout in minutes |
| `--fresh` | false | Ignore previous context, start fresh |
| `--auto-fix-workflow` | false | Attempt common fixes for pre-CIPE failures (e.g., lockfile updates) |
| `--new-cipe-timeout` | 10 | Minutes to wait for new CIPE after action |
| `--local-verify-attempts` | 3 | Max local verification + enhance cycles before pushing to CI |
Parse any overrides from `$ARGUMENTS` and merge with defaults.
## Nx Cloud Connection Check
**CRITICAL**: Before starting the monitoring loop, verify the workspace is connected to Nx Cloud.
### Step 0: Verify Nx Cloud Connection
1. **Check `nx.json`** at workspace root for `nxCloudId` or `nxCloudAccessToken`
2. **If `nx.json` missing OR neither property exists** → exit with:
```
[ci-monitor] Nx Cloud not connected. Unlock 70% faster CI and auto-fix broken PRs with https://nx.dev/nx-cloud
```
3. **If connected** → continue to main loop
## Session Context Behavior
**Important:** Within a Claude Code session, conversation context persists. If you Ctrl+C to interrupt the monitor and re-run `/ci-monitor`, Claude remembers the previous state and may continue from where it left off.
- **To continue monitoring:** Just re-run `/ci-monitor` (context is preserved)
- **To start fresh:** Use `/ci-monitor --fresh` to ignore previous context
- **For a completely clean slate:** Exit Claude Code and restart `claude`
## Default Behaviors by Status
The subagent returns with one of the following statuses. This table defines the **default behavior** for each status. User instructions can override any of these.
| Status | Default Behavior |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ci_success` | Exit with success. Log "CI passed successfully!" |
| `fix_auto_applying` | Fix will be auto-applied by self-healing. Do NOT call MCP. Record `last_cipe_url`, spawn new subagent in wait mode to poll for new CIPE. |
| `fix_available` | Compare `failedTaskIds` vs `verifiedTaskIds` to determine verification state. See **Fix Available Decision Logic** section below. |
| `fix_failed` | Self-healing failed to generate fix. Attempt local fix based on `taskOutputSummary`. If successful → commit, push, loop. If not → exit with failure. |
| `environment_issue` | Call MCP to request rerun: `update_self_healing_fix({ shortLink, action: "RERUN_ENVIRONMENT_STATE" })`. New CIPE spawns automatically. Loop to poll for new CIPE. |
| `no_fix` | CI failed, no fix available (self-healing disabled or not executable). Attempt local fix if possible. Otherwise exit with failure. |
| `no_new_cipe` | Expected CIPE never spawned (CI workflow likely failed before Nx tasks). Report to user, attempt common fixes if configured, or exit with guidance. |
| `polling_timeout` | Subagent polling timeout reached. Exit with timeout. |
| `cipe_canceled` | CIPE was canceled. Exit with canceled status. |
| `cipe_timed_out` | CIPE timed out. Exit with timeout status. |
| `error` | Increment `no_progress_count`. If >= 3 → exit with circuit breaker. Otherwise wait 60s and loop. |
### Fix Available Decision Logic
When subagent returns `fix_available`, main agent compares `failedTaskIds` vs `verifiedTaskIds`:
#### Step 1: Categorize Tasks
1. **Verified tasks** = tasks in both `failedTaskIds` AND `verifiedTaskIds`
2. **Unverified tasks** = tasks in `failedTaskIds` but NOT in `verifiedTaskIds`
3. **E2E tasks** = unverified tasks where target contains "e2e" (task format: `<project>:<target>` or `<project>:<target>:<config>`)
4. **Verifiable tasks** = unverified tasks that are NOT e2e
#### Step 2: Determine Path
| Condition | Path |
| --------------------------------------- | ---------------------------------------- |
| No unverified tasks (all verified) | Apply via MCP |
| Unverified tasks exist, but ALL are e2e | Apply via MCP (treat as verified enough) |
| Verifiable tasks exist | Local verification flow |
#### Step 3a: Apply via MCP (fully/e2e-only verified)
- Call `update_self_healing_fix({ shortLink, action: "APPLY" })`
- Record `last_cipe_url`, spawn subagent in wait mode
#### Step 3b: Local Verification Flow
When verifiable (non-e2e) unverified tasks exist:
1. **Detect package manager:**
- `pnpm-lock.yaml` exists → `pnpm nx`
- `yarn.lock` exists → `yarn nx`
- Otherwise → `npx nx`
2. **Run verifiable tasks in parallel:**
- Spawn `general` subagents to run each task concurrently
- Each subagent runs: `<pm> nx run <taskId>`
- Collect pass/fail results from all subagents
3. **Evaluate results:**
| Result | Action |
| ------------------------- | ---------------------------- |
| ALL verifiable tasks pass | Apply via MCP |
| ANY verifiable task fails | Apply-locally + enhance flow |
4. **Apply-locally + enhance flow:**
- Run `nx apply-locally <shortLink>`
- Enhance the code to fix failing tasks
- Run failing tasks again to verify fix
- If still failing → increment `local_verify_count`, loop back to enhance
- If passing → commit and push, record `expected_commit_sha`, spawn subagent in wait mode
5. **Track attempts** (wraps step 4):
- Increment `local_verify_count` after each enhance cycle
- If `local_verify_count >= local_verify_attempts` (default: 3):
- Get code in commit-able state
- Commit and push with message indicating local verification failed
- Report to user:
```
[ci-monitor] Local verification failed after <N> attempts. Pushed to CI for final validation. Failed: <taskIds>
```
- Record `expected_commit_sha`, spawn subagent in wait mode (let CI be final judge)
#### Commit Message Format
```bash
git commit -m "fix(<projects>): <brief description>
Failed tasks: <taskId1>, <taskId2>
Local verification: passed|enhanced|failed-pushing-to-ci"
```
### Unverified Fix Flow (No Verification Attempted)
When `verificationStatus` is `FAILED`, `NOT_EXECUTABLE`, or fix has `couldAutoApplyTasks != true` with no verification:
- Analyze fix content (`suggestedFix`, `suggestedFixReasoning`, `taskOutputSummary`)
- If fix looks correct → apply via MCP
- If fix needs enhancement → use Apply Locally + Enhance Flow above
- If fix is wrong → reject via MCP, fix from scratch, commit, push
### Auto-Apply Eligibility
The `couldAutoApplyTasks` field indicates whether the fix is eligible for automatic application:
- **`true`**: Fix is eligible for auto-apply. Subagent keeps polling while verification is in progress. Returns `fix_auto_applying` when verified, or `fix_available` if verification fails.
- **`false`** or **`null`**: Fix requires manual action (apply via MCP, apply locally, or reject)
**Key point**: When subagent returns `fix_auto_applying`, do NOT call MCP to apply - self-healing handles it. Just spawn a new subagent in wait mode.
### Apply vs Reject vs Apply Locally
- **Apply via MCP**: Calls `update_self_healing_fix({ shortLink, action: "APPLY" })`. Self-healing agent applies the fix in CI and a new CIPE spawns automatically. No local git operations needed.
- **Apply Locally**: Runs `nx apply-locally <shortLink>`. Applies the patch to your local working directory and sets state to `APPLIED_LOCALLY`. Use this when you want to enhance the fix before pushing.
- **Reject via MCP**: Calls `update_self_healing_fix({ shortLink, action: "REJECT" })`. Marks fix as rejected. Use only when the fix is completely wrong and you'll fix from scratch.
### Apply Locally + Enhance Flow
When the fix needs enhancement (use `nx apply-locally`, NOT reject):
1. Apply the patch locally: `nx apply-locally <shortLink>` (this also updates state to `APPLIED_LOCALLY`)
2. Make additional changes as needed
3. Commit and push:
```bash
git add -A
git commit -m "fix: resolve <failedTaskIds>"
git push origin $(git branch --show-current)
```
4. Loop to poll for new CIPE
### Reject + Fix From Scratch Flow
When the fix is completely wrong:
1. Call MCP to reject: `update_self_healing_fix({ shortLink, action: "REJECT" })`
2. Fix the issue from scratch locally
3. Commit and push:
```bash
git add -A
git commit -m "fix: resolve <failedTaskIds>"
git push origin $(git branch --show-current)
```
4. Loop to poll for new CIPE
### Environment Issue Handling
When `failureClassification == 'ENVIRONMENT_STATE'`:
1. Call MCP to request rerun: `update_self_healing_fix({ shortLink, action: "RERUN_ENVIRONMENT_STATE" })`
2. New CIPE spawns automatically (no local git operations needed)
3. Loop to poll for new CIPE with `previousCipeUrl` set
### No-New-CIPE Handling
When `status == 'no_new_cipe'`:
This means the expected CIPE was never created - CI likely failed before Nx tasks could run.
1. **Report to user:**
```
[ci-monitor] No CI attempt for <sha> after 10 min. Check CI provider for pre-Nx failures (install, checkout, auth). Last CI attempt: <previousCipeUrl>
```
2. **If user configured auto-fix attempts** (e.g., `--auto-fix-workflow`):
- Detect package manager: check for `pnpm-lock.yaml`, `yarn.lock`, `package-lock.json`
- Run install to update lockfile:
```bash
pnpm install # or npm install / yarn install
```
- If lockfile changed:
```bash
git add pnpm-lock.yaml # or appropriate lockfile
git commit -m "chore: update lockfile"
git push origin $(git branch --show-current)
```
- Record new commit SHA, loop to poll with `expectedCommitSha`
3. **Otherwise:** Exit with `no_new_cipe` status, providing guidance for user to investigate
## Exit Conditions
Exit the monitoring loop when ANY of these conditions are met:
| Condition | Exit Type |
| ------------------------------------------- | ---------------- |
| CI passes (`cipeStatus == 'SUCCEEDED'`) | Success |
| Max CIPE cycles reached | Timeout |
| Max duration reached | Timeout |
| 3 consecutive no-progress iterations | Circuit breaker |
| No fix available and local fix not possible | Failure |
| No new CIPE and auto-fix not configured | Pre-CIPE failure |
| User cancels | Cancelled |
## Main Loop
### Step 1: Initialize Tracking
```
cycle_count = 0
start_time = now()
no_progress_count = 0
local_verify_count = 0
last_state = null
last_cipe_url = null
expected_commit_sha = null
```
### Step 2: Spawn Subagent
Spawn the `ci-watcher` subagent to poll CI status:
**Fresh start (first spawn, no expected CIPE):**
```
Task(
agent: "ci-watcher",
prompt: "Monitor CI for branch '<branch>'.
Subagent timeout: <subagent-timeout> minutes.
New-CIPE timeout: <new-cipe-timeout> minutes.
Verbosity: <verbosity>."
)
```
**After action that triggers new CIPE (wait mode):**
```
Task(
agent: "ci-watcher",
prompt: "Monitor CI for branch '<branch>'.
Subagent timeout: <subagent-timeout> minutes.
New-CIPE timeout: <new-cipe-timeout> minutes.
Verbosity: <verbosity>.
WAIT MODE: A new CIPE should spawn. Ignore old CIPE until new one appears.
Expected commit SHA: <expected_commit_sha>
Previous CIPE URL: <last_cipe_url>"
)
```
### Step 3: Handle Subagent Response
When subagent returns:
1. Check the returned status
2. Look up default behavior in the table above
3. Check if user instructions override the default
4. Execute the appropriate action
5. **If action expects new CIPE**, update tracking (see Step 3a)
6. If action results in looping, go to Step 2
### Step 3a: Track State for New-CIPE Detection
After actions that should trigger a new CIPE, record state before looping:
| Action | What to Track | Subagent Mode |
| ----------------------------- | --------------------------------------------- | ------------- |
| Fix auto-applying | `last_cipe_url = current cipeUrl` | Wait mode |
| Apply via MCP | `last_cipe_url = current cipeUrl` | Wait mode |
| Apply locally + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Reject + fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Fix failed + local fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| No fix + local fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Environment rerun | `last_cipe_url = current cipeUrl` | Wait mode |
| No-new-CIPE + auto-fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
**CRITICAL**: When passing `expectedCommitSha` or `last_cipe_url` to the subagent, it enters **wait mode**:
- Subagent will **completely ignore** the old/stale CIPE
- Subagent will only wait for new CIPE to appear
- Subagent will NOT return to main agent with stale CIPE data
- Once new CIPE detected, subagent switches to normal polling
**Why wait mode matters for context preservation**: Stale CIPE data can be very large (task output summaries, suggested fix patches, reasoning). If subagent returns this to main agent, it pollutes main agent's context with useless data since we already processed that CIPE. Wait mode keeps stale data in the subagent, never sending it to main agent.
### Step 4: Progress Tracking
After each action:
- If state changed significantly → reset `no_progress_count = 0`
- If state unchanged → `no_progress_count++`
- On new CI attempt detected → reset `local_verify_count = 0`
## Status Reporting
Based on verbosity level:
| Level | What to Report |
| --------- | -------------------------------------------------------------------------- |
| `minimal` | Only final result (success/failure/timeout) |
| `medium` | State changes + periodic updates ("Cycle N \| Elapsed: Xm \| Status: ...") |
| `verbose` | All of medium + full subagent responses, git outputs, MCP responses |
## User Instruction Examples
Users can override default behaviors:
| Instruction | Effect |
| ------------------------------------------------ | --------------------------------------------- |
| "never auto-apply" | Always prompt before applying any fix |
| "always ask before git push" | Prompt before each push |
| "reject any fix for e2e tasks" | Auto-reject if `failedTaskIds` contains e2e |
| "apply all fixes regardless of verification" | Skip verification check, apply everything |
| "if confidence < 70, reject" | Check confidence field before applying |
| "run 'nx affected -t typecheck' before applying" | Add local verification step |
| "auto-fix workflow failures" | Attempt lockfile updates on pre-CIPE failures |
| "wait 45 min for new CIPE" | Override new-CIPE timeout (default: 10 min) |
## Error Handling
| Error | Action |
| ------------------------ | ------------------------------------------------------------------------------------- |
| Git rebase conflict | Report to user, exit |
| `nx apply-locally` fails | Report to user, attempt manual patch or exit |
| MCP tool error | Retry once, if fails report to user |
| Subagent spawn failure | Retry once, if fails exit with error |
| No new CIPE detected | If `--auto-fix-workflow`, try lockfile update; otherwise report to user with guidance |
| Lockfile auto-fix fails | Report to user, exit with guidance to check CI logs |
## Example Session
### Example 1: Normal Flow with Self-Healing (medium verbosity)
```
[ci-monitor] Starting CI monitor for branch 'feature/add-auth'
[ci-monitor] Config: max-cycles=5, timeout=120m, verbosity=medium
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] CI attempt: IN_PROGRESS | Self-Healing: NOT_STARTED | Elapsed: 1m
[CI Monitor] CI attempt: FAILED | Self-Healing: IN_PROGRESS | Elapsed: 3m
[CI Monitor] CI attempt: FAILED | Self-Healing: COMPLETED | Elapsed: 5m
[ci-monitor] Fix available! Verification: COMPLETED
[ci-monitor] Applying fix via MCP...
[ci-monitor] Fix applied in CI. Waiting for new CI attempt...
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] New CI attempt detected!
[CI Monitor] CI attempt: SUCCEEDED | Elapsed: 8m
[ci-monitor] CI passed successfully!
[ci-monitor] Summary:
- Total cycles: 2
- Total time: 12m 34s
- Fixes applied: 1
- Result: SUCCESS
```
### Example 2: Pre-CI Failure (medium verbosity)
```
[ci-monitor] Starting CI monitor for branch 'feature/add-products'
[ci-monitor] Config: max-cycles=5, timeout=120m, auto-fix-workflow=true
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] CI attempt: FAILED | Self-Healing: COMPLETED | Elapsed: 2m
[ci-monitor] Applying fix locally, enhancing, and pushing...
[ci-monitor] Committed: abc1234
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] Waiting for new CI attempt... (expected SHA: abc1234)
[CI Monitor] ⚠️ CI attempt timeout (10 min). Returning no_new_cipe.
[ci-monitor] Status: no_new_cipe
[ci-monitor] --auto-fix-workflow enabled. Attempting lockfile update...
[ci-monitor] Lockfile updated. Committed: def5678
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] New CI attempt detected!
[CI Monitor] CI attempt: SUCCEEDED | Elapsed: 18m
[ci-monitor] CI passed successfully!
[ci-monitor] Summary:
- Total cycles: 3
- Total time: 22m 15s
- Fixes applied: 1 (self-healing) + 1 (lockfile)
- Result: SUCCESS
```
+437
View File
@@ -0,0 +1,437 @@
---
name: ci-monitor
description: Monitor Nx Cloud CI pipeline and handle self-healing fixes automatically. Checks for Nx Cloud connection before starting.
---
# CI Monitor Command
You are the orchestrator for monitoring Nx Cloud CI pipeline executions and handling self-healing fixes. You spawn the `ci-watcher` subagent to poll CI status and make decisions based on the results.
## Context
- **Current Branch:** !`git branch --show-current`
- **Current Commit:** !`git rev-parse --short HEAD`
- **Remote Status:** !`git status -sb | head -1`
## User Instructions
$ARGUMENTS
**Important:** If user provides specific instructions, respect them over default behaviors described below.
## Configuration Defaults
| Setting | Default | Description |
| ------------------------- | ------------- | ------------------------------------------------------------------- |
| `--max-cycles` | 10 | Maximum CIPE cycles before timeout |
| `--timeout` | 120 | Maximum duration in minutes |
| `--verbosity` | medium | Output level: minimal, medium, verbose |
| `--branch` | (auto-detect) | Branch to monitor |
| `--subagent-timeout` | 60 | Subagent polling timeout in minutes |
| `--fresh` | false | Ignore previous context, start fresh |
| `--auto-fix-workflow` | false | Attempt common fixes for pre-CIPE failures (e.g., lockfile updates) |
| `--new-cipe-timeout` | 10 | Minutes to wait for new CIPE after action |
| `--local-verify-attempts` | 3 | Max local verification + enhance cycles before pushing to CI |
Parse any overrides from `$ARGUMENTS` and merge with defaults.
## Nx Cloud Connection Check
**CRITICAL**: Before starting the monitoring loop, verify the workspace is connected to Nx Cloud.
### Step 0: Verify Nx Cloud Connection
1. **Check `nx.json`** at workspace root for `nxCloudId` or `nxCloudAccessToken`
2. **If `nx.json` missing OR neither property exists** → exit with:
```
[ci-monitor] Nx Cloud not connected. Unlock 70% faster CI and auto-fix broken PRs with https://nx.dev/nx-cloud
```
3. **If connected** → continue to main loop
## Session Context Behavior
**Important:** Within a Claude Code session, conversation context persists. If you Ctrl+C to interrupt the monitor and re-run `/ci-monitor`, Claude remembers the previous state and may continue from where it left off.
- **To continue monitoring:** Just re-run `/ci-monitor` (context is preserved)
- **To start fresh:** Use `/ci-monitor --fresh` to ignore previous context
- **For a completely clean slate:** Exit Claude Code and restart `claude`
## Default Behaviors by Status
The subagent returns with one of the following statuses. This table defines the **default behavior** for each status. User instructions can override any of these.
| Status | Default Behavior |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ci_success` | Exit with success. Log "CI passed successfully!" |
| `fix_auto_applying` | Fix will be auto-applied by self-healing. Do NOT call MCP. Record `last_cipe_url`, spawn new subagent in wait mode to poll for new CIPE. |
| `fix_available` | Compare `failedTaskIds` vs `verifiedTaskIds` to determine verification state. See **Fix Available Decision Logic** section below. |
| `fix_failed` | Self-healing failed to generate fix. Attempt local fix based on `taskOutputSummary`. If successful → commit, push, loop. If not → exit with failure. |
| `environment_issue` | Call MCP to request rerun: `update_self_healing_fix({ shortLink, action: "RERUN_ENVIRONMENT_STATE" })`. New CIPE spawns automatically. Loop to poll for new CIPE. |
| `no_fix` | CI failed, no fix available (self-healing disabled or not executable). Attempt local fix if possible. Otherwise exit with failure. |
| `no_new_cipe` | Expected CIPE never spawned (CI workflow likely failed before Nx tasks). Report to user, attempt common fixes if configured, or exit with guidance. |
| `polling_timeout` | Subagent polling timeout reached. Exit with timeout. |
| `cipe_canceled` | CIPE was canceled. Exit with canceled status. |
| `cipe_timed_out` | CIPE timed out. Exit with timeout status. |
| `error` | Increment `no_progress_count`. If >= 3 → exit with circuit breaker. Otherwise wait 60s and loop. |
### Fix Available Decision Logic
When subagent returns `fix_available`, main agent compares `failedTaskIds` vs `verifiedTaskIds`:
#### Step 1: Categorize Tasks
1. **Verified tasks** = tasks in both `failedTaskIds` AND `verifiedTaskIds`
2. **Unverified tasks** = tasks in `failedTaskIds` but NOT in `verifiedTaskIds`
3. **E2E tasks** = unverified tasks where target contains "e2e" (task format: `<project>:<target>` or `<project>:<target>:<config>`)
4. **Verifiable tasks** = unverified tasks that are NOT e2e
#### Step 2: Determine Path
| Condition | Path |
| --------------------------------------- | ---------------------------------------- |
| No unverified tasks (all verified) | Apply via MCP |
| Unverified tasks exist, but ALL are e2e | Apply via MCP (treat as verified enough) |
| Verifiable tasks exist | Local verification flow |
#### Step 3a: Apply via MCP (fully/e2e-only verified)
- Call `update_self_healing_fix({ shortLink, action: "APPLY" })`
- Record `last_cipe_url`, spawn subagent in wait mode
#### Step 3b: Local Verification Flow
When verifiable (non-e2e) unverified tasks exist:
1. **Detect package manager:**
- `pnpm-lock.yaml` exists → `pnpm nx`
- `yarn.lock` exists → `yarn nx`
- Otherwise → `npx nx`
2. **Run verifiable tasks in parallel:**
- Spawn `general` subagents to run each task concurrently
- Each subagent runs: `<pm> nx run <taskId>`
- Collect pass/fail results from all subagents
3. **Evaluate results:**
| Result | Action |
| ------------------------- | ---------------------------- |
| ALL verifiable tasks pass | Apply via MCP |
| ANY verifiable task fails | Apply-locally + enhance flow |
4. **Apply-locally + enhance flow:**
- Run `nx apply-locally <shortLink>`
- Enhance the code to fix failing tasks
- Run failing tasks again to verify fix
- If still failing → increment `local_verify_count`, loop back to enhance
- If passing → commit and push, record `expected_commit_sha`, spawn subagent in wait mode
5. **Track attempts** (wraps step 4):
- Increment `local_verify_count` after each enhance cycle
- If `local_verify_count >= local_verify_attempts` (default: 3):
- Get code in commit-able state
- Commit and push with message indicating local verification failed
- Report to user:
```
[ci-monitor] Local verification failed after <N> attempts. Pushed to CI for final validation. Failed: <taskIds>
```
- Record `expected_commit_sha`, spawn subagent in wait mode (let CI be final judge)
#### Commit Message Format
```bash
git commit -m "fix(<projects>): <brief description>
Failed tasks: <taskId1>, <taskId2>
Local verification: passed|enhanced|failed-pushing-to-ci"
```
### Unverified Fix Flow (No Verification Attempted)
When `verificationStatus` is `FAILED`, `NOT_EXECUTABLE`, or fix has `couldAutoApplyTasks != true` with no verification:
- Analyze fix content (`suggestedFix`, `suggestedFixReasoning`, `taskOutputSummary`)
- If fix looks correct → apply via MCP
- If fix needs enhancement → use Apply Locally + Enhance Flow above
- If fix is wrong → reject via MCP, fix from scratch, commit, push
### Auto-Apply Eligibility
The `couldAutoApplyTasks` field indicates whether the fix is eligible for automatic application:
- **`true`**: Fix is eligible for auto-apply. Subagent keeps polling while verification is in progress. Returns `fix_auto_applying` when verified, or `fix_available` if verification fails.
- **`false`** or **`null`**: Fix requires manual action (apply via MCP, apply locally, or reject)
**Key point**: When subagent returns `fix_auto_applying`, do NOT call MCP to apply - self-healing handles it. Just spawn a new subagent in wait mode.
### Apply vs Reject vs Apply Locally
- **Apply via MCP**: Calls `update_self_healing_fix({ shortLink, action: "APPLY" })`. Self-healing agent applies the fix in CI and a new CIPE spawns automatically. No local git operations needed.
- **Apply Locally**: Runs `nx apply-locally <shortLink>`. Applies the patch to your local working directory and sets state to `APPLIED_LOCALLY`. Use this when you want to enhance the fix before pushing.
- **Reject via MCP**: Calls `update_self_healing_fix({ shortLink, action: "REJECT" })`. Marks fix as rejected. Use only when the fix is completely wrong and you'll fix from scratch.
### Apply Locally + Enhance Flow
When the fix needs enhancement (use `nx apply-locally`, NOT reject):
1. Apply the patch locally: `nx apply-locally <shortLink>` (this also updates state to `APPLIED_LOCALLY`)
2. Make additional changes as needed
3. Commit and push:
```bash
git add -A
git commit -m "fix: resolve <failedTaskIds>"
git push origin $(git branch --show-current)
```
4. Loop to poll for new CIPE
### Reject + Fix From Scratch Flow
When the fix is completely wrong:
1. Call MCP to reject: `update_self_healing_fix({ shortLink, action: "REJECT" })`
2. Fix the issue from scratch locally
3. Commit and push:
```bash
git add -A
git commit -m "fix: resolve <failedTaskIds>"
git push origin $(git branch --show-current)
```
4. Loop to poll for new CIPE
### Environment Issue Handling
When `failureClassification == 'ENVIRONMENT_STATE'`:
1. Call MCP to request rerun: `update_self_healing_fix({ shortLink, action: "RERUN_ENVIRONMENT_STATE" })`
2. New CIPE spawns automatically (no local git operations needed)
3. Loop to poll for new CIPE with `previousCipeUrl` set
### No-New-CIPE Handling
When `status == 'no_new_cipe'`:
This means the expected CIPE was never created - CI likely failed before Nx tasks could run.
1. **Report to user:**
```
[ci-monitor] No CI attempt for <sha> after 10 min. Check CI provider for pre-Nx failures (install, checkout, auth). Last CI attempt: <previousCipeUrl>
```
2. **If user configured auto-fix attempts** (e.g., `--auto-fix-workflow`):
- Detect package manager: check for `pnpm-lock.yaml`, `yarn.lock`, `package-lock.json`
- Run install to update lockfile:
```bash
pnpm install # or npm install / yarn install
```
- If lockfile changed:
```bash
git add pnpm-lock.yaml # or appropriate lockfile
git commit -m "chore: update lockfile"
git push origin $(git branch --show-current)
```
- Record new commit SHA, loop to poll with `expectedCommitSha`
3. **Otherwise:** Exit with `no_new_cipe` status, providing guidance for user to investigate
## Exit Conditions
Exit the monitoring loop when ANY of these conditions are met:
| Condition | Exit Type |
| ------------------------------------------- | ---------------- |
| CI passes (`cipeStatus == 'SUCCEEDED'`) | Success |
| Max CIPE cycles reached | Timeout |
| Max duration reached | Timeout |
| 3 consecutive no-progress iterations | Circuit breaker |
| No fix available and local fix not possible | Failure |
| No new CIPE and auto-fix not configured | Pre-CIPE failure |
| User cancels | Cancelled |
## Main Loop
### Step 1: Initialize Tracking
```
cycle_count = 0
start_time = now()
no_progress_count = 0
local_verify_count = 0
last_state = null
last_cipe_url = null
expected_commit_sha = null
```
### Step 2: Spawn Subagent
Spawn the `ci-watcher` subagent to poll CI status:
**Fresh start (first spawn, no expected CIPE):**
```
Task(
agent: "ci-watcher",
prompt: "Monitor CI for branch '<branch>'.
Subagent timeout: <subagent-timeout> minutes.
New-CIPE timeout: <new-cipe-timeout> minutes.
Verbosity: <verbosity>."
)
```
**After action that triggers new CIPE (wait mode):**
```
Task(
agent: "ci-watcher",
prompt: "Monitor CI for branch '<branch>'.
Subagent timeout: <subagent-timeout> minutes.
New-CIPE timeout: <new-cipe-timeout> minutes.
Verbosity: <verbosity>.
WAIT MODE: A new CIPE should spawn. Ignore old CIPE until new one appears.
Expected commit SHA: <expected_commit_sha>
Previous CIPE URL: <last_cipe_url>"
)
```
### Step 3: Handle Subagent Response
When subagent returns:
1. Check the returned status
2. Look up default behavior in the table above
3. Check if user instructions override the default
4. Execute the appropriate action
5. **If action expects new CIPE**, update tracking (see Step 3a)
6. If action results in looping, go to Step 2
### Step 3a: Track State for New-CIPE Detection
After actions that should trigger a new CIPE, record state before looping:
| Action | What to Track | Subagent Mode |
| ----------------------------- | --------------------------------------------- | ------------- |
| Fix auto-applying | `last_cipe_url = current cipeUrl` | Wait mode |
| Apply via MCP | `last_cipe_url = current cipeUrl` | Wait mode |
| Apply locally + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Reject + fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Fix failed + local fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| No fix + local fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
| Environment rerun | `last_cipe_url = current cipeUrl` | Wait mode |
| No-new-CIPE + auto-fix + push | `expected_commit_sha = $(git rev-parse HEAD)` | Wait mode |
**CRITICAL**: When passing `expectedCommitSha` or `last_cipe_url` to the subagent, it enters **wait mode**:
- Subagent will **completely ignore** the old/stale CIPE
- Subagent will only wait for new CIPE to appear
- Subagent will NOT return to main agent with stale CIPE data
- Once new CIPE detected, subagent switches to normal polling
**Why wait mode matters for context preservation**: Stale CIPE data can be very large (task output summaries, suggested fix patches, reasoning). If subagent returns this to main agent, it pollutes main agent's context with useless data since we already processed that CIPE. Wait mode keeps stale data in the subagent, never sending it to main agent.
### Step 4: Progress Tracking
After each action:
- If state changed significantly → reset `no_progress_count = 0`
- If state unchanged → `no_progress_count++`
- On new CI attempt detected → reset `local_verify_count = 0`
## Status Reporting
Based on verbosity level:
| Level | What to Report |
| --------- | -------------------------------------------------------------------------- |
| `minimal` | Only final result (success/failure/timeout) |
| `medium` | State changes + periodic updates ("Cycle N \| Elapsed: Xm \| Status: ...") |
| `verbose` | All of medium + full subagent responses, git outputs, MCP responses |
## User Instruction Examples
Users can override default behaviors:
| Instruction | Effect |
| ------------------------------------------------ | --------------------------------------------- |
| "never auto-apply" | Always prompt before applying any fix |
| "always ask before git push" | Prompt before each push |
| "reject any fix for e2e tasks" | Auto-reject if `failedTaskIds` contains e2e |
| "apply all fixes regardless of verification" | Skip verification check, apply everything |
| "if confidence < 70, reject" | Check confidence field before applying |
| "run 'nx affected -t typecheck' before applying" | Add local verification step |
| "auto-fix workflow failures" | Attempt lockfile updates on pre-CIPE failures |
| "wait 45 min for new CIPE" | Override new-CIPE timeout (default: 10 min) |
## Error Handling
| Error | Action |
| ------------------------ | ------------------------------------------------------------------------------------- |
| Git rebase conflict | Report to user, exit |
| `nx apply-locally` fails | Report to user, attempt manual patch or exit |
| MCP tool error | Retry once, if fails report to user |
| Subagent spawn failure | Retry once, if fails exit with error |
| No new CIPE detected | If `--auto-fix-workflow`, try lockfile update; otherwise report to user with guidance |
| Lockfile auto-fix fails | Report to user, exit with guidance to check CI logs |
## Example Session
### Example 1: Normal Flow with Self-Healing (medium verbosity)
```
[ci-monitor] Starting CI monitor for branch 'feature/add-auth'
[ci-monitor] Config: max-cycles=5, timeout=120m, verbosity=medium
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] CI attempt: IN_PROGRESS | Self-Healing: NOT_STARTED | Elapsed: 1m
[CI Monitor] CI attempt: FAILED | Self-Healing: IN_PROGRESS | Elapsed: 3m
[CI Monitor] CI attempt: FAILED | Self-Healing: COMPLETED | Elapsed: 5m
[ci-monitor] Fix available! Verification: COMPLETED
[ci-monitor] Applying fix via MCP...
[ci-monitor] Fix applied in CI. Waiting for new CI attempt...
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] New CI attempt detected!
[CI Monitor] CI attempt: SUCCEEDED | Elapsed: 8m
[ci-monitor] CI passed successfully!
[ci-monitor] Summary:
- Total cycles: 2
- Total time: 12m 34s
- Fixes applied: 1
- Result: SUCCESS
```
### Example 2: Pre-CI Failure (medium verbosity)
```
[ci-monitor] Starting CI monitor for branch 'feature/add-products'
[ci-monitor] Config: max-cycles=5, timeout=120m, auto-fix-workflow=true
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] CI attempt: FAILED | Self-Healing: COMPLETED | Elapsed: 2m
[ci-monitor] Applying fix locally, enhancing, and pushing...
[ci-monitor] Committed: abc1234
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] Waiting for new CI attempt... (expected SHA: abc1234)
[CI Monitor] ⚠️ CI attempt timeout (10 min). Returning no_new_cipe.
[ci-monitor] Status: no_new_cipe
[ci-monitor] --auto-fix-workflow enabled. Attempting lockfile update...
[ci-monitor] Lockfile updated. Committed: def5678
[ci-monitor] Spawning subagent to poll CI status...
[CI Monitor] New CI attempt detected!
[CI Monitor] CI attempt: SUCCEEDED | Elapsed: 18m
[ci-monitor] CI passed successfully!
[ci-monitor] Summary:
- Total cycles: 3
- Total time: 22m 15s
- Fixes applied: 1 (self-healing) + 1 (lockfile)
- Result: SUCCESS
```
+228
View File
@@ -0,0 +1,228 @@
---
name: nx-generate
description: Generate code using nx generators. USE WHEN scaffolding code or transforming existing code - for example creating libraries or applications, or anything else that is boilerplate code or automates repetitive tasks. ALWAYS use this first when generating code with Nx instead of calling MCP tools or running nx generate immediately.
---
# Run Nx Generator
Nx generators are powerful tools that scaffold projects, make automated code migrations or automate repetitive tasks in a monorepo. They ensure consistency across the codebase and reduce boilerplate work.
This skill applies when the user wants to:
- Create new projects like libraries or applications
- Scaffold features or boilerplate code
- Run workspace-specific or custom generators
- Do anything else that an nx generator exists for
## Generator Discovery Flow
### Step 1: List Available Generators
Use the Nx CLI to discover available generators:
- List all generators for a plugin: `npx nx list @nx/react`
- View available plugins: `npx nx list`
This includes:
- Plugin generators (e.g., `@nx/react:library`, `@nx/js:library`)
- Local workspace generators (defined in the repo's own plugins)
### Step 2: Match Generator to User Request
Based on the user's request, identify which generator(s) could fulfill their needs. Consider:
- What artifact type they want to create (library, application, etc.)
- Which framework or technology stack is relevant
- Whether they mentioned specific generator names
**IMPORTANT**: When both a local workspace generator and an external plugin generator could satisfy the request, **always prefer the local workspace generator**. Local generators are customized for the specific repo's patterns and conventions.
It's possible that the user request is something that no Nx generator exists for whatsoever. In this case, you can stop using this skill and try to help the user another way. HOWEVER, the burden of proof for this is high. Before aborting, carefully consider each and every generator that's available. Look into details for any that could be related in any way before making this decision.
## Pre-Execution Checklist
Before running any generator, complete these steps:
### 1. Fetch Generator Schema
Use the `--help` flag to understand all available options:
```bash
npx nx g @nx/react:library --help
```
Pay attention to:
- Required options that must be provided
- Optional options that may be relevant to the user's request
- Default values that might need to be overridden
### 2. Read Generator Source Code
Understanding what the generator actually does helps you:
- Know what files will be created/modified
- Understand any side effects (updating configs, installing deps, etc.)
- Identify options that might not be obvious from the schema
To find generator source code:
- For plugin generators: Use `node -e "console.log(require.resolve('@nx/<plugin>/generators.json'));"` to find the generators.json, then locate the source from there
- If that fails, read directly from `node_modules/<plugin>/generators.json`
- For local generators: They are typically in `tools/generators/` or a local plugin directory. You can search the repo for the generator name to find it.
### 2.5 Reevaluate if the generator is right
Once you have built up an understanding of what the selected generator does, reconsider: Is this the right generator to service the user request?
If not, it's okay to go back to the Generator Discovery Flow and select a different generator before proceeding. If you do, make sure to go through the entire pre-execution checklist once more.
### 3. Understand Repo Context
Before generating, examine the target area of the codebase:
- Look at similar existing artifacts (other libraries, applications, etc.)
- Identify patterns and conventions used in the repo
- Note naming conventions, file structures, and configuration patterns
- Try to match these patterns when configuring the generator
For example, if similar libraries are using a specific test runner, build tool or linter, try to match that if possible.
If projects or other artifacts are organized with a specific naming convention, try to match it.
### 4. Validate Required Options
Ensure all required options have values:
- Map the user's request to generator options
- Infer values from context where possible
- Ask the user for any critical missing information
## Execution
Keep in mind that you might have to prefix things with npx/pnpx/yarn if the user doesn't have nx installed globally.
Many generators will behave differently based on where they are executed. For example, first-party nx library generators use the cwd to determine the directory that the library should be placed in. This is highly important.
### Consider Dry-Run (Optional)
Running with `--dry-run` first is strongly encouraged but not mandatory. Use your judgment:
- For complex generators or unfamiliar territory: do a dry-run first
- For simple, well-understood generators: may proceed directly
- Dry-run shows file names and created/deleted/modified markers, but not content
- There are cases where a generator does not support dry-run (for example if it had to install an npm package) - in that case --dry-run might fail. Don't be discouraged but simply move on to running the generator for real and iterating from there.
### Running the Generator
Execute the generator with:
```bash
nx generate <generator-name> <options> --no-interactive
```
**CRITICAL**: Always include `--no-interactive` to prevent prompts that would hang the execution.
Example:
```bash
nx generate @nx/react:library --name=my-utils --no-interactive
```
### Handling Generator Failures
If the generator fails:
1. **Diagnose the error** - Read the error message carefully
2. **Identify the cause** - Missing options, invalid values, conflicts, etc.
3. **Attempt automatic fix** - Adjust options or resolve conflicts
4. **Retry** - Run the generator again with corrected options
Common failure reasons:
- Missing required options
- Invalid option values
- Conflicting with existing files
- Missing dependencies
- Generator doesn't support certain flag combinations
## Post-Generation
### 1. Modify Generated Code (If Needed)
Generators provide a starting point, but the output may need adjustment to match the user's specific requirements:
- Add or modify functionality as requested
- Adjust imports, exports, or configurations
- Integrate with existing code patterns in the repo
### 2. Format Code
Run formatting on all generated/modified files:
```bash
nx format --fix
```
Languages other than javascript/typescript might need other formatting invocations too.
### 3. Run Verification
Verify that the generated code works correctly. What this looks like will vary depending on the type of generator and the targets available.
If the generator created a new project, run its targets directly
Use your best judgement to determine what needs to be verified.
Example:
```bash
nx lint <new-project>
nx test <new-project>
nx build <new-project>
```
### 4. Handle Verification Failures
When verification fails:
**If scope is manageable** (a few lint errors, minor type issues):
- Fix the issues
- Re-run verification to confirm
**If issues are extensive** (many errors, complex problems):
- Attempt simple, obvious fixes first
- If still failing, escalate to the user with:
- Description of what was generated
- What verification is failing
- What you've attempted to fix
- Remaining issues that need user input
## Error Handling
### Generator Failures
- Check the error message for specific causes
- Verify all required options are provided
- Check for conflicts with existing files
- Ensure the generator name and options are correct
### Missing Options
- Consult the generator schema for required fields
- Infer values from context when reasonable
- Ask the user for values that cannot be inferred
## Key Principles
1. **Local generators first** - Always prefer workspace/local generators over external plugin generators when both could work
2. **Understand before running** - Read both the schema AND the source code to fully understand what will happen
3. **No prompts** - Always use `--no-interactive` to prevent hanging
4. **Generators are starting points** - Modify the output as needed to fully satisfy the user's requirements
5. **Verify changes work** - Don't just generate; ensure the code builds, lints, and tests pass
6. **Be proactive about fixes** - Don't just report errors; attempt to resolve them automatically when possible
7. **Match repo patterns** - Study existing similar code in the repo and match its conventions
+9
View File
@@ -0,0 +1,9 @@
---
name: nx-plugins
description: Find and add Nx plugins. USE WHEN user wants to discover available plugins, install a new plugin, or add support for a specific framework or technology to the workspace.
---
## Finding and Installing new plugins
- List plugins: `pnpm nx list`
- Install plugins `pnpm nx add <plugin>`. Example: `pnpm nx add @nx/react`.
+58
View File
@@ -0,0 +1,58 @@
---
name: nx-run-tasks
description: Helps with running tasks in an Nx workspace. USE WHEN the user wants to execute build, test, lint, serve, or run any other tasks defined in the workspace.
---
You can run tasks with Nx in the following way.
Keep in mind that you might have to prefix things with npx/pnpx/yarn if the user doesn't have nx installed globally. Look at the package.json or lockfile to determine which package manager is in use.
For more details on any command, run it with `--help` (e.g. `nx run-many --help`, `nx affected --help`).
## Understand which tasks can be run
You can check those via `nx show project <projectname> --json`, for example `nx show project myapp --json`. It contains a `targets` section which has information about targets that can be run. You can also just look at the `package.json` scripts or `project.json` targets, but you might miss out on inferred tasks by Nx plugins.
## Run a single task
```
nx run <project>:<task>
```
where `project` is the project name defined in `package.json` or `project.json` (if present).
## Run multiple tasks
```
nx run-many -t build test lint typecheck
```
You can pass a `-p` flag to filter to specific projects, otherwise it runs on all projects. You can also use `--exclude` to exclude projects, and `--parallel` to control the number of parallel processes (default is 3).
Examples:
- `nx run-many -t test -p proj1 proj2` — test specific projects
- `nx run-many -t test --projects=*-app --exclude=excluded-app` — test projects matching a pattern
- `nx run-many -t test --projects=tag:api-*` — test projects by tag
## Run tasks for affected projects
Use `nx affected` to only run tasks on projects that have been changed and projects that depend on changed projects. This is especially useful in CI and for large workspaces.
```
nx affected -t build test lint
```
By default it compares against the base branch. You can customize this:
- `nx affected -t test --base=main --head=HEAD` — compare against a specific base and head
- `nx affected -t test --files=libs/mylib/src/index.ts` — specify changed files directly
## Useful flags
These flags work with `run`, `run-many`, and `affected`:
- `--skipNxCache` — rerun tasks even when results are cached
- `--verbose` — print additional information such as stack traces
- `--nxBail` — stop execution after the first failed task
- `--configuration=<name>` — use a specific configuration (e.g. `production`)
+186
View File
@@ -0,0 +1,186 @@
---
name: nx-workspace
description: "Explore and understand Nx workspaces. USE WHEN answering any questions about the nx workspace, the projects in it or tasks to run. EXAMPLES: 'What projects are in this workspace?', 'How is project X configured?', 'What targets can I run?', 'What's affected by my changes?', 'Which projects depend on library Y?', or any questions about Nx workspace structure, project configuration, or available tasks."
---
# Nx Workspace Exploration
This skill provides read-only exploration of Nx workspaces. Use it to understand workspace structure, project configuration, available targets, and dependencies.
Keep in mind that you might have to prefix commands with `npx`/`pnpx`/`yarn` if nx isn't installed globally. Check the lockfile to determine the package manager in use.
## Listing Projects
Use `nx show projects` to list projects in the workspace.
```bash
# List all projects
nx show projects
# Filter by pattern (glob)
nx show projects --projects "apps/*"
nx show projects --projects "shared-*"
# Filter by project type
nx show projects --type app
nx show projects --type lib
nx show projects --type e2e
# Filter by target (projects that have a specific target)
nx show projects --withTarget build
nx show projects --withTarget e2e
# Find affected projects (changed since base branch)
nx show projects --affected
nx show projects --affected --base=main
nx show projects --affected --type app
# Combine filters
nx show projects --type lib --withTarget test
nx show projects --affected --exclude="*-e2e"
# Output as JSON
nx show projects --json
```
## Project Configuration
Use `nx show project <name> --json` to get the full resolved configuration for a project.
**Important**: Do NOT read `project.json` directly - it only contains partial configuration. The `nx show project` command returns the full resolved config including inferred targets from plugins.
You can read the full project schema at `node_modules/nx/schemas/project-schema.json` to understand nx project configuration options.
```bash
# Get full project configuration
nx show project my-app --json
# Extract specific parts from the JSON
nx show project my-app --json | jq '.targets'
nx show project my-app --json | jq '.targets.build'
nx show project my-app --json | jq '.targets | keys'
# Check project metadata
nx show project my-app --json | jq '{name, root, sourceRoot, projectType, tags}'
```
## Target Information
Targets define what tasks can be run on a project.
```bash
# List all targets for a project
nx show project my-app --json | jq '.targets | keys'
# Get full target configuration
nx show project my-app --json | jq '.targets.build'
# Check target executor/command
nx show project my-app --json | jq '.targets.build.executor'
nx show project my-app --json | jq '.targets.build.command'
# View target options
nx show project my-app --json | jq '.targets.build.options'
# Check target inputs/outputs (for caching)
nx show project my-app --json | jq '.targets.build.inputs'
nx show project my-app --json | jq '.targets.build.outputs'
# Find projects with a specific target
nx show projects --withTarget serve
nx show projects --withTarget e2e
```
## Workspace Configuration
Read `nx.json` directly for workspace-level configuration.
You can read the full project schema at `node_modules/nx/schemas/nx-schema.json` to understand nx project configuration options.
```bash
# Read the full nx.json
cat nx.json
# Or use jq for specific sections
cat nx.json | jq '.targetDefaults'
cat nx.json | jq '.namedInputs'
cat nx.json | jq '.plugins'
cat nx.json | jq '.generators'
```
Key nx.json sections:
- `targetDefaults` - Default configuration applied to all targets of a given name
- `namedInputs` - Reusable input definitions for caching
- `plugins` - Nx plugins and their configuration
- ...and much more, read the schema or nx.json for details
## Affected Projects
Find projects affected by changes in the current branch.
```bash
# Affected since base branch (auto-detected)
nx show projects --affected
# Affected with explicit base
nx show projects --affected --base=main
nx show projects --affected --base=origin/main
# Affected between two commits
nx show projects --affected --base=abc123 --head=def456
# Affected apps only
nx show projects --affected --type app
# Affected excluding e2e projects
nx show projects --affected --exclude="*-e2e"
# Affected by uncommitted changes
nx show projects --affected --uncommitted
# Affected by untracked files
nx show projects --affected --untracked
```
## Common Exploration Patterns
### "What's in this workspace?"
```bash
nx show projects
nx show projects --type app
nx show projects --type lib
```
### "How do I build/test/lint project X?"
```bash
nx show project X --json | jq '.targets | keys'
nx show project X --json | jq '.targets.build'
```
### "What depends on library Y?"
```bash
# Find projects that may depend on Y by searching for imports
# (Nx doesn't have a direct "dependents" command via CLI)
grep -r "from '@myorg/Y'" --include="*.ts" --include="*.tsx" apps/ libs/
```
### "What configuration options are available?"
```bash
cat node_modules/nx/schemas/nx-schema.json | jq '.properties | keys'
cat node_modules/nx/schemas/project-schema.json | jq '.properties | keys'
```
### "Why is project X affected?"
```bash
# Check what files changed
git diff --name-only main
# See which project owns those files
nx show project X --json | jq '.root'
```
+5
View File
@@ -54,3 +54,8 @@ _solution
# this file uses TS import attributes which the current prettier version does not support
tools/documentation/create-embeddings/src/main.mts
.nx/self-healing
# Inlined from `@yarnpkg/parser` keep as is
packages/nx/src/utils/yarn-syml/syml-grammar.js
+1
View File
@@ -1,6 +1,7 @@
{
"singleQuote": true,
"endOfLine": "lf",
"trailingComma": "es5",
"plugins": ["prettier-plugin-tailwindcss"],
"overrides": [
{
+31 -11
View File
@@ -9,6 +9,25 @@ When responding to queries about this repository:
Always strive to provide accurate, helpful responses that align with the best practices and workflows described in this
file.
## Documentation Contributions
When working on Nx documentation, all documentation content lives in the `astro-docs/` folder. This is the new Astro-based documentation site built with Starlight.
**Important**: Before making any documentation changes, read the `astro-docs/README.md` file for detailed guidance on:
- Project structure and architecture
- Content types (regular docs, dynamic plugin docs, CLI docs)
- Available Markdoc tags for rich content
- Development workflow and commands
- Sidebar management
### Quick Reference
- Documentation content: `astro-docs/src/content/docs/`
- Use `.mdoc` (Markdoc) or `.mdx` format for documentation files
- Run `nx serve astro-docs` to start the local dev server
- Sidebar structure is defined in `astro-docs/sidebar.mts`
## GitHub Issue Response Mode
When responding to GitHub issues, determine your approach based on how the request is phrased:
@@ -183,22 +202,23 @@ Fixes #ISSUE_NUMBER
<!-- nx configuration start-->
<!-- Leave the start & end comments to automatically receive updates. -->
# General Guidelines for working with Nx
## General Guidelines for working with Nx
- For navigating/exploring the workspace, invoke the `nx-workspace` skill first - it has patterns for querying projects, targets, and dependencies
- When running tasks (for example build, lint, test, e2e, etc.), always prefer running the task through `nx` (i.e. `nx run`, `nx run-many`, `nx affected`) instead of using the underlying tooling directly
- Prefix nx commands with the workspace's package manager (e.g., `pnpm nx build`, `npm exec nx test`) - avoids using globally installed CLI
- You have access to the Nx MCP server and its tools, use them to help the user
- When answering questions about the repository, use the `nx_workspace` tool first to gain an understanding of the workspace architecture where applicable.
- When working in individual projects, use the `nx_project_details` mcp tool to analyze and understand the specific project structure and dependencies
- For questions around nx configuration, best practices or if you're unsure, use the `nx_docs` tool to get relevant, up-to-date docs. Always use this instead of assuming things about nx configuration
- If the user needs help with an Nx configuration or project graph error, use the `nx_workspace` tool to get any errors
- For Nx plugin best practices, check `node_modules/@nx/<plugin>/PLUGIN.md`. Not all plugins have this file - proceed without it if unavailable.
- NEVER guess CLI flags - always check nx_docs or `--help` first when unsure
# CI Error Guidelines
## Scaffolding & Generators
If the user wants help with fixing an error in their CI pipeline, use the following flow:
- For scaffolding tasks (creating apps, libs, project structure, setup), ALWAYS invoke the `nx-generate` skill FIRST before exploring or calling MCP tools
- Retrieve the list of current CI Pipeline Executions (CIPEs) using the `nx_cloud_cipe_details` tool
- If there are any errors, use the `nx_cloud_fix_cipe_failure` tool to retrieve the logs for a specific task
- Use the task logs to see what's wrong and help the user fix their problem. Use the appropriate tools if necessary
- Make sure that the problem is fixed by running the task that you passed into the `nx_cloud_fix_cipe_failure` tool
## When to use nx_docs
- USE for: advanced config options, unfamiliar flags, migration guides, plugin configuration, edge cases
- DON'T USE for: basic generator syntax (`nx g @nx/react:app`), standard commands, things you already know
- The `nx-generate` skill handles generator discovery internally - don't call nx_docs just to look up generator syntax
<!-- nx configuration end-->
+33 -11
View File
@@ -9,6 +9,27 @@ When responding to queries about this repository:
Always strive to provide accurate, helpful responses that align with the best practices and workflows described in this
file.
## Documentation Contributions
When working on Nx documentation, all documentation content lives in the `astro-docs/` folder. This is the new Astro-based documentation site built with Starlight.
**Important**: Before making any documentation changes, read the `astro-docs/README.md` file for detailed guidance on:
- Project structure and architecture
- Content types (regular docs, dynamic plugin docs, CLI docs)
- Available Markdoc tags for rich content
- Development workflow and commands
- Sidebar management
**MANDATORY**: After editing any file in `astro-docs/src/content/`, run the `nx-docs-style-check` skill. No exceptions.
### Quick Reference
- Documentation content: `astro-docs/src/content/docs/`
- Use `.mdoc` (Markdoc) or `.mdx` format for documentation files
- Run `nx serve astro-docs` to start the local dev server
- Sidebar structure is defined in `astro-docs/sidebar.mts`
## GitHub Issue Response Mode
When responding to GitHub issues, determine your approach based on how the request is phrased:
@@ -183,22 +204,23 @@ Fixes #ISSUE_NUMBER
<!-- nx configuration start-->
<!-- Leave the start & end comments to automatically receive updates. -->
# General Guidelines for working with Nx
## General Guidelines for working with Nx
- For navigating/exploring the workspace, invoke the `nx-workspace` skill first - it has patterns for querying projects, targets, and dependencies
- When running tasks (for example build, lint, test, e2e, etc.), always prefer running the task through `nx` (i.e. `nx run`, `nx run-many`, `nx affected`) instead of using the underlying tooling directly
- Prefix nx commands with the workspace's package manager (e.g., `pnpm nx build`, `npm exec nx test`) - avoids using globally installed CLI
- You have access to the Nx MCP server and its tools, use them to help the user
- When answering questions about the repository, use the `nx_workspace` tool first to gain an understanding of the workspace architecture where applicable.
- When working in individual projects, use the `nx_project_details` mcp tool to analyze and understand the specific project structure and dependencies
- For questions around nx configuration, best practices or if you're unsure, use the `nx_docs` tool to get relevant, up-to-date docs. Always use this instead of assuming things about nx configuration
- If the user needs help with an Nx configuration or project graph error, use the `nx_workspace` tool to get any errors
- For Nx plugin best practices, check `node_modules/@nx/<plugin>/PLUGIN.md`. Not all plugins have this file - proceed without it if unavailable.
- NEVER guess CLI flags - always check nx_docs or `--help` first when unsure
# CI Error Guidelines
## Scaffolding & Generators
If the user wants help with fixing an error in their CI pipeline, use the following flow:
- For scaffolding tasks (creating apps, libs, project structure, setup), ALWAYS invoke the `nx-generate` skill FIRST before exploring or calling MCP tools
- Retrieve the list of current CI Pipeline Executions (CIPEs) using the `nx_cloud_cipe_details` tool
- If there are any errors, use the `nx_cloud_fix_cipe_failure` tool to retrieve the logs for a specific task
- Use the task logs to see what's wrong and help the user fix their problem. Use the appropriate tools if necessary
- Make sure that the problem is fixed by running the task that you passed into the `nx_cloud_fix_cipe_failure` tool
## When to use nx_docs
- USE for: advanced config options, unfamiliar flags, migration guides, plugin configuration, edge cases
- DON'T USE for: basic generator syntax (`nx g @nx/react:app`), standard commands, things you already know
- The `nx-generate` skill handles generator discovery internally - don't call nx_docs just to look up generator syntax
<!-- nx configuration end-->
+1 -164
View File
@@ -1,165 +1,2 @@
# Any file not covered by a rule below, will default to Jason + Victor and a few select others.
* @FrozenPandaz @vsavkin
/packages/**/* @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry
/e2e/**/* @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry
/scripts/**/* @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry
/tools/**/* @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry
package.json @nrwl/nx-core-reviewers
pnpm-lock.yaml @nrwl/nx-core-reviewers
rust-toolchain.toml @nrwl/nx-native-reviewers
# Docs Site + Graph
/astro-docs @nrwl/nx-docs-reviewers
/docs @nrwl/nx-docs-reviewers
/graph/** @philipjfulcher @FrozenPandaz @bcabanes @MaxKless @Coly010 @jaysoo @nartc
/images @nrwl/nx-docs-reviewers
/nx-dev/** @nrwl/nx-docs-reviewers
/typedoc-theme @nrwl/nx-docs-reviewers
# Plugin Verticals
## Angular
/packages/angular/** @nrwl/nx-angular-reviewers
/packages/angular-rspack/** @nrwl/nx-angular-reviewers
/packages/angular-rspack-compiler/** @nrwl/nx-angular-reviewers
/examples/angular-rspack/** @nrwl/nx-angular-reviewers
/e2e/angular/** @nrwl/nx-angular-reviewers
/packages/angular/plugins/component-testing.ts @nrwl/nx-angular-reviewers @nrwl/nx-testing-tools-reviewers
/packages/angular/src/generators/cypress-component-configuration/** @nrwl/nx-angular-reviewers @nrwl/nx-testing-tools-reviewers
/packages/angular/src/generators/component-test/** @nrwl/nx-angular-reviewers @nrwl/nx-testing-tools-reviewers
## React
/packages/react/** @nrwl/nx-react-reviewers
/e2e/react/** @nrwl/nx-react-reviewers
/packages/next/** @nrwl/nx-react-reviewers
/e2e/next/** @nrwl/nx-react-reviewers
/packages/react/plugins/component-testing/** @nrwl/nx-react-reviewers @nrwl/nx-testing-tools-reviewers
/packages/react/src/generators/cypress-component-configuration/** @nrwl/nx-react-reviewers @nrwl/nx-testing-tools-reviewers
/packages/react/src/generators/component-test/** @nrwl/nx-react-reviewers @nrwl/nx-testing-tools-reviewers
# React Native
/packages/detox/** @nrwl/nx-react-reviewers
/e2e/detox/** @nrwl/nx-react-reviewers
/packages/expo/** @nrwl/nx-react-reviewers
/e2e/expo/** @nrwl/nx-react-reviewers
/packages/react-native/** @nrwl/nx-react-reviewers
/e2e/react-native/** @nrwl/nx-react-reviewers
## remix
/packages/remix/** @nrwl/nx-react-reviewers @Coly010
/e2e/remix/** @nrwl/nx-react-reviewers @Coly010
# Vue
/packages/vue/** @nrwl/nx-vue-reviewers
/e2e/vue/** @nrwl/nx-vue-reviewers
/packages/nuxt/** @nrwl/nx-vue-reviewers
/e2e/nuxt/** @nrwl/nx-vue-reviewers
## Node
/packages/node/** @nrwl/nx-node-reviewers
/packages/express/** @nrwl/nx-node-reviewers
/packages/nest/** @nrwl/nx-node-reviewers
/e2e/node/** @nrwl/nx-node-reviewers
## JS
/packages/js/** @nrwl/nx-js-reviewers
/e2e/js/** @nrwl/nx-js-reviewers
/packages/web/** @nrwl/nx-js-reviewers
/e2e/web/** @nrwl/nx-js-reviewers
/packages/webpack/** @nrwl/nx-js-reviewers
/e2e/webpack/** @nrwl/nx-js-reviewers
/packages/rspack/** @nrwl/nx-js-reviewers
/e2e/rspack/** @nrwl/nx-js-reviewers
/packages/rsbuild/** @nrwl/nx-js-reviewers
/packages/esbuild/** @nrwl/nx-js-reviewers
/e2e/esbuild/** @nrwl/nx-js-reviewers
/packages/rollup/** @nrwl/nx-js-reviewers
/e2e/rollup/** @nrwl/nx-js-reviewers
/packages/vite/** @nrwl/nx-js-reviewers
/e2e/vite/** @nrwl/nx-js-reviewers
## Module Federation
/packages/module-federation/** @nrwl/nx-js-reviewers
## Tools
/packages/cypress/** @nrwl/nx-testing-tools-reviewers
/e2e/cypress/** @nrwl/nx-testing-tools-reviewers
/packages/jest/** @nrwl/nx-testing-tools-reviewers
/e2e/jest/** @nrwl/nx-testing-tools-reviewers
/packages/playwright/** @nrwl/nx-testing-tools-reviewers
/e2e/playwright/** @nrwl/nx-testing-tools-reviewers
# Linter
/packages/eslint-plugin/** @nrwl/nx-linter-reviewers
/packages/eslint/** @nrwl/nx-linter-reviewers
/e2e/eslint/** @nrwl/nx-linter-reviewers
.eslint* @nrwl/nx-linter-reviewers
# Storybook
/packages/storybook/** @nrwl/nx-storybook-reviewers
/e2e/storybook/** @nrwl/nx-storybook-reviewers
# Docker
/packages/docker/** @nrwl/nx-core-reviewers @Coly010
## Devkit
/packages/devkit/** @nrwl/nx-devkit-reviewers
/packages/devkit/index.ts @FrozenPandaz @vsavkin
/packages/devkit/public-api.ts @FrozenPandaz @vsavkin
# Gradle
/packages/gradle/** @FrozenPandaz @MaxKless @lourw
/e2e/gradle/** @FrozenPandaz @MaxKless @lourw
# Maven
/packages/maven/** @FrozenPandaz @MaxKless @lourw
/e2e/maven/** @FrozenPandaz @MaxKless @lourw
# Nx-Plugin
/packages/plugin/** @nrwl/nx-devkit-reviewers
/e2e/plugin/** @nrwl/nx-devkit-reviewers
## Core
/packages/nx/** @nrwl/nx-core-reviewers
/packages/nx/src/adapter @nrwl/nx-core-reviewers @leosvelperez
/packages/nx/src/native @nrwl/nx-core-reviewers @nrwl/nx-native-reviewers
/packages/nx/src/plugins/js/lock-file @nrwl/nx-core-reviewers @meeroslav
/packages/nx/src/command-line/init/implementation/angular/** @nrwl/nx-angular-reviewers @nrwl/nx-core-reviewers
/e2e/nx-init/src/nx-init-angular.test.ts @nrwl/nx-angular-reviewers
/packages/nx/src/command-line/init/implementation/react/** @nrwl/nx-react-reviewers
/e2e/nx-init/src/nx-init-react.test.ts @nrwl/nx-react-reviewers
/e2e/nx-init/src/files/cra/** @nrwl/nx-react-reviewers
/e2e/nx*/** @nrwl/nx-core-reviewers
/packages/workspace/** @nrwl/nx-core-reviewers
/e2e/workspace-create/** @nrwl/nx-core-reviewers
/e2e/release/** @nrwl/nx-core-reviewers
# Misc
/e2e/lerna-smoke-tests/** @vsavkin @JamesHenry
/e2e/utils/** @meeroslav @nrwl/nx-testing-tools-reviewers @vsavkin
/community @nrwl/nx-docs-reviewers
/CONTRIBUTING.md @FrozenPandaz
/CODE_OF_CONDUCT.md @FrozenPandaz
/CODEOWNERS @FrozenPandaz @AgentEnder
/packages/nx/src/nx-cloud/utilities/url-shorten.ts @MaxKless
# Scripts
/scripts/documentation @nrwl/nx-docs-reviewers
/scripts/angular-support-upgrades @nrwl/nx-angular-reviewers
# CI
/.nx/workflows/** @nrwl/nx-pipelines-reviewers
/.github/** @nrwl/nx-pipelines-reviewers
/.husky/** @nrwl/nx-pipelines-reviewers
/packages/workspace/src/generators/ci-workflow/** @nrwl/nx-pipelines-reviewers
# Claude AI Integration
CLAUDE.md @FrozenPandaz
.claude/** @FrozenPandaz
.mcp.json @FrozenPandaz
# Global Files
project.json @FrozenPandaz @vsavkin
jest.config.ts @nrwl/nx-testing-tools-reviewers @FrozenPandaz
jest.preset.js @nrwl/nx-testing-tools-reviewers @FrozenPandaz
* @nrwl/nx-cli-reviewers
+2 -11
View File
@@ -2,19 +2,10 @@
We would love for you to contribute to Nx! Read this document to see how to do it.
## How to Get Started Video
Watch this 5-minute video:
<a href="https://www.youtube.com/watch?v=8LCA_4qxc08" target="_blank" rel="noreferrer">
<p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/how-to-contribute.png" width="600" alt="Nx - How to contribute"></p>
</a>
## Got a Question?
We are trying to keep GitHub issues for bug reports and feature requests. Using the `nrwl` tag
on [Stack Overflow](https://stackoverflow.com/questions/tagged/nrwl) is a much better place to ask general questions
about how to use Nx.
We are trying to keep GitHub issues for bug reports and feature requests.
You can join our [Discord](https://go.nx.dev/community) for general questions and seeking help from others.
## Found an Issue?
Generated
+1693 -1409
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
(The MIT License)
Copyright (c) 2017-2025 Narwhal Technologies Inc.
Copyright (c) 2017-2026 Narwhal Technologies Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
+35 -57
View File
@@ -1,74 +1,52 @@
<p style="text-align: center;">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-dark.svg">
<img alt="Nx - Smart Repos · Fast Builds" src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-light.svg" width="100%">
</picture>
</p>
<div align="center">
<div style="text-align: center;">
<p>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="images/nx-logo-light.svg">
<img src="images/nx-logo.svg" alt="Nx Logo" width="140">
</picture>
</p>
[![CircleCI](https://circleci.com/gh/nrwl/nx.svg?style=svg)](https://circleci.com/gh/nrwl/nx)
[![License](https://img.shields.io/npm/l/nx.svg?style=flat-square)]()
[![NPM Version](https://badge.fury.io/js/nx.svg)](https://www.npmjs.com/package/nx)
[![Semantic Release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic-release-e10079.svg?style=flat-square)]()
[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
[![Join the chat at https://gitter.im/nrwl-nx/community](https://badges.gitter.im/nrwl-nx/community.svg)](https://gitter.im/nrwl-nx/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Join the Official Nx Discord Server](https://img.shields.io/discord/1143497901675401286?label=discord)](https://go.nx.dev/community)
<h1 align="center">Smart Monorepos · Fast Builds</h1>
<p>
<a href="https://www.npmjs.com/package/nx"><img src="https://img.shields.io/npm/v/nx.svg?style=for-the-badge" alt="NPM Version"></a>
<a href="https://github.com/nrwl/nx"><img src="https://img.shields.io/github/stars/nrwl/nx?style=for-the-badge&logo=github" alt="GitHub Stars"></a>
<a href=""><img src="https://img.shields.io/npm/l/nx.svg?style=for-the-badge" alt="License"></a>
<a href="https://go.nx.dev/community"><img src="https://img.shields.io/discord/1143497901675401286?label=discord&style=for-the-badge" alt="Discord"></a>
<a href="https://x.com/nxdevtools"><img src="https://img.shields.io/badge/@nxdevtools-555?style=for-the-badge&logo=x" alt="X (Twitter)"></a>
</p>
<br />
[**Docs**](https://nx.dev/docs) &nbsp;&bull;&nbsp; [**Changelog**](https://nx.dev/changelog) &nbsp;&bull;&nbsp; [**Blog**](https://nx.dev/blog) &nbsp;&bull;&nbsp; [**Courses**](https://nx.dev/courses) &nbsp;&bull;&nbsp; [**YouTube**](https://youtube.com/@nxdevtools)
<br />
</div>
<hr>
Nx is a monorepo solution for TypeScript and polyglot codebases. Built with Rust for performance, extensible via TypeScript. Caches what didn't change, runs only what's affected, and comes with an integrated CI solution. Start simple, scale as you grow.
# Smart Repos · Fast Builds
## Quick Start
Get to green PRs in half the time. Nx optimizes your builds, scales your CI, and fixes failed PRs. Built for developers and AI agents.
Visit the [Nx quickstart docs](https://nx.dev/docs/quickstart) to get started.
Create a new Nx workspace with
## Why Nx?
```shell
npx create-nx-workspace
```
- **Incremental by design -** Run `npx nx init` in any npm/pnpm/yarn workspace. Nx picks up your existing `package.json` scripts, caches their outputs, and runs only what's
affected. No changes to your setup required.
- **AI-native tooling -** The Nx CLI is optimized for autonomous AI agents so they get the context they need and can operate just like a human. [Learn more &raquo;](https://github.com/nrwl/nx-ai-agents-config)
- **Polyglot plugin system -** Optional plugins auto-discover tasks, configure cache inputs/outputs, and scaffold code based on your actual tooling. Works with Vite, Webpack, Jest, Vitest, ESLint, Gradle, Maven, .NET, Go, and [more](https://nx.dev/technologies).
- **Integrated CI solution -** [Connect Nx to your CI provider](https://nx.dev/ci/intro/ci-with-nx) (GitHub Actions, GitLab, Azure, etc.) to enable remote caching, task distribution across machines, affected-only runs, and automatic e2e test splitting. [Learn more &raquo;](https://nx.dev/ci/intro/ci-with-nx)
- **Self-healing CI -** An AI agent on your CI pipeline that detects failures, analyzes root cause, proposes a fix, and verifies it automatically. Local agents connect to CI via MCP to autonomously detect and fix failures. [Learn more &raquo;](https://nx.dev/ci/features/self-healing)
...or run
## Who uses Nx?
```
npx nx init
```
to add Nx to your existing workspace to get faster task scheduling, caching and more. More [in the docs](https://nx.dev/getting-started/intro).
## Learn about CI with Nx Cloud
[Nx Cloud](https://nx.dev/nx-cloud) connects directly to your existing CI setup, helping you scale your monorepos on CI by leveraging [remote caching](https://nx.dev/ci/features/remote-cache?utm_source=nxrepo&utm_medium=readme&utm_campaign=nxrepo), [task distribution across multiple machines](https://nx.dev/ci/features/distribute-task-execution?utm_source=nxrepo&utm_medium=readme&utm_campaign=nxrepo), [automated e2e test splitting](https://nx.dev/ci/features/split-e2e-tasks?utm_source=nxrepo&utm_medium=readme&utm_campaign=nxrepo) and [automated task flakiness detection](https://nx.dev/ci/features/flaky-tasks?utm_source=nxrepo&utm_medium=readme&utm_campaign=nxrepo)
Connect your existing Nx workspace with
```
npx nx connect
```
Learn more in the [Nx CI docs &raquo;](https://nx.dev/ci/getting-started/intro?utm_source=nxrepo&utm_medium=readme&utm_campaign=nxrepo)
## Useful links
- [Our docs](https://nx.dev/docs)
- [Our blog](https://nx.dev/blog)
- [Our community discord, live stream,...](https://nx.dev/community)
- [Our YouTube channel](https://www.youtube.com/@NxDevtools)
- [Our Twitter/X](https://x.com/nxdevtools)
<p style="text-align: center;"><a href="https://www.youtube.com/@nxdevtools/videos" target="_blank" rel="noreferrer"><img src="./images/nx-courses-and-videos.svg"
width="100%" alt="Nx - Smart Repos · Fast Builds"></a></p>
From startups to Fortune 500 companies. [See our Nx success stories &raquo;](https://nx.dev/customers)
## Want to help?
If you want to file a bug or submit a PR, read up on
our [guidelines for contributing](https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md) and watch this video that will
help you get started.
<a href="https://www.youtube.com/watch?v=8LCA_4qxc08" target="_blank" rel="noreferrer">
<p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/how-to-contribute.png" width="600" alt="Nx - How to contribute video"></p>
</a>
If you want to file a bug or submit a PR, read up on our [guidelines for contributing](https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md).
## Core Team
+12
View File
@@ -13,3 +13,15 @@ Instead, please report them to the Security Team at security@nrwl.io.
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message.
Nx follows the principle of Coordinated Vulnerability Disclosure.
## What Should Be Reported
The security email is for **demonstrable, verified vulnerabilities within the Nx codebase itself**.
**Please do not use the security email for:**
- Reports about outdated dependencies (e.g., "package X has a newer version available")
- Reports about dependencies with known CVEs that do not directly affect Nx functionality
- General vulnerability scanner output
If you have a concern about an outdated dependency that you believe impacts Nx users, please open a [GitHub issue](https://github.com/nrwl/nx/issues/new/choose) instead.
+162
View File
@@ -0,0 +1,162 @@
StylesPath = .vale/styles
MinAlertLevel = suggestion
# Treat Markdoc (.mdoc) files as markdown
[formats]
mdoc = md
# Ignore Markdoc tag syntax and @-scoped package names to avoid false positives
TokenIgnores = (\{%.*?%\}), (@\w+/[\w-]+)
[src/content/docs/**/*.{mdoc,mdx,md}]
BasedOnStyles = Nx
# Disable heading check for config option reference pages (headings are camelCase property names)
[src/content/docs/technologies/angular/angular-rsbuild/introduction.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/angular/angular-rspack/create-config.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/build-tools/webpack/Guides/webpack-plugins.mdoc]
Nx.Headings = NO
[src/content/docs/reference/Deprecated/affected-graph.mdoc]
Nx.Headings = NO
[src/content/docs/reference/Deprecated/print-affected.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/react/next/Guides/next-config-setup.mdoc]
Nx.Headings = NO
# Disable heading check for release notes (timestamps as headings)
[src/content/docs/reference/Nx Cloud/release-notes.mdoc]
Nx.Headings = NO
# Disable heading check for nx-cloud-cli (CLI flags as headings)
[src/content/docs/reference/nx-cloud-cli.mdoc]
Nx.Headings = NO
# Disable heading check for nx-console-settings (config option headings)
[src/content/docs/reference/nx-console-settings.mdoc]
Nx.Headings = NO
# Disable heading check for pages with camelCase API property headings
[src/content/docs/reference/nx-json.mdoc]
Nx.Headings = NO
[src/content/docs/reference/project-configuration.mdoc]
Nx.Headings = NO
[src/content/docs/reference/Deprecated/legacy-cache.mdoc]
Nx.Headings = NO
[src/content/docs/extending-nx/local-executors.mdoc]
Nx.Headings = NO
[src/content/docs/guides/Nx Release/programmatic-api.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/node/Guides/wait-for-tasks.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/test-tools/vitest/Guides/testing-without-building-dependencies.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/angular/Guides/nx-and-angular.mdoc]
Nx.Headings = NO
# Disable heading check for merge-atomized-outputs (warning message as heading)
[src/content/docs/technologies/test-tools/playwright/Guides/merge-atomized-outputs.mdoc]
Nx.Headings = NO
# Disable heading check for plugin introduction pages (@nx/ package name headings)
[src/content/docs/technologies/build-tools/docker/introduction.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/build-tools/rspack/introduction.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/build-tools/webpack/introduction.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/dotnet/introduction.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/eslint/introduction.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/java/gradle/introduction.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/java/maven/introduction.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/react/expo/introduction.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/react/react-native/introduction.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/test-tools/cypress/introduction.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/test-tools/detox/introduction.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/test-tools/playwright/introduction.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/test-tools/storybook/introduction.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/vue/nuxt/introduction.mdoc]
Nx.Headings = NO
# Disable heading check for remaining pages with structural false positives
# (code identifiers, slashes, quotes, parenthetical words in headings)
[src/content/docs/extending-nx/create-install-package.mdoc]
Nx.Headings = NO
[src/content/docs/extending-nx/create-preset.mdoc]
Nx.Headings = NO
[src/content/docs/getting-started/editor-setup.mdoc]
Nx.Headings = NO
[src/content/docs/guides/Adopting Nx/from-turborepo.mdoc]
Nx.Headings = NO
[src/content/docs/guides/Tasks & Caching/reduce-repetitive-configuration.mdoc]
Nx.Headings = NO
[src/content/docs/guides/Tasks & Caching/workspace-watching.mdoc]
Nx.Headings = NO
[src/content/docs/reference/Deprecated/custom-tasks-runner.mdoc]
Nx.Headings = NO
[src/content/docs/reference/Deprecated/rescope.mdoc]
Nx.Headings = NO
[src/content/docs/reference/Nx Cloud/credits-pricing.mdoc]
Nx.Headings = NO
[src/content/docs/reference/nx-mcp.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/eslint/Guides/custom-workspace-rules.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/module-federation/Guides/nx-module-federation-plugin.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/module-federation/introduction.mdoc]
Nx.Headings = NO
[src/content/docs/technologies/react/Guides/react-router.mdoc]
Nx.Headings = NO
[src/content/docs/troubleshooting/unknown-local-cache.mdoc]
Nx.Headings = NO
@@ -0,0 +1,29 @@
extends: existence
message: "Avoid AI-sounding phrase '%s'. Rewrite to be direct."
level: error
ignorecase: true
tokens:
- "It's important to note that"
- "It's worth noting that"
- 'It should be noted that'
- 'In this section, we will explore'
- "Let's dive into"
- "Let's take a closer look at"
- "Whether you're a beginner or an experienced developer"
- "In today's fast-paced development environment"
- 'Unlock the power of'
- 'Harness the power of'
- 'Take your workspace to the next level'
- 'Streamline your workflow'
- 'This comprehensive guide will'
- 'Without further ado'
- 'In conclusion'
- 'To summarize'
- "As we've seen"
- 'Needless to say'
- 'As a matter of fact'
- 'Generally speaking'
- 'It is worth mentioning'
- 'Game-changer'
- 'Cutting-edge'
- 'Groundbreaking'
+136
View File
@@ -0,0 +1,136 @@
extends: capitalization
message: "Use sentence case for headings. '%s' should be '%s'."
level: error
scope: heading
match: $sentence
indicators:
- ':'
exceptions:
- Nx
- Nx Cloud
- Nx Console
- Nx Agents
- Nx Replay
- AI
- CI
- CD
- API
- APIs
- URL
- URLs
- CLI
- PR
- PRs
- IDE
- TypeScript
- JavaScript
- Angular
- React
- Vue
- Nuxt
- Vite
- Webpack
- Rspack
- Rollup
- ESLint
- Prettier
- GitHub
- GitHub Actions
- GitLab
- BitBucket
- BitBucket Cloud
- Azure DevOps
- Azure
- Docker
- Dockerfile
- Kubernetes
- Gradle
- Maven
- Node.js
- Deno
- Bun
- pnpm
- npm
- Yarn
- Next.js
- Remix
- Astro
- Storybook
- Jest
- Vitest
- Cypress
- Playwright
- Express
- Fastify
- Nest.js
- NestJS
- Expo
- React Native
- Module Federation
- IntelliJ
- VS Code
- VSCode
- WebStorm
- Turborepo
- Lerna
- Bazel
- JSON
- YAML
- TOML
- CSS
- HTML
- SSR
- SSG
- MFE
- DTE
- SWC
- Rsbuild
- Rolldown
# Abbreviations and acronyms
- AI
- UI
- DX
- ID
- FAQ
- SAML
- DPE
- WSL
- EJS
- AST
- TTG
- PATs
- IDEs
- MCP
- HTTP
- HTTPS
- INI
- VCS
- LTS
- DTS
- SVG
- SVGs
- SVGR
- EAS
- iOS
- AWS
- S3
- E2E
- TL;DR
- NuGet
- MongoDB
- OpenShift
- Vercel
- Netlify
# Proper nouns
- RxJS
- JetBrains
- Neovim
- PnP
- Self-Healing
- AMD64
- ARM64
# Filenames and env vars
- SELF_HEALING.md
- CLAUDE.md
- NODE_AUTH_TOKEN
- NX_REJECT_UNKNOWN_LOCAL_CACHE
@@ -0,0 +1,20 @@
extends: existence
message: "Avoid marketing language '%s'. Be specific about what the feature does instead."
level: suggestion
ignorecase: true
tokens:
- 'effortless'
- 'effortlessly'
- 'seamless'
- 'seamlessly'
- 'powerful'
- 'robust'
- 'comprehensive'
- 'leverage'
- 'utilize'
- 'facilitate'
- 'aforementioned'
- 'best-in-class'
- 'world-class'
- 'next-level'
- 'supercharge'
@@ -0,0 +1,25 @@
extends: existence
message: "Prefer active voice. '%s' could be rewritten."
level: suggestion
ignorecase: true
tokens:
- 'is cached by'
- 'is built by'
- 'is run by'
- 'is executed by'
- 'is generated by'
- 'is created by'
- 'is managed by'
- 'is handled by'
- 'is provided by'
- 'is configured by'
- 'is determined by'
- 'is computed by'
- 'is resolved by'
- 'is stored by'
- 'are cached by'
- 'are built by'
- 'are run by'
- 'are executed by'
- 'are generated by'
- 'are created by'
@@ -0,0 +1,9 @@
extends: substitution
message: "Use '%s' instead of '%s'. Product names must be capitalized."
level: error
ignorecase: false
swap:
'(?:nx cloud|NX Cloud|Nx cloud|NX cloud)': Nx Cloud
'(?:nx console|NX Console|Nx console|NX console)': Nx Console
'(?:nx agents|NX Agents|Nx agents|NX agents)': Nx Agents
'(?:nx replay|NX Replay|Nx replay|NX replay)': Nx Replay
@@ -0,0 +1,6 @@
extends: existence
message: "Don't use possessives on product names. Use 'the Nx configuration' instead of 'Nx's configuration'."
level: error
ignorecase: false
tokens:
- "Nx's"
@@ -0,0 +1,26 @@
extends: existence
message: "Don't write about the document itself. Get right to the content. Remove '%s'."
level: error
ignorecase: true
tokens:
- 'This page explains'
- 'This page describes'
- 'This page covers'
- 'This page shows'
- 'This document covers'
- 'This document explains'
- 'This document describes'
- 'In this guide'
- 'In this tutorial'
- 'In this section'
- 'This guide will'
- 'This tutorial will'
- 'This section will'
- "we'll walk through"
- 'we will walk through'
- "we'll explore"
- 'we will explore'
- "we'll cover"
- 'we will cover'
- "we'll look at"
- 'we will look at'
@@ -0,0 +1,14 @@
extends: existence
message: "Rewrite to lead with the reader's action instead of '%s'. For example, 'You can ...' or 'Run ...'."
level: warning
ignorecase: true
tokens:
- 'This allows you to'
- 'This enables you to'
- 'This lets you'
- 'This provides you with'
- 'This gives you the ability to'
- 'Nx allows you to'
- 'Nx enables you to'
- 'Nx provides the ability to'
- 'Nx provides you with'
@@ -0,0 +1,7 @@
extends: existence
message: "Use the Oxford (serial) comma before 'and' or 'or' in a list of three or more items."
level: suggestion
scope: sentence
tokens:
- '\w+,\s\w+\sand\s'
- '\w+,\s\w+\sor\s'
@@ -0,0 +1,9 @@
extends: substitution
message: "Use '%s' instead of '%s'."
level: warning
ignorecase: true
swap:
schematic: generator
schematics: generators
memoized: cached
stored results: cached
+11
View File
@@ -0,0 +1,11 @@
extends: existence
message: "Avoid '%s'. If something were truly simple, you wouldn't need to document it."
level: suggestion
ignorecase: true
tokens:
- 'easily'
- 'simply'
- 'straightforward'
- 'obviously'
- 'of course'
- 'trivial'
+137 -4
View File
@@ -22,6 +22,48 @@ This documentation site leverages Astro's static site generation capabilities wi
- Dynamic API documentation generation from Nx packages and CLI commands
- Community plugin registry
## Information Architecture Principles
When creating or reorganizing documentation, follow these 5 principles to determine where content belongs.
### 1. Progressive Disclosure (The "Journey" Rule)
- **Concept:** Don't overwhelm the user. Reveal complexity only as they advance in their journey.
- **The Test:** _Is this for the First 30 Minutes (Getting Started), the First 30 Days (Features), or Forever (Reference)?_
### 2. Category Homogeneity (The "Scan" Rule)
- **Concept:** Items in a list must be of the same "type" (noun, verb, or concept) to reduce cognitive load.
- **The Test:** _Does this list mix Concepts (Mental Model), Tasks (Update Nx), and Products (React)? If yes, split it._
### 3. Type-Based Navigation (The "Intent" Rule)
- **Concept:** Separate **Learning** (Narrative/Guides) from **Looking Up** (Reference/API).
- **The Test:** _Is the user here to learn a workflow (Guide) or look up a flag syntax (Reference)?_
### 4. The Pen & Paper Test (The "Theory" Rule)
- **Concept:** Distinguish Architecture from Features to keep "Core Concepts" pure.
- **The Test:** _Can I explain this using only a pen and paper?_
- **Yes:** It goes in **How Nx Works** (Architecture).
- **No (I need a terminal):** It goes in **Platform Features** (Feature).
### 5. Universal vs. Specific (The "Placement" Rule)
- **Concept:** Distinguish Platform features from Ecosystem tools to prevent "Features" from becoming a junk drawer.
- **The Test:** _Does this feature apply to EVERY user (e.g., Caching, Agents)?_
- **Yes:** **Platform Features**.
- **No (Only React users):** **Technologies**.
### Sidebar Structure
The sidebar has 4 top-level sections that follow the user journey:
1. **Getting Started** - Essential setup, tutorials, and core concepts (How Nx Works, Platform Features)
2. **Technologies** - Framework and tool-specific guides (React, Angular, Node, build tools, test tools)
3. **Knowledge Base** - Recipes, troubleshooting, and topic-specific guides
4. **Reference** - Exhaustive facts, no narrative (CLI commands, configuration, API docs)
## Project Structure
```
@@ -36,9 +78,9 @@ astro-docs/
│ │ ├── markdoc/ # Markdoc tag components
│ │ └── utils/ # Utility functions
│ ├── content/ # Documentation content
│ │ ├── banner.json # Banner collection (generated by prebuild-banner)
│ │ ├── docs/ # Main documentation files (.mdoc, .mdx)
│ │ ── approved-community-plugins.json # Powers plugin registry
│ │ └── notifications.json # Notifications banners for docs site
│ │ ── approved-community-plugins.json # Powers plugin registry
│ ├── pages/ # Dynamic pages and routes (e.g. devkit)
│ ├── plugins/ # Content loaders and plugins
│ │ ├── *.loader.ts # Dynamic content loaders (e.g. CLI commands and API docs generation)
@@ -66,13 +108,11 @@ The site uses custom content loaders to dynamically generate documentation:
### Content Types
1. **Regular Documentation** (`src/content/docs/`)
- Written in `.mdoc` (Markdoc) or `.mdx` (MDX) format
- Organized by sections: getting-started, concepts, guides, api
- File-based routing (filename = URL path)
2. **Dynamic Plugin Documentation**
- Auto-generated from Nx packages
- Includes generators, executors, and migrations
- Updated during build process
@@ -233,3 +273,96 @@ export const sidebar = [
- Navigation structure
- Section organization
- Dynamic content injection points
## Banner Configuration
The floating banner promotes events/webinars. It's fetched at **build time** from a Framer CMS page and stored as an Astro content collection.
### Setup
Set `BANNER_URL` to point to a Framer page that renders banner JSON:
```
BANNER_URL=https://your-framer-site.framer.app/api/banners/main
```
The Framer page should render JSON inside a `<pre>` tag:
```json
{
"title": "Event Title",
"description": "Event description",
"primaryCtaUrl": "https://...",
"primaryCtaText": "Learn More",
"secondaryCtaUrl": "",
"secondaryCtaText": "",
"enabled": true,
"activeUntil": "2025-12-31T00:00:00.000Z"
}
```
### Schema
| Field | Type | Required | Description |
| ------------------ | -------- | -------- | ------------------------- |
| `title` | string | Yes | Banner headline |
| `description` | string | Yes | Banner body text |
| `primaryCtaUrl` | string | Yes | Primary button URL |
| `primaryCtaText` | string | Yes | Primary button text |
| `secondaryCtaUrl` | string | No | Secondary button URL |
| `secondaryCtaText` | string | No | Secondary button text |
| `enabled` | boolean | Yes | Show/hide the banner |
| `activeUntil` | ISO 8601 | No | Auto-hide after this date |
### Behavior
- Banner is fetched during `prebuild-banner` target and saved to `src/content/banner.json` as a collection (array)
- Uses Astro content collection with `file()` loader and schema validation
- Requires rebuild/redeploy to update the banner
- Users can dismiss the banner (stored in localStorage)
- If `enabled` is `false` or `activeUntil` has passed, the banner won't show
- If `BANNER_URL` is not set, an empty collection is generated
## Versioned Docs
When a new major Nx version is released (or about to be released), create a versioned snapshot of the docs site so the previous version remains accessible at `{major}.nx.dev` (e.g. `22.nx.dev`).
### Creating a Version Snapshot
```bash
node ./scripts/create-versioned-docs.mts 22
```
This will:
1. Fetch tags from origin, find the latest stable release for that major (e.g. `22.6.4`)
2. Checkout that tag, install deps, and build the docs site
3. Create an orphan git branch `22` containing only the pre-built static site plus minimal scaffolding (root `package.json`, `nx.json`, `pnpm-lock.yaml`, `netlify.toml`, and a no-op `nx-dev` project) so Netlify's configured build command succeeds instantly
4. Return to your original branch
If no stable tags exist for that major version, it builds from the current branch.
For Nx 21+, the script builds `astro-docs` (Astro/Starlight). For legacy Nx 1820, it builds `nx-dev` (Next.js with static export) — this path will be removed once those versions are no longer maintained.
#### Flags
- `--force` — overwrite an existing local/remote `{major}` branch
- `--redirect-to-prod` — skip the build and produce a branch that 301s every path to `https://nx.dev/docs`. Used to retire an old versioned subdomain (e.g. `16.nx.dev`) without maintaining its docs
```bash
# Retire an old versioned site
node ./scripts/create-versioned-docs.mts 16 --redirect-to-prod
```
### Pushing the Branch
```bash
git push -f origin 22
```
### Deployment Setup
Versioned sites are served via Netlify branch deploys of the main `nx-dev` Netlify site, with custom domains managed in Squarespace.
- **Netlify** — each `{major}` branch is deployed as a [branch deploy](https://docs.netlify.com/site-deploys/overview/#branch-deploy-controls) of the `nx-dev` site. The branch's root `netlify.toml` overrides the UI build settings so Netlify serves the pre-built static files (no rebuild, no `@netlify/plugin-nextjs`). Add the branch to the site's branch deploy allowlist, then add `{major}.nx.dev` as a domain alias pointing at the branch deploy
- **Squarespace** — DNS for `nx.dev` is managed in Squarespace. Add a CNAME for `{major}` pointing at the Netlify branch deploy hostname
+424
View File
@@ -0,0 +1,424 @@
# Nx Documentation Style Guide
This document defines the standards for Nx documentation on nx.dev, including voice, grammar, formatting, and terminology.
For automated enforcement, see the [Vale configuration](#vale-configuration) section below.
## Information architecture
When creating or reorganizing documentation, follow these five principles to determine where content belongs.
### 1. Progressive disclosure (the "journey" rule)
Don't overwhelm the user. Reveal complexity only as they advance in their journey.
**The test:** Is this for the first 30 minutes (Getting Started), the first 30 days (Features), or forever (Reference)?
### 2. Category homogeneity (the "scan" rule)
Items in a list must be of the same "type" (noun, verb, or concept) to reduce cognitive load.
**The test:** Does this list mix concepts (mental model), tasks (update Nx), and products (React)? If yes, split it.
### 3. Type-based navigation (the "intent" rule)
Separate learning (narrative/guides) from looking up (reference/API).
**The test:** Is the user here to learn a workflow (guide) or look up a flag syntax (reference)?
### 4. The pen and paper test (the "theory" rule)
Distinguish architecture from features to keep "core concepts" pure.
**The test:** Can I explain this using only a pen and paper?
- Yes: It goes in **How Nx Works** (architecture).
- No (I need a terminal): It goes in **Platform Features** (feature).
### 5. Universal vs. specific (the "placement" rule)
Distinguish platform features from ecosystem tools to prevent "Features" from becoming a junk drawer.
**The test:** Does this feature apply to every user (e.g., caching, Nx Agents)?
- Yes: **Platform Features**.
- No (only React users): **Technologies**.
### Sidebar structure
The sidebar has four top-level sections that follow the user journey:
1. **Getting Started** - Essential setup, tutorials, and core concepts (How Nx Works, Platform Features)
2. **Technologies** - Framework and tool-specific guides (React, Angular, Node, build tools, test tools)
3. **Knowledge Base** - Recipes, troubleshooting, and topic-specific guides
4. **Reference** - Exhaustive facts, no narrative (CLI commands, configuration, API docs)
## The Nx voice
Nx documentation is **direct, practical, and confident**. We write like a knowledgeable colleague pairing with you — not like a textbook, not like a marketing page, and not like a chatbot.
The voice should be:
- **Conversational but efficient.** Use contractions. Get to the point. Don't pad sentences.
- **Second person.** Write "you" — address the reader directly.
- **Action-oriented.** Lead with what the reader can _do_, not what Nx _is_.
- **Honest about tradeoffs.** Don't oversell. If something has limitations, say so.
### Voice do's and don'ts
| Do | Don't |
| ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
| "You can speed up builds by enabling remote caching." | "Nx allows you to speed up builds." |
| "Run `nx build` to build your project." | "In order to build your project, you can run the `nx build` command." |
| "This works best with fewer than 50 projects." | "This feature can easily scale to any number of projects." |
| "Nx reads your `vite.config.ts` and infers build targets automatically." | "Nx provides a robust and comprehensive mechanism for inferring build targets." |
| "If the cache is stale, delete `.nx/cache` and retry." | "Should you encounter issues with caching, you may want to consider clearing your cache directory." |
### Anti-AI language
Documentation must not read like it was generated by an AI assistant. Even when AI tools are used in the writing process, the output must be edited to sound like a human wrote it.
**Never use these phrases:**
- "It's important to note that..."
- "It's worth noting that..." / "It should be noted that..."
- "In this section, we will explore..."
- "Let's dive into..." / "Let's take a closer look at..."
- "Whether you're a beginner or an experienced developer..."
- "In today's fast-paced development environment..."
- "Unlock the power of..." / "Harness the power of..."
- "Take your workspace to the next level"
- "Streamline your workflow" (as a generic claim without specifics)
- "This comprehensive guide will..."
- "Without further ado..."
- "In conclusion..." / "To summarize..." / "As we've seen..."
- "Game-changer" / "Cutting-edge" / "Groundbreaking"
- "Seamless" / "Seamlessly" (unless describing an actual integration)
**Avoid hedging words unless genuinely needed:**
- "Essentially" / "Basically" / "Effectively"
- "Generally speaking"
- "It is worth mentioning"
- "Arguably"
- "Needless to say"
- "As a matter of fact"
**Watch for AI-style sentence patterns:**
- Sentences that start with "This allows you to..." or "This enables you to..." — rewrite to lead with the reader's action.
- Paragraphs that start with a general claim and then restate it slightly differently. Say it once.
- Excessive use of "robust", "leverage", "utilize", "facilitate", "comprehensive", "aforementioned."
- Lists where every item starts with the same grammatical structure repeated 5+ times with slight variation. Vary your phrasing.
### Self-referential writing
Don't write about the document itself.
Do:
- "Nx uses a project graph to determine task dependencies."
Don't:
- "This page explains how Nx uses a project graph."
- "In this guide, we'll walk through..."
- "This document covers..."
Get right to the point. The reader already knows they're on a page — they want the information.
### Building trust
Don't use filler words that undermine the reader's trust.
- Don't use "easily", "simply", "just", or "straightforward" — if something were truly simple, you wouldn't need to document it. These words also make readers feel bad when they struggle.
- Don't use marketing language: "This feature will save you hours" or "Nx makes CI effortless."
- Be specific instead: "Remote caching can reduce CI times from 45 minutes to under 5 minutes for cache-hit builds."
### Customer perspective
Focus on what the reader can do, not what Nx does.
Do:
- "Use `nx affected` to run tasks only for projects impacted by your changes."
Don't:
- "Nx allows you to run affected tasks."
- "Nx provides the ability to run tasks selectively."
Words like "allow" and "enable" are signals you're writing from the product's perspective instead of the reader's.
## Language
Write in US English.
### Active voice
Use active voice in most cases.
Do: "Nx caches the build output."
Don't: "The build output is cached by Nx."
Exception: When "Nx" as the subject sounds awkward, passive voice is fine. "The output is stored in `.nx/cache`" is better than "Nx stores the output in `.nx/cache`" if Nx isn't the focus of the sentence.
### Contractions
Use contractions. They make the text feel natural.
- "You'll need to configure..." not "You will need to configure..."
- "It doesn't support..." not "It does not support..."
Don't contract for emphasis in warnings or error descriptions:
- "**Do not** delete the `nx.json` file."
- "Requests to localhost **are not** allowed."
Don't contract proper nouns: "the Vite plugin is..." not "Vite's a plugin..."
### Capitalization
Use sentence case for headings. Capitalize proper nouns only.
- `# Use remote caching to speed up CI`
- `## Configure the Vite plugin`
Feature names are lowercase unless they are a proper product name:
| Correct | Incorrect |
| -------------- | -------------- |
| remote caching | Remote Caching |
| project graph | Project Graph |
| Nx Cloud | nx cloud |
| Nx Console | nx console |
| Nx Agents | nx agents |
| Nx Replay | nx replay |
### Acronyms
Spell out acronyms on first use per page. Don't spell out widely-known ones: CI, CD, API, URL, CLI, PR, IDE.
Don't make acronyms plural with apostrophes. Use `APIs`, not `API's`.
### Numbers
Spell out zero through nine. Use numerals for 10 and above. Always use numerals with units: "5 minutes", "3 projects."
### Possessives
Don't use possessives on product names. "the Docker CLI", not "Docker's CLI." "the Nx configuration", not "Nx's configuration."
## Text
### Headings
- Don't skip heading levels (e.g., `##` to `####`).
- Don't use code in headings unless it's essential (like a CLI command).
- Don't use bold text in headings.
- Keep headings short and scannable. Lead with keywords.
### Line length
- Wrap lines at approximately 100 characters for readability in diffs.
- Start each new sentence on a new line.
- Exception: Don't break links across lines.
### Punctuation
- Use serial (Oxford) commas: "React, Angular, and Vue."
- Use one space between sentences.
- Don't use semicolons. Use two sentences instead.
- Don't use em dashes or en dashes. Use commas or separate sentences.
### Placeholder text
Use `<` and `>` for values the reader must replace:
```shell
nx run <project-name>:build
```
If the placeholder is inline, wrap it in a single backtick: `<your-project>`.
### Bold
Use bold for:
- UI elements: "Select **Add Connection**."
- Navigation paths: "Go to **Settings** > **Workspace**."
Don't use bold for emphasis or keywords. If you need emphasis, rewrite the sentence to be clearer.
### Inline code
Use inline code (single backticks) for:
- Commands and CLI arguments: `nx build`, `--parallel`
- File names and paths: `nx.json`, `.nx/cache`
- Configuration keys: `targetDefaults`, `namedInputs`
- Short outputs and values: `true`, `false`, `success`
### Code blocks
Use triple backticks with a language identifier:
````markdown
```json
{
"targetDefaults": {
"build": {
"cache": true
}
}
}
```
````
- Always specify a syntax language. Use `plaintext` if nothing else fits.
- Add a blank line before and after code blocks.
- For long config files, show only the relevant section and use comments to indicate omitted parts:
```json
{
// ... other config
"targetDefaults": {
"build": {
"cache": true
}
}
}
```
## Links
Links help readers find related information, but too many links make text hard to read.
### General rules
- Don't duplicate links. If you link to a page once, don't link to it again on the same page.
- Don't use links in headings.
- Avoid more than 15 links to other pages on any single page.
- Avoid multiple links in a single paragraph when possible.
### Link text
Use descriptive text, not "here" or "this page."
Do:
- "For more information, see [remote caching](/features/cache)."
- "To configure task pipelines, see [task pipeline configuration](/concepts/task-pipeline-configuration)."
Don't:
- "For more information, see [this page](/features/cache)."
- "Click [here](/features/cache) to learn more."
- "For more information, see the [Remote Caching](/features/cache) documentation."
Standard patterns:
- `For more information, see [link text](url).`
- `To <do this thing>, see [link text](url).`
### External links
Minimize external links. They break over time and are hard to maintain. When you must link externally, prefer official documentation (e.g., Vite docs, Webpack docs) over blog posts or third-party guides.
## Lists
- Use ordered lists for sequences of steps.
- Use unordered lists when order doesn't matter.
- Use dashes (`-`) for unordered lists.
- Start ordered list items with `1.` (Markdown auto-increments).
- Make list items parallel in structure.
- Add a colon after the introductory phrase.
- Don't use list items to complete an introductory sentence.
Do:
```markdown
You can clear the cache in the following ways:
- Delete the `.nx/cache` directory manually.
- Run `nx reset` to clear all cached results.
```
Don't:
```markdown
You can clear the cache by:
- Deleting the `.nx/cache` directory manually.
- Running `nx reset`.
```
## Tables
Use tables for structured data that benefits from a matrix layout. For simple lists of items with descriptions, use a regular list instead.
- Don't leave cells empty. Use "N/A" or "None."
- Use sentence case for headers.
- Keep the header and delimiter rows the same length.
## Nx-specific terminology
Use these terms consistently. When writing about Nx concepts, use the exact term from this list.
| Term | Usage notes |
| -------------- | ------------------------------------------------------------------------------------------ |
| workspace | The root directory managed by Nx. Not "repo" or "monorepo" when referring to Nx's context. |
| project | An app or library within the workspace. |
| target | A task that can be run for a project (e.g., `build`, `test`, `lint`). |
| executor | The implementation behind a target. Not "builder." |
| generator | Code scaffolding tool. Not "schematic." |
| plugin | An Nx plugin that provides executors, generators, or graph inference. |
| task | A specific invocation of a target for a project (e.g., `myapp:build`). |
| project graph | The dependency graph between projects. |
| affected | Projects impacted by a code change. |
| cache / cached | Not "memoized" or "stored results." |
| remote caching | Sharing cached results across machines. Specific product: "Nx Replay." |
| Nx Cloud | The hosted CI/CD product. Always capitalized. |
| Nx Console | The IDE extension. Always capitalized. |
| Nx Agents | Distributed task execution product. Always capitalized. |
| Nx Replay | Remote caching product. Always capitalized. |
| `nx.json` | Always in code style. |
| `project.json` | Always in code style. |
## Vale configuration
[Vale](https://vale.sh) enforces many of the rules in this style guide automatically.
Configuration lives in `astro-docs/`:
- `.vale.ini` — Main config. Scopes rules to `src/content/docs/**/*.{mdoc,mdx,md}`.
- `.vale/styles/Nx/` — Custom rules for Nx documentation.
### Running Vale
```shell
# Via Nx target (recommended)
nx vale astro-docs
# Directly (from astro-docs/ directory)
vale src/content/docs/
```
### Installing Vale
Vale is managed via [mise](https://mise.jdx.dev/). Run `mise install` from the repo root to install it.
You can also install directly via `brew install vale` (macOS) or `apt-get install vale` (Linux).
### Rule tiers
| Tier | Severity | Rules |
| -------------- | ------------ | ------------------------------------------------------------------------------------------- |
| 1 - Mechanical | `error` | Banned phrases, product capitalization |
| 2 - Structural | `warning` | Heading case, terminology, product possessives, self-referential writing, sentence patterns |
| 3 - Voice | `suggestion` | Trust-undermining words, marketing language, passive voice, serial commas |
### Adding new rules
Create a new `.yml` file in `.vale/styles/Nx/`.
Vale supports several [extension points](https://vale.sh/docs/styles): `existence`, `substitution`, `occurrence`, `repetition`, `consistency`, `conditional`, `capitalization`, and `metric`.
Set `level` to match the tier: `error` for mechanical rules, `warning` for structural, `suggestion` for voice/judgment.
+23 -29
View File
@@ -5,15 +5,19 @@ import netlify from '@astrojs/netlify';
import react from '@astrojs/react';
import markdoc from '@astrojs/markdoc';
import tailwindcss from '@tailwindcss/vite';
import sitemap from '@astrojs/sitemap';
import { sidebar } from './sidebar.mts';
import rehypeTableOptionLinks from './src/plugins/utils/rehype-table-option-links.ts';
import { resolveNxDevUrl } from './src/utils/resolve-nx-dev-url.ts';
// Always resolve NX_DEV_URL so downstream consumers (Footer, Header) pick it up.
// For deploy previews this overrides any site-level env var to point to the matching preview.
process.env.NX_DEV_URL = resolveNxDevUrl();
const BASE = '/docs';
// This is exposed as window.__CONFIG
const PUBLIC_CONFIG = {
cookiebotDisabled: process.env.COOKIEBOT_DISABLED === 'true',
cookiebotId: process.env.COOKIEBOT_ID ?? null,
gaMeasurementId: 'UA-88380372-10',
gtmMeasurementId: 'GTM-KW8423B6',
isProd: process.env.NODE_ENV === 'production',
};
@@ -22,7 +26,7 @@ const PUBLIC_CONFIG = {
export default defineConfig({
base: BASE,
vite: { plugins: [tailwindcss()] },
// Allow this to be configured per environment
// Allow this to be configured per environment for robots.txt detection
// Note: this happens during build time so we don't use `import.meta.env`
site: process.env.NX_DEV_URL ?? 'https://nx.dev',
image: {
@@ -33,6 +37,9 @@ export default defineConfig({
},
},
},
markdown: {
rehypePlugins: [rehypeTableOptionLinks],
},
trailingSlash: 'never',
// This adapter doesn't support local previews, so only load it on Netlify.
adapter: process.env['NETLIFY'] ? netlify() : undefined,
@@ -51,27 +58,12 @@ export default defineConfig({
replacesTitle: true,
},
disable404Route: true,
lastUpdated: true,
head: [
{
tag: 'script',
content: `window.__CONFIG = ${JSON.stringify(PUBLIC_CONFIG)};`,
},
...(process.env.COOKIEBOT_ID &&
process.env.COOKIEBOT_DISABLED !== 'true'
? [
{
/** @type {"script"} */
tag: 'script',
attrs: {
id: 'Cookiebot',
src: 'https://consent.cookiebot.com/uc.js',
'data-cbid': process.env.COOKIEBOT_ID,
'data-blockingmode': 'auto',
type: 'text/javascript',
},
},
]
: []),
{
tag: 'script',
attrs: {
@@ -82,20 +74,19 @@ export default defineConfig({
],
plugins: [],
routeMiddleware: [
'./src/plugins/banner.middleware.ts',
// NOTE: this is responsibile for populating the Reference section
// with generated routes from the nx-reference-packages content collection
// since the sidebar doesn't auto generate w/ dynamic routes from src/pages/reference
// only the src/content/docs/reference files
'./src/plugins/sidebar-reference-updater.middleware.ts',
'./src/plugins/sidebar-icons.middleware.ts',
'./src/plugins/og.middleware.ts',
'./src/plugins/github-stars.middleware.ts',
'./src/plugins/raw-content.middleware.ts',
'./src/plugins/canonical.middleware.ts',
'./src/plugins/schema.middleware.ts',
],
markdown: {
// this breaks the renderMarkdown function in the plugin loader due to starlight path normalization
// as to _why_ it has to normalize a path?
// idk just working around the issue for now but we'll want to have linked headers so will need to fix
headingLinks: false,
headingLinks: true,
},
social: [
{ icon: 'github', label: 'GitHub', href: 'https://github.com/nrwl/nx' },
@@ -134,15 +125,15 @@ export default defineConfig({
// frequency of the term relative to document length
// versus weighted term count.
// default is 1.0
termFrequency: 0.75,
termFrequency: 0.65,
// pageLength changes the way ranking compares page lengths with the average page lengths on your site.
// default 0.75
pageLength: 0.5,
pageLength: 0.3,
// termSaturation controls how quickly a term “saturates” on a page.
// Once a term has appeared on a page many times,
// further appearances have a reduced impact on the page rank.
// default: 1.4
// termSaturation: 1.4,
termSaturation: 1.2,
// termSimilarity changes the ranking based on
// similarity of terms to the search query.
// Currently this only takes the length of the term into account.
@@ -152,5 +143,8 @@ export default defineConfig({
},
}),
react(),
sitemap({
lastmod: new Date(),
}),
],
});
@@ -0,0 +1,129 @@
import { test, expect } from '@playwright/test';
test.describe('CLI sub-command formatting', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/docs/reference/nx-commands');
await expect(
page.getByRole('heading', { name: 'Nx Commands' })
).toBeVisible();
});
test('parent commands render as h2 and sub-commands as h3', async ({
page,
}) => {
const mainContent = page.getByTestId('main-pane');
// "nx show" should be an h2 (top-level parent command)
const showHeading = mainContent.getByRole('heading', {
name: 'nx show',
level: 2,
exact: true,
});
await expect(showHeading).toBeVisible();
// "nx show projects" should be an h3 (sub-command nested under parent)
const showProjectsHeading = mainContent.getByRole('heading', {
name: 'nx show projects',
level: 3,
exact: true,
});
await expect(showProjectsHeading).toBeVisible();
// "nx show project" should also be an h3
const showProjectHeading = mainContent.getByRole('heading', {
name: 'nx show project',
level: 3,
exact: true,
});
await expect(showProjectHeading).toBeVisible();
});
test('sub-command usage blocks show the full command name', async ({
page,
}) => {
const mainContent = page.getByTestId('main-pane');
// Find the "nx show projects" section and verify its usage block
// The usage code block should contain "nx show projects", not "nx projects"
const showProjectsHeading = mainContent.getByRole('heading', {
name: 'nx show projects',
level: 3,
exact: true,
});
await expect(showProjectsHeading).toBeVisible();
// Get the section between "nx show projects" heading and the next heading.
// We look for a code block containing the correct usage pattern.
const codeBlocks = mainContent.locator('pre code');
const allCodeTexts = await codeBlocks.allTextContents();
// There should be a usage block with "nx show projects" (full sub-command name)
expect(allCodeTexts.some((text) => text.includes('nx show projects'))).toBe(
true
);
// There should NOT be a usage block with just "nx projects" (missing parent)
expect(
allCodeTexts.some(
(text) => text.match(/^nx projects/) || text.match(/\nnx projects/)
)
).toBe(false);
});
test('release sub-commands use correct heading and usage format', async ({
page,
}) => {
const mainContent = page.getByTestId('main-pane');
// "nx release" should be h2
const releaseHeading = mainContent.getByRole('heading', {
name: 'nx release',
level: 2,
exact: true,
});
await expect(releaseHeading).toBeVisible();
// "nx release version" should be h3
const releaseVersionHeading = mainContent.getByRole('heading', {
name: 'nx release version',
level: 3,
exact: true,
});
await expect(releaseVersionHeading).toBeVisible();
// Verify usage block includes the full command
const codeBlocks = mainContent.locator('pre code');
const allCodeTexts = await codeBlocks.allTextContents();
expect(
allCodeTexts.some((text) => text.includes('nx release version'))
).toBe(true);
});
test('options and examples are h4 headings excluded from the TOC', async ({
page,
}) => {
const mainContent = page.getByTestId('main-pane');
// Options/Examples should be h4 headings — linkable but below the TOC threshold (h2-h3)
const sharedOptionsHeading = mainContent.getByRole('heading', {
name: 'Shared Options',
level: 4,
});
await expect(sharedOptionsHeading.first()).toBeVisible();
const optionsHeading = mainContent.getByRole('heading', {
name: 'Options',
level: 4,
});
await expect(optionsHeading.first()).toBeVisible();
// They should NOT appear as h2 or h3 (which would put them in the TOC)
await expect(
mainContent.getByRole('heading', { name: 'Options', level: 2 })
).toHaveCount(0);
await expect(
mainContent.getByRole('heading', { name: 'Options', level: 3 })
).toHaveCount(0);
});
});
+1 -1
View File
@@ -11,7 +11,7 @@ test('links in descriptions of properties should correctly link to the same page
await page
.getByTestId('main-pane')
.getByRole('link', { name: 'nxCloudAccessToken' })
.getByRole('link', { name: 'nxCloudAccessToken', exact: true })
.click();
await expect(
+49
View File
@@ -4,9 +4,15 @@ import {
Markdoc,
} from '@astrojs/markdoc/config';
import starlightMarkdoc from '@astrojs/starlight-markdoc';
import { transformOptionsTable } from './src/utils/markdoc-table-option-links';
export default defineMarkdocConfig({
extends: [starlightMarkdoc()],
nodes: {
table: {
transform: transformOptionsTable,
},
},
tags: {
call_to_action: {
render: component('./src/components/markdoc/CallToAction.astro'),
@@ -238,6 +244,15 @@ export default defineMarkdocConfig({
},
},
},
sidebar_group_cards: {
render: component('./src/components/markdoc/SidebarGroupCards.astro'),
attributes: {
group: {
type: 'String',
required: true,
},
},
},
metrics: {
render: component('./src/components/markdoc/Metrics.astro'),
attributes: {
@@ -402,6 +417,40 @@ export default defineMarkdocConfig({
},
},
},
llm_copy_prompt: {
render: component('./src/components/markdoc/LlmCopyPrompt.astro'),
attributes: {
title: { type: 'String', required: true },
},
children: ['paragraph', 'tag', 'list'],
transform(node, config) {
const attributes = node.transformAttributes(config);
function extractText(n) {
if (typeof n === 'string') return n;
if (n.type === 'text' || n.type === 'softbreak')
return n.attributes?.content ?? '\n';
if (n.type === 'inline')
return (n.children || []).map(extractText).join('');
if (n.type === 'paragraph')
return (n.children || []).map(extractText).join('') + '\n';
if (n.type === 'item')
return '- ' + (n.children || []).map(extractText).join('');
if (n.type === 'list')
return (n.children || []).map(extractText).join('\n') + '\n';
if (n.children) return n.children.map(extractText).join('');
return '';
}
const promptText = node.children.map(extractText).join('\n').trim();
return new Markdoc.Tag(this.render, { ...attributes, promptText }, []);
},
},
llm_only: {
attributes: {},
children: ['paragraph', 'tag', 'list'],
transform() {
return null;
},
},
youtube: {
render: component('./src/components/markdoc/Youtube.astro'),
attributes: {
+63
View File
@@ -1,4 +1,27 @@
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
Content-Security-Policy = "frame-ancestors 'none'"
Referrer-Policy = "strict-origin-when-cross-origin"
Permissions-Policy = "camera=(), microphone=(), geolocation=()"
# Disable gradle and maven plugins on Netlify
# (Netlify only supports Java 8 but these plugins require Java 17)
[build.environment]
NX_GRADLE_DISABLE = "true"
NX_MAVEN_DISABLE = "true"
# Edge functions are auto-discovered from netlify/edge-functions/
# Path configuration is in each function's inline `config` export
# Permanent redirects (301 by default)
# Storybook docs consolidation
[[redirects]]
from = "/docs/technologies/test-tools/storybook/guides/storybook-9-setup"
to = "/docs/technologies/test-tools/storybook/guides/upgrading-storybook"
[[redirects]]
from = "/"
to = "/docs/getting-started/intro"
@@ -15,6 +38,46 @@ to = "/docs/quickstart"
from = "/showcase/benchmarks/*"
to = "/docs/reference/benchmarks/:splat"
# DOC-452: Old framework tutorials redirect to new topic-based tutorials
[[redirects]]
from = "/docs/getting-started/tutorials/react-monorepo-tutorial"
to = "/docs/getting-started/tutorials/crafting-your-workspace"
[[redirects]]
from = "/docs/getting-started/tutorials/angular-monorepo-tutorial"
to = "/docs/getting-started/tutorials/crafting-your-workspace"
[[redirects]]
from = "/docs/getting-started/tutorials/typescript-packages-tutorial"
to = "/docs/getting-started/tutorials/crafting-your-workspace"
# DOC-452: Learn Nx URLs redirect to Tutorials (in case any were indexed)
[[redirects]]
from = "/docs/getting-started/learn-nx/*"
to = "/docs/getting-started/tutorials/:splat"
# Fix broken /docs/ paths still linked from CLI/Cloud source code (DOC-428)
[[redirects]]
from = "/docs/features/ci-features/self-healing"
to = "/docs/features/ci-features/self-healing-ci"
[[redirects]]
from = "/docs/extending-nx/recipes/create-preset"
to = "/docs/extending-nx/create-preset"
[[redirects]]
from = "/docs/guides/adopting-nx/adding-to-monorepos"
to = "/docs/guides/adopting-nx/adding-to-monorepo"
# Angular multiple workspace migration page removed (DOC-419)
[[redirects]]
from = "/docs/technologies/angular/migration/angular-multiple"
to = "/docs/technologies/angular/migration/angular"
[[redirects]]
from = "/docs/getting-started/nx-cloud"
to = "/docs/features/ci-features"
# Rewrite for base path handling (keeps URL the same)
[[redirects]]
from = "/docs/*"
@@ -0,0 +1,59 @@
import type { Context } from 'https://edge.netlify.com';
/**
* Content negotiation for LLM-friendly docs access.
* See: https://llmstxt.org/
*/
export default async function handler(
request: Request,
context: Context
): Promise<Response | URL> {
const url = new URL(request.url);
const pathname = url.pathname;
const acceptHeader = request.headers.get('accept') || '';
// Serve markdown for LLM tools that explicitly request it
// Or if there are no accept headers passed (e.g. Cursor)
if (!acceptHeader || acceptHeader.includes('text/markdown')) {
const mdPath = pathname.replace(/\/?$/, '.md');
return new URL(mdPath, request.url);
}
const response = await context.next();
const contentType = response.headers.get('content-type') || '';
if (!contentType.includes('text/html')) {
return response;
}
const mdPath = pathname.replace(/\/?$/, '.md');
const linkHeader = [
`<${mdPath}>; rel="alternate"; type="text/markdown"`,
`</docs/llms.txt>; rel="alternate"; type="text/markdown"; title="LLM Index"`,
`</docs/llms-full.txt>; rel="alternate"; type="text/markdown"; title="Full Documentation"`,
].join(', ');
// Netlify responses are immutable
const newHeaders = new Headers(response.headers);
newHeaders.set('Link', linkHeader);
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: newHeaders,
});
}
export const config = {
path: ['/docs/*'],
excludedPath: [
'/docs/*.md',
'/docs/*.js',
'/docs/*.txt',
'/docs/images/*',
// _astro and other asset paths
'/docs/_*',
],
};
+3
View File
@@ -7,6 +7,7 @@
"@astrojs/markdoc": "^0.15.0",
"@astrojs/netlify": "^6.4.0",
"@astrojs/react": "^4.3.0",
"@astrojs/sitemap": "^3.3.0",
"@astrojs/starlight": "0.34.6",
"@astrojs/starlight-markdoc": "^0.4.0",
"@astrojs/starlight-tailwind": "^4.0.1",
@@ -16,9 +17,11 @@
"@nx/nx-dev-ui-icons": "workspace:*",
"@nx/nx-dev-ui-markdoc": "workspace:*",
"@tailwindcss/vite": "^4.1.11",
"@types/hast": "^3.0.4",
"astro": "^5.10.1",
"astro-og-canvas": "^0.7.0",
"canvaskit-wasm": "^0.40.0",
"octokit": "^2.0.14",
"tailwindcss": "4.1.11"
}
}
+72 -4
View File
@@ -3,11 +3,30 @@
"$schema": "../node_modules/nx/schemas/project-schema.json",
"comment": "package.json#scripts runs in the project root directory with astro assumes is where the node_modules is. which fails. so run the scripts in project.json#targets with --root command instead",
"targets": {
"prebuild-banner": {
"cache": false,
"outputs": ["{projectRoot}/src/content/banner.json"],
"command": "node ../scripts/documentation/prebuild-banner.mjs",
"options": {
"cwd": "astro-docs",
"env": {
"BANNER_OUTPUT_PATH": "src/content/banner.json",
"BANNER_ENV_VAR": "BANNER_URL"
}
}
},
"serve": {
"continuous": true,
"dependsOn": [
"prebuild-banner",
{
"projects": ["devkit", "create-nx-workspace", "dotnet", "maven"],
"projects": [
"nx",
"devkit",
"create-nx-workspace",
"dotnet",
"maven"
],
"target": "build"
}
],
@@ -18,11 +37,24 @@
},
"build": {
"dependsOn": [
"prebuild-banner",
{
"projects": ["devkit", "create-nx-workspace", "dotnet", "maven"],
"projects": [
"nx",
"devkit",
"create-nx-workspace",
"dotnet",
"maven"
],
"target": "build"
}
],
"inputs": [
"production",
"^production",
"{projectRoot}/src/content/banner.json",
{ "env": "NX_DEV_URL" }
],
"outputs": [
"{projectRoot}/dist",
"{projectRoot}/.astro",
@@ -49,7 +81,7 @@
},
"test": {
"executor": "nx:noop",
"dependsOn": ["vite:test", "validate-links", "format"]
"dependsOn": ["validate-links", "format"]
},
"pw-e2e": {
"dependsOn": ["serve"],
@@ -69,6 +101,8 @@
"dependsOn": ["build"],
"cache": true,
"inputs": [
"{projectRoot}/validate-links.ts",
{ "dependentTasksOutputFiles": "**/sitemap*.xml" },
"{projectRoot}/src/**/*",
"{projectRoot}/astro.config.mjs",
"{projectRoot}/sidebar.mts",
@@ -81,10 +115,44 @@
"cwd": "astro-docs"
}
},
"vale": {
"command": "node scripts/vale-changed.mjs",
"options": {
"cwd": "{projectRoot}"
},
"cache": true,
"inputs": [
"{projectRoot}/src/content/docs/**/*.mdoc",
"{projectRoot}/src/content/docs/**/*.mdx",
"{projectRoot}/src/content/docs/**/*.md",
"{projectRoot}/.vale.ini",
"{projectRoot}/.vale/styles/**/*",
"{projectRoot}/scripts/vale-changed.mjs"
]
},
"vale:all": {
"command": "node scripts/vale-changed.mjs --all",
"options": {
"cwd": "{projectRoot}"
},
"inputs": [
"{projectRoot}/src/content/docs/**/*.mdoc",
"{projectRoot}/src/content/docs/**/*.mdx",
"{projectRoot}/src/content/docs/**/*.md",
"{projectRoot}/.vale.ini",
"{projectRoot}/.vale/styles/**/*",
"{projectRoot}/scripts/vale-changed.mjs"
]
},
"format": {
"cache": true,
"//": "nx format doesn't respect overrides, so we manually run prettier for mdoc files",
"command": "prettier **/*.mdoc --check"
"command": "prettier **/*.mdoc --check",
"inputs": [
"{projectRoot}/**/*.mdoc",
"{workspaceRoot}/.prettierrc",
"{workspaceRoot}/.prettierignore"
]
},
"format:write": {
"command": "prettier **/*.mdoc --write"
+134 -113
View File
@@ -1,32 +1,46 @@
(function () {
// Open search modal if signaled via sessionStorage (e.g., from Cmd+K on non-docs pages)
var SEARCH_STORAGE_KEY = 'nx-open-search';
var SEARCH_EXPIRY_MS = 30000; // 30 seconds
function openSearchFromStorage() {
var timestamp = sessionStorage.getItem(SEARCH_STORAGE_KEY);
if (!timestamp) return;
// Clear immediately to prevent re-triggering
sessionStorage.removeItem(SEARCH_STORAGE_KEY);
// Check if expired (older than 30 seconds)
var age = Date.now() - parseInt(timestamp, 10);
if (age > SEARCH_EXPIRY_MS) return;
var openSearchBtn = document.querySelector('button[data-open-modal]');
if (openSearchBtn) {
openSearchBtn.click();
// Focus the search input after modal opens
setTimeout(function () {
var searchInput = document.querySelector('dialog[open] input');
if (searchInput) {
searchInput.focus();
}
}, 100);
}
}
// Check on load
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', openSearchFromStorage);
} else {
// Small delay to ensure search component is initialized
setTimeout(openSearchFromStorage, 100);
}
const config = window.__CONFIG || {};
if (!config.isProd) return;
const isCookiebotDisabled = config.cookiebotDisabled ?? false;
const gaMeasurementId = config.gaMeasurementId ?? 'UA-88380372-10';
const gtmMeasurementId = config.gtmMeasurementId ?? 'GTM-KW8423B6';
// Initialize global objects
window.Cookiebot = window.Cookiebot || {};
window.dataLayer = window.dataLayer || [];
window.gtag =
window.gtag ||
function () {
window.dataLayer.push(arguments);
};
const loadGoogleAnalytics = () => {
const script = document.createElement('script');
script.src = `https://www.googletagmanager.com/gtag/js?id=${gaMeasurementId}`;
script.async = true;
document.head.appendChild(script);
// Initialize gtag
window.gtag('js', new Date());
window.gtag('config', gaMeasurementId, {
page_path: window.location.pathname,
});
};
const loadGTM = () => {
if (!gtmMeasurementId) return;
@@ -43,80 +57,92 @@
})(window, document, 'script', 'dataLayer', gtmMeasurementId);
};
const loadHubSpot = () => {
const hsScript = document.createElement('script');
hsScript.src = 'https://js.hs-scripts.com/2757427.js';
hsScript.async = true;
hsScript.defer = true;
document.head.appendChild(hsScript);
// Load HubSpot Forms
const hsFormsScript = document.createElement('script');
hsFormsScript.src = '//js.hsforms.net/forms/v2.js';
hsFormsScript.async = true;
hsFormsScript.defer = true;
document.head.appendChild(hsFormsScript);
// GA4 events are dispatched via GTM dataLayer.
const pushGtmEvent = (eventName, payload) => {
window.dataLayer.push({ event: eventName, ...payload });
};
const loadApollo = () => {
const n = Math.random().toString(36).substring(7);
const script = document.createElement('script');
script.src = `https://assets.apollo.io/micro/website-tracker/tracker.iife.js?nocache=${n}`;
script.async = true;
script.defer = true;
script.onload = function () {
if (window.trackingFunctions?.onLoad) {
window.trackingFunctions.onLoad({
appId: '65e1db2f1976f30300fd8b26',
// Scroll depth tracking
const SCROLL_THRESHOLDS = [10, 25, 50, 75, 90];
let firedThresholds = new Set();
let scrollTrackingEnabled = false;
let scrollRafId = null;
function getScrollPercentage() {
const scrollTop = window.scrollY || document.documentElement.scrollTop;
const scrollHeight = document.documentElement.scrollHeight;
const clientHeight = window.innerHeight;
return (scrollTop + clientHeight) / scrollHeight;
}
function handleScrollTracking() {
if (!scrollTrackingEnabled) return;
const scrollPercentage = getScrollPercentage() * 100;
// Fire events for all thresholds we've passed but haven't fired yet
for (const threshold of SCROLL_THRESHOLDS) {
if (scrollPercentage >= threshold && !firedThresholds.has(threshold)) {
firedThresholds.add(threshold);
sendSearchEvent(`scroll_${threshold}`, {
event_category: 'scroll',
event_label: window.location.pathname,
});
}
};
document.head.appendChild(script);
};
}
}
const loadHotjar = () => {
(function (h, o, t, j, a, r) {
h.hj =
h.hj ||
function () {
(h.hj.q = h.hj.q || []).push(arguments);
};
h._hjSettings = { hjid: 2774127, hjsv: 6 };
a = o.getElementsByTagName('head')[0];
r = o.createElement('script');
r.async = 1;
r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv;
a.appendChild(r);
})(window, document, 'https://static.hotjar.com/c/hotjar-', '.js?sv=');
};
function throttledScrollHandler() {
if (scrollRafId !== null) return;
const loadTwitterPixel = () => {
!(function (e, t, n, s, u, a) {
e.twq ||
((s = e.twq =
function () {
s.exe ? s.exe.apply(s, arguments) : s.queue.push(arguments);
}),
(s.version = '1.1'),
(s.queue = []),
(u = t.createElement(n)),
(u.async = !0),
(u.src = 'https://static.ads-twitter.com/uwt.js'),
(a = t.getElementsByTagName(n)[0]),
a.parentNode.insertBefore(u, a));
})(window, document, 'script');
window.twq('config', 'obtp4');
};
scrollRafId = requestAnimationFrame(() => {
handleScrollTracking();
scrollRafId = null;
});
}
function attachScrollListener() {
window.addEventListener('scroll', throttledScrollHandler, {
passive: true,
});
}
function setupScrollTracking() {
// Reset scroll depth on navigation (for SPA-like behavior via View Transitions)
firedThresholds = new Set();
scrollTrackingEnabled = false;
// Delay tracking start to avoid false triggers during navigation
setTimeout(() => {
scrollTrackingEnabled = true;
// Immediately check current scroll position to capture thresholds
// that may have been passed during the delay
handleScrollTracking();
}, 500);
attachScrollListener();
// Handle Astro View Transitions - reset on navigation
document.addEventListener('astro:after-swap', () => {
firedThresholds = new Set();
scrollTrackingEnabled = false;
setTimeout(() => {
scrollTrackingEnabled = true;
// Immediately check current scroll position after navigation
handleScrollTracking();
}, 500);
});
}
const SEARCH_DEBOUNCE_MS = 1000;
let searchDebounceTimer;
let lastSearchQuery = '';
let currentSearchInput = null;
let inputHandler = null;
let resultClickHandler = null;
function sendSearchEvent(eventType, data) {
if (typeof window.gtag !== 'undefined')
window.gtag('event', eventType, data);
pushGtmEvent(eventType, data);
}
function trackSearchQuery(query) {
@@ -125,8 +151,8 @@
clearTimeout(searchDebounceTimer);
searchDebounceTimer = setTimeout(() => {
lastSearchQuery = query;
sendSearchEvent('search_query', {
query: query,
sendSearchEvent('search', {
search_term: query,
});
}, SEARCH_DEBOUNCE_MS);
}
@@ -150,12 +176,30 @@
searchInput.addEventListener('input', inputHandler);
currentSearchInput = searchInput;
}
// Track search result clicks via event delegation
if (!resultClickHandler) {
resultClickHandler = (e) => {
const link = e.target.closest('a[href]');
if (!link) return;
const query = currentSearchInput
? currentSearchInput.value.trim()
: '';
pushGtmEvent('select_content', {
content_type: 'search_result',
item_id: link.getAttribute('href'),
search_term: query,
});
};
searchDialog.addEventListener('click', resultClickHandler);
}
}
// If dialog is not found but we have handler, etc. then it must be closed and we should clean up
else if (currentSearchInput && inputHandler) {
currentSearchInput.removeEventListener('input', inputHandler);
currentSearchInput = null;
inputHandler = null;
resultClickHandler = null;
}
});
@@ -167,31 +211,11 @@
});
}
const checkAndLoadScripts = () => {
if (isCookiebotDisabled) {
loadGoogleAnalytics();
loadGTM();
loadHubSpot();
setupSearchTracking();
} else if (window.Cookiebot && window.Cookiebot.consent) {
// Statistics cookies (Google Analytics, GTM, Search Tracking)
if (window.Cookiebot.consent.statistics) {
loadGoogleAnalytics();
loadGTM();
setupSearchTracking();
}
// Marketing cookies (HubSpot, Apollo, Hotjar, Twitter)
if (window.Cookiebot.consent.marketing) {
loadHubSpot();
loadApollo();
loadHotjar();
loadTwitterPixel();
}
} else {
// Wait for Cookiebot to load
setTimeout(checkAndLoadScripts, 100);
}
const initializeAnalytics = () => {
if (!gtmMeasurementId) return;
loadGTM();
setupSearchTracking();
setupScrollTracking();
};
// Add GTM noscript iframe to body
@@ -208,11 +232,8 @@
document.body.insertBefore(noscript, document.body.firstChild);
};
// Listen for user consent to cookies
window.addEventListener('CookiebotOnAccept', checkAndLoadScripts);
// Initial check
checkAndLoadScripts();
initializeAnalytics();
// Add GTM noscript on DOM ready
if (document.readyState === 'loading') {
+1 -9
View File
@@ -1,9 +1 @@
<svg
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
>
<title>Java</title>
<path d="m16.5093 4.9869-.0607-.0347c-1.1014.369-4.4915 1.707-4.4915 4.202 0 1.411 1.378 2.1925 1.378 3.5158 0 .472-.2666.9146-.4836 1.1791l.1091.063c.5735-.3728 1.589-1.18 1.589-2.2222 0-.8825-1.2216-1.943-1.2216-3.0774 0-1.7875 2.357-3.1899 3.1813-3.6256zm-1.6642-3.27c0 3.6925-5.0604 5.1055-5.0604 7.7309 0 1.843 1.2222 2.9987 1.8983 3.7293l-.055.0317c-.8536-.534-3.0995-1.876-3.0995-4.0927 0-3.112 5.8123-4.599 5.8123-8.134 0-.435-.0644-.7683-.1095-.9482L14.2901 0c.1842.2315.555.8102.555 1.7168m.514 14.9392c-.5962.1688-1.9389.4441-3.859.4441-1.8844 0-3.424-.3226-3.4289-.7024-.0032-.2527.3024-.3628.3024-.3628l-.0544-.0316c-.9023.1595-1.7406.406-1.7357.7752.0084.6698 2.5697 1.1728 4.9129 1.1728 1.992 0 3.9053-.3343 4.7684-.7722zm-6.368 2.0708c-.4185.0832-1.3305.2926-1.3305.7361 0 .6144 1.9513 1.085 3.835 1.085 2.5922 0 3.6539-.667 3.702-.7016l-1.078-.6235c-.4583.1092-1.2306.2808-2.6214.2808-1.5521 0-2.5634-.2658-2.5634-.5569 0-.0617.0386-.135.1106-.1886zm10.5923-4.1337c-.0725 1.3911-1.3577 2.2573-2.6423 2.9893l.1164.067c1.3708-.3855 3.8166-1.5085 3.6144-3.2346-.1007-.8608-.8875-1.4758-1.9133-1.4758-.3194 0-.6036.0563-.834.1265l-.0007.0022-.0486.1224c.9175-.1796 1.7558.4904 1.7082 1.403zm-8.1232 8.1638c3.6058-.0313 7.6402-.737 7.6298-1.9232-.0019-.215-.1418-.3622-.2635-.4513l-.0592.034c-.3333.9188-3.1508 1.5977-7.3132 1.634-2.6859.0234-6.4063-.62-6.4128-1.3636-.0065-.7455 1.7625-1.1552 1.7625-1.1552l-.125-.0714c-1.1854.1632-3.3697.731-3.3625 1.5506.0104 1.185 5.0304 1.7734 8.1439 1.7461zm-.375.847c-1.4333.0126-3.1833-.1061-4.6555-.3535l-.1363.0784c1.4664.43 3.508.6896 5.7514.6702 4.4059-.0386 7.9779-1.1311 8.0485-2.446l-.051-.0297c-.2953.3604-2.2009 2.0216-8.9572 2.0806zm-5.5195-9.328c0-.6646 2.521-1.0374 3.6947-1.1277l.112.0647c-.451.082-2.26.401-2.26.8172 0 .4532 2.7747.7501 4.3853.7501 2.7355 0 4.595-.414 5.095-.5505l.6997.4072c-.4792.2346-2.5362.8495-5.7945.8495-3.6214 0-5.9322-.7086-5.9322-1.2105" />
</svg>
<svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M 16.921875 2.25 C 16.71679725 2.26171875 16.4970705 2.3408205 16.2890625 2.5078125 C 15.40722675 3.2138669999999996 15.541992 3.5771482499999996 15.1171875 4.4296875 C 14.973633 4.9248045 14.736328499999999 4.962891 14.53125 4.5234375 C 14.28515625 4.08691425 14.16503925 3.5419919999999996 13.78125 3.2109375 C 13.16308575 2.67773475 12.4658205 3.0791017500000004 12.84375 3.6796875 C 13.2216795 4.28027325 13.376953499999999 4.91308575 13.5234375 5.90625 C 13.74316425 7.3857420000000005 13.125 9.03222675 12.3046875 9.8203125 C 10.822266 6.7880857500000005 8.885742 4.53808575 7.5234375 3.84375 C 7.1103517499999995 3.6328125 6.984375 3.80859375 6.984375 4.0078125 C 7.2421875 6.978516000000001 7.3359375 9.02929725 7.171875 10.546875 C 7.0986329999999995 11.2265625 5.49609375 13.734375 5.578125 14.3203125 C 5.66015625 14.9033205 6.12890625 15.817383 6.4453125 16.2890625 C 6.31640625 16.1953125 5.99121075 16.4091795 6.0703125 16.7109375 C 5.49902325 17.03027325 5.551758 17.51953125 6.140625 17.6484375 C 6.29296875 18.0439455 6.3251954999999995 18.24023475 6.75 18.421875 C 6.66796875 19.25683575 6.580078500000001 20.11523475 6.4921875 21.046875 C 6.873047250000001 22.921875 9.776367 19.67871075 10.1484375 19.40625 C 12.161133 17.9296875 12.46875 21.15234375 13.875 21.65625 C 16.2421875 22.5029295 15.474609749999999 17.52246075 13.5703125 12.6328125 C 13.34472675 9.489258 14.40234375 8.59277325 15.421875 8.1796875 C 15.958008 8.00390625 16.3564455 7.96875 17.0859375 8.1796875 C 18.33984375 8.54003925 18.60058575 7.11328125 17.484375 6.9375 C 17.0595705 6.8701170000000005 16.7519535 6.8759767499999995 16.359375 6.703125 C 16.5175785 6.0732420000000005 17.14453125 6.041016000000001 17.765625 5.953125 C 19.17773475 5.75390625 19.0546875 4.23046875 17.484375 4.59375 C 16.7988285 4.754883 16.49121075 5.16210975 16.2421875 5.15625 C 16.56152325 4.573242 17.10058575 4.072266 17.625 3.328125 C 18.0175785 2.7685545 17.5341795 2.21484375 16.921875 2.25 Z M 9.6328125 7.734375 C 9.817383 7.7109375 9.978516 7.72265625 10.1484375 7.78125 C 10.8251955 8.009766 11.05371075 8.87109375 10.640625 9.6796875 C 10.22753925 10.48828125 9.3251955 10.9394535 8.6484375 10.7109375 C 7.9716795000000005 10.48242225 7.7666017499999995 9.64453125 8.1796875 8.8359375 C 8.49023475 8.229492 9.07910175 7.8076170000000005 9.6328125 7.734375 Z M 8.90625 8.8359375 C 8.80371075 8.838867 8.698242 8.89746075 8.6015625 9 C 8.4082035 9.208008 8.34375 9.55078125 8.4609375 9.75 C 8.5810545 9.94921875 8.8300785 9.9345705 9.0234375 9.7265625 C 9.21679725 9.5185545 9.2841795 9.17578125 9.1640625 8.9765625 C 9.10546875 8.8769535 9.00878925 8.833008 8.90625 8.8359375 Z M 11.390625 10.7578125 C 12.521484749999999 12.919922249999999 13.587890999999999 15.48046875 13.8046875 18.3984375 C 13.90722675 19.78710975 12.791015999999999 18.28710975 12.65625 18.046875 C 10.359375 13.91015625 7.4091795000000005 22.40625 7.9921875 17.0859375 C 8.2939455 14.89453125 8.4404295 14.604492 8.5078125 12.046875 C 8.5078125 12.046875 10.265625 12.963867 11.390625 10.7578125 Z M 7.21875 13.2890625 C 7.1630857500000005 14.0126955 7.1484375 14.490234749999999 7.078125 15.234375 C 6.9228517499999995 14.830078499999999 6.7177732500000005 14.7890625 6.609375 14.4140625 C 6.8349607500000005 14.16796875 6.990234750000001 13.6875 7.21875 13.2890625 Z"/></svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

-9
View File
@@ -1,9 +0,0 @@
# *
User-agent: *
Allow: /
# Host
Host: https://nx.dev
# Sitemaps
Sitemap: https://nx.dev/sitemap-index.xml
+19
View File
@@ -0,0 +1,19 @@
/**
* Run Vale on all docs files.
*
* Exit codes mirror Vale: 1 = errors found (fail CI), 0 = warnings/suggestions only or clean.
*/
import { execSync } from 'child_process';
try {
execSync('vale src/content/docs/', { stdio: 'inherit' });
} catch (err) {
if (err.status === 1) {
console.log(
'\nVale found errors. Fix all error-level violations before committing.'
);
process.exit(1);
}
// Exit code 2 = warnings/suggestions only — don't fail
process.exit(0);
}
+1184 -176
View File
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,122 @@
<svg width="980" height="720" viewBox="0 0 980 720" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- Defs: arrow markers -->
<defs>
<marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto" markerUnits="strokeWidth">
<polygon points="0 0, 10 3.5, 0 7" fill="#476088"/>
</marker>
<marker id="arrowGreen" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto" markerUnits="strokeWidth">
<polygon points="0 0, 10 3.5, 0 7" fill="#70AF40"/>
</marker>
</defs>
<!-- Outer dotted border: Synthetic Monorepo boundary -->
<rect x="40" y="40" width="900" height="590" rx="24" ry="24"
stroke="#94A3B8" stroke-width="3" stroke-dasharray="12 6" fill="none"/>
<!-- "Synthetic Monorepo" label at bottom inside box -->
<text x="490" y="665" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="26" font-weight="700" fill="#94A3B8">Synthetic Monorepo</text>
<!-- ============================================ -->
<!-- Monorepo A (top-left): a rounded rect with 3 internal projects -->
<!-- ============================================ -->
<rect x="80" y="70" width="260" height="200" rx="16" ry="16"
stroke="#9CA3AF" stroke-width="2" fill="none"/>
<text x="210" y="100" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="14" font-weight="600" fill="#9CA3AF">Monorepo A</text>
<!-- App 1 (blue) -->
<circle cx="140" cy="165" r="38" fill="#476088"/>
<text x="140" y="161" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="white">App 1</text>
<text x="140" y="178" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" fill="#CBD5E1">frontend</text>
<!-- Lib A (green) -->
<circle cx="270" cy="145" r="32" fill="#70AF40"/>
<text x="270" y="141" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="white">Lib A</text>
<text x="270" y="157" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" fill="#E8F5E9">utils</text>
<!-- Lib B (green) -->
<circle cx="248" cy="222" r="28" fill="#70AF40"/>
<text x="248" y="218" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="12" font-weight="600" fill="white">Lib B</text>
<text x="248" y="233" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="10" fill="#E8F5E9">ui</text>
<!-- Internal arrows within Monorepo A -->
<line x1="175" y1="155" x2="238" y2="143" stroke="#9CA3AF" stroke-width="1.5" marker-end="url(#arrowBlue)" opacity="0.4"/>
<line x1="165" y1="190" x2="225" y2="212" stroke="#9CA3AF" stroke-width="1.5" marker-end="url(#arrowBlue)" opacity="0.4"/>
<!-- ============================================ -->
<!-- Monorepo B (right): a rounded rect with 2 internal projects -->
<!-- ============================================ -->
<rect x="640" y="70" width="260" height="200" rx="16" ry="16"
stroke="#9CA3AF" stroke-width="2" fill="none"/>
<text x="770" y="100" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="14" font-weight="600" fill="#9CA3AF">Monorepo B</text>
<!-- App 2 (blue) -->
<circle cx="710" cy="170" r="38" fill="#476088"/>
<text x="710" y="166" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="white">App 2</text>
<text x="710" y="183" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" fill="#CBD5E1">backend</text>
<!-- Lib C (green) -->
<circle cx="840" cy="185" r="32" fill="#70AF40"/>
<text x="840" y="181" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="white">Lib C</text>
<text x="840" y="197" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" fill="#E8F5E9">auth</text>
<!-- Internal arrow within Monorepo B -->
<line x1="745" y1="175" x2="808" y2="182" stroke="#9CA3AF" stroke-width="1.5" marker-end="url(#arrowBlue)" opacity="0.4"/>
<!-- ============================================ -->
<!-- Standalone repos -->
<!-- ============================================ -->
<!-- Lib D (green, standalone, CENTER - pushed down to middle row) -->
<circle cx="490" cy="340" r="38" fill="#70AF40"/>
<text x="490" y="336" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="white">Lib D</text>
<text x="490" y="352" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" fill="#E8F5E9">shared</text>
<text x="490" y="390" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" font-weight="500" fill="#9CA3AF">standalone repo</text>
<!-- App 3 (blue, standalone, bottom-left) -->
<circle cx="200" cy="500" r="42" fill="#476088"/>
<text x="200" y="496" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="white">App 3</text>
<text x="200" y="513" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" fill="#CBD5E1">mobile</text>
<text x="200" y="554" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" font-weight="500" fill="#9CA3AF">standalone repo</text>
<!-- Lib E (green, standalone, bottom-center) -->
<circle cx="490" cy="520" r="32" fill="#70AF40"/>
<text x="490" y="516" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="white">Lib E</text>
<text x="490" y="532" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" fill="#E8F5E9">design</text>
<text x="490" y="564" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" font-weight="500" fill="#9CA3AF">standalone repo</text>
<!-- App 4 (blue, standalone, bottom-right) -->
<circle cx="770" cy="500" r="42" fill="#476088"/>
<text x="770" y="496" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="white">App 4</text>
<text x="770" y="513" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" fill="#CBD5E1">API</text>
<text x="770" y="554" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="11" font-weight="500" fill="#9CA3AF">standalone repo</text>
<!-- ============================================ -->
<!-- Cross-repo dependency arrows -->
<!-- ============================================ -->
<!-- App 2 → Lib D (shared): curve down-left -->
<path d="M 675 185 C 620 240, 560 280, 525 325" stroke="#476088" stroke-width="2.5" fill="none" marker-end="url(#arrowBlue)"/>
<!-- Lib A → Lib D: gentle arc down -->
<path d="M 300 155 C 370 200, 420 260, 458 322" stroke="#70AF40" stroke-width="2" fill="none" marker-end="url(#arrowGreen)"/>
<!-- App 3 → Lib B (in Monorepo A): straight up -->
<path d="M 210 458 C 220 380, 230 320, 242 252" stroke="#476088" stroke-width="2.5" fill="none" marker-end="url(#arrowBlue)"/>
<!-- App 3 → Lib E (design): horizontal -->
<path d="M 242 500 C 320 490, 400 500, 458 515" stroke="#476088" stroke-width="2.5" fill="none" marker-end="url(#arrowBlue)"/>
<!-- App 4 → Lib C (in Monorepo B): straight up -->
<path d="M 790 458 C 805 380, 820 310, 835 217" stroke="#476088" stroke-width="2.5" fill="none" marker-end="url(#arrowBlue)"/>
<!-- App 4 → Lib D (shared): arc up-left -->
<path d="M 730 490 C 650 460, 570 410, 525 358" stroke="#476088" stroke-width="2.5" fill="none" marker-end="url(#arrowBlue)"/>
<!-- App 4 → Lib E (design): horizontal left -->
<path d="M 728 505 C 660 510, 580 515, 522 518" stroke="#476088" stroke-width="2" fill="none" marker-end="url(#arrowBlue)"/>
<!-- Lib D → Lib C (cross-repo lib dependency): arc up-right -->
<path d="M 525 330 C 620 300, 740 260, 812 200" stroke="#70AF40" stroke-width="2" fill="none" marker-end="url(#arrowGreen)"/>
</svg>

After

Width:  |  Height:  |  Size: 8.1 KiB

Some files were not shown because too many files have changed in this diff Show More