feat(tabs): live tab resync + adopt-by-targetId + open --reuse-tab (#21)
Multi-session over one relayed Chrome had a tab-identity fracture: each daemon discovered targets ONCE at connect and assigned its own t<N> indices, so a tab filled in session A was unreachable from session B — B saw a disjoint/blank set and rebinding via 'open' piled up duplicate tabs. A stranded, still-filled tab could not be finished from any other session. - 'tab list' now re-syncs the live target set on every call: adopts tabs other sessions opened (or that re-attached after a cross-process nav), drops gone ones (clears phantom rows), and refreshes url/title from each live tab via Target.getTargetInfo (the relay only stamps target_info on attach, so it goes stale/blank after navigation — which made rows indistinguishable). - 'tab list --full' now prints each tab's stable CDP targetId. Unlike t<N> (per-session, reassigned each connect), targetId is stable across every session on the relayed Chrome. - 'tab <targetId>' adopts a specific pre-existing tab — including another session's — WITHOUT reloading, so a half-filled form survives. handle_tab_switch resyncs first, then resolves a raw targetId before falling back to t<N>/label. - 'open <url> --reuse-tab' (alias --reuse) switches to an existing tab already on that URL (matched by origin+path, ignoring volatile query/fragment) instead of spawning a duplicate. Verified live over the extension relay: a fresh session's 'tab list --full' lists the user's real tabs with correct titles + full URLs + targetIds, and 'tab <targetId>' lands on and reads the exact stranded Rakuten account-recovery form from the report. Unit tests cover URL normalization + --reuse-tab parsing; full suite green. Docs: --help Tabs section + core skill multi-session guidance.
This commit is contained in:
@@ -370,6 +370,12 @@ fn parse_command_inner(args: &[String], flags: &Flags) -> Result<Value, ParseErr
|
||||
if flags.provider.is_some() {
|
||||
nav_cmd["waitUntil"] = json!("none");
|
||||
}
|
||||
// `--reuse-tab`: adopt an existing tab already on this URL instead of
|
||||
// navigating/spawning a new one (issue #21 — avoids duplicate tabs on
|
||||
// rebind, preserves in-page state).
|
||||
if rest.iter().any(|a| *a == "--reuse-tab" || *a == "--reuse") {
|
||||
nav_cmd["reuseTab"] = json!(true);
|
||||
}
|
||||
// Explicit readiness override (issue #10): SPAs whose `load` event
|
||||
// never fires (a long-lived XHR/websocket holds it open) hang out the
|
||||
// load-event wait. `--wait-until domcontentloaded` returns as soon as
|
||||
@@ -3575,6 +3581,24 @@ mod tests {
|
||||
assert_eq!(cmd["url"], "https://example.com");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_navigate_reuse_tab_flag() {
|
||||
let cmd = parse_command(
|
||||
&args("open https://example.com --reuse-tab"),
|
||||
&default_flags(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(cmd["action"], "navigate");
|
||||
assert_eq!(cmd["reuseTab"], true);
|
||||
// Alias.
|
||||
let cmd2 =
|
||||
parse_command(&args("open https://example.com --reuse"), &default_flags()).unwrap();
|
||||
assert_eq!(cmd2["reuseTab"], true);
|
||||
// Absent by default.
|
||||
let cmd3 = parse_command(&args("open https://example.com"), &default_flags()).unwrap();
|
||||
assert!(cmd3.get("reuseTab").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_navigate_with_headers() {
|
||||
let mut flags = default_flags();
|
||||
|
||||
Reference in New Issue
Block a user