aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/domains/dialog.ts31
-rw-r--r--src/registry.ts2
-rw-r--r--src/tools.ts42
3 files changed, 33 insertions, 42 deletions
diff --git a/src/domains/dialog.ts b/src/domains/dialog.ts
new file mode 100644
index 0000000..a5872a1
--- /dev/null
+++ b/src/domains/dialog.ts
@@ -0,0 +1,31 @@
+import { Type } from "typebox";
+import { type Result, err, ok } from "../util/result";
+import { defineBrowserTool, type ToolErr, type ToolOk } from "../util/tool";
+
+const HandleDialogArgs = Type.Object({
+ accept: Type.Boolean({ description: "true = accept, false = dismiss" }),
+ promptText: Type.Optional(Type.String({ description: "Text to type if dialog is a prompt()" })),
+});
+
+export const handleDialogTool = defineBrowserTool({
+ name: "browser_handle_dialog",
+ label: "Browser Handle Dialog",
+ description:
+ "Accept or dismiss the currently open JS dialog (alert/confirm/prompt/beforeunload).",
+ promptSnippet: "Accept or dismiss a JS dialog",
+ promptGuidelines: [
+ "Use after browser_page_info reports a dialog is open. Until handled, no other browser action will work.",
+ "For prompt() dialogs, supply promptText with the value to submit.",
+ ],
+ parameters: HandleDialogArgs,
+ async handler(args, { client }): Promise<Result<ToolOk, ToolErr>> {
+ const params: Record<string, unknown> = { accept: args.accept };
+ if (args.promptText !== undefined) params["promptText"] = args.promptText;
+ const r = await client.session().call("Page.handleJavaScriptDialog", params);
+ if (!r.success) return err({ kind: "cdp_error", message: r.error.message });
+ return ok({
+ text: `Dialog ${args.accept ? "accepted" : "dismissed"}`,
+ details: { accept: args.accept },
+ });
+ },
+});
diff --git a/src/registry.ts b/src/registry.ts
index c92f136..d3559ed 100644
--- a/src/registry.ts
+++ b/src/registry.ts
@@ -5,6 +5,7 @@ import { clickTool } from "./domains/click";
import { typeTool, pressKeyTool, dispatchKeyTool } from "./domains/keyboard";
import { pageInfoTool, waitTool, waitForLoadTool } from "./domains/page";
import { scrollTool } from "./domains/scroll";
+import { handleDialogTool } from "./domains/dialog";
const TOOLS: ReadonlyArray<AnyBrowserToolDefinition> = [
clickTool,
@@ -15,6 +16,7 @@ const TOOLS: ReadonlyArray<AnyBrowserToolDefinition> = [
pageInfoTool,
waitTool,
waitForLoadTool,
+ handleDialogTool,
];
export const registerAllTools = (pi: ExtensionAPI, client: BrowserClient): void => {
diff --git a/src/tools.ts b/src/tools.ts
index 25e49d4..be74a03 100644
--- a/src/tools.ts
+++ b/src/tools.ts
@@ -720,48 +720,6 @@ export function registerTools(pi: ExtensionAPI, daemon: BrowserDaemon): void {
});
// ═══════════════════════════════════════════════════════════════════════════
- // browser_handle_dialog
- // ═══════════════════════════════════════════════════════════════════════════
- pi.registerTool({
- name: "browser_handle_dialog",
- label: "Browser Handle Dialog",
- description:
- "Handle a JavaScript dialog (alert, confirm, prompt, beforeunload). Use when browser_page_info reports an open dialog.",
- promptSnippet: "Accept or dismiss a JavaScript dialog (alert/confirm/prompt)",
- promptGuidelines: [
- "Check browser_page_info first — if it returns a dialog, use browser_handle_dialog before any other browser actions.",
- "JS dialogs freeze the page's JS thread, so no other interaction works until the dialog is handled.",
- 'Use action: "accept" for alerts and confirms, "dismiss" to cancel. For prompts, provide promptText.',
- ],
- parameters: Type.Object({
- action: Type.String({ description: '"accept" or "dismiss"' }),
- promptText: Type.Optional(Type.String({ description: 'Text to enter for prompt dialogs (only used with "accept")' })),
- }),
- async execute(_id, params) {
- try {
- await daemon.ensureAlive();
-
- if (params.action === "accept") {
- await daemon.cdp("Page.handleJavaScriptDialog", {
- accept: true,
- ...(params.promptText !== undefined ? { promptText: params.promptText } : {}),
- });
- } else {
- await daemon.cdp("Page.handleJavaScriptDialog", { accept: false });
- }
-
- return { content: [{ type: "text" as const, text: `Dialog ${params.action}ed.` }], details: undefined };
- } catch (err) {
- return {
- isError: true,
- content: [{ type: "text" as const, text: `Dialog handling failed: ${err instanceof Error ? err.message : String(err)}` }],
- details: undefined,
- };
- }
- },
- });
-
- // ═══════════════════════════════════════════════════════════════════════════
// browser_download
// ═══════════════════════════════════════════════════════════════════════════
pi.registerTool({