The second half of #17: the agent booting inside a nested same-origin
document registered via window.parent — which for a nested frame is the
app document between it and the shell (Storybook's manager), where no
hook exists — so it was stranded, and with it went click-to-select,
wheel-to-zoom, the text-edit guard and editor shortcuts inside the
nested document.
frame-agent: one findHost walk replaces all four window.parent reaches —
upward past hookless app documents to the first window exposing the
ready hook, capped at MAX_NEST_DEPTH, stopping at a cross-origin hop
exactly like the old behaviour. Memoised on success only, since a nested
agent can boot before the shell has installed its hooks.
shell-app: the three forwarded-event routes resolve their frame with
frameOfWindow and share one frame-to-screen mapping that composes the
nested chain, so a press or wheel inside a nested document lands where
the cursor actually is. setTextOwner arms the guard on every agent of
the text frame — the realm the caret lives in, not just the root.
keys.observe binds to the registering agent's own document, which is
what keeps shortcuts alive while focus is inside a nested document.
Teardown keyed two-deep: frameUnsubs is per frame id, per agent window,
so a nested agent registering no longer tears down the root agent's
subscriptions — and a root realm rebuild disposes the whole set, because
the nested realms died with it. destroy() and pruneFrameUnsubs walk the
inner maps.