From bc610e0f60dd01b71e9dae2017f56dab3de779c4 Mon Sep 17 00:00:00 2001 From: richard-epsilla Date: Tue, 22 Sep 2026 01:15:23 -0700 Subject: [PATCH 1/2] kits: the tab a launch opens is the tab the app lands in window.open with noopener returns null, so the tab opened on the click stayed blank and the app went to a second tab the popup blocker could refuse. The kit app is this origin's own page, so the tab keeps its handle and is navigated once the launch returns. Co-Authored-By: Claude Fable 5.1 --- ui/src/app/(app)/kits/page.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ui/src/app/(app)/kits/page.tsx b/ui/src/app/(app)/kits/page.tsx index 1beab505..58158f6e 100644 --- a/ui/src/app/(app)/kits/page.tsx +++ b/ui/src/app/(app)/kits/page.tsx @@ -84,15 +84,17 @@ export default function KitsPage() { }, []); /** A kit app runs outside this Next app, so it gets its own tab. */ + /** The kit app is this origin's own page, so the tab keeps its handle: `noopener` makes + * window.open return null, which is what left the tab launch opened blank forever. */ function openApp(route: string) { - window.open(route, '_blank', 'noopener,noreferrer'); + window.open(route, '_blank'); } async function launch(kit: Kit, base?: string, model?: string, database?: DbDraft) { // Open the tab NOW, on the click, and navigate it when the launch returns. Opening it after // the await is a popup the browser is entitled to block, because by then it is no longer a // user gesture. - const tab = window.open('', '_blank', 'noopener,noreferrer'); + const tab = window.open('', '_blank'); setBusy(kit.id); setErr(''); try { const r = await harnessFetch(`/api/harness/v1/kits/${kit.id}/launch`, { From cfe49226b436ad053f234e0dcdf0a3cc41d95f5a Mon Sep 17 00:00:00 2001 From: richard-epsilla Date: Tue, 22 Sep 2026 01:16:24 -0700 Subject: [PATCH 2/2] ci: run the checks on #241