aboutsummaryrefslogtreecommitdiff
path: root/extensions/chrome-profile-bridge/browser-extension
diff options
context:
space:
mode:
authorIgor Soarez <igor@soarez.org>2026-11-08 17:11:15 +0000
committerIgor Soarez <igor@soarez.org>2026-11-08 17:11:15 +0000
commitb8b63ea4d1bad9c4bbac6b05b03cce5f2cfa3f94 (patch)
tree255a0979c1d590ea759e27980ca3d9d655b690f5 /extensions/chrome-profile-bridge/browser-extension
parentb5f7a9eb2cf46867085b46514d6c9faf0d552fad (diff)
tabs: back to one window per session; keep new tabs out of the user's window
A window shows only one tab, so sessions sharing one hid each other's tabs: no real input and blank screenshots for every session but the one whose tab was active (castle-pirc-web, 2026-11-08). Time-sharing the active tab would flip tabs under the user while they sign in for an agent, so revert 66fbd30: a session gets its own unfocused window. Kept: chrome_tab new for a session with no window opens one for it instead of landing in the user's focused window. The primer and chrome_tab description now say why to reuse a tab.
Diffstat (limited to 'extensions/chrome-profile-bridge/browser-extension')
-rw-r--r--extensions/chrome-profile-bridge/browser-extension/service_worker.js45
1 files changed, 14 insertions, 31 deletions
diff --git a/extensions/chrome-profile-bridge/browser-extension/service_worker.js b/extensions/chrome-profile-bridge/browser-extension/service_worker.js
index 0ceabda..d47b385 100644
--- a/extensions/chrome-profile-bridge/browser-extension/service_worker.js
+++ b/extensions/chrome-profile-bridge/browser-extension/service_worker.js
@@ -226,26 +226,12 @@ function isPiChromeOwnedTarget(tabId, sessionKey) {
return false;
}
-// The window agents share. Every session has its own tab group and a group cannot span windows,
-// but sessions do not need their own windows: new tabs go to the window that already holds any
-// "Pi Session:" group, so agents stay together instead of opening one window each. Returns
-// undefined when no such window exists (the first session then creates one).
-async function sharedPiWindowId() {
- if (!chrome.tabGroups || typeof chrome.windows?.get !== "function") return undefined;
- const groups = await chrome.tabGroups.query({}).catch(() => []);
- for (const group of groups) {
- if (!/^pi session:/i.test((group.title || "").trim()) || typeof group.windowId !== "number") continue;
- const win = await chrome.windows.get(group.windowId).catch(() => null);
- if (win && (win.type === undefined || win.type === "normal")) return win.id ?? group.windowId;
- }
- return undefined;
-}
-
// Create a fresh automation target for `sessionKey`. If this session already has a tab group,
// create the tab inside that group's window so one Pi session keeps one Chrome tab group (Chrome
-// groups cannot span windows). If it has none, use the shared Pi window; only when there is no
-// Pi window yet, create one; fall back to a tab. When the tab is created in a pre-existing window,
-// leave windowId unset so cleanup only closes our tab, never that whole window.
+// groups cannot span windows). If it has none, give the session its own window: a window shows
+// only one tab, so sessions sharing a window would hide each other's tabs, and a hidden tab gets no
+// real input and blank screenshots (measured 2026-11-08). Fall back to a tab. When the tab is
+// created in a pre-existing window, leave windowId unset so cleanup only closes our tab.
async function createAutomationTarget(sessionKey, groupTitle) {
const existingGroup = groupTitle ? await findGroupRecordByTitle(groupTitle) : null;
if (existingGroup && typeof existingGroup.windowId === "number") {
@@ -254,14 +240,6 @@ async function createAutomationTarget(sessionKey, groupTitle) {
await persistAutomationTargets();
return tab;
}
- const sharedWindowId = await sharedPiWindowId();
- if (sharedWindowId !== undefined) {
- // Someone else's window: leave windowId unset so cleanup only ever closes our tab.
- const tab = await chrome.tabs.create({ url: "about:blank", active: false, windowId: sharedWindowId });
- automationTargets.set(sessionKey, { windowId: undefined, tabId: typeof tab.id === "number" ? tab.id : undefined });
- await persistAutomationTargets();
- return tab;
- }
if (chrome.windows && typeof chrome.windows.create === "function") {
try {
const win = await chrome.windows.create({ url: "about:blank", focused: false });
@@ -1911,15 +1889,20 @@ async function dispatch(action, params) {
const existingGroup = await findGroupRecordByTitle(groupTitle);
const createParams = { url: params.url || "about:blank", active: foregroundRequested(params) };
if (existingGroup && typeof existingGroup.windowId === "number") createParams.windowId = existingGroup.windowId;
- else {
- // No group of this session yet: use the shared Pi window, never the user's focused one.
- const sharedWindowId = await sharedPiWindowId();
- if (sharedWindowId !== undefined) createParams.windowId = sharedWindowId;
+ // No group of this session yet: use the window of its automation tab if it has one, else open
+ // the tab in a window of its own. Never the user's focused window, where Chrome would put it.
+ let ownWindow = false;
+ if (createParams.windowId === undefined) {
+ const home = await resolveOwnedAutomationTarget(sessionKeyOf(params)).catch(() => null);
+ if (home && typeof home.windowId === "number") createParams.windowId = home.windowId;
+ else ownWindow = typeof chrome.windows?.create === "function";
}
// Register the creation as in flight until the tab is tracked, so early capture (which only
// runs in tracked tabs) waits for it instead of skipping the new tab's first page load.
const creation = (async () => {
- const created = await chrome.tabs.create(createParams);
+ const created = ownWindow
+ ? (await chrome.windows.create({ url: createParams.url, focused: false })).tabs[0]
+ : await chrome.tabs.create(createParams);
await trackSessionTab(sessionKeyOf(params), created.id, true);
return created;
})();