@@ -4,9 +4,11 @@ use crate::prompt_ui::{ |
| 4 | 4 | }; |
| 5 | 5 | use anyhow::{Context, Result}; |
| 6 | 6 | use std::process::{Command, ExitStatus}; |
| 7 | +use std::time::{Duration, Instant}; |
| 7 | 8 | |
| 8 | 9 | const DEFAULT_ASK_TIMEOUT_SECS: u64 = 120; |
| 9 | 10 | const FEEDBACK_TIMEOUT_SECS: u64 = 1; |
| 11 | +const RAPID_CANCEL_THRESHOLD: Duration = Duration::from_millis(300); |
| 10 | 12 | |
| 11 | 13 | #[derive(Debug, Clone, Copy)] |
| 12 | 14 | enum PromptTone { |
@@ -53,12 +55,14 @@ impl Default for CommandPrompt { |
| 53 | 55 | impl CommandPrompt { |
| 54 | 56 | fn run_prompt(&mut self, prompt: &str, visible: bool) -> Result<PromptResponse> { |
| 55 | 57 | if let Some(command) = self.prompt_command.as_deref() { |
| 58 | + tracing::debug!(visible, "Using custom prompt command backend"); |
| 56 | 59 | return run_custom_prompt_command(command, prompt, visible); |
| 57 | 60 | } |
| 58 | 61 | |
| 59 | 62 | let timeout_secs = self.prompt_timeout_secs; |
| 60 | 63 | let session_result = match self.ensure_session() { |
| 61 | 64 | Some(session) => { |
| 65 | + tracing::debug!(visible, "Using persistent prompt session backend"); |
| 62 | 66 | let request = PromptRequest { |
| 63 | 67 | message: prompt.to_string(), |
| 64 | 68 | mode: if visible { |
@@ -69,15 +73,27 @@ impl CommandPrompt { |
| 69 | 73 | timeout_secs, |
| 70 | 74 | tone: UiPromptTone::Default, |
| 71 | 75 | }; |
| 72 | | - Some(session.run(request)) |
| 76 | + let started = Instant::now(); |
| 77 | + Some((session.run(request), started.elapsed())) |
| 73 | 78 | } |
| 74 | 79 | None => None, |
| 75 | 80 | }; |
| 76 | 81 | |
| 77 | | - if let Some(result) = session_result { |
| 82 | + if let Some((result, elapsed)) = session_result { |
| 78 | 83 | match result { |
| 79 | 84 | Ok(PromptExit::Submitted(value)) => return Ok(PromptResponse::Submitted(value)), |
| 80 | | - Ok(PromptExit::Canceled) => return Ok(PromptResponse::Canceled), |
| 85 | + Ok(PromptExit::Canceled) => { |
| 86 | + if elapsed < RAPID_CANCEL_THRESHOLD { |
| 87 | + tracing::warn!( |
| 88 | + elapsed_ms = elapsed.as_millis(), |
| 89 | + "Persistent prompt session canceled immediately; falling back to subprocess prompt" |
| 90 | + ); |
| 91 | + self.session = None; |
| 92 | + self.session_unavailable = true; |
| 93 | + } else { |
| 94 | + return Ok(PromptResponse::Canceled); |
| 95 | + } |
| 96 | + } |
| 81 | 97 | Ok(PromptExit::TimedOut) => return Ok(PromptResponse::TimedOut), |
| 82 | 98 | Err(err) => { |
| 83 | 99 | tracing::warn!( |
@@ -91,7 +107,10 @@ impl CommandPrompt { |
| 91 | 107 | } |
| 92 | 108 | |
| 93 | 109 | match run_gartk_prompt_subcommand(prompt, visible, timeout_secs) { |
| 94 | | - Ok(response) => Ok(response), |
| 110 | + Ok(response) => { |
| 111 | + tracing::debug!(visible, response = ?response, "Prompt subprocess completed"); |
| 112 | + Ok(response) |
| 113 | + } |
| 95 | 114 | Err(err) => { |
| 96 | 115 | tracing::warn!( |
| 97 | 116 | error = %err, |
@@ -228,6 +247,14 @@ fn run_gartk_prompt_subcommand( |
| 228 | 247 | scrub_bytes(&mut output.stderr); |
| 229 | 248 | anyhow::bail!("garcard prompt subcommand unavailable: {}", stderr); |
| 230 | 249 | } |
| 250 | + if !output.status.success() { |
| 251 | + let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string(); |
| 252 | + tracing::debug!( |
| 253 | + code = ?output.status.code(), |
| 254 | + stderr = %stderr, |
| 255 | + "Prompt subprocess exited non-success" |
| 256 | + ); |
| 257 | + } |
| 231 | 258 | |
| 232 | 259 | let response = map_output_to_prompt_response(&output.status, &output.stdout); |
| 233 | 260 | scrub_bytes(&mut output.stdout); |
@@ -274,6 +301,14 @@ fn run_systemd_ask_password( |
| 274 | 301 | let mut output = command |
| 275 | 302 | .output() |
| 276 | 303 | .context("failed to run systemd-ask-password")?; |
| 304 | + if !output.status.success() { |
| 305 | + let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string(); |
| 306 | + tracing::debug!( |
| 307 | + code = ?output.status.code(), |
| 308 | + stderr = %stderr, |
| 309 | + "systemd-ask-password exited non-success" |
| 310 | + ); |
| 311 | + } |
| 277 | 312 | let response = map_output_to_prompt_response(&output.status, &output.stdout); |
| 278 | 313 | scrub_bytes(&mut output.stdout); |
| 279 | 314 | scrub_bytes(&mut output.stderr); |