Nocter v0.31.0 Release Notes
Nocter v0.31.0 adds complete standard-output and standard-error capture to the synchronous subprocess API. A consumed Command now returns an owning Output containing arbitrary bytes from both streams and the child's typed terminal status. The only implemented host and native target remains arm64-darwin.
Captured Commands
std/process now exposes:
use std/process.Command
use std/string.String
var command = Command.new("./helper")?
command.arg("one argument")?
let output = command.output()?
let stdout = String.from_utf8(&output.stdout)?
let stderr = String.from_utf8(&output.stderr)?
Command.output inherits standard input, the environment, and the working directory. It creates exactly one child, captures stdout and stderr simultaneously, waits for that exact child, and returns only after both byte streams reach end of file and the terminal state is observed. The returned Output owns all three values and contains no live descriptor or process handle.
The streams are Vec<u8> rather than String because process output need not be UTF-8. A caller that knows a text contract validates it explicitly with String.from_utf8. Each stream preserves its own byte order; no ordering between stdout and stderr is invented.
Closed Capture Lifecycle
Both finite pipes are drained through one fair readiness loop while the child can still run. This prevents a child that fills either stream from deadlocking behind a sequential whole-stream read. Hangup does not discard buffered bytes, interrupted operations are retried, and descriptors are normalized away from standard descriptors before child setup.
A private close-on-exec report distinguishes standard-descriptor setup failure from executable rejection without reserving a child exit code. Every representable post-fork error path closes owned descriptors and attempts to observe the exact child before returning. Nonzero exit and signal termination remain successful observations and retain all bytes written before termination.
Practical Integration
The new subprocess-output package example invokes a repository-owned helper, passes one whitespace-bearing argument, verifies a typed nonzero exit, converts both streams explicitly to UTF-8, and prints a deterministic report. The same authored source crosses native execution, formatter checks, semantic diagnostics, hover, completion, declaration and implementation navigation, and installed-home qualification.
Compatibility and Non-goals
This release adds API without changing Command.status or existing process argument, environment, current-directory, exit, and abort behavior. It does not add an asynchronous child handle, incremental stream access, input redirection, caller-provided descriptors, merged output, bounded capture, timeout, PATH search, shell execution, environment edits, working-directory overrides, or another native target.
Candidate Qualification
Release-content commit c06cb1b1ca86622c926b4a4dcbfd08fb481acb96 passed two independent locked workspace runs with 1,539 tests passed, zero failed, and one ignored in each run. The ignored public-HTTPS acquisition test passed separately. Warnings-denied all-target Clippy, no-default-features checking, deterministic documentation, formatter checks, and repository validation also passed.
Two independent optimized builds produced the same archive and installed home. The retained local archive is 8,286,135 bytes and has SHA-256 914ad97e360f8451aa2c212a21445af7ec457d1cc64d102f64a181fd6c563453. Its isolated installed home passed version and integrity checks, every public example, package run/build/test/graph operations, the exact text-banner, stdin-prefix, subprocess-status, and subprocess-output process contracts, framed LSP requests, immutability checking, and compiler and standard-library tamper rejection. Publication reuses that retained candidate without rebuilding it.