Skip to content

[Proposal] Use native stdio streams in the Node SDK - #1220

Closed
Branden Bonaby (bbonaby) wants to merge 4 commits into
mainfrom
user/bbonaby/node-native-stdio-endpoints
Closed

Branden Bonaby (bbonaby) wants to merge 4 commits into
mainfrom
user/bbonaby/node-native-stdio-endpoints

Conversation

@bbonaby

@bbonaby Branden Bonaby (bbonaby) commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator

📖 Description

Replace callback-driven byte coordination with direct native stdio ownership in the Node SDK. Rust retains process lifecycle control, while Node adopts Windows HANDLEs through windowsHandle and Unix file descriptors through net.Socket.

Streaming remains limited to process-backed backends that expose transferable native endpoints. The Node SDK now requires Node.js 24.21.0 or later.

🔗 References

🔍 Validation

  • cargo fmt --all -- --check
  • Windows cargo check -p mxc_engine -p mxc_ffi
  • Linux cross-check for x86_64-unknown-linux-gnu
  • Focused mxc_engine and mxc_ffi lifecycle tests
  • Node SDK build and unit-test compilation
  • Native streaming unit tests on Node.js 24.21.0
  • Integration TypeScript type-check

The native streaming integration workload was not run on this development machine.

✅ Checklist

📋 Issue Type

  • Bug fix
  • Feature
  • Task
Microsoft Reviewers: Open in CodeFlow

Move blocking stream, process-control, timeout, and state-aware execution work onto native threads and expose callback-driven completion through mxc_ffi.

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

Copilot-Session: bbe1ffbf-7cf8-48a0-8e3b-956f1d634e6c
Transfer caller-owned native pipe endpoints for the four pipe-backed streaming backends and expose them through the SDK and C ABI.

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

Copilot-Session: bbe1ffbf-7cf8-48a0-8e3b-956f1d634e6c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: bbe1ffbf-7cf8-48a0-8e3b-956f1d634e6c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: bbe1ffbf-7cf8-48a0-8e3b-956f1d634e6c
@bbonaby
Branden Bonaby (bbonaby) requested a review from a team as a code owner September 19, 2026 00:39
Copilot AI balanced review requested due to automatic review settings September 19, 2026 00:39
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@bbonaby

Copy link
Copy Markdown
Collaborator Author

Closing because this PR was opened prematurely without the user's authorization. The branch remains available for continued work.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Wrapper omissions break native streaming, stdin errors can incorrectly fail waits, and both npm lockfiles violate CI integrity rules.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 2 High severity · 5 Medium severity

Open (7)
What changed in this PR

Reworks Node SDK streaming to transfer native stdio handles while Rust retains process lifecycle control.

Changes:

  • Adds native stdio ownership and lifecycle coordination across Rust, FFI, and Node.
  • Adds streaming tests and raises the minimum Node.js version to 24.21.0.
  • Updates documentation, dependencies, and CI environments.
