mirror of
https://github.com/Tencent/BrowserSkill.git
synced 2026-09-10 13:01:23 +08:00
fix(dsh-plugin-browserskill): address review findings (leaks, trust fence, queue race)
Blocking: - B1: delete screenshot scratch PNGs — observation frames reuse one fixed per-session path and unlink after every read (finally); browser_screenshot unlinks once the bytes are in the attachment store (kept only when the file itself is the model-facing artifact). - B2: replicate dsh's browser-trust fence on /bsk-observation/*: loopback Host only, Origin must match Host, sec-fetch-site: cross-site refused, POST requires application/json; README documents the loopback trust premise and the 0.0.0.0 warning. Major: - M1: KeyedExecutor tail chains previous+task (allSettled) so a task aborted while queued cannot release the next one into the running session. - M2: client tracks the live frame per session — replacing/removing/reset revokes the old blob URL at once; loads settling after replacement never resurrect it. Minor: drop replaced thumbRefs (+on remove); beginAction fires inside the queue (no label overwrite while queued, no idle flash); half-initialized session cleanup stops through the queue with one retry; SSE (re)open refetches /state (+ snapshot flag renamed subscribed); install probe uses --version (no daemon spawn); emulate mobile documents the width+height requirement (the daemon refuses it alone — verified). Nit: single BskRunOptions declaration; tails map entry dropped on drain; SSE cleanup on res close; popOut catches requestWindow rejections; resize handle gains keyboard control (arrows, 16px steps, aria value attrs). Tests: +14 (fence rules, scratch lifecycle, queue race, blob revocation, instrumentation timing, SSE resync). 113/113 green.
This commit is contained in:
@@ -434,10 +434,15 @@ export function ObservationOverlay({ store }: { store: ObservationClientStore })
|
||||
const popOut = async (): Promise<void> => {
|
||||
const pip = pipApi();
|
||||
if (pip === undefined) return;
|
||||
const win = await pip.requestWindow({ width: size.w, height: size.h });
|
||||
cloneStylesInto(win);
|
||||
win.addEventListener("pagehide", () => setPipWindow(null));
|
||||
setPipWindow(win);
|
||||
try {
|
||||
const win = await pip.requestWindow({ width: size.w, height: size.h });
|
||||
cloneStylesInto(win);
|
||||
win.addEventListener("pagehide", () => setPipWindow(null));
|
||||
setPipWindow(win);
|
||||
} catch {
|
||||
// requestWindow rejects without a user gesture (or when the window was
|
||||
// closed mid-request): stay on the in-page card, no state change.
|
||||
}
|
||||
};
|
||||
|
||||
// Hidden while no owned session exists (and no PiP is up).
|
||||
@@ -496,7 +501,28 @@ export function ObservationOverlay({ store }: { store: ObservationClientStore })
|
||||
data-testid="obs-resize"
|
||||
aria-label="Resize overlay"
|
||||
role="separator"
|
||||
aria-valuenow={size.w}
|
||||
aria-valuetext={`${Math.round(size.w)} by ${Math.round(size.h)} pixels`}
|
||||
aria-valuemin={MIN_SIZE.w}
|
||||
aria-valuemax={Math.round(viewport().w * 0.8)}
|
||||
tabIndex={0}
|
||||
onPointerDown={beginDrag("resize")}
|
||||
onKeyDown={(event) => {
|
||||
const step = 16;
|
||||
const delta =
|
||||
event.key === "ArrowRight"
|
||||
? { w: step, h: 0 }
|
||||
: event.key === "ArrowLeft"
|
||||
? { w: -step, h: 0 }
|
||||
: event.key === "ArrowDown"
|
||||
? { w: 0, h: step }
|
||||
: event.key === "ArrowUp"
|
||||
? { w: 0, h: -step }
|
||||
: undefined;
|
||||
if (delta === undefined) return;
|
||||
event.preventDefault();
|
||||
setSize(clampSize({ w: size.w + delta.w, h: size.h + delta.h }, viewport()));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user