diff --git a/plugins/_browser/AGENTS.md b/plugins/_browser/AGENTS.md index 70211d3a0..15a7ac85c 100644 --- a/plugins/_browser/AGENTS.md +++ b/plugins/_browser/AGENTS.md @@ -20,6 +20,7 @@ - Keep the WebUI Browser inside its own modal/canvas affordance; do not replace it with page-level navigation. - Default the visible WebUI Browser to live CDP screencast for responsiveness. Keep lightweight CDP/DOM state snapshots as the fallback transport. - Keep narrow WebUI Browser controls usable by grouping navigation with Annotate/settings above a full-width address bar. +- Browser URL-intent handling must only claim web URL schemes and leave custom Agent Zero schemes to their owning surfaces. - Prefer DOM/CDP browser actions with refs, selectors, frame-chain refs, and screenshots over viewport coordinate input. Coordinates remain a visual fallback. - Do not hardcode user-specific browser paths or secrets. diff --git a/plugins/_browser/webui/browser-store.js b/plugins/_browser/webui/browser-store.js index c278d63f0..6e70a1891 100644 --- a/plugins/_browser/webui/browser-store.js +++ b/plugins/_browser/webui/browser-store.js @@ -2846,8 +2846,21 @@ const model = { export const store = createStore("browserPage", model); +const WEB_INTENT_SCHEMES = new Set(["http", "https", "file", "about"]); + +function isWebUrlIntent(url = "") { + const value = String(url || "").trim(); + if (!value) return true; + const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(value); + if (!scheme) return true; + return WEB_INTENT_SCHEMES.has(scheme[1].toLowerCase()); +} + registerUrlHandler(async (intent = {}) => { const url = String(intent.url || "").trim(); + // Custom schemes such as a0-editor: belong to other surfaces; claiming them + // here would navigate the browser to an unloadable URL. + if (!isWebUrlIntent(url)) return false; const payload = { url, source: intent.source || "surface-url-intent" }; await openLatestSurface("browser", payload); return await store.openUrlIntent(url, { source: payload.source }); diff --git a/tests/test_office_canvas_setup.py b/tests/test_office_canvas_setup.py index a7759a1dc..404e09c5e 100644 --- a/tests/test_office_canvas_setup.py +++ b/tests/test_office_canvas_setup.py @@ -592,6 +592,7 @@ def test_desktop_text_open_with_routes_to_editor_surface(): desktop_session = read("plugins", "_desktop", "helpers", "desktop_session.py") desktop_store = read("plugins", "_desktop", "webui", "desktop-store.js") editor_store = read("plugins", "_editor", "webui", "editor-store.js") + browser_store = read("plugins", "_browser", "webui", "browser-store.js") assert 'EDITOR_HANDLER_DESKTOP_ID = "agent-zero-editor.desktop"' in desktop_session assert "def _write_editor_bridge_script" in desktop_session @@ -607,6 +608,11 @@ def test_desktop_text_open_with_routes_to_editor_surface(): assert "handleEditorUrlIntent" in editor_store assert 'openLatestSurface("editor"' in editor_store + # The browser surface must not claim a0-editor: intents, otherwise the + # editor "Open With" handler lands on an unloadable about:blank page. + assert "function isWebUrlIntent" in browser_store + assert "if (!isWebUrlIntent(url)) return false;" in browser_store + def test_office_and_desktop_skills_are_rehomed_and_renamed(): office_skills = PROJECT_ROOT / "plugins" / "_office" / "skills"