Skip to content

[rush-daemon][WS2.5][4/9] Isolate global command context - #3

Open
mojaza wants to merge 1 commit into
mojazayeri-microsoft-rushd-ws2-route-phased-requestsfrom
mojazayeri-microsoft-rushd-ws2-global-context
Open

[rush-daemon][WS2.5][4/9] Isolate global command context#3
mojaza wants to merge 1 commit into
mojazayeri-microsoft-rushd-ws2-route-phased-requestsfrom
mojazayeri-microsoft-rushd-ws2-global-context

Conversation

@mojaza

@mojaza mojaza commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Summary

Adds the opt-in WS2.5 global-command execution seam for rushd, with validated per-request cwd, immutable environment snapshots/overlays, terminal capabilities, cancellation, and isolated child-process propagation.

Depends on #2. This stack follows merged microsoft#5949 and advances microsoft#5897. Azure PBI: https://onedrive.visualstudio.com/EFun/_workitems/edit/3216021

Details

  • Resolves and canonicalizes each request cwd within the warm workspace, snapshots its environment with platform-correct key semantics, and freezes terminal columns/color/TTY properties.
  • Executes caller-supplied real global command logic against the warm WorkspaceSession through IGlobalCommandExecutionContext, without changing daemon-wide cwd, environment, stdin/stdout/stderr, or terminal globals.
  • Provides request-scoped terminal routing with ordered bounded backpressure, explicit child spawning with cwd/environment overlays, process-tree cancellation, and LIFO async resource cleanup.
  • Preserves concurrent isolation and waits for cooperative executor settlement before cancellation completes; the warm workspace session is never disposed per request.
  • Adds focused tests for concurrent cwd/env/terminal isolation, daemon-global immutability, child propagation, success/failure/cancellation/disconnect cleanup, request validation, and cross-workspace rejection.

Limitations

This layer intentionally does not parse commands or directly run arbitrary existing RushCommandLineParser/BaseRushAction instances, because those APIs still consult or mutate process-global state. Integrations must supply already resolved command logic that consumes the injected context. The remaining action/engine adaptation boundary is tracked by open microsoft#5895.

Exit-code and warnings-as-errors parity (WS2.6), stdin/raw-mode/PTY fallback (WS2.7), scheduler classification/admission (WS2.8), shared-build merging (WS2.9), lifecycle/restart, and CLI cutover are out of scope.

How it was tested

  • rush test --only @rushstack/rush-daemon
  • rushx build in libraries/rush-daemon
  • Parent-relative API Extractor report regeneration and stabilization
  • Focused code review of cancellation, backpressure, child-process cleanup, and disposer failure paths

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

There are a few concrete correctness/test-isolation issues (child tracking promise handling/leak, untrusted env validation robustness, and a lingering Jest spy) that should be addressed before merging.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds the WS2.5 “global command” execution seam to @rushstack/rush-daemon, enabling integrations to run caller-resolved global command logic through a per-request execution context that avoids mutating daemon-wide process/terminal globals.

Changes:

  • Introduces GlobalCommandRequestRouter plus request validation/snapshotting (cwd, environment snapshot, terminal properties) and request result shape.
  • Adds GlobalCommandExecutionContext with request-scoped terminal output routing/backpressure, cancellation, child-process spawning with environment overlays, and async resource cleanup.
  • Exposes the new public surface via the package barrel/API report and adds focused tests + README documentation + a change file.
File summaries
File Description
libraries/rush-daemon/src/test/GlobalCommandRequestRouter.test.ts Adds coverage for concurrent isolation, env snapshotting, cancellation/cleanup, disconnect behavior, and request validation.
libraries/rush-daemon/src/index.ts Re-exports the new WS2.5 global-command router/context request types from the package entrypoint.
libraries/rush-daemon/src/GlobalCommandRequestRouter.ts Implements the router that validates requests, constructs the execution context, and ensures cleanup/error aggregation.
libraries/rush-daemon/src/GlobalCommandRequestClient.ts Defines the per-request client contract for abort + terminal chunk backpressure.
libraries/rush-daemon/src/GlobalCommandRequest.ts Validates/canonicalizes cwd within workspace and snapshots environment + terminal properties for safe execution.
libraries/rush-daemon/src/GlobalCommandExecutionContext.ts Provides the isolated execution context: terminal routing, child spawning, cancellation, and LIFO async disposal.
libraries/rush-daemon/README.md Documents the new opt-in global-command seam and its limitations/expectations.
common/reviews/api/rush-daemon.api.md Updates the public API report to include the new global-command types.
common/changes/@rushstack/rush-daemon/mojazayeri-global-command-context_2026-08-21-18-44.json Declares a minor change entry for the new opt-in API surface.
Review details
  • Files reviewed: 9/9 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +215 to +218
const trackedChild: ITrackedChild = {
completion: this.#trackChildAsync(child)
};
this.#trackedChildren.add(trackedChild);
Comment on lines +152 to +156
function validateEnvironmentValue(name: string, value: string): void {
if (value.includes('\0')) {
throw new Error(`The global command environment variable "${name}" contains a null character.`);
}
}
Comment on lines +278 to +282
await expect(resultPromise).resolves.toEqual({ aborted: true, requestId: 'cancelled' });
expect(resourceDisposed).toBe(true);
expect(killProcessTreeSpy).toHaveBeenCalledTimes(1);
expect(process.cwd()).toBe(processCwd);
expect(process.env.RUSHD_CONTEXT_TEST).toBe(processEnvironmentValue);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants