@ticktockbent/charlotte 0.5.1 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +15 -23
  3. package/dist/browser/browser-manager.d.ts +3 -0
  4. package/dist/browser/browser-manager.d.ts.map +1 -1
  5. package/dist/browser/browser-manager.js +13 -2
  6. package/dist/browser/browser-manager.js.map +1 -1
  7. package/dist/cli.d.ts +1 -0
  8. package/dist/cli.d.ts.map +1 -1
  9. package/dist/cli.js +41 -16
  10. package/dist/cli.js.map +1 -1
  11. package/dist/index.js +2 -6
  12. package/dist/index.js.map +1 -1
  13. package/dist/renderer/interactive-extractor.d.ts.map +1 -1
  14. package/dist/renderer/interactive-extractor.js +10 -2
  15. package/dist/renderer/interactive-extractor.js.map +1 -1
  16. package/dist/renderer/layout-extractor.d.ts.map +1 -1
  17. package/dist/renderer/layout-extractor.js +10 -2
  18. package/dist/renderer/layout-extractor.js.map +1 -1
  19. package/dist/renderer/renderer-pipeline.d.ts +2 -2
  20. package/dist/renderer/renderer-pipeline.d.ts.map +1 -1
  21. package/dist/renderer/renderer-pipeline.js +5 -3
  22. package/dist/renderer/renderer-pipeline.js.map +1 -1
  23. package/dist/server.d.ts.map +1 -1
  24. package/dist/server.js +9 -4
  25. package/dist/server.js.map +1 -1
  26. package/dist/state/snapshot-store.d.ts +4 -0
  27. package/dist/state/snapshot-store.d.ts.map +1 -1
  28. package/dist/state/snapshot-store.js +15 -3
  29. package/dist/state/snapshot-store.js.map +1 -1
  30. package/dist/tools/dev-mode.d.ts.map +1 -1
  31. package/dist/tools/dev-mode.js +10 -10
  32. package/dist/tools/dev-mode.js.map +1 -1
  33. package/dist/tools/dialog.js +5 -5
  34. package/dist/tools/dialog.js.map +1 -1
  35. package/dist/tools/evaluate.d.ts +1 -1
  36. package/dist/tools/evaluate.d.ts.map +1 -1
  37. package/dist/tools/evaluate.js +3 -2
  38. package/dist/tools/evaluate.js.map +1 -1
  39. package/dist/tools/interaction-helpers.d.ts +55 -0
  40. package/dist/tools/interaction-helpers.d.ts.map +1 -0
  41. package/dist/tools/interaction-helpers.js +312 -0
  42. package/dist/tools/interaction-helpers.js.map +1 -0
  43. package/dist/tools/interaction.d.ts +1 -17
  44. package/dist/tools/interaction.d.ts.map +1 -1
  45. package/dist/tools/interaction.js +120 -500
  46. package/dist/tools/interaction.js.map +1 -1
  47. package/dist/tools/meta-tool.d.ts +2 -2
  48. package/dist/tools/meta-tool.js +3 -3
  49. package/dist/tools/monitoring.js +9 -9
  50. package/dist/tools/monitoring.js.map +1 -1
  51. package/dist/tools/navigation.d.ts.map +1 -1
  52. package/dist/tools/navigation.js +36 -76
  53. package/dist/tools/navigation.js.map +1 -1
  54. package/dist/tools/observation.d.ts.map +1 -1
  55. package/dist/tools/observation.js +94 -98
  56. package/dist/tools/observation.js.map +1 -1
  57. package/dist/tools/session.d.ts.map +1 -1
  58. package/dist/tools/session.js +135 -184
  59. package/dist/tools/session.js.map +1 -1
  60. package/dist/tools/tool-groups.d.ts +8 -8
  61. package/dist/tools/tool-groups.d.ts.map +1 -1
  62. package/dist/tools/tool-groups.js +113 -142
  63. package/dist/tools/tool-groups.js.map +1 -1
  64. package/dist/tools/tool-helpers.d.ts +18 -0
  65. package/dist/tools/tool-helpers.d.ts.map +1 -1
  66. package/dist/tools/tool-helpers.js +69 -2
  67. package/dist/tools/tool-helpers.js.map +1 -1
  68. package/dist/tools/wait-for.d.ts +5 -0
  69. package/dist/tools/wait-for.d.ts.map +1 -0
  70. package/dist/tools/wait-for.js +169 -0
  71. package/dist/tools/wait-for.js.map +1 -0
  72. package/dist/types/config.d.ts +16 -0
  73. package/dist/types/config.d.ts.map +1 -1
  74. package/dist/types/config.js +15 -0
  75. package/dist/types/config.js.map +1 -1
  76. package/dist/utils/wait.js +11 -5
  77. package/dist/utils/wait.js.map +1 -1
  78. package/package.json +5 -2
