fix: redirect raw fd1 writes in MCP mode, add cloud_sync alias for /set#143
Conversation
- MCP mode previously only reassigned Go's os.Stdout to stderr, which protects fmt.Print calls but not lower-level fd 1 writes from subprocesses/libraries. redirectStdoutForMCP additionally dup2's the real fd 1 to stderr on Unix, so stray writes can't corrupt the newline-delimited JSON-RPC stream the client reads. - /set cloudsync only matched the undocumented key name; add the documented cloud_sync key as the primary spelling, keeping cloudsync as a legacy alias.
Sigilix OverviewEffort: 4/5 (large) Quality gates
Summary — latest pushFixes a transport-corruption bug in MCP mode where raw fd 1 writes from subprocesses bypassed Go's os.Stdout variable swap and poisoned the newline-delimited JSON-RPC stream. The fix introduces a platform-aware redirectStdoutForMCP that dup2s fd 1 to stderr on Unix while preserving the original fd for the JSON-RPC encoder, with a variable-swap fallback on other platforms. Also adds cloud_sync as the documented primary key for /set, keeping cloudsync as a legacy alias. Important files
Sequence diagramsequenceDiagram
participant Client
participant RunServer
participant redirectStdoutForMCP
participant serveMCP
Client->>RunServer: Start MCP mode
RunServer->>redirectStdoutForMCP: Call
redirectStdoutForMCP->>redirectStdoutForMCP: Dup original fd 1 (jsonOut)
redirectStdoutForMCP->>redirectStdoutForMCP: Dup2 stderr -> fd 1
redirectStdoutForMCP-->>RunServer: Return jsonOut & restore func
RunServer->>serveMCP: Pass jsonOut for JSON-RPC
Note over Client: Raw fd 1 writes now go to stderr
serveMCP-->>Client: JSON-RPC responses on jsonOut
RunServer->>RunServer: defer restoreStdout()
Note over RunServer: Dup2 restore fd -> fd 1 & close
Confidence: 4/5The core fd redirection logic is well-isolated with a targeted integration test verifying the exact corruption scenario, though the Unix dup2 manipulation warrants careful review of fd lifecycle and restore edge cases.
Suggested labels:
|
✅ QualityMax Pipeline
Powered by QualityMax — AI-Powered Test Automation |
Summary
qmax-code serve --mcp) previously only reassigned Go'sos.Stdoutvariable toos.Stderr, which protects normalfmt.Printcalls but not raw fd 1 writes made by subprocesses or lower-level libraries. Those stray writes corrupt the newline-delimited JSON-RPC stream the client (Codex/CC rmcp) reads, killing the transport worker.redirectStdoutForMCPadditionallydup2s the real fd 1 to stderr on Unix (Linux/macOS), with a plain variable-swap fallback on other platforms./set cloudsynconly matched the undocumented key namecloudsync;cloud_sync(the documented key) now works as the primary spelling, withcloudsynckept as a legacy alias.Test plan
go build ./...go vet ./...go test -count=1 ./internal/mcp/... ./internal/repl/...— includes newTestRunServerRedirectsFDStdoutAwayFromJSONRPC(verifies raw fd1 writes land on stderr, not the JSON-RPC stdout stream) and new/set cloud_synccoverage inrepl_set_test.go