Skip to content

Tags: nrwl/nx

Tags

23.2.0-beta.2

Toggle 23.2.0-beta.2's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(core): strip terminal query sequences when replaying task output (#…

…36432)

## Current Behavior

When a task's captured pty output is replayed (TUI summary, static
terminal output, cache replays), any terminal *query* escape sequences
the child emitted are written to the real terminal verbatim. The
terminal dutifully replies on stdin — but by then nx has restored cooked
mode and nothing is consuming replies, so the reply gets echoed into the
visible output as garbage next to the run summary, e.g.:

```
> nvim

^[[?62;22;52c
 NX   Successfully ran target edit for project @nx/nx-source (3m)
```

`ESC[?62;22;52c` is the terminal's Primary Device Attributes reply to
the `ESC[c` probe nvim sends at startup. The existing passthrough filter
only handles one such sequence (`ESC[6n`), fixing a single symptom
rather than the class.

## Expected Behavior

Replayed output is a recording — no process is waiting for the
terminal's answers anymore, so reply-eliciting sequences are stripped
before the replay is written. A new `stripTerminalQueries()` helper
removes:

- DA1/DA2/DA3 device attribute queries (`CSI c`, `CSI > c`, `CSI = c`) —
replies (`CSI ? … c`) are intentionally preserved
- DSR status/cursor reports (`CSI 5 n`, `CSI 6 n`, `CSI ? Ps n`)
- XTVERSION (`CSI > q`) and DECRQM mode queries (`CSI ? Ps $ p`)
- kitty keyboard protocol query (`CSI ? u`)
- XTWINOPS report requests (`CSI 14 t`, `CSI 18 t`, …) while preserving
non-reporting window ops
- OSC color/clipboard queries (`OSC 10;?`, `OSC 52;c;?`, …) while
preserving OSC sets like window titles
- XTGETTCAP / DECRQSS (`DCS + q … ST`, `DCS $ q … ST`)

The strip is applied in `output.logCommandOutput`, which every replay
path (tui-summary, static run-one/run-many, empty, invoke-runner life
cycles) funnels through. Live pty passthrough is untouched: while a task
runs, queries must reach the real terminal and the replies are consumed
in raw mode.

## Related Issue(s)

N/A — reported while testing #36322 locally; reproduced on stock nx
22.4.1, pre-existing and unrelated to that PR.

