Bots now announce every click and typing step before it runs, and the web app draws a cursor in the bot's colour that glides to that point over the live computer screen, ripples on clicks and shows typing. - contracts: ComputerPointerPayload on the existing thread.computer event - executor: computer_act and browser_act announce pointer steps (best effort); the page-browser helper reports element screen boxes, which are stripped before results reach the model - web: agentPointerFeed + AgentCursor over the side-panel preview and the full-window screen, mapped through the noVNC letterbox - in-app browser: native WebContentsView on desktop (own session, http(s) only, clamped bounds, back/forward, reload, DevTools, load errors) and a sandboxed iframe on the web; replaces the dead panel, the fake 50%/40% cursors and the unimplemented devServer bridge Claude-Session: https://claude.ai/code/session_01WiGooXtsKrZQmdszepRrNi Co-authored-by: Claude <noreply@anthropic.com>
39 lines
1.4 KiB
TypeScript
39 lines
1.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { browserFrameSandbox, normalizeBrowserUrl } from "./browser-url";
|
|
|
|
describe("normalizeBrowserUrl", () => {
|
|
it("defaults local dev servers to http and the web to https", () => {
|
|
expect(normalizeBrowserUrl("localhost:5173")).toBe("http://localhost:5173/");
|
|
expect(normalizeBrowserUrl("127.0.0.1:3000/app?x=1")).toBe("http://127.0.0.1:3000/app?x=1");
|
|
expect(normalizeBrowserUrl("example.com/docs")).toBe("https://example.com/docs");
|
|
expect(normalizeBrowserUrl(" https://example.com ")).toBe("https://example.com/");
|
|
expect(normalizeBrowserUrl("http://example.com")).toBe("http://example.com/");
|
|
});
|
|
|
|
it("rejects input that is not an http(s) address", () => {
|
|
for (const input of [
|
|
"",
|
|
"hello world",
|
|
"hello",
|
|
"javascript:alert(1)",
|
|
"file:///etc/passwd",
|
|
"data:text/html,hi",
|
|
"ftp://example.com",
|
|
"https://user:fake-password@example.com",
|
|
]) {
|
|
expect(normalizeBrowserUrl(input), input).toBeNull();
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("browserFrameSandbox", () => {
|
|
it("never grants same-origin access to the app's own origin", () => {
|
|
expect(browserFrameSandbox("https://app.test/x", "https://app.test")).not.toContain(
|
|
"allow-same-origin",
|
|
);
|
|
expect(browserFrameSandbox("http://localhost:5173/", "https://app.test")).toContain(
|
|
"allow-same-origin",
|
|
);
|
|
});
|
|
});
|