Add browser pane element picker (#670)

* feat: add browser pane element picker

Port the browser pane from PR #198 and route picked elements through workspace attachments so the context follows every agent composer in a workspace.

Co-authored-by: Jason Kneen <jason.kneen@bouncingfish.com>

* docs: document electron platform overlays

* fix: harden browser pane navigation

* fix: polish browser tab interactions

* fix: route browser pane focus shortcuts

---------

Co-authored-by: Jason Kneen <jason.kneen@bouncingfish.com>
This commit is contained in:
Mohamed Boudra
2026-05-02 19:28:40 +08:00
committed by GitHub
parent 34b95e7f01
commit 906205f97a
35 changed files with 1990 additions and 25 deletions

View File

@@ -0,0 +1,17 @@
import type { WebContents } from "electron";
const browserIdsByWebContentsId = new Map<number, string>();
export function registerPaseoBrowserWebContents(contents: WebContents, browserId: string): void {
browserIdsByWebContentsId.set(contents.id, browserId);
contents.once("destroyed", () => {
browserIdsByWebContentsId.delete(contents.id);
});
}
export function getPaseoBrowserIdForWebContents(contents: WebContents | null): string | null {
if (!contents || contents.isDestroyed()) {
return null;
}
return browserIdsByWebContentsId.get(contents.id) ?? null;
}

View File

@@ -1,4 +1,5 @@
import { app, Menu, BrowserWindow, ipcMain } from "electron";
import { app, Menu, BrowserWindow, ipcMain, webContents } from "electron";
import { getPaseoBrowserIdForWebContents } from "./browser-webviews.js";
interface ShowContextMenuInput {
kind?: "terminal";
@@ -14,6 +15,33 @@ function withBrowserWindow(
};
}
function getFocusedPaseoBrowserWebContents(): Electron.WebContents | null {
const focusedContents = webContents.getFocusedWebContents();
return getPaseoBrowserIdForWebContents(focusedContents) ? focusedContents : null;
}
function reloadFocusedContentsOrWindow(win: BrowserWindow, options?: { ignoreCache?: boolean }) {
const browserContents = getFocusedPaseoBrowserWebContents();
if (browserContents) {
if (options?.ignoreCache) {
browserContents.reloadIgnoringCache();
return;
}
if (browserContents.isLoadingMainFrame()) {
browserContents.stop();
return;
}
browserContents.reload();
return;
}
if (options?.ignoreCache) {
win.webContents.reloadIgnoringCache();
return;
}
win.webContents.reload();
}
export function setupApplicationMenu(): void {
const isMac = process.platform === "darwin";
@@ -73,8 +101,20 @@ export function setupApplicationMenu(): void {
}),
},
{ type: "separator" },
{ role: "reload" },
{ role: "forceReload" },
{
label: "Reload",
accelerator: "CmdOrCtrl+R",
click: withBrowserWindow((win) => {
reloadFocusedContentsOrWindow(win);
}),
},
{
label: "Force Reload",
accelerator: "CmdOrCtrl+Shift+R",
click: withBrowserWindow((win) => {
reloadFocusedContentsOrWindow(win, { ignoreCache: true });
}),
},
{ role: "toggleDevTools" },
{ type: "separator" },
{ role: "togglefullscreen" },