fix(update): pipe post-core child stdio on Windows to prevent terminal hang (#78445)#78483
Conversation
|
Codex review: needs real behavior proof before merge. Summary Reproducibility: no. high-confidence live reproduction was established in this review. Source inspection shows current main uses inherited stdio in the post-core child and the linked issue gives concrete Windows PowerShell steps, but the PR still needs a real Windows after-fix run. Real behavior proof Next step before merge Security Review detailsBest possible solution: Keep the focused Windows stdio change if Windows package-update proof shows the prompt returns, and use a separate follow-up only if live proof shows a remaining child-wait hang. Do we have a high-confidence way to reproduce the issue? No high-confidence live reproduction was established in this review. Source inspection shows current main uses inherited stdio in the post-core child and the linked issue gives concrete Windows PowerShell steps, but the PR still needs a real Windows after-fix run. Is this the best way to solve the issue? Unclear as a complete fix until Windows proof is supplied. The stdio switch is narrow and plausible, but the merge-ready path is to show a real package-install Acceptance criteria:
What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 9324af7d46bf. |
32511d9 to
fa09b11
Compare
fa09b11 to
75fdac6
Compare
|
Maintainer pass update:
Prepared head pushed: |
…l hang On Windows, spawning the post-core-update Node.js process with stdio:"inherit" passes the parent's console HANDLE to the child and any grandchildren it spawns (doctor, gateway restart, etc.). PowerShell/CMD will not return the prompt until every holder of those handles exits, causing the terminal to hang indefinitely even though `openclaw update` has finished and the new version is installed. Fix: resolve the child's stdio mode through a new exported helper `resolvePostCoreUpdateChildStdio` that returns "pipe" on Windows and "inherit" everywhere else. When piped, the child's stdout/stderr are relayed to the parent process so terminal output is preserved. Adds two unit tests for the stdio resolution helper, one per platform class (win32 vs non-Windows). Fixes openclaw#78445. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
75fdac6 to
321608e
Compare
|
Refreshed again after
Latest prepared head: |
Fixes openclaw#78445. - Use piped stdio for the post-core update child on Windows so the child and descendants do not inherit the parent console handles. - Relay child stdout/stderr back to the parent when piped so update output remains visible. - Keep non-Windows behavior on inherited stdio. - Add focused coverage for the stdio resolver. Verification: - `pnpm vitest run src/cli/update-cli/update-command.test.ts` - `pnpm build` - `pnpm exec oxlint src/cli/update-cli/update-command.ts src/cli/update-cli/update-command.test.ts` - Full GitHub CI green at `321608e00ba118421ea65124f494458ed229defd`. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fixes openclaw#78445. - Use piped stdio for the post-core update child on Windows so the child and descendants do not inherit the parent console handles. - Relay child stdout/stderr back to the parent when piped so update output remains visible. - Keep non-Windows behavior on inherited stdio. - Add focused coverage for the stdio resolver. Verification: - `pnpm vitest run src/cli/update-cli/update-command.test.ts` - `pnpm build` - `pnpm exec oxlint src/cli/update-cli/update-command.ts src/cli/update-cli/update-command.test.ts` - Full GitHub CI green at `321608e00ba118421ea65124f494458ed229defd`. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
openclaw updatecompletes on Windows, the PowerShell/CMD prompt never returns. The upgrade itself succeeds (runningopenclaw --versionin a new window shows the new version), but the original terminal is permanently blocked.openclaw updatemust kill their PowerShell/CMD window and open a new one after every update, making the update experience broken on Windows.continuePostCoreUpdateInFreshProcessnow spawns the post-core-update child withstdio:"pipe"on Windows instead ofstdio:"inherit". A new exported helperresolvePostCoreUpdateChildStdioencapsulates the platform selection. When piped, the child's stdout/stderr streams are relayed to the parent process so terminal output is still displayed.stdio:"inherit"still used).stopPostCoreUpdateChild/taskkilllogic is unchanged. All non-Windows update paths are identical.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Real behavior proof (required for external PRs)
openclaw updatecompletes on Windows.pnpm test src/cli/update-cli/update-command.test.ts --reporter=verboseresolvePostCoreUpdateChildStdio > returns "pipe" on Windowspasses; macOS/Linux regression test passes; all existing tests green.openclaw updaterun on a real Windows PowerShell session — the bug is in the Windows console-handle inheritance model which is not reproducible in this macOS dev environment. The logic is mechanically correct per Node.js docs.Root Cause (if applicable)
continuePostCoreUpdateInFreshProcesscalledspawn(node, argv, { stdio: "inherit" }). On Windows,stdio:"inherit"passes the calling process'sSTDIN,STDOUT, andSTDERRhandles (which are Windows console HANDLE objects) directly to the child via handle inheritance. The WindowsConsolesubsystem keeps the console "attached" to any process that holds an open handle. PowerShell/CMD waits for the console to be fully released before returning the prompt. The child spawns its own sub-processes (doctor, gateway-restart wrapper, etc.) which also inherit those handles transitively. When the child exits, the grandchildren may still hold the handles, causing the hang.stdio:"inherit"works correctly on macOS/Linux because Unix shells track process exit viawait(), not console handle reference counting.Regression Test Plan (if applicable)
New tests for
resolvePostCoreUpdateChildStdio(the extracted helper):"returns 'pipe' on Windows so the child never inherits the parent console handles"— passes"win32"as platform, asserts result is"pipe"."returns 'inherit' on non-Windows platforms"— passes"linux"and"darwin", asserts result is"inherit"in both cases.Environment
Steps (to reproduce before fix on Windows)
openclaw updateExpected (after fix)
Actual (after fix)
stdio:"pipe"; output is relayed viachild.stdout.pipe(process.stdout)andchild.stderr.pipe(process.stderr); no console handles are inherited; terminal returns when the child process exits.Evidence
Human Verification (required)
resolvePostCoreUpdateChildStdio("win32")returns"pipe";resolvePostCoreUpdateChildStdio("linux")/"darwin"returns"inherit"; existing test suite still passes.child.stdout/child.stderrare only piped whenchildStdio === "pipe"(optional chaining guards against them being null when stdio is not piped).Review Conversations
Compatibility / Migration
Risks and Mitigations
stdio:"inherit".openclaw updatepass that primarily installs plugins and prints progress text — it does not use interactive TTY features. Any loss of color/formatting is a minor cosmetic trade-off for a working terminal prompt.