File Description
src/​ffi/​mxc_ffi/​src/​lib.rs Exposes event-loop streaming FFI.
src/​ffi/​mxc_ffi/​src/​io_coordinator.rs Implements native lifecycle C APIs.
src/​ffi/​mxc_ffi/​Cargo.toml Adds engine dependency.
src/​ffi/​mxc_ffi/​build.rs Tracks the new FFI source.
src/​core/​wxc_common/​src/​sandbox_process.rs Adds native stdio abstractions.
src/​core/​wxc_common/​src/​process_util.rs Adds Windows handle duplication.
src/​core/​wxc_common/​src/​interruptible_reader.rs Adds Unix descriptor duplication.
src/​core/​wxc_common/​src/​exec_stream.rs Exposes exec native endpoints.
src/​core/​mxc-sdk/​src/​sandbox.rs Forwards native stdio access.
src/​core/​mxc_engine/​src/​lib.rs Exports and integrates coordination.
src/​core/​mxc_engine/​src/​io_coordinator.rs Implements lifecycle coordination.
src/​core/​mxc_engine/​Cargo.toml Adds channel dependency.
src/​Cargo.toml Registers workspace dependency.
src/​Cargo.lock Updates Rust dependency resolution.
src/​backends/​seatbelt/​common/​src/​seatbelt_runner.rs Transfers Seatbelt endpoints.
src/​backends/​process_container/​common/​src/​dispatcher.rs Updates process wrapper delegation.
src/​backends/​process_container/​common/​src/​base_container_runner.rs Adds native handles and timeout state.
src/​backends/​process_container/​common/​src/​appcontainer_runner.rs Adds native handles and timeout state.
src/​backends/​isolation_session/​common/​src/​sandbox.rs Updates one-shot wrapper delegation.
src/​backends/​bubblewrap/​common/​src/​bwrap_runner.rs Transfers Bubblewrap endpoints.
sdk/​node/​tests/​unit/​streaming-binding.test.ts Tests native binding ownership.
sdk/​node/​tests/​unit/​sandbox-process.test.ts Tests lifecycle behavior.
sdk/​node/​tests/​integration/​package.json Updates integration dependencies.
sdk/​node/​tests/​integration/​package-lock.json Refreshes integration lock data.
sdk/​node/​tests/​integration/​native-streaming.test.ts Adds native streaming integration coverage.
sdk/​node/​src/​sandbox-process.ts Implements Node process lifecycle API.
sdk/​node/​src/​bindings/​streaming.ts Adopts native handles as streams.
sdk/​node/​README.md Documents the Node requirement.
sdk/​node/​package.json Raises the Node engine version.
sdk/​node/​package-lock.json Refreshes SDK lock data.
docs/​isolation-session/​state-aware-rust.md Documents state-aware streaming.
docs/​architecture.md Updates SDK and FFI architecture.
.github/​workflows/​Versioning.Checks.Job.yml Updates versioning CI Node runtime.
.github/​workflows/​SDK.Unit.Test.Job.yml Updates unit-test Node runtime.
.github/​workflows/​SDK.Integration.Test.Job.yml Updates integration-test Node runtime.
.github/​workflows/​Package.NpmSdk.Job.yml Updates packaging Node runtime.
.github/​workflows/​Package.Lock.Check.Job.yml Updates lock-check Node runtime.
.azure-pipelines/​templates/​SDK.Unit.Test.Job.yml Updates Azure unit-test runtime.
.azure-pipelines/​templates/​SDK.Integration.Test.Job.yml Updates Azure integration runtime.
.azure-pipelines/​templates/​Package.NpmSdk.Job.yml Updates Azure packaging runtime.
.azure-pipelines/​templates/​Package.Lock.Check.Job.yml Updates Azure lock-check runtime.
.azure-pipelines/​templates/​IsolationSession.TestBundle.Build.Job.yml Updates test-bundle Node runtime.
Files not reviewed (2)
  • sdk/node/package-lock.json: Generated file
  • sdk/node/tests/integration/package-lock.json: Generated file

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

Comment on lines +380 to +381
"resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/node/-/node-24.13.4.tgz",
"integrity": "sha1-5U90zq5oOL/1eoFLfTH1BCoPkHQ=",
Comment on lines +23 to +24
"resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@koromix/koffi-android-arm64/-/koffi-android-arm64-3.2.1.tgz",
"integrity": "sha1-Lc55jTZp0re1bpwCqKaidKvWx8Y=",
this.rejectWait = reject;
});
void this.waitPromise.catch(() => {});
this.input?.on('error', (error) => void this.finish(undefined, asError(error)));
Comment on lines +315 to +317
fn stdin_closer(&self) -> Option<Box<dyn StreamCloser>> {
self.inner.stdin_closer()
}
Comment on lines +781 to +783
fn stdin_closer(&self) -> Option<Box<dyn wxc_common::sandbox_process::StreamCloser>> {
self.inner.stdin_closer()
}
Comment on lines +527 to +529
fn stdin_closer(&self) -> Option<Box<dyn wxc_common::sandbox_process::StreamCloser>> {
self.inner.stdin_closer()
}
Comment on lines +648 to +650
fn stdin_closer(&self) -> Option<Box<dyn wxc_common::sandbox_process::StreamCloser>> {
self.inner.stdin_closer()
}
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.

2 participants