chore: 更新 Cloudflare 及浏览器自动化攻防文章并补发 blog 链接
This commit is contained in:
@@ -197,6 +197,22 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
|
||||
});
|
||||
}
|
||||
}
|
||||
if let Some(ref wait_until) = flags.wait_until {
|
||||
if matches!(
|
||||
wait_until.as_str(),
|
||||
"load" | "domcontentloaded" | "networkidle"
|
||||
) {
|
||||
nav_cmd["waitUntil"] = json!(wait_until);
|
||||
} else {
|
||||
return Err(ParseError::InvalidValue {
|
||||
message: format!(
|
||||
"Invalid --wait-until value: {} (expected load, domcontentloaded, or networkidle)",
|
||||
wait_until
|
||||
),
|
||||
usage: "open <url>",
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(nav_cmd)
|
||||
}
|
||||
"back" => Ok(json!({ "id": id, "action": "back" })),
|
||||
@@ -2068,6 +2084,7 @@ mod tests {
|
||||
tab_group: None,
|
||||
tab_group_plugin_id: None,
|
||||
risk_mode: None,
|
||||
wait_until: None,
|
||||
cli_tab_group: false,
|
||||
cli_tab_group_plugin_id: false,
|
||||
}
|
||||
@@ -2349,6 +2366,14 @@ mod tests {
|
||||
assert_eq!(cmd["riskMode"], "block");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_navigate_with_wait_until() {
|
||||
let mut flags = default_flags();
|
||||
flags.wait_until = Some("domcontentloaded".to_string());
|
||||
let cmd = parse_command(&args("open https://example.com"), &flags).unwrap();
|
||||
assert_eq!(cmd["waitUntil"], "domcontentloaded");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_navigate_with_multiple_headers() {
|
||||
let mut flags = default_flags();
|
||||
|
||||
@@ -39,6 +39,7 @@ pub struct Config {
|
||||
pub tab_group: Option<String>,
|
||||
pub tab_group_plugin_id: Option<String>,
|
||||
pub risk_mode: Option<String>,
|
||||
pub wait_until: Option<String>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@@ -76,6 +77,7 @@ impl Config {
|
||||
tab_group: other.tab_group.or(self.tab_group),
|
||||
tab_group_plugin_id: other.tab_group_plugin_id.or(self.tab_group_plugin_id),
|
||||
risk_mode: other.risk_mode.or(self.risk_mode),
|
||||
wait_until: other.wait_until.or(self.wait_until),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,6 +147,7 @@ fn extract_config_path(args: &[String]) -> Option<Option<String>> {
|
||||
"--tab-group",
|
||||
"--tab-group-plugin-id",
|
||||
"--risk-mode",
|
||||
"--wait-until",
|
||||
];
|
||||
let mut i = 0;
|
||||
while i < args.len() {
|
||||
@@ -220,6 +223,9 @@ pub struct Flags {
|
||||
/// How verification/captcha detections are handled on navigation:
|
||||
/// `off` (disable), `warn` (retry and warn), `block` (fail fast).
|
||||
pub risk_mode: Option<String>,
|
||||
/// Navigation wait strategy passed to navigate/open commands:
|
||||
/// `load`, `domcontentloaded`, or `networkidle`.
|
||||
pub wait_until: Option<String>,
|
||||
|
||||
// Track which launch-time options were explicitly passed via CLI
|
||||
// (as opposed to being set only via environment variables)
|
||||
@@ -316,6 +322,7 @@ pub fn parse_flags(args: &[String]) -> Flags {
|
||||
.ok()
|
||||
.or(config.risk_mode)
|
||||
.map(|s| s.to_ascii_lowercase()),
|
||||
wait_until: config.wait_until.map(|s| s.to_ascii_lowercase()),
|
||||
cli_executable_path: false,
|
||||
cli_extensions: false,
|
||||
cli_state: false,
|
||||
@@ -509,6 +516,12 @@ pub fn parse_flags(args: &[String]) -> Flags {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
"--wait-until" => {
|
||||
if let Some(s) = args.get(i + 1) {
|
||||
flags.wait_until = Some(s.to_ascii_lowercase());
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
"--config" => {
|
||||
// Already handled by load_config(); skip the value
|
||||
i += 1;
|
||||
@@ -568,6 +581,7 @@ pub fn clean_args(args: &[String]) -> Vec<String> {
|
||||
"--tab-group",
|
||||
"--tab-group-plugin-id",
|
||||
"--risk-mode",
|
||||
"--wait-until",
|
||||
"--config",
|
||||
];
|
||||
|
||||
@@ -918,6 +932,18 @@ mod tests {
|
||||
assert_eq!(cleaned, vec!["open", "example.com"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_wait_until_flag() {
|
||||
let flags = parse_flags(&args("--wait-until domcontentloaded open example.com"));
|
||||
assert_eq!(flags.wait_until.as_deref(), Some("domcontentloaded"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clean_args_removes_wait_until() {
|
||||
let cleaned = clean_args(&args("--wait-until networkidle open example.com"));
|
||||
assert_eq!(cleaned, vec!["open", "example.com"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cli_multiple_flags_tracking() {
|
||||
let flags = parse_flags(&args(
|
||||
|
||||
+8
-3
@@ -874,11 +874,13 @@ Global Options:
|
||||
--session <name> Use specific session
|
||||
--headers <json> Set HTTP headers (scoped to this origin)
|
||||
--risk-mode <mode> Risk handling for verify/captcha pages: off, warn, block
|
||||
--wait-until <mode> Navigation wait strategy: load, domcontentloaded, networkidle
|
||||
--headed Show browser window
|
||||
|
||||
Examples:
|
||||
agent-browser open example.com
|
||||
agent-browser --risk-mode block open example.com
|
||||
agent-browser --wait-until domcontentloaded open example.com
|
||||
agent-browser open https://github.com
|
||||
agent-browser open localhost:3000
|
||||
agent-browser open api.example.com --headers '{"Authorization": "Bearer token"}'
|
||||
@@ -2232,19 +2234,21 @@ Examples:
|
||||
}
|
||||
"doctor" => {
|
||||
r##"
|
||||
agent-browser doctor - Diagnose CDP and tab-group plugin health
|
||||
agent-browser doctor - Diagnose CDP, sourceURL sanitization, and tab-group plugin health
|
||||
|
||||
Usage: agent-browser doctor
|
||||
|
||||
Runs a non-destructive health check focused on:
|
||||
- CDP endpoint reachability (preferred :9333 + common ports)
|
||||
- DevToolsActivePort discovery from local Chrome profiles
|
||||
- CDP sourceURL sanitization probe (Runtime.evaluate leakage check)
|
||||
- Plugin handshake page context suitability (internal page vs http(s))
|
||||
- Tab-group plugin handshake status (when connected via CDP)
|
||||
|
||||
Notes:
|
||||
- doctor does not accept positional arguments
|
||||
- If browser is not already connected, doctor will still report CDP probe results
|
||||
- Plugin handshake requires a live CDP page and the extension to be installed
|
||||
- Plugin handshake requires CDP mode, a normal http(s) page, and the extension installed
|
||||
|
||||
Global Options:
|
||||
--json Output as JSON
|
||||
@@ -2483,7 +2487,7 @@ Sessions:
|
||||
Setup:
|
||||
install Install browser binaries
|
||||
install --with-deps Also install system dependencies (Linux)
|
||||
doctor Diagnose CDP + plugin health
|
||||
doctor Diagnose CDP + sourceURL + plugin health
|
||||
|
||||
Snapshot Options:
|
||||
-i, --interactive Only interactive elements
|
||||
@@ -2520,6 +2524,7 @@ Options:
|
||||
--tab-group <name> Base title for agent tab groups (CDP plugin mode; silent no-op if plugin unavailable)
|
||||
--tab-group-plugin-id <id> Expected Chrome extension ID for tab-group handshake (or AGENT_BROWSER_TAB_GROUP_PLUGIN_ID)
|
||||
--risk-mode <mode> Verify/captcha handling: off, warn, block (or AGENT_BROWSER_RISK_MODE)
|
||||
--wait-until <mode> Navigation wait strategy for open/navigate: load, domcontentloaded, networkidle
|
||||
--session-name <name> Auto-save/restore session state (defaults to --session)
|
||||
--content-boundaries Wrap page output in boundary markers (or AGENT_BROWSER_CONTENT_BOUNDARIES)
|
||||
--max-output <chars> Truncate page output to N chars (or AGENT_BROWSER_MAX_OUTPUT)
|
||||
|
||||
Reference in New Issue
Block a user