diff options
| author | amankumarsingh77 <amankumarsingh7702@gmal.com> | 2026-05-02 16:35:30 +0530 |
|---|---|---|
| committer | amankumarsingh77 <amankumarsingh7702@gmal.com> | 2026-05-02 16:35:30 +0530 |
| commit | 96934b772378b57aed243919d3c1d6ad6e96df1f (patch) | |
| tree | 0d6adf2751d5ffae38a00b32343b122c9ccf9286 /src | |
| parent | dc07a5157188c09b79487af8b47fbda51b6af7d6 (diff) | |
feat(domains): migrate drag_and_drop
Diffstat (limited to 'src')
| -rw-r--r-- | src/domains/drag.ts | 66 | ||||
| -rw-r--r-- | src/registry.ts | 2 | ||||
| -rw-r--r-- | src/tools.ts | 49 |
3 files changed, 68 insertions, 49 deletions
diff --git a/src/domains/drag.ts b/src/domains/drag.ts new file mode 100644 index 0000000..bc8e789 --- /dev/null +++ b/src/domains/drag.ts @@ -0,0 +1,66 @@ +import { Type } from "typebox"; +import { type Result, err, ok } from "../util/result"; +import { defineBrowserTool, type ToolErr, type ToolOk } from "../util/tool"; + +const DragArgs = Type.Object({ + startX: Type.Number(), + startY: Type.Number(), + endX: Type.Number(), + endY: Type.Number(), + dataTransfer: Type.Optional( + Type.Record(Type.String(), Type.String(), { + description: "Optional MIME → data map for DataTransfer (e.g., { 'text/plain': 'hello' })", + }), + ), +}); + +export const dragAndDropTool = defineBrowserTool({ + name: "browser_drag_and_drop", + label: "Browser Drag & Drop", + description: "Drag from (startX, startY) to (endX, endY) using CDP Input.dispatchDragEvent.", + promptSnippet: "Drag and drop between two coordinates", + promptGuidelines: [ + "Coordinates in CSS pixels.", + "dataTransfer is an optional MIME→data map (e.g., { 'text/plain': 'hello' }).", + ], + parameters: DragArgs, + async handler(args, { client }): Promise<Result<ToolOk, ToolErr>> { + const data = args.dataTransfer + ? { + items: Object.entries(args.dataTransfer).map(([mimeType, payload]) => ({ + mimeType, + data: Buffer.from(payload).toString("base64"), + })), + dragOperationsMask: 1, + } + : { items: [], dragOperationsMask: 1 }; + const cdp = client.session(); + const calls: ReadonlyArray<readonly [string, Record<string, unknown>]> = [ + ["Input.dispatchMouseEvent", { type: "mousePressed", x: args.startX, y: args.startY, button: "left", clickCount: 1 }], + ["Input.dispatchDragEvent", { type: "dragEnter", x: args.startX, y: args.startY, data, modifiers: 0 }], + // 5 interpolated dragOver steps from start → end so the page sees a smooth drag. + ...Array.from({ length: 5 }, (_, i): readonly [string, Record<string, unknown>] => { + const t = (i + 1) / 5; + return [ + "Input.dispatchDragEvent", + { + type: "dragOver", + x: Math.round(args.startX + (args.endX - args.startX) * t), + y: Math.round(args.startY + (args.endY - args.startY) * t), + data, + modifiers: 0, + }, + ]; + }), + ["Input.dispatchDragEvent", { type: "drop", x: args.endX, y: args.endY, data, modifiers: 0 }], + ["Input.dispatchMouseEvent", { type: "mouseReleased", x: args.endX, y: args.endY, button: "left", clickCount: 1 }], + ]; + for (const [method, params] of calls) { + const r = await cdp.call(method, params); + if (!r.success) return err({ kind: "cdp_error", message: r.error.message }); + } + return ok({ + text: `Dragged from (${args.startX},${args.startY}) to (${args.endX},${args.endY})`, + }); + }, +}); diff --git a/src/registry.ts b/src/registry.ts index 2e8e574..06ec74b 100644 --- a/src/registry.ts +++ b/src/registry.ts @@ -12,6 +12,7 @@ import { goBackTool, goForwardTool, reloadTool } from "./domains/history"; import { listTabsTool, currentTabTool, switchTabTool, newTabTool } from "./domains/tabs"; import { uploadFileTool, downloadTool, printToPdfTool } from "./domains/files"; import { viewportResizeTool } from "./domains/viewport"; +import { dragAndDropTool } from "./domains/drag"; const TOOLS: ReadonlyArray<AnyBrowserToolDefinition> = [ clickTool, @@ -37,6 +38,7 @@ const TOOLS: ReadonlyArray<AnyBrowserToolDefinition> = [ downloadTool, printToPdfTool, viewportResizeTool, + dragAndDropTool, ]; export const registerAllTools = (pi: ExtensionAPI, client: BrowserClient): void => { diff --git a/src/tools.ts b/src/tools.ts index 1e5308e..f665287 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -270,55 +270,6 @@ export function registerTools(pi: ExtensionAPI, daemon: BrowserDaemon): void { }); // ═══════════════════════════════════════════════════════════════════════════ - // browser_drag_and_drop - // ═══════════════════════════════════════════════════════════════════════════ - pi.registerTool({ - name: "browser_drag_and_drop", - label: "Browser Drag And Drop", - description: - "Perform a drag-and-drop operation from one viewport coordinate to another. " + - "Use for kanban boards, file uploads via drag, reorderable lists, and " + - "other drag-based UIs.", - promptSnippet: "Drag from (startX, startY) and drop at (endX, endY)", - promptGuidelines: [ - "Use browser_drag_and_drop for drag-based interactions like moving cards, reordering items, or drag-to-upload.", - "Capture a screenshot BEFORE to find the start and end coordinates.", - "Capture a screenshot AFTER to verify the drag-and-drop worked.", - "If the target site expects DOM-level drag events (not just compositor events), try browser_upload_file instead for file uploads.", - ], - parameters: Type.Object({ - startX: Type.Number({ description: "X coordinate to start dragging from" }), - startY: Type.Number({ description: "Y coordinate to start dragging from" }), - endX: Type.Number({ description: "X coordinate to drop at" }), - endY: Type.Number({ description: "Y coordinate to drop at" }), - }), - async execute(_id, params) { - try { - await daemon.ensureAlive(); - await daemon.dragAndDrop( - params.startX, - params.startY, - params.endX, - params.endY, - ); - return { - content: [{ - type: "text" as const, - text: `Dragged from (${params.startX}, ${params.startY}) to (${params.endX}, ${params.endY}).`, - }], - details: undefined, - }; - } catch (err) { - return { - isError: true, - content: [{ type: "text" as const, text: `Drag-and-drop failed: ${err instanceof Error ? err.message : String(err)}` }], - details: undefined, - }; - } - }, - }); - - // ═══════════════════════════════════════════════════════════════════════════ // browser_get_network_log // ═══════════════════════════════════════════════════════════════════════════ pi.registerTool({ |
