feat: add dialog detection and document dialog commands (#999)

Fixes #992

When a JavaScript dialog (alert/confirm/prompt) blocks the page, agents
had no way to detect it — all commands just timed out with generic errors.

- Add `dialog status` command to check for pending dialogs
- Track dialog state via CDP Page.javascriptDialogOpening/Closed events
- Auto-inject `warning` field into all command responses when a dialog is
  pending, so agents can distinguish dialog-blocked timeouts from other issues
- Document dialog commands in SKILL.md (was missing entirely), README.md,
  docs site, and --help output

Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
This commit is contained in:
Chris Tate
2026-03-24 11:38:23 -05:00
committed by GitHub
co-authored by ctate
parent 780edb2c45
commit 32ffd8f3c4
8 changed files with 155 additions and 11 deletions
+45 -2
View File
@@ -122,6 +122,7 @@ pub fn print_response_with_opts(resp: &Response, action: Option<&str>, opts: &Ou
} else {
println!("{}", serde_json::to_string(resp).unwrap_or_default());
}
// JSON mode includes the warning field in the JSON payload already
return;
}
@@ -131,10 +132,42 @@ pub fn print_response_with_opts(resp: &Response, action: Option<&str>, opts: &Ou
color::error_indicator(),
resp.error.as_deref().unwrap_or("Unknown error")
);
// Still print dialog warning after errors, since a pending dialog
// is the most common cause of commands timing out
if let Some(ref warning) = resp.warning {
eprintln!("{} {}", color::warning_indicator(), warning);
}
return;
}
if let Some(data) = &resp.data {
// Dialog status response
if action == Some("dialog") {
if let Some(has_dialog) = data.get("hasDialog").and_then(|v| v.as_bool()) {
if has_dialog {
let dtype = data
.get("type")
.and_then(|v| v.as_str())
.unwrap_or("unknown");
let message = data.get("message").and_then(|v| v.as_str()).unwrap_or("");
println!(
"{} JavaScript {} dialog is open: \"{}\"",
color::warning_indicator(),
dtype,
message
);
if let Some(default_prompt) = data.get("defaultPrompt").and_then(|v| v.as_str())
{
println!(" Default prompt text: \"{}\"", default_prompt);
}
println!(" Use `dialog accept [text]` or `dialog dismiss` to resolve it");
} else {
println!("{} No dialog is currently open", color::success_indicator());
}
print_warning(resp);
return;
}
}
if action == Some("storage_get") {
if let Some(output) = format_storage_text(data) {
println!("{}", output);
@@ -888,6 +921,14 @@ pub fn print_response_with_opts(resp: &Response, action: Option<&str>, opts: &Ou
// Default success
println!("{} Done", color::success_indicator());
}
print_warning(resp);
}
fn print_warning(resp: &Response) {
if let Some(ref warning) = resp.warning {
eprintln!("{} {}", color::warning_indicator(), warning);
}
}
/// Print command-specific help. Returns true if help was printed, false if command unknown.
@@ -1995,13 +2036,14 @@ Examples:
r##"
agent-browser dialog - Handle browser dialogs
Usage: agent-browser dialog <response> [text]
Usage: agent-browser dialog <accept|dismiss|status> [text]
Respond to browser dialogs (alert, confirm, prompt).
Respond to or check for browser dialogs (alert, confirm, prompt).
Operations:
accept [text] Accept dialog, optionally with prompt text
dismiss Dismiss/cancel dialog
status Check if a dialog is currently open
Global Options:
--json Output as JSON
@@ -2011,6 +2053,7 @@ Examples:
agent-browser dialog accept
agent-browser dialog accept "my input"
agent-browser dialog dismiss
agent-browser dialog status
"##
}