diff options
Diffstat (limited to 'src/domains')
| -rw-r--r-- | src/domains/isolated-tab.ts | 27 | ||||
| -rw-r--r-- | src/domains/navigate.ts | 31 | ||||
| -rw-r--r-- | src/domains/setup.ts | 6 |
3 files changed, 29 insertions, 35 deletions
diff --git a/src/domains/isolated-tab.ts b/src/domains/isolated-tab.ts index 73ed158..7969c6b 100644 --- a/src/domains/isolated-tab.ts +++ b/src/domains/isolated-tab.ts @@ -13,7 +13,7 @@ import type { BrowserClient } from "../client"; import { type Result, err, ok } from "../util/result"; import { safeJs } from "../util/js-template"; -import { bindHarnessWindowId } from "../cdp/window-binding"; +import { ensureHarnessWindow, openHarnessTab } from "../cdp/target-factory"; import type { ToolErr } from "../util/tool"; /** A tab attached by its own sessionId, ready to drive via callOnTarget. */ @@ -32,20 +32,19 @@ const toToolErr = (message: string, kind: ToolErr["kind"] = "cdp_error"): ToolEr * sessionId. Does not navigate. The caller MUST `closeIsolatedTab` when done. */ export const openIsolatedTab = async (client: BrowserClient): Promise<Result<IsolatedTab, ToolErr>> => { - const hw = client.ownership().harnessWindow(); - const createParams: Record<string, unknown> = hw - ? { url: "about:blank", openerId: hw } - : { url: "about:blank", newWindow: true }; - - const created = await client.session().callBrowser("Target.createTarget", createParams); - if (!created.success) return err(toToolErr(created.error.message)); - const { targetId } = created.data as { targetId: string }; - - if (createParams["newWindow"]) { - client.ownership().setHarnessWindow(targetId); - await bindHarnessWindowId(client, targetId); + // Routed through the target factory so an isolated tab lands in the pinned + // profile like every other harness tab — otherwise a search or page read + // would run with a different profile's cookies than the visible tabs. + const window = await ensureHarnessWindow(client); + if (!window.success) return err(toToolErr(window.error.message)); + let targetId: string; + if (window.data.freshlyCreated) { + targetId = window.data.targetId; + } else { + const opened = await openHarnessTab(client, window.data.targetId); + if (!opened.success) return err(toToolErr(opened.error.message)); + targetId = opened.data; } - client.ownership().add(targetId); const attached = await client.session().callBrowser("Target.attachToTarget", { targetId, flatten: true }); if (!attached.success) { diff --git a/src/domains/navigate.ts b/src/domains/navigate.ts index e402efc..aa0d671 100644 --- a/src/domains/navigate.ts +++ b/src/domains/navigate.ts @@ -4,7 +4,7 @@ import { type Result, err, ok } from "../util/result"; import { defineBrowserTool, type ToolErr, type ToolOk } from "../util/tool"; import { applyTruncation } from "../util/truncate"; import { safeJs } from "../util/js-template"; -import { bindHarnessWindowId } from "../cdp/window-binding"; +import { ensureHarnessWindow, openHarnessTab } from "../cdp/target-factory"; const NavigateArgs = Type.Object({ url: Type.String({ description: "Full URL to navigate to (e.g. https://github.com)" }), @@ -89,28 +89,21 @@ export const openUrlsTool = defineBrowserTool({ // (fresh/closed), create the FIRST url as a new dedicated window (binding // its windowId) and open the rest as children of it — a parallel // newWindow:true per url would otherwise scatter tabs across N windows. - let seed = client.ownership().harnessWindow(); - let seedResult: TabResult | undefined; - if (!seed) { - const url0 = args.urls[0]; - if (url0 === undefined) return err({ kind: "invalid_state", message: "no URLs provided" }); - const r0 = await client.session().callBrowser("Target.createTarget", { url: "about:blank", newWindow: true }); - if (!r0.success) return err({ kind: "cdp_error", message: r0.error.message }); - seed = (r0.data as { targetId: string }).targetId; - client.ownership().setHarnessWindow(seed); - await bindHarnessWindowId(client, seed); - client.ownership().add(seed); - seedResult = { url: url0, targetId: seed, ok: true }; - } - const seededWindow = seed; + const url0 = args.urls[0]; + if (url0 === undefined) return err({ kind: "invalid_state", message: "no URLs provided" }); + const window = await ensureHarnessWindow(client); + if (!window.success) return err({ kind: "cdp_error", message: window.error.message }); + const seededWindow = window.data.targetId; + // A freshly created window's seed tab serves as the first URL's tab. + const seedResult: TabResult | undefined = window.data.freshlyCreated + ? { url: url0, targetId: seededWindow, ok: true } + : undefined; const created = await Promise.all(args.urls.map(async (url, i): Promise<TabResult> => { // Reuse the seed tab (created above) for the first url instead of duplicating it. if (i === 0 && seedResult) return seedResult; - const r = await client.session().callBrowser("Target.createTarget", { url: "about:blank", openerId: seededWindow }); + const r = await openHarnessTab(client, seededWindow); if (!r.success) return { url, targetId: "", ok: false, error: r.error.message }; - const c = r.data as { targetId: string }; - client.ownership().add(c.targetId); - return { url, targetId: c.targetId, ok: true }; + return { url, targetId: r.data, ok: true }; })); // Phase 2: attach + navigate each created tab in parallel. let completed = 0; diff --git a/src/domains/setup.ts b/src/domains/setup.ts index bbd767f..2ddd739 100644 --- a/src/domains/setup.ts +++ b/src/domains/setup.ts @@ -31,8 +31,10 @@ export const setupTool = defineBrowserTool({ // ensureAlive:false — this tool IS the setup; it must bypass the socket guard ensureAlive: false, renderCall: () => new Text("🔧 Initializing browser...", 0, 0), - async handler(_args, { client }): Promise<Result<ToolOk, ToolErr>> { - const result = await performSetup(client); + async handler(_args, { client, extensionCtx }): Promise<Result<ToolOk, ToolErr>> { + // extensionCtx carries the UI, so the agent calling browser_setup gets the + // same first-run profile picker the user gets from /browser-setup. + const result = await performSetup(client, extensionCtx); if (result.success) { return ok({ text: result.data }); } |