<!-- polygraph-session-start -->
---
[View session information
↗](https://app.trypolygraph.com/orgs/6a061dcb561c062131116eca/sessions/Strip-terminal-query-sequences-from-replayed-task-output-895a849d)
<!-- polygraph-session-end -->

23.2.0-beta.1

Toggle 23.2.0-beta.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(core): render critical-path tasks as a nested list in the job sum…

…mary (#36394)

## Current Behavior

In the GitHub Actions job summary, the Nx Run Report's "Speed up or
split the longest tasks on the critical path" recommendation renders its
task list as terminal-style rows collapsed with `<br>`:

```
- Speed up or split the longest tasks on the critical path:<br>e2e-react-native:e2e-macos-local                 20m 2s<br>@nx/nx-source:populate-local-registry-storage    5m 31s
```

The rows are space-padded for terminal column alignment, but HTML
collapses runs of spaces, so the rendered summary shows ragged,
hard-to-read lines jammed into a single bullet.

## Expected Behavior

The Markdown renderer formats the task list as a nested list under the
recommendation's bullet:

```
- Speed up or split the longest tasks on the critical path:
  - `e2e-react-native:e2e-macos-local` — 20m 2s
  - `@nx/nx-source:populate-local-registry-storage` — 5m 31s
```

Structurally, the critical-path recommendation now carries its task rows
as data (`RecTaskRows`) instead of a pre-joined terminal string, and
each renderer formats them natively. The terminal report and the TUI
popup payload output are byte-for-byte unchanged (covered by the
existing tests, which pass unmodified); only the job-summary Markdown
changes.

## Related Issue(s)

N/A

<!-- polygraph-session-start -->
---
[View session information
↗](https://app.trypolygraph.com/orgs/6a061dcb561c062131116eca/sessions/Speed-up-main-macos-CI-job-parallel-e2e--drop-dead-Homebrew-cache-7918829a)
<!-- polygraph-session-end -->

---------

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

23.2.0-beta.0

Toggle 23.2.0-beta.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(core): add a full-width TUI status bar and vim-style pane search (

…#36263)

## Current Behavior

The TUI task list renders its own bottom rows (keyboard hints, Nx Cloud
message, filter display) inside its own column, so they are cramped in
split layouts and disappear entirely when the task list is hidden
(fullscreen pane). The run title and NX badge live in the task-list
table header, terminal panes draw their own keybinding hints on their
bottom borders, and there is no way to search a pane's output. Much of
the UI state (cloud message/link, filter text, perf-report flag) is
duplicated between `TuiState` and `TasksList`, kept in sync via
broadcast actions.

## Expected Behavior

**Full-width status bar** on the bottom row of the TUI:

- Left: minimal progress counts with a live overall run duration —
`63/174 (1m 23s)` — which double as the clickable Nx Cloud link when a
structured link exists.
- Middle: free-text cloud messages (they can carry errors), transient
pane feedback ("copied to clipboard"), or the compact confirmed-search
display.
- Right: context-aware keyboard hints (task-list vs focused-pane) with
progressive fitting — as many whole hint items as fit the space — and
the `NON-INTERACTIVE i to toggle` / `INTERACTIVE <ctrl>+z to toggle`
indicator pinned right-most, never dropped.
- The task-list filter (`/`) swaps the bar row vim-style while typing;
the bar is mouse-selectable (drag to highlight + copy) and always
visible, including fullscreen-pane mode.
- The ` NX ` badge (run-state colored) and the run title stay at the
top-left of the task list in a minimal form; both columns keep
bottom-aligned scrollbars.

**Vim-style pane search**: `/` in a non-interactive pane searches the
full scrollback (case-insensitive, wrap-aware) with incremental jumping
while typing; Enter confirms into `n`/`N` navigation with wrap-around;
Esc cancels/clears. Matches highlight reverse-video with the current
match on a warning-colored background, and the bar shows `/query 2/5
(n/N)` while a confirmed search is active.

**State consolidation (started)**: `TuiState` is now the single owner of
the cloud message/link, filter text, and perf-report flag — the
`TasksList` mirrors and the `UpdateCloudMessage`/`UpdateCloudLink`
actions are deleted, and filter persistence across TUI mode switches is
automatic. Remaining mirrors (task statuses/timings, focus, pinned
tasks) are named follow-ups.

## Related Issue(s)


[NXC-4610](https://linear.app/nxdev/issue/NXC-4610/tui-full-width-status-bar-and-vim-style-terminal-pane-search)

<!-- polygraph-session-start -->
---
[View session information
↗](https://app.trypolygraph.com/orgs/6a061dcb561c062131116eca/sessions/TUI-Status-Bar-Development-11a216a4)
<!-- polygraph-session-end -->

23.1.0

Toggle 23.1.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
chore(repo): migrate to nx 23.1.0-rc.3 (#36321)

23.1.0-rc.3

Toggle 23.1.0-rc.3's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(testing): template the e2e config for fresh projects instead of a…

…st-parsing it (#36304)

## Current Behavior

`@nx/cypress`'s e2e configuration generator scaffolds a `cypress.config`
from a base template (`defineConfig({})`), reads it back, and uses
`@phenomnomnominal/tsquery` to inject the `e2e` block. Loading tsquery
reads `ts.SyntaxKind` at import time. When a workspace resolves an
incompatible TypeScript — e.g. `npm install` hoisting `typescript@7` to
satisfy tsquery's unbounded `>3.0.0` peer in a workspace that pins no
TypeScript — that read throws:

```
 NX   Cannot convert undefined or null to object
    at Object.keys (<anonymous>)
    at .../@phenomnomnominal/tsquery/dist/src/syntax-kind.js
```

…and app generation fails. This is what crashes `e2e-expo` /
`e2e-react-native` (and any cypress-scaffolded app) on the macOS CI job,
which installs test workspaces with npm. The bare `apps` workspace pins
no TypeScript, so npm hoists TS 7 for tsquery's peer.

## Expected Behavior

For a freshly generated config the AST round-trip is unnecessary: nx
just wrote the empty base and knows every value going in (the module
shape was already decided when the base template was selected). The
generator now templates the complete `cypress.config` directly via a new
`buildE2EConfigFromBase` (no tsquery), so generation never loads tsquery
and no longer depends on the resolved TypeScript version.

The AST-based `addDefaultE2EConfig` is kept for the case that genuinely
needs it — merging the e2e config into a **pre-existing, possibly
user-authored** config (`nx g @nx/cypress:configuration` on a project
that already has a config). The templated output is **byte-identical**
to the previous AST output, so generated files and snapshots are
unchanged.

Verified: 227 cypress unit tests pass, 41 config snapshots unchanged,
and `e2e-expo:e2e-macos-local` passes under npm with **zero** tsquery
crashes (was 53).

## Related Issue(s)

Surfaced by the macOS e2e (`e2e-expo` / `e2e-react-native`) crashing
once TypeScript 7 was published to npm — cypress config generation
loaded tsquery, which reads the top-level `SyntaxKind` export that TS 7
removed.

<!-- polygraph-session-start -->
---
[View session information
↗](https://app.trypolygraph.com/orgs/6a061dcb561c062131116eca/sessions/Migrate-nrwl-repos-to-nx-23.1.0-rc.0-b8c94700)
<!-- polygraph-session-end -->

23.0.2

Toggle 23.0.2's commit message
fix(rspack): stop mocking non-existent is-serve-mode util in apply-ba…

…se-config test

22.7.7

Toggle 22.7.7's commit message
fix(dotnet): declare directory build props on the analyzer tests dotn…

…et targets

MsbuildAnalyzer.Tests build:dotnet/build:dotnet:release/test-native run dotnet build/test, which auto-import the workspace-root Directory.Build.props. Those inferred inputs did not declare it, so the sandbox flagged the read (build:dotnet was the next task the DTE terminated on after the MsbuildAnalyzer targets were fixed). Declare {workspaceRoot}/Directory.Build.props on all three cacheable dotnet targets. Verified locally: the build:dotnet report flips from ok:false to ok:true. Completes coverage across both .NET projects.

23.1.0-rc.2

Toggle 23.1.0-rc.2's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(js): pin rootDir on composite tsconfigs for ts6 (ts-jest strips c…

…omposite) (#36285)

## Current Behavior

The `23-1-0-set-tsconfig-root-dir-for-ts6` migration **exempts composite
configs** from pinning `rootDir`. That rests on a correct-in-isolation
fact — TypeScript 6's TS5011 containment check carries an explicit
`!options.composite` guard, so a genuinely composite program never emits
TS5011.

The gap: **ts-jest strips `composite`** (it does transpile-only,
per-file compilation and force-disables
`composite`/`incremental`/`declaration`). So a spec tsconfig that
inherits `composite: true` from a base — the standard TS-solution layout
— is composite at rest but *not* composite when ts-jest compiles a
single test file. The `!composite` guard no longer applies, the per-file
program re-infers a deeper common directory, and it fails with:

```
error TS5011: The common source directory of 'tsconfig.spec.json' is './src/lib'.
The 'rootDir' setting must be explicitly set to this or another path...
```

This breaks the atomized `e2e-ci` jest tasks in any such workspace. It
surfaced on nrwl/nx-console migrating to 23.1.0-rc.1: **31 of 33** spec
tsconfigs resolve as composite (inherited from the base) and the
migration pinned none of them, so a whole set of projects (`shared-npm`,
the language-server libs, etc.) failed with TS5011. Note the earlier
own-dir fix (#36272) deliberately *kept* the composite exemption, so
rc.1 has that fix yet still skips these.

## Expected Behavior

Composite configs (with an emit gate and input files) are pinned to
their **own directory (`"."`)**. Under `tsc` a composite `rootDir`
already defaults there, so `"."` is a no-op for a real composite build —
but it's the explicit value ts-jest's composite-stripped per-file
compile needs. It's pinned to the config dir, **not** the deeper
file-derived value, so a genuine composite build's emit layout is
unchanged.

Because every emitting config now receives its own explicit `rootDir` in
phase 2, no config is left to inherit a value pinned on a base — so the
phase-3 shield loop and `inheritsRootDir` are removed (the migration is
~100 lines shorter).

Re-stamped `23.1.0-rc.1` → `23.1.0-rc.2` so workspaces already on rc.1
re-run it (idempotent: `has-rootDir` configs are skipped).

## Validation

- Unit spec: 11/11 pass, incl. new tests — `pins a composite project to
its own directory`, `pins a composite spec config compiled by ts-jest
(composite inherited from base)`. The new tests fail on the pre-fix
source.
- End-to-end on nx-console (transpiled this migration, swapped into
node_modules, reset spec tsconfigs to the un-pinned baseline): the
migration pins **33/33** spec tsconfigs to `"."` (rc.1's version pinned
**0/33**). After it runs, the previously-failing `shared-npm` tests
**pass** (5 + 2), and `nxls-e2e` / `nx-mcp-e2e` config-load with **no
TS5011**.

## Related Issue(s)

Follow-up to #36272 (same migration). Fixes the composite-spec case
exposed by the nx 23.1.0-rc.1 migration of nrwl/nx-console.

<!-- polygraph-session-start -->
---
[View session information
↗](https://app.trypolygraph.com/orgs/6a061dcb561c062131116eca/sessions/Migrate-nrwl-repos-to-nx-23.1.0-rc.0-b8c94700)
<!-- polygraph-session-end -->

23.1.0-rc.1

Toggle 23.1.0-rc.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(core): size TUI bottom bar reservations to the actual help text (#…

…36261)

## Current Behavior

The TUI task list's bottom bar decides its layout from hardcoded width
constants (`COLLAPSED_HELP_WIDTH = 19`, `FULL_HELP_WIDTH = 86`) plus a
phantom `SCROLLBAR_WIDTH = 3` that the bottom row never actually
renders. These constants have drifted from the real help content: the
collapsed help is 16 columns, and the post-run help (which now includes
`perf report: p`) is 100 columns.

Next to an Nx Cloud message this over/under-reservation causes:

- The cloud message drops its prefix (URL-only fallback) while blank
columns visibly remain (e.g. at 81 cols, `View logs and run details at
…` is cut to just the URL with ~6 spare columns).
- The full help collapses several columns before it stops fitting
(147–151 cols).
- The `perf report: p` hint is clipped off the right edge entirely
whenever a cloud message is shown after a run finishes, because the real
100-col help is drawn into an 86-col reservation.

## Expected Behavior

Layout reservations match what actually renders. `HelpText` exposes
`width()` derived from the same spans it renders (including the
perf-report variant), the bottom-bar math consumes it instead of the
stale constants, the phantom scrollbar reservation is removed, and cloud
message widths are measured as display columns rather than byte lengths.
The full message, full help, and perf-report hint each appear exactly
when they fit.

Three regression tests pin the boundary widths (79 / 147 / 163 cols);
one snapshot updated where the full help now correctly expands at 90
cols.

## Related Issue(s)

Polygraph session: cloud-link-tui-reserves-too-much-space

<!-- polygraph-session-start -->
---
[View session information
↗](https://app.trypolygraph.com/orgs/6a061dcb561c062131116eca/sessions/cloud-link-tui-reserves-too-much-space-43247752)
<!-- polygraph-session-end -->

23.1.0-rc.0

Toggle 23.1.0-rc.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(core): prevent TUI hint popup from permanently stealing focus (#3…

…6256)

## Current Behavior

The fullscreen TUI can wedge into a state where `q` (quit), task-list
navigation, and all mouse clicks/selection are unresponsive, while `?`
(help), F10, and F11 still work. Switching to inline mode and back with
F11 restores normal behavior.

Deterministic reproduction: focus an output pane, press any unhandled
key (e.g. `x`) to trigger the "press 'i' to enter interactive mode"
toast, then press F10 within 2 seconds. When the mouse-capture toast
fades, the app is wedged.

Root cause: focus was tracked in a one-slot register (`focus` +
`previous_focus`), and `update_focus` recorded the current focus as
"previous" even for no-op transitions. F10 dispatches its own `ShowHint`
while the first hint is still focused, so `previous_focus` became
`Focus::HintPopup` itself. Every focus-restore path (auto-dismiss, Esc,
click-away) then self-looped, parking focus permanently on an invisible
modal: the hint key branch consumed every key except those handled
earlier in dispatch (Ctrl+C, F10-F12, `?`), and `active_modal_kind()`
absorbed every mouse event. Only F11 escaped, because switching modes
constructs a fresh `App`.

## Expected Behavior

Focus is tracked as a **layer stack** and popups can never wedge the UI:

- `focus_stack[0]` is always a base layer (task list or output pane)
that lateral navigation (Tab/Esc/click) replaces in place; popup layers
(help, run report, hints) push above it
- `push_focus` is a no-op for the already-focused layer and moves a
buried layer instead of duplicating it — the stack can never hold the
same layer twice, so dismissal can never self-loop (the original bug is
structurally impossible)
- `close_popup` removes a layer wherever it sits (popups can die while
buried, e.g. a hint auto-expiring under the run report) and prunes
revealed layers that are no longer active, so focus always lands on
something visible
- layer classification and liveness live on `Focus` itself (`is_popup`,
`is_active`)
- defense in depth retained: a hidden hint popup is never treated as a
modal for keys or mouse, and a key arriving while focus points at one
repairs the focus and falls through to its normal handler

Regression tests drive the focus-stack API directly: the poisoning
sequence via repeated `push_focus`, buried-popup pruning, hidden-hint
key fall-through, modal hit-testing, and the hidden-popup geometry
contract (a hidden popup reports no hit-test areas even before the next
draw clears them). The full key-event → action-queue → `ShowHint`
pipeline is not unit-tested — `handle_action` requires a real terminal
backend — so the end-to-end F10-during-toast sequence was validated with
the manual reproduction above. The full `nx` crate Rust suite passes.

## Related Issue(s)

No linked issue — diagnosed from a user report of the TUI becoming
unresponsive after toggling mouse capture (F10) while a hint toast was
visible.

---------

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