@@ -0,0 +1,312 @@
1
+ import { CharlotteError, CharlotteErrorCode } from "../types/errors.js";
2
+ import { logger } from "../utils/logger.js";
3
+ /** Maps short modifier names to Puppeteer KeyInput values. */
4
+ export const MODIFIER_KEY_MAP = {
5
+ ctrl: "Control",
6
+ shift: "Shift",
7
+ alt: "Alt",
8
+ meta: "Meta",
9
+ };
10
+ /**
11
+ * Click an element by backend node ID using CDP to get coordinates, then click at those coords.
12
+ */
13
+ export async function clickElementByBackendNodeId(page, backendNodeId, clickType = "left", modifiers = []) {
14
+ // Get the element's box model to find clickable coordinates
15
+ const cdpSession = await page.createCDPSession();
16
+ try {
17
+ // First, scroll the element into view
18
+ await cdpSession.send("DOM.scrollIntoViewIfNeeded", { backendNodeId });
19
+ // Get box model for coordinates
20
+ const { model } = await cdpSession.send("DOM.getBoxModel", {
21
+ backendNodeId,
22
+ });
23
+ if (!model) {
24
+ throw new CharlotteError(CharlotteErrorCode.ELEMENT_NOT_FOUND, "Element has no visible box model — it may be hidden or zero-sized.", "Call charlotte_observe to check the element's state.");
25
+ }
26
+ // content quad: [x1,y1, x2,y2, x3,y3, x4,y4]
27
+ const contentQuad = model.content;
28
+ const centerX = (contentQuad[0] + contentQuad[2] + contentQuad[4] + contentQuad[6]) / 4;
29
+ const centerY = (contentQuad[1] + contentQuad[3] + contentQuad[5] + contentQuad[7]) / 4;
30
+ // Hold down modifier keys before the click
31
+ for (const modifier of modifiers) {
32
+ const modifierKey = MODIFIER_KEY_MAP[modifier];
33
+ await page.keyboard.down(modifierKey);
34
+ }
35
+ try {
36
+ if (clickType === "right") {
37
+ await page.mouse.click(centerX, centerY, { button: "right" });
38
+ }
39
+ else if (clickType === "double") {
40
+ await page.mouse.click(centerX, centerY, { clickCount: 2 });
41
+ }
42
+ else {
43
+ await page.mouse.click(centerX, centerY);
44
+ }
45
+ }
46
+ finally {
47
+ // Release modifier keys in reverse order (always release even if click fails)
48
+ for (const modifier of [...modifiers].reverse()) {
49
+ const modifierKey = MODIFIER_KEY_MAP[modifier];
50
+ await page.keyboard.up(modifierKey);
51
+ }
52
+ }
53
+ }
54
+ finally {
55
+ await cdpSession.detach();
56
+ }
57
+ }
58
+ /**
59
+ * Wait for any navigation triggered by an action, or fall back to a brief settle pause.
60
+ *
61
+ * Listens for the `framenavigated` CDP event to detect if a click caused navigation.
62
+ * If navigation is detected within `detectionWindowMs`, waits for the page load event
63
+ * (up to `loadTimeoutMs`). If no navigation fires, returns after `settleMs`.
64
+ *
65
+ * Also races against dialog events — if the action triggers a JavaScript dialog
66
+ * (alert, confirm, prompt, beforeunload), the action promise will block indefinitely.
67
+ * This function detects that and returns early so the caller can surface `pending_dialog`.
68
+ */
69
+ export async function waitForPossibleNavigation(page, action, { detectionWindowMs = 500, loadTimeoutMs = 10000, settleMs = 50 } = {}) {
70
+ let navigationDetected = false;
71
+ let dialogDetected = false;
72
+ // Listen for navigation start via page event (fires on any navigation)
73
+ const navigationStartPromise = new Promise((resolve) => {
74
+ const handler = () => {
75
+ navigationDetected = true;
76
+ page.off("framenavigated", handler);
77
+ resolve();
78
+ };
79
+ page.on("framenavigated", handler);
80
+ // Clean up listener if no navigation fires within detection window
81
+ setTimeout(() => {
82
+ page.off("framenavigated", handler);
83
+ resolve();
84
+ }, detectionWindowMs);
85
+ });
86
+ // Listen for dialog (blocks the action from completing)
87
+ const dialogPromise = new Promise((resolve) => {
88
+ const handler = () => {
89
+ dialogDetected = true;
90
+ page.off("dialog", handler);
91
+ resolve();
92
+ };
93
+ page.on("dialog", handler);
94
+ // Clean up on timeout — if no dialog fires, we don't need this listener
95
+ setTimeout(() => {
96
+ page.off("dialog", handler);
97
+ resolve();
98
+ }, detectionWindowMs);
99
+ });
100
+ // Race: action vs dialog
101
+ const actionPromise = action();
102
+ await Promise.race([
103
+ actionPromise.then(() => "action"),
104
+ dialogPromise.then(() => "dialog"),
105
+ ]);
106
+ if (dialogDetected) {
107
+ // Dialog is blocking the action. Don't await actionPromise — it will
108
+ // resolve later when the dialog is handled via charlotte_dialog.
109
+ // Guard against unhandled rejection from the fire-and-forget promise.
110
+ actionPromise.catch(() => {
111
+ logger.debug("Post-dialog action promise rejected (expected)");
112
+ });
113
+ return;
114
+ }
115
+ // Action completed normally — check for navigation
116
+ await navigationStartPromise;
117
+ if (navigationDetected) {
118
+ // Navigation occurred — wait for the page to finish loading
119
+ try {
120
+ await page.waitForNavigation({ waitUntil: "load", timeout: loadTimeoutMs });
121
+ }
122
+ catch {
123
+ // Page may have already finished loading before we called waitForNavigation,
124
+ // or the load timed out. Either way, render what we have.
125
+ logger.debug("Post-navigation load wait ended (page may already be loaded)");
126
+ }
127
+ }
128
+ else {
129
+ // No navigation — brief settle for in-page DOM updates
130
+ await new Promise((resolve) => setTimeout(resolve, settleMs));
131
+ }
132
+ }
133
+ /**
134
+ * Focus an element by backend node ID using CDP.
135
+ */
136
+ export async function focusElementByBackendNodeId(page, backendNodeId) {
137
+ const cdpSession = await page.createCDPSession();
138
+ try {
139
+ await cdpSession.send("DOM.focus", { backendNodeId });
140
+ }
141
+ finally {
142
+ await cdpSession.detach();
143
+ }
144
+ }
145
+ /**
146
+ * Hover over an element by backend node ID.
147
+ */
148
+ export async function hoverElementByBackendNodeId(page, backendNodeId) {
149
+ const cdpSession = await page.createCDPSession();
150
+ try {
151
+ await cdpSession.send("DOM.scrollIntoViewIfNeeded", { backendNodeId });
152
+ const { model } = await cdpSession.send("DOM.getBoxModel", {
153
+ backendNodeId,
154
+ });
155
+ if (!model) {
156
+ throw new CharlotteError(CharlotteErrorCode.ELEMENT_NOT_FOUND, "Element has no visible box model for hover.");
157
+ }
158
+ const contentQuad = model.content;
159
+ const centerX = (contentQuad[0] + contentQuad[2] + contentQuad[4] + contentQuad[6]) / 4;
160
+ const centerY = (contentQuad[1] + contentQuad[3] + contentQuad[5] + contentQuad[7]) / 4;
161
+ await page.mouse.move(centerX, centerY);
162
+ }
163
+ finally {
164
+ await cdpSession.detach();
165
+ }
166
+ }
167
+ /**
168
+ * Get the center coordinates of an element by backend node ID.
169
+ * Scrolls the element into view first.
170
+ */
171
+ async function getElementCenter(page, backendNodeId) {
172
+ const cdpSession = await page.createCDPSession();
173
+ try {
174
+ await cdpSession.send("DOM.scrollIntoViewIfNeeded", { backendNodeId });
175
+ const { model } = await cdpSession.send("DOM.getBoxModel", {
176
+ backendNodeId,
177
+ });
178
+ if (!model) {
179
+ throw new CharlotteError(CharlotteErrorCode.ELEMENT_NOT_FOUND, "Element has no visible box model — it may be hidden or zero-sized.", "Call charlotte_observe to check the element's state.");
180
+ }
181
+ const contentQuad = model.content;
182
+ return {
183
+ x: (contentQuad[0] + contentQuad[2] + contentQuad[4] + contentQuad[6]) / 4,
184
+ y: (contentQuad[1] + contentQuad[3] + contentQuad[5] + contentQuad[7]) / 4,
185
+ };
186
+ }
187
+ finally {
188
+ await cdpSession.detach();
189
+ }
190
+ }
191
+ /**
192
+ * Drag one element to another using mouse primitives.
193
+ * Sequence: move to source → mousedown → move to target → mouseup
194
+ * Includes intermediate move steps and delays to ensure drag events fire reliably.
195
+ */
196
+ export async function dragElementToElement(page, sourceBackendNodeId, targetBackendNodeId) {
197
+ const sourceCenter = await getElementCenter(page, sourceBackendNodeId);
198
+ const targetCenter = await getElementCenter(page, targetBackendNodeId);
199
+ // Move to source and press down
200
+ await page.mouse.move(sourceCenter.x, sourceCenter.y);
201
+ await page.mouse.down();
202
+ // Intermediate move to trigger dragstart (some browsers need movement to begin a drag)
203
+ await page.mouse.move(sourceCenter.x + (targetCenter.x - sourceCenter.x) * 0.25, sourceCenter.y + (targetCenter.y - sourceCenter.y) * 0.25, { steps: 5 });
204
+ await new Promise((resolve) => setTimeout(resolve, 50));
205
+ // Move to target
206
+ await page.mouse.move(targetCenter.x, targetCenter.y, { steps: 10 });
207
+ await new Promise((resolve) => setTimeout(resolve, 50));
208
+ // Release
209
+ await page.mouse.up();
210
+ }
211
+ /**
212
+ * Type text into an input element. Uses CDP to focus, optionally clears, then types via keyboard.
213
+ */
214
+ export async function typeIntoElement(page, backendNodeId, text, clearFirst, pressEnter, characterDelay) {
215
+ // Focus the element
216
+ await focusElementByBackendNodeId(page, backendNodeId);
217
+ if (clearFirst) {
218
+ // Select all text then delete — works cross-platform
219
+ await page.keyboard.down("Control");
220
+ await page.keyboard.press("a");
221
+ await page.keyboard.up("Control");
222
+ await page.keyboard.press("Backspace");
223
+ }
224
+ // Type the text — with optional per-character delay for sites with
225
+ // key-by-key event handlers (autocomplete, search-as-you-type, etc.)
226
+ await page.keyboard.type(text, characterDelay ? { delay: characterDelay } : undefined);
227
+ if (pressEnter) {
228
+ await page.keyboard.press("Enter");
229
+ }
230
+ }
231
+ /**
232
+ * Select a value in a <select> element using CDP to set the value and dispatch change events.
233
+ */
234
+ export async function selectOptionByBackendNodeId(page, backendNodeId, value) {
235
+ const cdpSession = await page.createCDPSession();
236
+ try {
237
+ // Resolve the node to get a remote object reference
238
+ const { object } = await cdpSession.send("DOM.resolveNode", {
239
+ backendNodeId,
240
+ });
241
+ if (!object?.objectId) {
242
+ throw new CharlotteError(CharlotteErrorCode.ELEMENT_NOT_FOUND, "Could not resolve select element.");
243
+ }
244
+ // Use Runtime.callFunctionOn to set the value and fire events
245
+ await cdpSession.send("Runtime.callFunctionOn", {
246
+ objectId: object.objectId,
247
+ functionDeclaration: `function(targetValue) {
248
+ const options = Array.from(this.options);
249
+ const matchByValue = options.find(o => o.value === targetValue);
250
+ const matchByText = options.find(o => o.textContent.trim() === targetValue);
251
+ const match = matchByValue || matchByText;
252
+ if (match) {
253
+ this.value = match.value;
254
+ this.dispatchEvent(new Event('input', { bubbles: true }));
255
+ this.dispatchEvent(new Event('change', { bubbles: true }));
256
+ } else {
257
+ throw new Error('Option "' + targetValue + '" not found');
258
+ }
259
+ }`,
260
+ arguments: [{ value }],
261
+ });
262
+ }
263
+ finally {
264
+ await cdpSession.detach();
265
+ }
266
+ }
267
+ /**
268
+ * Submit a form by backend node ID — calls form.submit() via CDP.
269
+ */
270
+ export async function submitFormByBackendNodeId(page, backendNodeId) {
271
+ const cdpSession = await page.createCDPSession();
272
+ try {
273
+ const { object } = await cdpSession.send("DOM.resolveNode", {
274
+ backendNodeId,
275
+ });
276
+ if (!object?.objectId) {
277
+ throw new CharlotteError(CharlotteErrorCode.ELEMENT_NOT_FOUND, "Could not resolve form element.");
278
+ }
279
+ await cdpSession.send("Runtime.callFunctionOn", {
280
+ objectId: object.objectId,
281
+ functionDeclaration: `function() {
282
+ this.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
283
+ }`,
284
+ });
285
+ }
286
+ finally {
287
+ await cdpSession.detach();
288
+ }
289
+ }
290
+ /**
291
+ * Set files on a file input element using CDP DOM.setFileInputFiles.
292
+ * Validates that the target element is actually an <input type="file">.
293
+ */
294
+ export async function setFileInputFiles(page, backendNodeId, filePaths) {
295
+ const cdpSession = await page.createCDPSession();
296
+ try {
297
+ const { node } = await cdpSession.send("DOM.describeNode", { backendNodeId });
298
+ const isFileInput = node.nodeName === "INPUT" &&
299
+ (node.attributes ?? []).some((attr, i, arr) => attr === "type" && arr[i + 1] === "file");
300
+ if (!isFileInput) {
301
+ throw new CharlotteError(CharlotteErrorCode.SESSION_ERROR, "Element is not a file input.", "Use charlotte_find to locate file_input elements.");
302
+ }
303
+ await cdpSession.send("DOM.setFileInputFiles", {
304
+ files: filePaths,
305
+ backendNodeId,
306
+ });
307
+ }
308
+ finally {
309
+ await cdpSession.detach();
310
+ }
311
+ }
312
+ //# sourceMappingURL=interaction-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction-helpers.js","sourceRoot":"","sources":["../../src/tools/interaction-helpers.ts"],"names":[],"mappings":"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"}
@@ -1,22 +1,6 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import type { Page } from "puppeteer";
3
2
  import type { RegisteredTool } from "@modelcontextprotocol/sdk/server/mcp.js";
