You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Running vip @app.environment wp against a WebSocket environment sent an empty command to the API instead of opening the interactive shell. Restore the Go shell loop so commands are triggered only after input, retain the prompt between commands, and print API errors once without GraphQL location prefixes.
Update Node WebSocket completion so explicit remote exit events return to the shell and preserve delayed nonzero statuses. Add terminal editing, safe stdin handoff, Ctrl-C delivery to remote stdin, and terminal restoration on interruption. Replace the obsolete WebSocket redirect fixture with real Node-versus-Go subprocess coverage.
Browser-launch test stubbing is intentionally excluded and will be handled separately.
Changelog Description
Fixed
WP-CLI: Restore the interactive WebSocket shell in VIP CLI 5 and keep the shell available after command failures.
WP-CLI: Avoid duplicate API errors and retain remote command exit statuses.
Pull request checklist
Add automated regression tests for both runtimes.
Build both runtimes and run relevant checks.
Manually test against a live VIP environment
No new environment variables or documented command syntax changes.
Steps to Test
Run npm run build and make build.
Run npm run jest -- --runTestsByPath __tests__/commands/wp-ssh.ts __tests__/lib/cli/command-wp-matrix.test.js --runInBand.
Run go test -race ./cmd/vip-next/commands ./internal/wpshell ./internal/wpstream -run 'TestWP|TestREPL|TestInput|TestEngineIO|TestClient|TestRun|TestStream|TestSocket' -count=1 with ambient proxy variables cleared.
Run NODE_VIP_BIN=$PWD/dist/bin/vip.js go test -tags=parity -count=1 ./internal/parity -run '^(TestWPWebsocket|TestEverySurfaceScenarioIsClassified|TestSurfaceClassificationIsExclusive)' -v.
Run npm run check-types, npm run cmd:lint -- src/bin/vip-wp.js, and make lint.
These checks passed locally. The focused subprocess checks also passed with hostile ambient credentials, API-host, and proxy settings; no tests skipped. They cover opening and exiting the shell, invalid input, API errors, successive successful commands, stdout EOF before a nonzero exit event, one-shot exit codes, PTY interaction, remote Ctrl-C byte delivery, and terminal restoration after SIGTERM.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Reconnection timers and listeners can terminate resumed jobs or duplicate exit handling, while repeated remote interruptions exit the shell unexpectedly.
Cumulative interrupt count cancels later commands on first Ctrl-C
cmd/vip-next/commands/wp.go:174
interrupts is cumulative for the entire shell session. After Ctrl-C is forwarded to one remote command, it remains 1, so the first Ctrl-C during any later command satisfies interrupts > 1, cancels the whole shell, and is never delivered remotely. Reset the counter when each command starts, and mirror that reset for Node's countSIGINT to preserve cross-runtime behavior.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
SIGTERM handling changes exit semantics, and one-shot Node.js completion can lose telemetry.
0 open findings
Previously missed (1)
In code that hasn't changed since last review
Preserve SIGTERM exit semantics instead of returning context.Canceled
cmd/vip-next/commands/wp.go:161
signal.NotifyContext consumes SIGTERM, but the resulting context.Canceled is returned from the command and main prints it as an error and exits with code 1. Consequently kill -TERM no longer preserves normal signal termination semantics and emits a spurious Error: context canceled. Handle the signal explicitly so terminal restoration runs, then restore/re-deliver the signal (or otherwise preserve its exit status) instead of returning the context error.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Reconnect timing can terminate a resumed Node command, and multiline Go input renders incorrect prompts.
0 open findings
Previously missed (1)
In code that hasn't changed since last review
Suppress repeated prompts while reading multiline commands
internal/wpshell/repl.go:32
In terminal mode, term.Terminal.ReadLine renders its prompt on every call. A multiline quoted WP command leaves the parser incomplete and loops back here, so Go prints another full shell prompt for each continuation line, while the Node shell only prompts initially and after a completed command. The line-reader API needs a continuation mode that reads the next physical line without rendering the normal prompt.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Go derives remote stdin normalization from stdout TTY state, breaking interactive input when stdout is redirected.
0 open findings
Previously missed (1)
In code that hasn't changed since last review
Derive IsTTY from stdin instead of stdout
cmd/vip-next/commands/wp.go:505
IsTTY controls CR→LF conversion in wpstream, but it is still derived from os.Stdout while this path now supplies stdin independently. With terminal stdin and redirected stdout (for example, vip … wp >log), the shell enters raw mode but remote stdin receives \r instead of \n, unlike Node which keys normalization off stdin. Determine TTY status from cmd.InOrStdin() before passing this reader.
This reconnect path can drop the first byte entered after reconnection. Each runOnce starts an io.Copy from the same opts.Stdin; abortAll only aborts the old destination stream, so when the old copier is blocked in Read, the new copier waits behind it. The next byte is consumed by the old copier and then discarded when its write hits the aborted stream. Use a single stdin pump that can switch active streams, or otherwise cancel and fully join the prior attempt without consuming input before starting the next attempt.
Addressed both reconnect findings in 58b81bc: a single stdin pump now spans reconnect attempts, and queued exit packets/status take priority over transport failure. Added unit regressions and real Node/Go parity coverage. Also isolated release-promotion test HTTP transports in 9cae212 to prevent parallel httptest server shutdown from interrupting asset uploads. Validation: 37 focused Node tests, Node build/type-check, focused Go race tests, 100 race-enabled release-promotion runs, 11 WP differential tests without skips, five repeated runs of both new differential tests, Go vet, and Windows cross-compilation. Full Go tests were not run locally because existing unrelated tests open a browser; CI has been triggered by the push.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Running
vip @app.environment wpagainst a WebSocket environment sent an empty command to the API instead of opening the interactive shell. Restore the Go shell loop so commands are triggered only after input, retain the prompt between commands, and print API errors once without GraphQL location prefixes.Update Node WebSocket completion so explicit remote exit events return to the shell and preserve delayed nonzero statuses. Add terminal editing, safe stdin handoff, Ctrl-C delivery to remote stdin, and terminal restoration on interruption. Replace the obsolete WebSocket redirect fixture with real Node-versus-Go subprocess coverage.
Fixes #3096.
Browser-launch test stubbing is intentionally excluded and will be handled separately.
Changelog Description
Fixed
Pull request checklist
Steps to Test
npm run buildandmake build.npm run jest -- --runTestsByPath __tests__/commands/wp-ssh.ts __tests__/lib/cli/command-wp-matrix.test.js --runInBand.go test -race ./cmd/vip-next/commands ./internal/wpshell ./internal/wpstream -run 'TestWP|TestREPL|TestInput|TestEngineIO|TestClient|TestRun|TestStream|TestSocket' -count=1with ambient proxy variables cleared.NODE_VIP_BIN=$PWD/dist/bin/vip.js go test -tags=parity -count=1 ./internal/parity -run '^(TestWPWebsocket|TestEverySurfaceScenarioIsClassified|TestSurfaceClassificationIsExclusive)' -v.npm run check-types,npm run cmd:lint -- src/bin/vip-wp.js, andmake lint.These checks passed locally. The focused subprocess checks also passed with hostile ambient credentials, API-host, and proxy settings; no tests skipped. They cover opening and exiting the shell, invalid input, API errors, successive successful commands, stdout EOF before a nonzero exit event, one-shot exit codes, PTY interaction, remote Ctrl-C byte delivery, and terminal restoration after SIGTERM.
Ref: PLTFRM-3036