fix: Show toolchain tasks in the TUI and never run in silence - #13308
Merged
Merged
Conversation
Two fixes for TUI behavior in Cargo-enabled repos: The TUI task list came from a package.json scripts lookup, so Cargo tasks were never registered (resolving the standing TODO in tasks_with_command). Ask the package's toolchain via Toolchain::defines_task instead - the same authority execution uses - so the TUI, display, and execution cannot drift. JS behavior is unchanged (its defines_task is the scripts lookup). This also fixes the task list in watch mode. Worse than the missing panes: events for those unknown tasks killed the TUI event loop mid-run via TaskNotFound, after the terminal sink had already been disabled - the rest of the run executed with no live sink and every task's output silently vanished. Wrap the render-thread handle in a watchdog inside start_terminal_ui that re-enables the terminal sink the moment the TUI is gone, however it exits (normal shutdown, render error, panic). Both run and watch inherit it, and neither caller can forget it.
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
tknickman
approved these changes
Jul 7, 2026
…3309) ## Why In a Cargo-enabled repo, the TUI showed a column of `»` running tasks whose processes didn't exist. The running marker fired at the very top of task execution — before the cache check and before the serial-group lock. For JS tasks that gap is milliseconds and invisible; Cargo's serial group (one cargo at a time, because they'd fight over the build directory) stretched it to minutes of tasks claiming to run while queued. ## What `task_output.start()` moves to immediately before the process spawn, after serial-group acquisition. States now tell the truth: | Situation | Before | After | |---|---|---| | Waiting on serial group | `»` running, empty pane | pending — same as waiting on a dependency | | Holding the lock / executing | `»` | `»` | | Cache hit | brief false `»` flash | pending → ✓ directly (it never ran; duration truthfully ~0) | | JS task wrapping cargo (e.g. napi builds) | unchanged | unchanged — its process is real, and cargo self-reports "Blocking waiting for file lock" | ## How Two consequences the move forces, both handled: - **Cache hits never start**, so `finish_task` learns the planned → finished transition (`start().finish()` back to back). Unknown task names remain a hard error — this is a legitimate state transition, not event-swallowing. Persistence on TUI exit is unaffected: `tasks_started()` reads the finished/running lists, which now include these tasks. - **`StartTask` was the only carrier of the task's `outputLogs` setting.** A never-started cache hit would have defaulted to full log persistence, ignoring `hash-only`/`new-only`. `Event::Status` — which every cache-restore path already emits before any start — now carries `output_logs` too, threaded through `TaskSender::status` → `UISender` → `TuiSender`. Exit-path audit: the only `execute_inner` return remaining before the new start location is the cache-hit return (verified — no `?` operators in between), and spawn-failure paths sit after the start call, keeping start→finish ordering. `start()` is a no-op outside the TUI, so stream/grouped log modes are untouched (their "cache miss, executing" lines come from the run cache, not this signal). Tests: `finish_task` planned→finished (+ unknown-name error + `tasks_started` inclusion), `set_status` delivering `output_logs`; existing UI/executor/run-cache/cargo-workspace suites green. Follow-ups deliberately not in this PR: run-summary durations still include serial-group wait (`tracker.start()` unmoved); batching contended cargo invocations into one process remains a parked design discussion.
anthonyshew
pushed a commit
that referenced
this pull request
Jul 9, 2026
## Release v2.10.5-canary.4 > [!CAUTION] > Versioned docs aliasing FAILED. [View logs](https://github.com/vercel/turborepo/actions/runs/29034517569) ### Changes - release(turborepo): 2.10.5-canary.3 (#13302) (`7e44a29`) - ci: Authenticate to Remote Cache via OIDC token exchange (#13303) (`a86839c`) - fix: Keep pnpm patches with version range keys during prune (#13307) (`3c27a89`) - test: Scrub ambient turbo configuration from integration test children (#13306) (`b03d0d6`) - fix: Show toolchain tasks in the TUI and never run in silence (#13308) (`d7622b6`) - ci: Fix change detection on push events (#13304) (`eec3d61`) - refactor: Rename the Cargo toolchain id to rust (#13311) (`a548b02`) - fix: Remove extraneous bun.lock entries during prune (#13317) (`382e9f5`) - feat: Require a user-declared name for the Cargo workspace package (#13312) (`5f01746`) - feat: Parse and validate the task command field (#13313) (`389ea49`) - chore: Harden turbo-vsc to invoke turbo without a shell (#13319) (`4a19b6e`) - feat: Resolve and execute task command overrides (#13315) (`a549baa`) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
anthonyshew
pushed a commit
that referenced
this pull request
Jul 13, 2026
## Release v2.10.5 > [!CAUTION] > Versioned docs aliasing FAILED. [View logs](https://github.com/vercel/turborepo/actions/runs/29267191097) ### Changes - perf: Evaluate simple include globs without wax compilation (#13285) (`189897a`) - chore: Dogfood native Cargo support in this repository (#13283) (`42f067b`) - release(turborepo): 2.10.4 (#13286) (`f2fce38`) - ci: Remove dead sccache configuration (#13289) (`558df3f`) - feat: Serve the Remote Cache as an sccache backend for Cargo tasks (#13288) (`0d9803f`) - fix: Reject output path traversal (#13290) (`733ccca`) - fix: Disable the sccache proxy when remote cache use is off (#13291) (`3249e22`) - feat: Embed sccache so the Cargo compile cache needs no installation (#13293) (`b6d0035`) - release(turborepo): 2.10.5-canary.1 (#13294) (`e6cd498`) - fix: Pin a flag-aware turbo canary for the eve-agent deployment (#13295) (`e60a4bd`) - fix: Make the sccache compile cache actually cache (#13296) (`2ac099c`) - release(turborepo): 2.10.5-canary.2 (#13297) (`e6e6fb6`) - fix: Stop ambient CARGO_INCREMENTAL from suppressing compile cache injection (#13298) (`784af75`) - fix: Never let compile cache storage failures fail the build (#13299) (`a6fc6c5`) - test: Add outputs path-traversal negative-case regression tests (#13300) (`2ff6df9`) - release(turborepo): 2.10.5-canary.3 (#13302) (`7e44a29`) - ci: Authenticate to Remote Cache via OIDC token exchange (#13303) (`a86839c`) - fix: Keep pnpm patches with version range keys during prune (#13307) (`3c27a89`) - test: Scrub ambient turbo configuration from integration test children (#13306) (`b03d0d6`) - fix: Show toolchain tasks in the TUI and never run in silence (#13308) (`d7622b6`) - ci: Fix change detection on push events (#13304) (`eec3d61`) - refactor: Rename the Cargo toolchain id to rust (#13311) (`a548b02`) - fix: Remove extraneous bun.lock entries during prune (#13317) (`382e9f5`) - feat: Require a user-declared name for the Cargo workspace package (#13312) (`5f01746`) - feat: Parse and validate the task command field (#13313) (`389ea49`) - chore: Harden turbo-vsc to invoke turbo without a shell (#13319) (`4a19b6e`) - feat: Resolve and execute task command overrides (#13315) (`a549baa`) - release(turborepo): 2.10.5-canary.4 (#13325) (`6626261`) - feat: Run the Rust workspace tests through nextest via command override (#13316) (`6711bbc`) - feat: Engage the Remote Cache and sccache compile cache for Rust CI (#13292) (`1ae2065`) - ci: Pin GitHub Actions to full commit SHAs (#13143) (`ad614d6`) - fix: Make npm prune rehoisting deterministic and complete (#13323) (`2dac737`) - feat: Report incremental cache reuse in the run summary (#13327) (`9f3d24a`) - chore: Remove planning docs (#13329) (`5cd1d02`) - docs: Migrate docs site to @vercel/geistdocs package (#13320) (`5517bb2`) - ci: Update Remote Cache action (#13330) (`4a39887`) - release(turborepo): 2.10.5-canary.5 (#13331) (`f699719`) - ci: Remove path-based workflow scheduling (#13332) (`84f2b2c`) - fix: Resolve EADDRINUSE in kitchen-sink api dev script (#13328) (`5886c71`) - ci: Disable telemetry messages in workflows (#13334) (`2218dea`) - fix: Prevent Cargo run tasks from being cached (#13335) (`68f449b`) - fix: Isolate Cargo cache by host platform (#13337) (`c71f5cd`) - fix: Continue TUI text selection beyond viewport (#13338) (`9cbfd90`) - ci: Dogfood Cargo target restoration (#13336) (`8ad90a7`) - fix: Require current Cargo lockfiles for caching (#13339) (`3a3d381`) - fix: Reject unsupported Cargo local packages (#13340) (`708d656`) - fix: Allow outputs outside package roots (#13342) (`de6a0d3`) - fix: Resolve Cargo lock dependencies by source (#13343) (`2223a33`) - docs: Update Cargo workspace support (#13349) (`241ada8`) - fix: Build Ghostty for baseline CPUs (#13352) (`a2a04cc`) - fix: Preserve watch rerun semantics for task inputs (#13351) (`6ed5eab`) - fix: Isolate Command Overrides From Toolchain Cache I/O (#13354) (`e76f0b4`) - release(turborepo): 2.10.5-canary.6 (#13355) (`f82e2c7`) - fix: Include patched Ghostty crate in Cargo workspace (#13357) (`b3cd7a1`) - ci: Shard Rust tests across runners (#13356) (`ef122d9`) - fix: Hash Cargo build environment inputs (#13348) (`d533266`) - fix: Synchronize Cargo prune Docker lockfile (#13350) (`ed17249`) - chore: Update agents app Eve dependency (#13364) (`38aa7d2`) - fix: Preserve Yarn package extension ranges when pruning (#13363) (`6ed2fb4`) - refactor: Add `Toolchain` output availability (#13360) (`82bcfb6`) --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This branch was previously deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
In a Cargo-enabled repo (
futureFlags.experimentalCargoWorkspaces), running through the default TUI produced a blank, idle screen — not even the JS tasks rendered — while--ui=streamworked fine. Two stacked bugs:tasks_with_command) came from a package.json scripts lookup, so Cargo tasks were never registered.TaskNotFound, and the?in the event loop killed the entire TUI mid-run — after the terminal sink had already been disabled for TUI startup. Nothing re-enabled it until the run finished, so every task's output, JS included, silently vanished.What
tasks_with_commandnow asks the package's toolchain viaToolchain::defines_task— the same authority execution uses (and the same pattern the engine builder already uses for hashing), resolving the standing TODO. JS behavior is bit-identical; Cargo tasks come from the verb tables. Watch mode's task list is fixed by the same change.start_terminal_uiwraps the render-thread handle in a watchdog that re-enables the terminal sink the moment the TUI exits, however it exits (normal shutdown, render error, panic). The invariant it establishes: task output always has a live sink. Bothrunandwatchinherit it because it lives insidestart_ui— no caller can forget it.Deliberately not included: swallowing
TaskNotFoundevents in the TUI. A task-list/event mismatch stays loud (TUI dies, bug gets reported) — but now it degrades to streamed output instead of silence.How
turborepo-engine'sdefinitions.rs(package_info→toolchains().get(&info.toolchain)→defines_task); the"proxy"special case is preserved.run.rs/watch.rspreviously duplicated it); the handle type inUIResultbecomesJoinHandle<()>.cargo metadata) and asserts: JS task with script ✓, JS task without script ✗,cargo#test✓, binary cratebuild✓.To verify manually:
turbo buildin this repo with the default UI — Cargo task panes should appear with live output (the repro from the original report).