4
3
  import type { ToolDependencies } from "./tool-helpers.js";
5
- /**
6
- * Wait for any navigation triggered by an action, or fall back to a brief settle pause.
7
- *
8
- * Listens for the `framenavigated` CDP event to detect if a click caused navigation.
9
- * If navigation is detected within `detectionWindowMs`, waits for the page load event
10
- * (up to `loadTimeoutMs`). If no navigation fires, returns after `settleMs`.
11
- *
12
- * Also races against dialog events — if the action triggers a JavaScript dialog
13
- * (alert, confirm, prompt, beforeunload), the action promise will block indefinitely.
14
- * This function detects that and returns early so the caller can surface `pending_dialog`.
15
- */
16
- export declare function waitForPossibleNavigation(page: Page, action: () => Promise<void>, { detectionWindowMs, loadTimeoutMs, settleMs }?: {
17
- detectionWindowMs?: number | undefined;
18
- loadTimeoutMs?: number | undefined;
19
- settleMs?: number | undefined;
20
- }): Promise<void>;
4
+ export { waitForPossibleNavigation } from "./interaction-helpers.js";
21
5
  export declare function registerInteractionTools(server: McpServer, deps: ToolDependencies): Record<string, RegisteredTool>;
22
6
  //# sourceMappingURL=interaction.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"interaction.d.ts","sourceRoot":"","sources":["../../src/tools/interaction.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,IAAI,EAAY,MAAM,WAAW,CAAC;AAGhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAC9E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAgF1D;;;;;;;;;;GAUG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAC3B,EAAE,iBAAuB,EAAE,aAAqB,EAAE,QAAa,EAAE;;;;CAAK,GACrE,OAAO,CAAC,IAAI,CAAC,CAoEf;AAmPD,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,gBAAgB,GACrB,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CA4pBhC"}
1
+ {"version":3,"file":"interaction.d.ts","sourceRoot":"","sources":["../../src/tools/interaction.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAC9E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAyB1D,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAErE,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,gBAAgB,GACrB,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CA+sBhC"}