Summary
Four related problems in apps/rush-cli-client (the opt-in rush-client), each reproduced independently on Linux with rush-client from main @ 60007c9 and RUSH_DAEMON=1:
- Non-build commands connect to, and auto-start, the daemon, are rejected, and print a misleading warning.
rush-client list with no daemon running takes 2.98 s, compared with 0.98 s for native, because it auto-starts a daemon. Warm, it takes 1.06 s. tab-complete, and repo-defined custom phased or global commands, do the same. Every call prints rush-client: The production daemon requires an explicitly identified native build/rebuild request. Ambiguous custom/rushx requests require --no-daemon.; using in-process Rush. (note the .;). Root cause: routing.ts:9-28 neverDaemonize is a partial deny-list (missing list, tab-complete, init-subspace, install-autoinstaller, update-cloud-credentials, upgrade-interactive, alert, bridge-package, link-package), and repo-defined commands are routed to the daemon (routing.ts:71-80). The daemon then rejects everything except build/rebuild (ProductionDaemonRequestResolver.ts:137-143). Fix: route by an allowlist (build/rebuild, plus install/update when the peer supports them); send everything else in-process without connecting, and show a rejection only in verbose/debug mode.
- A TTY with 0 columns hard-fails the build. Under
script, docker exec -t before a resize, or agent PTYs created 0x0, process.stdout.columns === 0, and the client exits 1 with Request terminal columns must be a positive safe integer. and no fallback. Native Rush builds fine in the same terminal. Root cause: launchClient.ts:91, :108 pass process.stdout.columns verbatim, and :131 uses ?? 80, which does not catch 0. Fix: treat 0 or undefined as unknown (omit it, or fall back to 80).
- Queue-position feedback is suppressed when stderr is not a TTY. AI agents and CI waiting behind another build see 0 bytes for up to 30 s, and then only the wait-timeout failure. TTY clients get
waiting for daemon admission (position 1). after about 1 s, repeated even when the position has not changed. Root cause: launchClient.ts:162-168 (onQueuePositionAsync: process.stderr.isTTY ? ... : undefined). The duplicates come from RequestScheduler.ts:304-311. Fix: always write a queue line to stderr (non-TTY: once when queued and on each change), include what the request is waiting for, and de-duplicate unchanged positions.
- No immediate feedback while the daemon starts or initializes the graph. The client writes nothing until the daemon streams activity: 3.4-3.9 s of silence on a cold auto-start, 3.6-7.6 s on first graph initialization, and 2.5-4 s for
daemon start/restart. Native Rush prints its banner within 0.6-0.8 s. A first line within about 40 ms is achievable (for example rush-client: starting daemon for <workspace>... or connected; preparing graph...).
Repro steps
rush-client daemon stop; time rush-client list # 2.98 s + daemon auto-started + warning
script -qefc 'rush-client build --to p01; echo EXIT=$?' /dev/null # 0x0 PTY -> exit 1
rush-client build & sleep 5; rush-client build --only p03 2>err.txt # long holder; err.txt is empty for 30 s
rush-client daemon stop; rush-client build 2>&1 | head -1 # first byte only after ~3.7 s
Expected result: Native parity for non-daemon commands. Immediate, TTY-independent feedback for waiting and startup. No hard failure on a 0-column TTY.
Actual result: As described above.
Details
Found during an automated performance/behavior analysis of rush-client/rushd on Linux (the goals were immediate feedback for every terminal action and agent-friendly output). Each item was reproduced by at least two independent runs.
Standard questions
| Question |
Answer |
@microsoft/rush globally installed version? |
built from main @ 60007c9 (5.179.0) |
rushVersion from rush.json? |
5.179.0 |
pnpmVersion, npmVersion, or yarnVersion from rush.json? |
pnpm@10.27.0 |
(if pnpm) useWorkspaces from pnpm-config.json? |
true |
| Operating system? |
Linux (WSL2 Ubuntu 24.04) |
| Would you consider contributing a PR? |
Yes |
Node.js version (node -v)? |
22.23.2 |
Summary
Four related problems in
apps/rush-cli-client(the opt-inrush-client), each reproduced independently on Linux withrush-clientfrommain@ 60007c9 andRUSH_DAEMON=1:rush-client listwith no daemon running takes 2.98 s, compared with 0.98 s for native, because it auto-starts a daemon. Warm, it takes 1.06 s.tab-complete, and repo-defined custom phased or global commands, do the same. Every call printsrush-client: The production daemon requires an explicitly identified native build/rebuild request. Ambiguous custom/rushx requests require --no-daemon.; using in-process Rush.(note the.;). Root cause:routing.ts:9-28neverDaemonizeis a partial deny-list (missinglist,tab-complete,init-subspace,install-autoinstaller,update-cloud-credentials,upgrade-interactive,alert,bridge-package,link-package), and repo-defined commands are routed to the daemon (routing.ts:71-80). The daemon then rejects everything except build/rebuild (ProductionDaemonRequestResolver.ts:137-143). Fix: route by an allowlist (build/rebuild, plus install/update when the peer supports them); send everything else in-process without connecting, and show a rejection only in verbose/debug mode.script,docker exec -tbefore a resize, or agent PTYs created 0x0,process.stdout.columns === 0, and the client exits 1 withRequest terminal columns must be a positive safe integer.and no fallback. Native Rush builds fine in the same terminal. Root cause:launchClient.ts:91, :108passprocess.stdout.columnsverbatim, and:131uses?? 80, which does not catch 0. Fix: treat 0 or undefined as unknown (omit it, or fall back to 80).waiting for daemon admission (position 1).after about 1 s, repeated even when the position has not changed. Root cause:launchClient.ts:162-168(onQueuePositionAsync: process.stderr.isTTY ? ... : undefined). The duplicates come fromRequestScheduler.ts:304-311. Fix: always write a queue line to stderr (non-TTY: once when queued and on each change), include what the request is waiting for, and de-duplicate unchanged positions.daemon start/restart. Native Rush prints its banner within 0.6-0.8 s. A first line within about 40 ms is achievable (for examplerush-client: starting daemon for <workspace>...orconnected; preparing graph...).Repro steps
Expected result: Native parity for non-daemon commands. Immediate, TTY-independent feedback for waiting and startup. No hard failure on a 0-column TTY.
Actual result: As described above.
Details
Found during an automated performance/behavior analysis of
rush-client/rushdon Linux (the goals were immediate feedback for every terminal action and agent-friendly output). Each item was reproduced by at least two independent runs.Standard questions
@microsoft/rushglobally installed version?main@ 60007c9 (5.179.0)rushVersionfrom rush.json?pnpmVersion,npmVersion, oryarnVersionfrom rush.json?useWorkspacesfrom pnpm-config.json?node -v)?