Skip to content

fix(status): keep stdout clean for status --json during gateway recovery#4644

Merged
cv merged 3 commits into
NVIDIA:mainfrom
latenighthackathon:fix/status-json-stdout-recovery
Jun 3, 2026
Merged

fix(status): keep stdout clean for status --json during gateway recovery#4644
cv merged 3 commits into
NVIDIA:mainfrom
latenighthackathon:fix/status-json-stdout-recovery

Conversation

@latenighthackathon

@latenighthackathon latenighthackathon commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Summary

status --json is meant to print only a machine-readable document on stdout, but when the status check finds the gateway in a recoverable error state it reconciles (recovers) the gateway while building the report, and that recovery streams human progress ([2/8] Starting OpenShell gateway, Starting gateway cluster..., Waiting for gateway health...) to stdout. Those lines land ahead of the JSON, so the stdout stream is not valid JSON and anything piping status --json into a parser fails. This builds the --json report under a small stdout guard that redirects such writes to stderr, so the machine-readable document on stdout stays parseable while the progress stays visible on stderr. The plain (non---json) status view is unchanged. During review, this was extended to the other gateway-recovery-adjacent JSON paths (list --json and sandbox doctor --json) so their structured stdout stays clean if report construction has to recover the gateway as well.

Related Issue

Fixes #4643

Changes

  • Added withStdoutRedirectedToStderr (src/lib/cli/stdout-guard.ts), which runs a callback with process.stdout writes sent to process.stderr and restores the original writer afterwards (including when the callback throws).
  • getSandboxStatusReport now builds the report under that guard, so the gateway reconcile/recovery progress it can trigger no longer reaches stdout on the --json path. The human showSandboxStatus path is untouched and keeps printing that progress as before.
  • list --json now builds the sandbox inventory under the same guard, covering inventory recovery that can reattach/restart the named gateway while preparing the JSON payload.
  • sandbox doctor --json now builds diagnostics under the same guard, covering doctor’s gateway recovery probe before oclif serializes the report.
  • Threaded an optional reconcile seam into the report builder so the stdout-cleanliness behavior is unit-testable without a live gateway.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)

Verification

  • Added a regression test that the --json report builder keeps stdout clean while the reconcile path writes progress (fails before the guard, passes after), plus unit tests for the guard itself (redirect, restore, restore-on-throw)
  • Added adapter-level regressions for list --json and sandbox doctor --json to verify progress writes are redirected away from stdout before oclif emits JSON
  • No secrets, API keys, or credentials committed

Ran: the status --json suite (7 passing), the new stdout-guard and sandbox-status-json-stdout tests, the global/sandbox oclif adapter regression tests, typecheck:cli, and markdownlint/biome lint on the touched files (all clean). The push hook also re-ran CLI typecheck and CLI tests successfully.

Signed-off-by: latenighthackathon latenighthackathon@users.noreply.github.com

Summary by CodeRabbit

  • New Features

    • JSON output paths now keep progress/logging off of stdout so machine-readable output remains clean.
  • Bug Fixes

    • Commands that emit JSON no longer have human-progress text interleaved with their JSON payloads.
  • Tests

    • Added tests ensuring progress output is redirected away from stdout and JSON responses remain intact.

@copy-pr-bot

copy-pr-bot Bot commented Jun 2, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a helper to redirect stdout writes to stderr during async work, applies it to sandbox status/report and JSON CLI paths (list, sandbox doctor), and adds unit and integration tests ensuring human progress output does not appear on stdout when --json is used.

Changes

Stdout Redirection for JSON Status Reports

Layer / File(s) Summary
Stdout redirection utility
src/lib/cli/stdout-guard.ts
withStdoutRedirectedToStderr async wrapper temporarily replaces process.stdout.write with process.stderr.write and restores it in a finally block.
Status report dependency injection and stdout protection
src/lib/actions/sandbox/status-snapshot.ts
collectSandboxStatusSnapshot gains an injectable deps.reconcile; getSandboxStatusReport wraps buildSandboxStatusReport in withStdoutRedirectedToStderr and accepts optional deps.
Stdout guard unit tests
test/stdout-guard.test.ts
Unit tests verify redirection to stderr during callback, correct return/rethrow behavior, and restoration of original process.stdout.write.
Status report integration tests
test/sandbox-status-json-stdout.test.ts
Integration test injects a reconcile that writes progress to stdout, asserts stdout remains empty, stderr contains progress, and the returned JSON report fields are correct.
List command JSON path and test
src/commands/list.ts, src/commands/global-oclif-command-adapters.test.ts
ListCommand uses the stdout-redirect wrapper for --json; test verifies inventory recovery progress is sent to stderr and final JSON is logged.
Sandbox doctor JSON path and test
src/commands/sandbox/doctor.ts, src/commands/sandbox/oclif-command-adapters.test.ts
sandbox:doctor JSON execution is wrapped with the stdout-redirect helper and quietJson: true; test ensures progress goes to stderr and final JSON is emitted on stdout via console.log.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

fix, NemoClaw CLI, Sandbox, v0.0.57

Suggested reviewers

  • cv
  • prekshivyas
  • cjagwani

Poem

🐰 I nudge the streams so JSON stays clear,
Progress to stderr — no parser will fear.
A hop, a redirect, a tidy small fix,
Now machine output parses without tricks. 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly describes the main fix: keeping stdout clean for status --json during gateway recovery.
Linked Issues check ✅ Passed All changes directly address issue #4643 requirements: withStdoutRedirectedToStderr guards --json output, progress routed to stderr, snapshot building protected, and tests verify clean stdout.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing stdout cleanliness for status --json; no out-of-scope modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

…ery (NVIDIA#4643)

status --json builds its report by reconciling the gateway, and on a
recoverable gateway error that reconcile streams human startup progress
("[2/8] Starting OpenShell gateway", "Starting gateway cluster...") to stdout
via console.log. On the --json path those lines land ahead of the JSON
document and make stdout unparseable.

Build the report under a stdout guard that redirects writes to stderr, so the
machine-readable document on stdout stays valid while recovery progress stays
visible on stderr. The plain (non --json) status view is unchanged.

Fixes NVIDIA#4643

Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
@latenighthackathon latenighthackathon force-pushed the fix/status-json-stdout-recovery branch from cd7f5b1 to 98b872e Compare June 2, 2026 04:57
@cv cv added the v0.0.58 Release target label Jun 3, 2026
@cv cv enabled auto-merge (squash) June 3, 2026 18:05
@cv cv merged commit 032f6d0 into NVIDIA:main Jun 3, 2026
18 checks passed
@wscurran wscurran added area: cli Command line interface, flags, terminal UX, or output bug-fix PR fixes a bug or regression labels Jun 3, 2026
@latenighthackathon latenighthackathon deleted the fix/status-json-stdout-recovery branch June 3, 2026 19:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: cli Command line interface, flags, terminal UX, or output bug-fix PR fixes a bug or regression v0.0.58 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

status --json emits non-JSON when the gateway is recovered during the status check

3 participants