Skip to content

Releases: link-foundation/command-stream

[Rust] 0.12.0 (Rust)

11 Jun 08:53

Choose a tag to compare

Crates.io Docs.rs

Added

  • CommandResult::exit_code() accessor as an alias for the code field, mirroring the exitCode alias exposed by the JavaScript implementation (issue #36).

JavaScript 0.14.0

11 Jun 08:51

Choose a tag to compare

Add exitCode as an alias for the code property on all command result objects (issue #36). Code written against the exitCode convention (e.g. child_process / execa) now works without changes, while the existing code property remains fully supported.

Related Pull Request: #112


npm version

JavaScript 0.13.0

11 Jun 00:56

Choose a tag to compare

Handle getcwd() failed errors gracefully during subshell execution (issue #44).

process.cwd() throws getcwd() failed: No such file or directory when the current working directory has been deleted or becomes inaccessible (common in CI/CD with temporary directories). Subshell execution and directory restoration now degrade gracefully instead of crashing:

  • capturing the working directory before a subshell no longer throws when getcwd() fails
  • directory restoration falls back to a safe location (HOME, then /) when the original directory is gone
  • simple commands fall back to the inherited cwd when getcwd() is unavailable
  • spawning a child process no longer fails with posix_spawn ENOENT when the inherited working directory has been deleted; the process is launched from a valid fallback directory (HOME, USERPROFILE, the temp dir, then /) instead

Make the built-in cd command fully sh/bash compatible so shell scripts translate directly to .mjs (issue #50):

  • cd - switches to the previous directory and prints it, like sh
  • ~ and ~/path tilde expansion
  • successful cd updates the PWD and OLDPWD environment variables
  • relative targets resolve against the cwd option for consistency

Also documents the working-directory behavior (persistence across commands, subshell isolation, and cd vs. the cwd option) in the README.

Fix CI false positives where a global teardown preempted an in-flight, awaited command (issue #170).

Three related defects made tests intermittently report a SIGTERM result (exit code 143) and emit a MaxListenersExceeded warning, most visibly on Windows/Bun. All are now keyed on a new _awaited flag, set synchronously when user code starts consuming a runner (await/then/catch/finally/stream):

  • _handleParentStreamClosure() killed any active runner when a parent stdout/stderr close event fired. On Windows/Bun the parent WriteStream can emit a spurious close (the same instability behind the MaxListenersExceeded warning), which preempted the awaited command and replaced its real exit code with 143. It now skips runners that are being awaited, since the await is the authoritative consumer. This was the actual CI trigger.
  • cleanupActiveRunners() (invoked by resetGlobalState() between tests) could force-kill a command that user code was still awaiting, replacing its real exit code with a synthetic SIGTERM result. The reaper now skips awaited, unfinished runners.
  • monitorParentStreams() attached a close listener to process.stdout/process.stderr on every ProcessRunner construction but never removed them on reset, so they accumulated until Node/Bun emitted a MaxListenersExceeded warning. The listeners are now tracked and removed in resetGlobalState()/resetParentStreamMonitoring().

Related Pull Request: #171


npm version

[Rust] 0.11.1 (Rust)

10 Jun 22:43

Choose a tag to compare

Crates.io Docs.rs

Fixed

  • Handle getcwd()/current_dir() failures during command execution (issue #44). When the inherited working directory has been deleted or becomes inaccessible, the child process is now spawned from a valid fallback directory (HOME, USERPROFILE, the temp dir, then /) instead of failing at the OS level. Applies to both ProcessRunner and Pipeline.

[Rust] 0.11.0 (Rust)

10 Jun 10:44

Choose a tag to compare

Crates.io Docs.rs

Changed

  • Make the built-in cd command fully sh/bash compatible so shell scripts translate directly to Rust (issue #50):
    • cd - switches to the previous directory and prints it, like sh
    • ~ and ~/path tilde expansion
    • a successful cd updates the PWD and OLDPWD environment variables
    • relative targets resolve against the cwd option for consistency

[Rust] 0.10.0 (Rust)

10 Jun 00:33

Choose a tag to compare

Crates.io Docs.rs

Added

  • StreamingRunner::kill_signal to configure the signal used to stop a process
    (default SIGTERM), mirroring the JavaScript killSignal option.
  • StreamingRunner::exit_pump_grace_ms to configure the post-exit pipe drain
    grace period (default 100ms).
  • OutputStream::kill / OutputStream::kill_with to stop a streaming process
    from inside the consumption loop; abandoning the stream (drop/break) now
    stops the process too.

Fixed

  • OutputStream no longer hangs when the process has exited but a grandchild
    keeps the stdio pipes open: readers are drained with a grace period and then
    aborted, and the exit chunk is always delivered (parity with the JavaScript
    fix for issue #155).

JavaScript 0.12.0

10 Jun 00:32

Choose a tag to compare

Fix stream() async iterator to yield exit chunks and never hang on open pipes (issue #155)

  • stream() now yields a final { type: 'exit', code } chunk when the process
    exits, so the documented chunk.type === 'exit' handling is no longer dead
    code. Consumers that touch chunk.data must guard on chunk.type first.
  • Both stream() and awaiting a command no longer hang forever when the process
    has exited but a grandchild keeps the stdio pipes open (e.g.
    sh -c 'long-task & echo done'). The command resolves as soon as the process
    exits; remaining buffered output is drained within a short grace period before
    the lingering reads are aborted.
  • The grace period is configurable via the exitPumpGrace option (milliseconds,
    default 100). For ordinary commands the pumps drain immediately, so the grace
    adds no latency — it only bounds the wait in the grandchild-holds-pipe case.
  • A long-running command can be stopped from inside the stream() loop, either by
    calling kill() (the loop then ends with a terminating exit chunk) or by
    breaking out of the loop (which kills the process as the iterator unwinds).
  • The stop signal is configurable via the new killSignal option (default
    SIGTERM). An argument-less kill(), a break, and an external AbortSignal
    all use it; an explicit kill(signal) argument still overrides it. Exit codes
    follow the conventional 128 + signal mapping (e.g. SIGINT => 130).
  • Awaiting a command while an external AbortSignal fires no longer hangs: the
    abort listener is now registered on the await/then path too, so the command
    resolves promptly with the configured signal's exit code.

Related Pull Request: #169


npm version

[Rust] 0.9.6 (Rust)

09 Jun 14:40

Choose a tag to compare

Crates.io Docs.rs

Changed

  • Separate Rust crate documentation, release scripts, changelog fragments, and
    GitHub release tags from the JavaScript npm package release path.

Fixed

  • Ensure the Rust release job still evaluates on main pushes after the
    pull-request-only changelog gate is skipped.

Fixed

  • Rebase onto the latest origin/<branch> before staging the version bump
    in the Rust release script, so concurrent releases no longer abort with
    "cannot rebase: Your index contains uncommitted changes". The release now
    syncs on a clean working tree, matching the JavaScript release script.

JavaScript 0.11.1

09 Jun 19:14

Choose a tag to compare

Fix false-positive releases and the "failed to deploy" restart in the JavaScript
release pipeline (issue #166):

  • publish-to-npm.mjs: only report success when output-scan, exit code, and an
    npm view registry check all agree — a failed changeset publish (e.g. npm
    E404) can no longer create a GitHub release for a version that never reached
    npm.
  • check-release-needed.mjs: always probe npm and emit current_unpublished,
    so a version that was committed to main but never published self-heals on the
    next push regardless of changeset state (closes the restart that "failed to do
    any deploy").
  • New wait-for-npm.mjs step verifies, after publish, that the exact version is
    actually installable from npm — turning any "tagged but not on npm" divergence
    into a hard CI failure.
  • setup-npm.mjs now asserts npm ≥ 11.5.1 (required for OIDC trusted
    publishing) and create-github-release.mjs caps the release-notes body and is
    idempotent on an already-existing release.

Related Pull Request: #168


npm version

JavaScript 0.11.0

09 Jun 18:47

Choose a tag to compare

Add literal() function to preserve apostrophes in shell arguments

When passing text containing apostrophes to programs that store it literally (like API calls via CLI tools), apostrophes would appear corrupted as triple quotes ('''). The new literal() function uses double-quote escaping which preserves apostrophes while still escaping shell-dangerous characters.

New features:

  • literal(value) - Mark text for double-quote escaping, preserving apostrophes
  • quoteLiteral(value) - Low-level function for manual command building

Usage:

import { $, literal } from 'command-stream';

// Apostrophes now preserved for API storage
const notes = "Dependencies didn't exist";
await $`gh release create --notes ${literal(notes)}`;

Related Pull Request: #148


npm version