fix: preserve stderr-only CLI output semantics (#47) - #102
Conversation
Adding CLAUDE.md with task information for AI processing. This file will be removed when the task is complete. Issue: #47
- Add needsRealShell() check to virtual command bypass logic - Ensure commands with stderr redirection (>&2, 2>&1) use real shell - Add comprehensive test suite for stderr redirection scenarios - Fixes issue where gh pr create output wasn't captured properly - Update version to 0.7.2 This resolves GitHub issue #47 where gh pr create output was not properly captured because the virtual echo command was being used instead of falling back to the real shell for stderr redirection. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
|
We should double check more cases similar like this, make sure we have test coverage similar to all our competitors, and select behavior closer to how it would behave in sh scripts or with least surprise based on best practices from competitors. If there multiple options we should allow to configure, and use closer to sh behavior by default. We also must support all our supported language versions. |
|
🤖 AI Work Session Started Starting automated work session at 2026-09-15T12:27:15.278Z The PR has been converted to draft mode while work is in progress. This comment marks the beginning of an AI work session. Please wait for the session to finish, and provide your feedback. Runtime: solve |
# Conflicts: # js/examples/comprehensive-stderr-test.mjs # js/examples/debug-2to1.mjs # js/examples/debug-stderr-redirection.mjs # js/examples/simple-stderr-test.mjs # js/examples/test-gh-pr-create-fix.mjs # js/examples/test-gh-pr-create-issue.mjs # js/tests/stderr-redirection.test.mjs # package.json # src/$.mjs # src/shell-parser.mjs
Working session summaryImplemented and finalized PR #102.
This summary was automatically extracted from the AI working session output. |
🤖 Solution Draft LogThis log file contains the complete execution trace of the AI solution draft process. 💰 Cost estimation:
📊 Context and tokens usage:
Total: (284.6K + 8.6M cached) input tokens, 39.5K output tokens, $10.362001 cost 🤖 Models used:
📎 Log file uploaded as Gist (4552KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
✅ Ready to mergeThis pull request is now ready to be merged:
Monitored by hive-mind with --auto-restart-until-mergeable flag |
Summary
stderrin both JavaScript and Rust./bin/shparity suites with stdout-only, stderr-only PR URL, mixed-stream, and explicit2>&1cases.Resolves #47.
Root cause and selected behavior
The issue reported an empty
stdoutwhen agh pr createversion wrote its success URL to file descriptor 2. An emptystdoutis expected in that case: shells and process libraries preserve the child-selected descriptor, and command-stream exposes the URL throughresult.stderr.There was also a historical virtual-command bug: a command such as
echo URL >&2could treat>&2as literal data instead of shell syntax. The cross-language real-shell routing fix landed onmainin #103; this branch now includes that fix and adds the missing stderr assertions that prevent a regression.The least-surprising default remains shell-compatible separation:
result.stdoutresult.stderr2>&1No new library setting is needed: standard
2>&1is the opt-in configuration for callers that want one combined stream, while the default retains information instead of silently relabelling it.Reproduction and coverage
On the historical 0.7.1 implementation, the minimal shell simulation produced the wrong result:
The same case now matches
/bin/sh:stdoutis empty andstderrcontains the URL. An explicit2>&1case verifies the inverse capture.The
stdout-stderr-separationbehavior port is shared by every selected competitor source in the audited corpora: 12 JavaScript/runtime sources and 14 Rust process libraries/runtime primitives. The focused parity suites also compare exit code, filesystem effects, stdout, and stderr directly with/bin/shin both implementations.Verification
bun test js/tests/ --timeout 10000— 1,407 passed, 6 skipped, 0 failedcargo test --manifest-path rust/Cargo.toml --all-features --verbose— passed, including doctestsbun run check— ESLint, formatting, and duplication gates passedcargo fmt --all -- --check, Clippy with warnings denied, and rustdoc with warnings denied — passed/bin/shThis is not a UI change, so screenshots are not applicable.