aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoramankumarsingh77 <amankumarsingh7702@gmal.com>2026-05-02 16:35:30 +0530
committeramankumarsingh77 <amankumarsingh7702@gmal.com>2026-05-02 16:35:30 +0530
commit96934b772378b57aed243919d3c1d6ad6e96df1f (patch)
tree0d6adf2751d5ffae38a00b32343b122c9ccf9286 /src
parentdc07a5157188c09b79487af8b47fbda51b6af7d6 (diff)
feat(domains): migrate drag_and_drop
Diffstat (limited to 'src')
-rw-r--r--src/domains/drag.ts66
-rw-r--r--src/registry.ts2
-rw-r--r--src/tools.ts49
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({