From bbd4f3d99303a8f2e1daa729b42c8ad8764cc2ef Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 16:15:57 +0000 Subject: [PATCH 01/11] Initial plan From 4fcf188e61c79e7eda24940e1bf7f22e548c66e3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 16:19:08 +0000 Subject: [PATCH 02/11] Add exception handling to REPL to prevent session crashes Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- features/shell.feature | 38 ++++++++++++++++++++++++++++++++++++++ src/WP_CLI/Shell/REPL.php | 19 +++++++++++++++---- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/features/shell.feature b/features/shell.feature index d5595506..4cb42887 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -77,3 +77,41 @@ Feature: WordPress REPL """ history: -1: invalid option """ + + Scenario: Exception handling preserves session state + Given a WP install + And a session file: + """ + $foo = 'test_value'; + require 'nonexistent_file.txt'; + echo $foo; + """ + + When I run `wp shell --basic < session` + Then STDOUT should contain: + """ + test_value + """ + And STDERR should contain: + """ + Error: Failed opening required 'nonexistent_file.txt' + """ + + Scenario: Exception handling for expression errors + Given a WP install + And a session file: + """ + $bar = 'preserved'; + nonexistent_function(); + $bar; + """ + + When I run `wp shell --basic < session` + Then STDOUT should contain: + """ + string(9) "preserved" + """ + And STDERR should contain: + """ + Call to undefined function nonexistent_function() + """ diff --git a/src/WP_CLI/Shell/REPL.php b/src/WP_CLI/Shell/REPL.php index 99b8f1f8..3e0604fb 100644 --- a/src/WP_CLI/Shell/REPL.php +++ b/src/WP_CLI/Shell/REPL.php @@ -29,8 +29,13 @@ public function start() { if ( self::starts_with( self::non_expressions(), $line ) ) { ob_start(); - // phpcs:ignore Squiz.PHP.Eval.Discouraged -- This is meant to be a REPL, no way to avoid eval. - eval( $line ); + try { + // phpcs:ignore Squiz.PHP.Eval.Discouraged -- This is meant to be a REPL, no way to avoid eval. + eval( $line ); + } catch ( \Throwable $e ) { + // Display the error message but continue the session + fwrite( STDERR, $e . "\n" ); + } $out = (string) ob_get_clean(); if ( 0 < strlen( $out ) ) { $out = rtrim( $out, "\n" ) . "\n"; @@ -43,8 +48,14 @@ public function start() { // Write directly to STDOUT, to sidestep any output buffers created by plugins ob_start(); - // phpcs:ignore Squiz.PHP.Eval.Discouraged -- This is meant to be a REPL, no way to avoid eval. - $evl = eval( $line ); + try { + // phpcs:ignore Squiz.PHP.Eval.Discouraged -- This is meant to be a REPL, no way to avoid eval. + $evl = eval( $line ); + } catch ( \Throwable $e ) { + // Display the error message but continue the session + fwrite( STDERR, $e . "\n" ); + $evl = null; + } $out = (string) ob_get_clean(); if ( 0 < strlen( $out ) ) { echo rtrim( $out, "\n" ) . "\n"; From a234f7c94dea80db64987fe2b4bcbf173b2948de Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 16:20:44 +0000 Subject: [PATCH 03/11] Improve error message format for better user experience Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- src/WP_CLI/Shell/REPL.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WP_CLI/Shell/REPL.php b/src/WP_CLI/Shell/REPL.php index 3e0604fb..5008adc4 100644 --- a/src/WP_CLI/Shell/REPL.php +++ b/src/WP_CLI/Shell/REPL.php @@ -34,7 +34,7 @@ public function start() { eval( $line ); } catch ( \Throwable $e ) { // Display the error message but continue the session - fwrite( STDERR, $e . "\n" ); + fwrite( STDERR, get_class( $e ) . ': ' . $e->getMessage() . "\n" ); } $out = (string) ob_get_clean(); if ( 0 < strlen( $out ) ) { @@ -53,7 +53,7 @@ public function start() { $evl = eval( $line ); } catch ( \Throwable $e ) { // Display the error message but continue the session - fwrite( STDERR, $e . "\n" ); + fwrite( STDERR, get_class( $e ) . ': ' . $e->getMessage() . "\n" ); $evl = null; } $out = (string) ob_get_clean(); From c62bc6b9541e3b0d84481798be6309131773594d Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Wed, 4 Feb 2026 14:23:56 -0500 Subject: [PATCH 04/11] Update features/shell.feature Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- features/shell.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/shell.feature b/features/shell.feature index 4cb42887..e3f103bf 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -113,5 +113,5 @@ Feature: WordPress REPL """ And STDERR should contain: """ - Call to undefined function nonexistent_function() + Error: Call to undefined function nonexistent_function() """ From 6a4f313b8a4fae31e9021c7d3d0f007960085fec Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 19:27:33 +0000 Subject: [PATCH 05/11] Fix test failures: use 'try' instead of 'run' for STDERR output Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- features/shell.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/shell.feature b/features/shell.feature index e3f103bf..3fcf6ec8 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -87,7 +87,7 @@ Feature: WordPress REPL echo $foo; """ - When I run `wp shell --basic < session` + When I try `wp shell --basic < session` Then STDOUT should contain: """ test_value @@ -106,7 +106,7 @@ Feature: WordPress REPL $bar; """ - When I run `wp shell --basic < session` + When I try `wp shell --basic < session` Then STDOUT should contain: """ string(9) "preserved" From 0d5a5f2387c214b5e47ff7ed6f32ff58afd56368 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Mar 2026 21:45:44 +0000 Subject: [PATCH 06/11] Fix variable name after merge and code style Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- src/WP_CLI/Shell/REPL.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WP_CLI/Shell/REPL.php b/src/WP_CLI/Shell/REPL.php index 9bf29162..74d5c1ae 100644 --- a/src/WP_CLI/Shell/REPL.php +++ b/src/WP_CLI/Shell/REPL.php @@ -54,9 +54,9 @@ public function start() { } catch ( \Throwable $e ) { // Display the error message but continue the session fwrite( STDERR, get_class( $e ) . ': ' . $e->getMessage() . "\n" ); - $evl = null; + $__repl_eval_result = null; } - $__repl_output = (string) ob_get_clean(); + $__repl_output = (string) ob_get_clean(); if ( 0 < strlen( $__repl_output ) ) { echo rtrim( $__repl_output, "\n" ) . "\n"; } From a5c12f4a518ef7c6b6ea839a4879adb38c10b8a2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 08:53:28 +0000 Subject: [PATCH 07/11] Suppress PHP warnings in eval to show clean error messages Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- src/WP_CLI/Shell/REPL.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/WP_CLI/Shell/REPL.php b/src/WP_CLI/Shell/REPL.php index 74d5c1ae..cf94bfd6 100644 --- a/src/WP_CLI/Shell/REPL.php +++ b/src/WP_CLI/Shell/REPL.php @@ -30,8 +30,8 @@ public function start() { if ( self::starts_with( self::non_expressions(), $__repl_input_line ) ) { ob_start(); try { - // phpcs:ignore Squiz.PHP.Eval.Discouraged -- This is meant to be a REPL, no way to avoid eval. - eval( $__repl_input_line ); + // phpcs:ignore Squiz.PHP.Eval.Discouraged,WordPress.PHP.NoSilencedErrors.Discouraged -- This is meant to be a REPL, no way to avoid eval. Suppress PHP warnings to show clean error messages. + @eval( $__repl_input_line ); } catch ( \Throwable $e ) { // Display the error message but continue the session fwrite( STDERR, get_class( $e ) . ': ' . $e->getMessage() . "\n" ); @@ -49,8 +49,8 @@ public function start() { // Write directly to STDOUT, to sidestep any output buffers created by plugins ob_start(); try { - // phpcs:ignore Squiz.PHP.Eval.Discouraged -- This is meant to be a REPL, no way to avoid eval. - $__repl_eval_result = eval( $__repl_input_line ); + // phpcs:ignore Squiz.PHP.Eval.Discouraged,WordPress.PHP.NoSilencedErrors.Discouraged -- This is meant to be a REPL, no way to avoid eval. Suppress PHP warnings to show clean error messages. + $__repl_eval_result = @eval( $__repl_input_line ); } catch ( \Throwable $e ) { // Display the error message but continue the session fwrite( STDERR, get_class( $e ) . ': ' . $e->getMessage() . "\n" ); From aed09181f143749dbfd486455320876d22278d5f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 09:40:11 +0000 Subject: [PATCH 08/11] Remove error suppression operator - keep warnings visible Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- src/WP_CLI/Shell/REPL.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/WP_CLI/Shell/REPL.php b/src/WP_CLI/Shell/REPL.php index cf94bfd6..74d5c1ae 100644 --- a/src/WP_CLI/Shell/REPL.php +++ b/src/WP_CLI/Shell/REPL.php @@ -30,8 +30,8 @@ public function start() { if ( self::starts_with( self::non_expressions(), $__repl_input_line ) ) { ob_start(); try { - // phpcs:ignore Squiz.PHP.Eval.Discouraged,WordPress.PHP.NoSilencedErrors.Discouraged -- This is meant to be a REPL, no way to avoid eval. Suppress PHP warnings to show clean error messages. - @eval( $__repl_input_line ); + // phpcs:ignore Squiz.PHP.Eval.Discouraged -- This is meant to be a REPL, no way to avoid eval. + eval( $__repl_input_line ); } catch ( \Throwable $e ) { // Display the error message but continue the session fwrite( STDERR, get_class( $e ) . ': ' . $e->getMessage() . "\n" ); @@ -49,8 +49,8 @@ public function start() { // Write directly to STDOUT, to sidestep any output buffers created by plugins ob_start(); try { - // phpcs:ignore Squiz.PHP.Eval.Discouraged,WordPress.PHP.NoSilencedErrors.Discouraged -- This is meant to be a REPL, no way to avoid eval. Suppress PHP warnings to show clean error messages. - $__repl_eval_result = @eval( $__repl_input_line ); + // phpcs:ignore Squiz.PHP.Eval.Discouraged -- This is meant to be a REPL, no way to avoid eval. + $__repl_eval_result = eval( $__repl_input_line ); } catch ( \Throwable $e ) { // Display the error message but continue the session fwrite( STDERR, get_class( $e ) . ': ' . $e->getMessage() . "\n" ); From 4130f4ebd4f5d3e557cf1d18acb6672bf3a48259 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 17 Mar 2026 10:55:06 +0100 Subject: [PATCH 09/11] Update assertion --- features/shell.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/shell.feature b/features/shell.feature index d5f3507a..3a9e6cff 100644 --- a/features/shell.feature +++ b/features/shell.feature @@ -163,7 +163,7 @@ Feature: WordPress REPL """ And STDERR should contain: """ - Error: Failed opening required 'nonexistent_file.txt' + Failed opening required 'nonexistent_file.txt' """ Scenario: Exception handling for expression errors From 1a039c7038fc186be63d8a7b376c9a9a52fd8eaf Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 17 Mar 2026 11:17:37 +0100 Subject: [PATCH 10/11] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/WP_CLI/Shell/REPL.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/WP_CLI/Shell/REPL.php b/src/WP_CLI/Shell/REPL.php index b649999c..ecd9a401 100644 --- a/src/WP_CLI/Shell/REPL.php +++ b/src/WP_CLI/Shell/REPL.php @@ -79,18 +79,23 @@ public function start() { // Write directly to STDOUT, to sidestep any output buffers created by plugins ob_start(); + $__repl_eval_had_error = false; try { // phpcs:ignore Squiz.PHP.Eval.Discouraged -- This is meant to be a REPL, no way to avoid eval. $__repl_eval_result = eval( $__repl_input_line ); } catch ( \Throwable $e ) { // Display the error message but continue the session fwrite( STDERR, get_class( $e ) . ': ' . $e->getMessage() . "\n" ); - $__repl_eval_result = null; + $__repl_eval_had_error = true; + $__repl_eval_result = null; } $__repl_output = (string) ob_get_clean(); if ( 0 < strlen( $__repl_output ) ) { echo rtrim( $__repl_output, "\n" ) . "\n"; } + if ( $__repl_eval_had_error ) { + continue; + } echo '=> '; var_dump( $__repl_eval_result ); fwrite( STDOUT, (string) ob_get_clean() ); From 3b059802e75d99f0aa87a88d27e7fc8a6812bf09 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 17 Mar 2026 11:24:40 +0100 Subject: [PATCH 11/11] Lint fix --- src/WP_CLI/Shell/REPL.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WP_CLI/Shell/REPL.php b/src/WP_CLI/Shell/REPL.php index afa3a818..5dcff93b 100644 --- a/src/WP_CLI/Shell/REPL.php +++ b/src/WP_CLI/Shell/REPL.php @@ -95,7 +95,7 @@ public function start() { // Display the error message but continue the session fwrite( STDERR, get_class( $e ) . ': ' . $e->getMessage() . "\n" ); $__repl_eval_had_error = true; - $__repl_eval_result = null; + $__repl_eval_result = null; } $__repl_output = (string) ob_get_clean(); if ( 0 < strlen( $__repl_output ) ) {