No job gets stranded on a blank tab
- pick_tab: a page that went somewhere (http) beats about:blank at every rank — own live tab > free live tab > own blank > free blank. Headless Chrome boots on about:blank and a job that claims it was pinned there; desktop behaviour unchanged (the front tab is a live page anyway) - the tabs list shows a page's url when its title is empty, so the model never reads a faceless '1. (current)' line Live proof (headless Chrome + qwen brain, same scenario that failed before): reads the number through the browser path, 172s -> 92s, and the model now flags the page's own link as untrusted (S3 working)
This commit is contained in:
parent
61c38dca66
commit
cf1d4d618c
|
|
@ -542,15 +542,16 @@ pub fn release(job: &str) -> Vec<String> {
|
|||
|
||||
/// The tab of a page list (latest-used first) this step works on: its job's latest own tab, else
|
||||
/// the latest one no other job owns (a job's first step).
|
||||
///
|
||||
/// A page that actually went somewhere (http/https) beats a blank one at every step: a browser
|
||||
/// that boots on about:blank (headless Chrome does) must not strand a job on the empty tab.
|
||||
pub fn pick_tab(list: &[Value]) -> Option<&Value> {
|
||||
let me = job();
|
||||
let id = |t: &Value| t["id"].as_str().unwrap_or("").to_string();
|
||||
if !me.is_empty() {
|
||||
if let Some(t) = list.iter().find(|t| owner(&id(t)).as_deref() == Some(me.as_str())) {
|
||||
return Some(t);
|
||||
}
|
||||
}
|
||||
list.iter().find(|t| !others_tab(&id(t)))
|
||||
let mine = |t: &Value| !me.is_empty() && owner(&id(t)).as_deref() == Some(me.as_str());
|
||||
let live = |t: &Value| t["url"].as_str().unwrap_or("").starts_with("http");
|
||||
let free = |t: &Value| !others_tab(&id(t));
|
||||
list.iter().find(|t| mine(t) && live(t)).or_else(|| list.iter().find(|t| free(t) && live(t))).or_else(|| list.iter().find(|t| mine(t))).or_else(|| list.iter().find(|t| free(t)))
|
||||
}
|
||||
|
||||
/// The open page tabs' ids (none when the browser isn't open; it isn't started for this).
|
||||
|
|
@ -889,6 +890,16 @@ mod tests {
|
|||
assert_eq!(as_job("job-b", || pick_tab(&list).map(|t| t["id"].clone())), Some("tab-b".into()));
|
||||
// A new job starts on the latest tab nobody has; another job's tabs are off limits.
|
||||
assert_eq!(as_job("job-c", || pick_tab(&list).map(|t| t["id"].clone())), Some("tab-free".into()));
|
||||
// A real page beats a blank tab, whoever's it is: the blank-tab trap (headless Chrome
|
||||
// boots on about:blank; a job that claims it must not be stranded there).
|
||||
let pages = vec![serde_json::json!({"type": "page", "id": "blank", "url": "about:blank"}), serde_json::json!({"type": "page", "id": "real", "url": "https://example.com"})];
|
||||
assert_eq!(as_job("job-x", || { claim("blank"); pick_tab(&pages).map(|t| t["id"].clone()) }), Some("real".into()));
|
||||
// A job's own real page still wins over a stranger's.
|
||||
let mine = vec![serde_json::json!({"type": "page", "id": "theirs", "url": "https://other.example"}), serde_json::json!({"type": "page", "id": "mine", "url": "https://mine.example"})];
|
||||
assert_eq!(as_job("job-y", || { claim("mine"); pick_tab(&mine).map(|t| t["id"].clone()) }), Some("mine".into()));
|
||||
// All blank: keep the old behaviour (own tab, then any free one).
|
||||
let blanks = vec![serde_json::json!({"type": "page", "id": "b1", "url": "about:blank"}), serde_json::json!({"type": "page", "id": "b2", "url": "about:blank"})];
|
||||
assert_eq!(as_job("job-z", || { claim("b2"); pick_tab(&blanks).map(|t| t["id"].clone()) }), Some("b2".into()));
|
||||
assert!(as_job("job-c", || others_tab("tab-a") && !others_tab("tab-free")));
|
||||
assert!(as_job("job-a", || !others_tab("tab-a")));
|
||||
// A claimed tab stays its first owner's.
|
||||
|
|
|
|||
|
|
@ -1012,7 +1012,13 @@ fn tabs(args: &Value, profile: Option<&str>) -> Result<String, String> {
|
|||
_ => Ok(if list.is_empty() {
|
||||
"沒有開著的分頁。".into()
|
||||
} else {
|
||||
list.iter().enumerate().map(|(i, t)| format!("{}. {}{}\n {}", i + 1, t["title"].as_str().unwrap_or(""), if t["id"].as_str() == Some(current.as_str()) { "(目前)" } else { "" }, t["url"].as_str().unwrap_or(""))).collect::<Vec<_>>().join("\n")
|
||||
// Untitled pages (about:blank, bare pages) show their url, so the model never sees an empty line.
|
||||
list.iter().enumerate().map(|(i, t)| {
|
||||
let url = t["url"].as_str().unwrap_or("");
|
||||
let title = t["title"].as_str().unwrap_or("");
|
||||
let title = if title.is_empty() { url } else { title };
|
||||
format!("{}. {}{}\n {}", i + 1, title, if t["id"].as_str() == Some(current.as_str()) { "(目前)" } else { "" }, url)
|
||||
}).collect::<Vec<_>>().join("\n")
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue