发布

  • fix(native): revive discarded tabs on tab switch instead of hanging the daemon (#1532)

    frostbyte_neo 发布于 2026-07-23 17:32:56 +00:00 | 45 次提交 在此版本后已推送到 main

    • fix(native): revive discarded tabs on tab switch instead of hanging the daemon

    A tab discarded by Chrome's Memory Saver keeps its CDP session but has
    no renderer, so tab_switch's Page.enable never answered: the switch hung
    for the full CDP timeout, left active_page_index on the dead tab, and
    wedged the daemon behind the state lock while the client retried.

    Probe the renderer with a short timeout and revive a dead tab with
    Page.reload before enabling domains, committing active_page_index only
    once the tab is usable. Covered by two mock-CDP regression tests.

    Fixes #1528.

    • Harden discarded-tab revival per review (#1528)
    • Recover a discarded tab with Target.activateTarget instead of
      Page.reload. Activation reloads a genuinely discarded tab but only
      focuses a live one, so a liveness-probe false positive cannot lose
      page state. It is a browser-level command that answers promptly, so it
      cannot ride the 30s renderer-command ceiling a page-level reload could.
    • Report "revived": true on a switch that recovered the tab (in --json,
      MCP structured output, and the default line), and document it in the
      README, so the recovery is not silent.
    • Clean up a liveness probe's pending CDP request when its outer timeout
      cancels it, via a drop guard on send_command, instead of leaking it
      until the connection closes.
    • Fix three clippy 1.97 lints (question_mark, useless_borrows_in_formatting)
      that were failing the Rust CI check.
    • fix(native): handle dialog-blocked tabs and close-successor revival

    Address the review notes on discarded-tab revival:

    • Do not misclassify a tab paused by a JavaScript dialog as discarded.
      ensure_renderer_alive now returns Responsive/Revived/DialogBlocked; a
      blocked tab is reported alive without reactivation, and the switch falls
      back to cached url/title so it does not hang on script evaluation.
    • Preserve the previous tab's refs and frame context on a failed switch by
      clearing them only after the switch commits.
    • Revive a discarded successor on tab close, so closing the active tab no
      longer hangs enable_domains on a dead renderer.
    • Document the revival behavior and the revived result on the skill and
      docs surfaces, not only the README.

    Tests: dialog-blocked switch stays live without reactivation; closing onto
    a discarded successor revives instead of hanging. Both fail without the fix.

    • feat(native): surface dialogBlocked on tab switch

    A tab paused by a JavaScript dialog is alive, not discarded, so the switch
    now reports "dialogBlocked": true instead of recovering silently. Agents can
    resolve the dialog before treating the tab as interactive.

    Cover the result field and the two switch special cases across the CLI line,
    README, docs site, and both skill surfaces (overview and command reference).

    • fix(native): don't fail a committed tab close on successor recovery

    A codex review pass found that tab_close closed and removed the target and
    cleared refs before the successor-revival step, which could then return an
    error, so a completed close reported failure and left the caller unable to
    retry a tab that was already gone. The successor is now revived on a
    best-effort basis: its failure no longer propagates, and a reloaded
    successor is surfaced as activeTabRevived, mirroring tab switch.

    Also neutralize the "discarded or crashed" probe-failure wording, since a
    paused renderer produces the same non-response, and broaden the dialog-type
    note in the skill docs.

    • fix(native): note activeTabRevived on the tab close CLI line

    The close result carried activeTabRevived in JSON but the default CLI line
    did not mention it, unlike the revived note on tab switch. Surface it so the
    reload is visible without --json.

    • fix(native): don't stall or fail on dialog-blocked switch and committed close

    A second review pass surfaced two residuals:

    • With streaming enabled, the switch still ran a viewport-sync eval on the
      target after committing; on a dialog-blocked (paused) renderer that stalled
      on the CDP timeout. Skip the viewport sync when the switch is dialogBlocked.
    • The committed tab close still propagated an enable_domains error on the
      successor, contradicting the best-effort contract. Enabling domains on the
      successor is now best-effort too, so a completed close never reports failure.
    • fix(native): don't wipe refs when a tab close is rejected

    handle_tab_close cleared ref_map/iframe_sessions/active_frame_id before
    tab_close_by_id, so a rejected close (last tab, out-of-range index) wiped
    the caller's refs and frame scope without closing anything. Clear only after
    the close commits, matching the tab switch path.

    下载附件