Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions crates/tower-cmd/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,10 @@ where

// Wait for app to complete or SIGTERM
let status_result = tokio::select! {
status = status_task => status.unwrap(),
status = status_task => {
debug!("Status task completed, result: {:?}", status);
status.unwrap()
},
_ = tokio::signal::ctrl_c(), if !output::get_output_mode().is_mcp() => {
output::write("\nReceived Ctrl+C, stopping local run...\n");
app.lock().await.terminate().await.ok();
Expand All @@ -205,8 +208,8 @@ where
// And if we crashed, err out
match status_result {
Status::Exited => output::success("Your local run exited cleanly."),
Status::Crashed { .. } => {
output::error("Your local run crashed!");
Status::Crashed { code } => {
output::error(&format!("Your local run crashed with exit code: {}", code));
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message doesn't clarify what the exit code number means or provide guidance on next steps. Consider adding context like 'Oh no! Your local run crashed with exit code: {}' to match the description, or provide guidance on interpreting common exit codes.

Suggested change
output::error(&format!("Your local run crashed with exit code: {}", code));
let explanation = match code {
// 130: terminated by Ctrl+C / SIGINT in many environments
130 => " (the run was interrupted, often by Ctrl+C or SIGINT)",
// 137: often indicates the process was killed due to out-of-memory (SIGKILL)
137 => " (this often means the process was killed, for example due to out-of-memory)",
_ => " (check your app logs for details, or consult documentation for this exit code)",
};
output::error(&format!(
"Oh no! Your local run crashed with exit code: {}{}",
code, explanation
));

Copilot uses AI. Check for mistakes.
return Err(Error::AppCrashed);
}
_ => {
Expand Down Expand Up @@ -611,20 +614,19 @@ async fn monitor_local_status(app: Arc<Mutex<LocalApp>>) -> Status {
err_count = 0;

match status {
tower_runtime::Status::Exited => {
Status::Exited => {
debug!("Run exited cleanly, stopping status monitoring");

// We're done. Exit this loop and function.
return status;
}
tower_runtime::Status::Crashed { .. } => {
Status::Crashed { .. } => {
debug!("Run crashed, stopping status monitoring");

// We're done. Exit this loop and function.
return status;
}
_ => {
debug!("App status: other, continuing to monitor");
sleep(Duration::from_millis(100)).await;
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/features/steps/cli_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def step_final_status_should_show_crashed_in_red(context):
red_color_code in output
), f"Expected red color codes in output, got: {output}"
assert (
"Your local run crashed!" in output
"Your local run crashed with exit code:" in output
), f"Expected 'Your local run crashed!' message, got: {output}"


Expand Down