@silbercue/chrome 0.2.0

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 (129) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +229 -0
  3. package/build/cache/a11y-tree.d.ts +252 -0
  4. package/build/cache/a11y-tree.js +1956 -0
  5. package/build/cache/index.d.ts +8 -0
  6. package/build/cache/index.js +4 -0
  7. package/build/cache/selector-cache.d.ts +47 -0
  8. package/build/cache/selector-cache.js +119 -0
  9. package/build/cache/session-defaults.d.ts +27 -0
  10. package/build/cache/session-defaults.js +130 -0
  11. package/build/cache/tab-state-cache.d.ts +39 -0
  12. package/build/cache/tab-state-cache.js +171 -0
  13. package/build/cdp/cdp-client.d.ts +25 -0
  14. package/build/cdp/cdp-client.js +146 -0
  15. package/build/cdp/chrome-launcher.d.ts +85 -0
  16. package/build/cdp/chrome-launcher.js +502 -0
  17. package/build/cdp/console-collector.d.ts +53 -0
  18. package/build/cdp/console-collector.js +147 -0
  19. package/build/cdp/debug.d.ts +1 -0
  20. package/build/cdp/debug.js +6 -0
  21. package/build/cdp/dialog-handler.d.ts +54 -0
  22. package/build/cdp/dialog-handler.js +129 -0
  23. package/build/cdp/dom-watcher.d.ts +45 -0
  24. package/build/cdp/dom-watcher.js +195 -0
  25. package/build/cdp/emulation.d.ts +12 -0
  26. package/build/cdp/emulation.js +17 -0
  27. package/build/cdp/index.d.ts +11 -0
  28. package/build/cdp/index.js +6 -0
  29. package/build/cdp/network-collector.d.ts +77 -0
  30. package/build/cdp/network-collector.js +257 -0
  31. package/build/cdp/protocol.d.ts +20 -0
  32. package/build/cdp/protocol.js +1 -0
  33. package/build/cdp/session-manager.d.ts +62 -0
  34. package/build/cdp/session-manager.js +205 -0
  35. package/build/cdp/settle.d.ts +16 -0
  36. package/build/cdp/settle.js +71 -0
  37. package/build/cli/license-commands.d.ts +19 -0
  38. package/build/cli/license-commands.js +199 -0
  39. package/build/cli/top-level-commands.d.ts +49 -0
  40. package/build/cli/top-level-commands.js +222 -0
  41. package/build/hooks/index.d.ts +2 -0
  42. package/build/hooks/index.js +1 -0
  43. package/build/hooks/pro-hooks.d.ts +126 -0
  44. package/build/hooks/pro-hooks.js +17 -0
  45. package/build/index.d.ts +4 -0
  46. package/build/index.js +86 -0
  47. package/build/license/free-tier-config.d.ts +14 -0
  48. package/build/license/free-tier-config.js +18 -0
  49. package/build/license/index.d.ts +4 -0
  50. package/build/license/index.js +2 -0
  51. package/build/license/license-status.d.ts +15 -0
  52. package/build/license/license-status.js +9 -0
  53. package/build/overlay/session-overlay.d.ts +22 -0
  54. package/build/overlay/session-overlay.js +372 -0
  55. package/build/plan/index.d.ts +7 -0
  56. package/build/plan/index.js +4 -0
  57. package/build/plan/plan-conditions.d.ts +12 -0
  58. package/build/plan/plan-conditions.js +242 -0
  59. package/build/plan/plan-executor.d.ts +49 -0
  60. package/build/plan/plan-executor.js +259 -0
  61. package/build/plan/plan-state-store.d.ts +24 -0
  62. package/build/plan/plan-state-store.js +43 -0
  63. package/build/plan/plan-variables.d.ts +16 -0
  64. package/build/plan/plan-variables.js +71 -0
  65. package/build/registry.d.ts +124 -0
  66. package/build/registry.js +884 -0
  67. package/build/server.d.ts +1 -0
  68. package/build/server.js +245 -0
  69. package/build/tools/click.d.ts +34 -0
  70. package/build/tools/click.js +293 -0
  71. package/build/tools/configure-session.d.ts +15 -0
  72. package/build/tools/configure-session.js +45 -0
  73. package/build/tools/console-logs.d.ts +18 -0
  74. package/build/tools/console-logs.js +44 -0
  75. package/build/tools/dom-snapshot.d.ts +13 -0
  76. package/build/tools/dom-snapshot.js +259 -0
  77. package/build/tools/element-utils.d.ts +23 -0
  78. package/build/tools/element-utils.js +133 -0
  79. package/build/tools/error-utils.d.ts +8 -0
  80. package/build/tools/error-utils.js +27 -0
  81. package/build/tools/evaluate.d.ts +34 -0
  82. package/build/tools/evaluate.js +217 -0
  83. package/build/tools/file-upload.d.ts +20 -0
  84. package/build/tools/file-upload.js +174 -0
  85. package/build/tools/fill-form.d.ts +39 -0
  86. package/build/tools/fill-form.js +256 -0
  87. package/build/tools/handle-dialog.d.ts +15 -0
  88. package/build/tools/handle-dialog.js +48 -0
  89. package/build/tools/index.d.ts +35 -0
  90. package/build/tools/index.js +18 -0
  91. package/build/tools/navigate.d.ts +18 -0
  92. package/build/tools/navigate.js +111 -0
  93. package/build/tools/network-monitor.d.ts +18 -0
  94. package/build/tools/network-monitor.js +66 -0
  95. package/build/tools/observe.d.ts +44 -0
  96. package/build/tools/observe.js +339 -0
  97. package/build/tools/press-key.d.ts +33 -0
  98. package/build/tools/press-key.js +155 -0
  99. package/build/tools/read-page.d.ts +22 -0
  100. package/build/tools/read-page.js +100 -0
  101. package/build/tools/run-plan.d.ts +205 -0
  102. package/build/tools/run-plan.js +215 -0
  103. package/build/tools/screenshot.d.ts +16 -0
  104. package/build/tools/screenshot.js +283 -0
  105. package/build/tools/scroll.d.ts +28 -0
  106. package/build/tools/scroll.js +143 -0
  107. package/build/tools/switch-tab.d.ts +26 -0
  108. package/build/tools/switch-tab.js +355 -0
  109. package/build/tools/tab-status.d.ts +7 -0
  110. package/build/tools/tab-status.js +50 -0
  111. package/build/tools/type.d.ts +31 -0
  112. package/build/tools/type.js +247 -0
  113. package/build/tools/virtual-desk.d.ts +7 -0
  114. package/build/tools/virtual-desk.js +108 -0
  115. package/build/tools/visual-constants.d.ts +3 -0
  116. package/build/tools/visual-constants.js +10 -0
  117. package/build/tools/wait-for.d.ts +26 -0
  118. package/build/tools/wait-for.js +323 -0
  119. package/build/transport/index.d.ts +3 -0
  120. package/build/transport/index.js +2 -0
  121. package/build/transport/pipe-transport.d.ts +18 -0
  122. package/build/transport/pipe-transport.js +63 -0
  123. package/build/transport/transport.d.ts +8 -0
  124. package/build/transport/transport.js +1 -0
  125. package/build/transport/websocket-transport.d.ts +22 -0
  126. package/build/transport/websocket-transport.js +200 -0
  127. package/build/types.d.ts +21 -0
  128. package/build/types.js +1 -0
  129. package/package.json +62 -0
@@ -0,0 +1,256 @@
1
+ import { z } from "zod";
2
+ import { resolveElement, buildRefNotFoundError, RefNotFoundError } from "./element-utils.js";
3
+ import { wrapCdpError } from "./error-utils.js";
4
+ // --- Constants ---
5
+ /** Roles relevant for form fields — used to filter "Did you mean?" suggestions */
6
+ const FORM_FIELD_ROLES = new Set([
7
+ "textbox", "searchbox", "combobox", "spinbutton",
8
+ "checkbox", "radio", "listbox", "switch",
9
+ ]);
10
+ // --- Schema (Task 1.1) ---
11
+ const fieldSchema = z.object({
12
+ ref: z
13
+ .string()
14
+ .optional()
15
+ .describe("A11y-Tree element ref (e.g. 'e5') — preferred over selector"),
16
+ selector: z
17
+ .string()
18
+ .optional()
19
+ .describe("CSS selector (e.g. '#email') — fallback when ref is not available"),
20
+ value: z
21
+ .union([z.string(), z.boolean(), z.number()])
22
+ .describe("Value to set: string for text/select, boolean for checkbox/radio, number coerced to string"),
23
+ });
24
+ export const fillFormSchema = z.object({
25
+ fields: z
26
+ .array(fieldSchema)
27
+ .min(1)
28
+ .describe("Array of fields to fill. Each field needs ref or selector plus value."),
29
+ });
30
+ // --- Helpers ---
31
+ function truncate(text, maxLen) {
32
+ return text.length > maxLen ? text.slice(0, maxLen) + "..." : text;
33
+ }
34
+ function fieldIdentifier(field) {
35
+ return field.ref ?? field.selector ?? "unknown";
36
+ }
37
+ // --- Element type detection (Task 1.2, step 3) ---
38
+ async function getElementTypeInfo(cdpClient, objectId, sessionId) {
39
+ const typeInfo = await cdpClient.send("Runtime.callFunctionOn", {
40
+ objectId,
41
+ functionDeclaration: `function() {
42
+ var tag = this.tagName;
43
+ var type = (this.type || '').toLowerCase();
44
+ var checked = !!this.checked;
45
+ return JSON.stringify({ tag: tag, type: type, checked: checked });
46
+ }`,
47
+ returnByValue: true,
48
+ }, sessionId);
49
+ return JSON.parse(typeInfo.result.value);
50
+ }
51
+ // --- Select handler (Task 1.2, step 4A — AC #2) ---
52
+ async function fillSelect(cdpClient, objectId, sessionId, value) {
53
+ await cdpClient.send("Runtime.callFunctionOn", {
54
+ objectId,
55
+ functionDeclaration: `function(val) {
56
+ var opts = Array.from(this.options);
57
+ var match = opts.find(function(o) { return o.value === val || o.textContent.trim() === val; });
58
+ if (!match) {
59
+ var available = opts.map(function(o) { return o.textContent.trim() || o.value; }).filter(Boolean);
60
+ throw new Error('Option not found: ' + val + ' — available: [' + available.join(', ') + ']');
61
+ }
62
+ this.value = match.value;
63
+ this.dispatchEvent(new Event('change', { bubbles: true }));
64
+ }`,
65
+ arguments: [{ value }],
66
+ returnByValue: true,
67
+ }, sessionId);
68
+ }
69
+ // --- Checkbox/Radio click handler (Task 1.2, step 4B — AC #3) ---
70
+ async function clickCheckboxOrRadio(cdpClient, sessionId, backendNodeId) {
71
+ // Step 1: Reset scroll to origin (same pattern as click.ts)
72
+ await cdpClient.send("Runtime.evaluate", { expression: "window.scrollTo(0,0)" }, sessionId);
73
+ // Step 2: Scroll element into view
74
+ await cdpClient.send("DOM.scrollIntoViewIfNeeded", { backendNodeId }, sessionId);
75
+ // Step 3: Get viewport-relative center via DOM.getContentQuads
76
+ const quadsResult = await cdpClient.send("DOM.getContentQuads", { backendNodeId }, sessionId);
77
+ if (!quadsResult.quads || quadsResult.quads.length === 0) {
78
+ throw new Error("Element has no visible layout quads");
79
+ }
80
+ const q = quadsResult.quads[0];
81
+ const x = (q[0] + q[2] + q[4] + q[6]) / 4;
82
+ const y = (q[1] + q[3] + q[5] + q[7]) / 4;
83
+ // Step 4: Dispatch mouse events
84
+ await cdpClient.send("Input.dispatchMouseEvent", { type: "mousePressed", x, y, button: "left", clickCount: 1 }, sessionId);
85
+ await cdpClient.send("Input.dispatchMouseEvent", { type: "mouseReleased", x, y, button: "left", clickCount: 1 }, sessionId);
86
+ }
87
+ // --- Text input handler (Task 1.2, step 4C — AC #1) ---
88
+ async function fillTextInput(cdpClient, sessionId, backendNodeId, objectId, value, humanType) {
89
+ // Step 1: Focus
90
+ await cdpClient.send("DOM.focus", { backendNodeId }, sessionId);
91
+ // Step 2: Clear (always — fill_form sets definitive values)
92
+ await cdpClient.send("Runtime.callFunctionOn", {
93
+ objectId,
94
+ functionDeclaration: "function() { this.value = ''; this.dispatchEvent(new Event('input', { bubbles: true })); }",
95
+ returnByValue: true,
96
+ }, sessionId);
97
+ // Step 3: Type text
98
+ // Story 16.5: If humanType callback is injected (via Pro-Hook), delegate.
99
+ if (value.length > 0) {
100
+ if (humanType) {
101
+ await humanType(cdpClient, sessionId, value);
102
+ }
103
+ else {
104
+ await cdpClient.send("Input.insertText", { text: value }, sessionId);
105
+ }
106
+ }
107
+ }
108
+ // --- Main handler (Task 1.2) ---
109
+ export async function fillFormHandler(params, cdpClient, sessionId, sessionManager) {
110
+ const start = performance.now();
111
+ const results = [];
112
+ // Story 16.5: Extract optional humanType callback injected by the
113
+ // `enhanceTool` Pro-Hook. The field is NOT part of the Zod schema and must
114
+ // be stripped from `params` before downstream code uses it (so it never
115
+ // leaks into per-field validation or response payloads).
116
+ const rawParams = params;
117
+ const maybeHuman = rawParams.humanType;
118
+ const humanType = typeof maybeHuman === "function" ? maybeHuman : undefined;
119
+ if ("humanType" in rawParams) {
120
+ const { humanType: _humanType, ...rest } = rawParams;
121
+ void _humanType;
122
+ params = rest;
123
+ }
124
+ // Process fields sequentially (CDP commands are not parallelizable on same tab)
125
+ for (const field of params.fields) {
126
+ const id = fieldIdentifier(field);
127
+ // Step 1: Validate ref/selector — at least one must be set
128
+ if (!field.ref && !field.selector) {
129
+ results.push({
130
+ ref: field.ref,
131
+ selector: field.selector,
132
+ status: "error",
133
+ message: "Field needs either 'ref' or 'selector'",
134
+ value: field.value,
135
+ });
136
+ continue;
137
+ }
138
+ try {
139
+ // Step 2: Resolve element
140
+ const target = field.ref ? { ref: field.ref } : { selector: field.selector };
141
+ const element = await resolveElement(cdpClient, sessionId, target, sessionManager);
142
+ const targetSession = element.resolvedSessionId;
143
+ // Step 3: Determine element type via DOM inspection
144
+ const info = await getElementTypeInfo(cdpClient, element.objectId, targetSession);
145
+ // Build display name for response
146
+ const displayName = element.name
147
+ ? `${element.role} '${element.name}'`
148
+ : id;
149
+ // Step 4: Dispatch based on element type
150
+ if (info.tag === "SELECT") {
151
+ // --- SELECT ---
152
+ await fillSelect(cdpClient, element.objectId, targetSession, String(field.value));
153
+ results.push({
154
+ ref: field.ref,
155
+ selector: field.selector,
156
+ status: "ok",
157
+ displayName,
158
+ value: field.value,
159
+ });
160
+ }
161
+ else if (info.tag === "INPUT" &&
162
+ (info.type === "checkbox" || info.type === "radio")) {
163
+ // --- CHECKBOX / RADIO ---
164
+ const desiredChecked = !!field.value;
165
+ if (desiredChecked !== info.checked) {
166
+ await clickCheckboxOrRadio(cdpClient, targetSession, element.backendNodeId);
167
+ }
168
+ results.push({
169
+ ref: field.ref,
170
+ selector: field.selector,
171
+ status: "ok",
172
+ displayName,
173
+ value: field.value,
174
+ });
175
+ }
176
+ else if (info.tag === "INPUT" && info.type === "file") {
177
+ // --- FILE INPUT — not supported, point to file_upload tool ---
178
+ results.push({
179
+ ref: field.ref,
180
+ selector: field.selector,
181
+ status: "error",
182
+ message: `Field ${id} is a file input — use the file_upload tool instead of fill_form`,
183
+ value: field.value,
184
+ });
185
+ continue;
186
+ }
187
+ else {
188
+ // --- TEXT INPUT (default) ---
189
+ const textValue = String(field.value);
190
+ await fillTextInput(cdpClient, targetSession, element.backendNodeId, element.objectId, textValue, humanType);
191
+ results.push({
192
+ ref: field.ref,
193
+ selector: field.selector,
194
+ status: "ok",
195
+ displayName,
196
+ value: field.value,
197
+ });
198
+ }
199
+ }
200
+ catch (err) {
201
+ // RefNotFoundError — contextual "did you mean?" error
202
+ if (err instanceof RefNotFoundError && field.ref) {
203
+ const errorText = buildRefNotFoundError(field.ref, FORM_FIELD_ROLES);
204
+ results.push({
205
+ ref: field.ref,
206
+ selector: field.selector,
207
+ status: "error",
208
+ message: errorText,
209
+ value: field.value,
210
+ });
211
+ continue;
212
+ }
213
+ // CDP connection error or other — wrap and continue
214
+ const message = wrapCdpError(err, "fill_form");
215
+ results.push({
216
+ ref: field.ref,
217
+ selector: field.selector,
218
+ status: "error",
219
+ message,
220
+ value: field.value,
221
+ });
222
+ }
223
+ }
224
+ // --- Build response (Task 1.3) ---
225
+ const elapsedMs = Math.round(performance.now() - start);
226
+ const okCount = results.filter((r) => r.status === "ok").length;
227
+ const errorCount = results.filter((r) => r.status === "error").length;
228
+ const totalCount = results.length;
229
+ // Format response lines
230
+ const lines = [];
231
+ if (errorCount === 0) {
232
+ lines.push(`Filled ${okCount} fields:`);
233
+ }
234
+ else {
235
+ lines.push(`Filled ${okCount}/${totalCount} fields (${errorCount} error${errorCount > 1 ? "s" : ""}):`);
236
+ }
237
+ for (const r of results) {
238
+ const id = r.ref ?? r.selector ?? "unknown";
239
+ if (r.status === "ok") {
240
+ const displayValue = typeof r.value === "boolean"
241
+ ? String(r.value)
242
+ : `"${truncate(String(r.value ?? ""), 50)}"`;
243
+ const name = r.displayName ?? id;
244
+ lines.push(`- ${id} (${name}): ${displayValue} \u2713`);
245
+ }
246
+ else {
247
+ lines.push(`- ${id}: ${r.message}`);
248
+ }
249
+ }
250
+ const allFailed = okCount === 0;
251
+ return {
252
+ content: [{ type: "text", text: lines.join("\n") }],
253
+ ...(allFailed ? { isError: true } : {}),
254
+ _meta: { elapsedMs, method: "fill_form" },
255
+ };
256
+ }
@@ -0,0 +1,15 @@
1
+ import { z } from "zod";
2
+ import type { DialogHandler } from "../cdp/dialog-handler.js";
3
+ import type { ToolResponse } from "../types.js";
4
+ export declare const handleDialogSchema: z.ZodObject<{
5
+ action: z.ZodEnum<["accept", "dismiss", "get_status"]>;
6
+ text: z.ZodOptional<z.ZodString>;
7
+ }, "strip", z.ZodTypeAny, {
8
+ action: "accept" | "dismiss" | "get_status";
9
+ text?: string | undefined;
10
+ }, {
11
+ action: "accept" | "dismiss" | "get_status";
12
+ text?: string | undefined;
13
+ }>;
14
+ export type HandleDialogParams = z.infer<typeof handleDialogSchema>;
15
+ export declare function handleDialogHandler(params: HandleDialogParams, dialogHandler: DialogHandler): Promise<ToolResponse>;
@@ -0,0 +1,48 @@
1
+ import { z } from "zod";
2
+ export const handleDialogSchema = z.object({
3
+ action: z.enum(["accept", "dismiss", "get_status"]).describe("accept: accept the next dialog, dismiss: dismiss/cancel it, get_status: check pending dialogs"),
4
+ text: z.string().optional().describe("Text to enter in prompt dialogs (only used with action: accept)"),
5
+ });
6
+ export async function handleDialogHandler(params, dialogHandler) {
7
+ const start = performance.now();
8
+ switch (params.action) {
9
+ case "accept": {
10
+ const config = {
11
+ autoAccept: true,
12
+ promptText: params.text,
13
+ timeoutMs: 0,
14
+ };
15
+ dialogHandler.pushHandler(config);
16
+ const message = params.text
17
+ ? `Dialog handler configured: next dialog will be accepted with text: '${params.text}'`
18
+ : "Dialog handler configured: next dialog will be accepted";
19
+ return {
20
+ content: [{ type: "text", text: message }],
21
+ _meta: { elapsedMs: Math.round(performance.now() - start), method: "handle_dialog" },
22
+ };
23
+ }
24
+ case "dismiss": {
25
+ dialogHandler.pushHandler({
26
+ autoAccept: false,
27
+ timeoutMs: 0,
28
+ });
29
+ return {
30
+ content: [{ type: "text", text: "Dialog handler configured: next dialog will be dismissed" }],
31
+ _meta: { elapsedMs: Math.round(performance.now() - start), method: "handle_dialog" },
32
+ };
33
+ }
34
+ case "get_status": {
35
+ const notifications = dialogHandler.consumeNotifications();
36
+ if (notifications.length === 0) {
37
+ return {
38
+ content: [{ type: "text", text: "No dialogs occurred" }],
39
+ _meta: { elapsedMs: Math.round(performance.now() - start), method: "handle_dialog" },
40
+ };
41
+ }
42
+ return {
43
+ content: [{ type: "text", text: JSON.stringify(notifications, null, 2) }],
44
+ _meta: { elapsedMs: Math.round(performance.now() - start), method: "handle_dialog" },
45
+ };
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,35 @@
1
+ export { evaluateSchema, evaluateHandler } from "./evaluate.js";
2
+ export type { EvaluateParams } from "./evaluate.js";
3
+ export { navigateSchema, navigateHandler } from "./navigate.js";
4
+ export type { NavigateParams } from "./navigate.js";
5
+ export { readPageSchema, readPageHandler } from "./read-page.js";
6
+ export type { ReadPageParams } from "./read-page.js";
7
+ export { screenshotSchema, screenshotHandler } from "./screenshot.js";
8
+ export type { ScreenshotParams } from "./screenshot.js";
9
+ export { waitForSchema, waitForHandler } from "./wait-for.js";
10
+ export type { WaitForParams } from "./wait-for.js";
11
+ export { clickSchema, clickHandler } from "./click.js";
12
+ export type { ClickParams } from "./click.js";
13
+ export { typeSchema, typeHandler } from "./type.js";
14
+ export type { TypeParams } from "./type.js";
15
+ export { resolveElement, buildRefNotFoundError } from "./element-utils.js";
16
+ export type { ResolvedElement, ElementTarget } from "./element-utils.js";
17
+ export { tabStatusSchema, tabStatusHandler } from "./tab-status.js";
18
+ export type { TabStatusParams } from "./tab-status.js";
19
+ export { switchTabSchema, switchTabHandler } from "./switch-tab.js";
20
+ export type { SwitchTabParams } from "./switch-tab.js";
21
+ export { virtualDeskSchema, virtualDeskHandler } from "./virtual-desk.js";
22
+ export type { VirtualDeskParams } from "./virtual-desk.js";
23
+ export { runPlanSchema, runPlanHandler } from "./run-plan.js";
24
+ export type { RunPlanParams } from "./run-plan.js";
25
+ export { domSnapshotSchema, domSnapshotHandler } from "./dom-snapshot.js";
26
+ export type { DomSnapshotParams } from "./dom-snapshot.js";
27
+ export { CLICKABLE_TAGS, CLICKABLE_ROLES, COMPUTED_STYLES } from "./visual-constants.js";
28
+ export { consoleLogsSchema, consoleLogsHandler } from "./console-logs.js";
29
+ export type { ConsoleLogsParams } from "./console-logs.js";
30
+ export { networkMonitorSchema, networkMonitorHandler } from "./network-monitor.js";
31
+ export type { NetworkMonitorParams } from "./network-monitor.js";
32
+ export { configureSessionSchema, configureSessionHandler } from "./configure-session.js";
33
+ export type { ConfigureSessionParams } from "./configure-session.js";
34
+ export { observeSchema, observeHandler } from "./observe.js";
35
+ export type { ObserveParams } from "./observe.js";
@@ -0,0 +1,18 @@
1
+ export { evaluateSchema, evaluateHandler } from "./evaluate.js";
2
+ export { navigateSchema, navigateHandler } from "./navigate.js";
3
+ export { readPageSchema, readPageHandler } from "./read-page.js";
4
+ export { screenshotSchema, screenshotHandler } from "./screenshot.js";
5
+ export { waitForSchema, waitForHandler } from "./wait-for.js";
6
+ export { clickSchema, clickHandler } from "./click.js";
7
+ export { typeSchema, typeHandler } from "./type.js";
8
+ export { resolveElement, buildRefNotFoundError } from "./element-utils.js";
9
+ export { tabStatusSchema, tabStatusHandler } from "./tab-status.js";
10
+ export { switchTabSchema, switchTabHandler } from "./switch-tab.js";
11
+ export { virtualDeskSchema, virtualDeskHandler } from "./virtual-desk.js";
12
+ export { runPlanSchema, runPlanHandler } from "./run-plan.js";
13
+ export { domSnapshotSchema, domSnapshotHandler } from "./dom-snapshot.js";
14
+ export { CLICKABLE_TAGS, CLICKABLE_ROLES, COMPUTED_STYLES } from "./visual-constants.js";
15
+ export { consoleLogsSchema, consoleLogsHandler } from "./console-logs.js";
16
+ export { networkMonitorSchema, networkMonitorHandler } from "./network-monitor.js";
17
+ export { configureSessionSchema, configureSessionHandler } from "./configure-session.js";
18
+ export { observeSchema, observeHandler } from "./observe.js";
@@ -0,0 +1,18 @@
1
+ import { z } from "zod";
2
+ import type { CdpClient } from "../cdp/cdp-client.js";
3
+ import type { ToolResponse } from "../types.js";
4
+ export declare const navigateSchema: z.ZodObject<{
5
+ url: z.ZodOptional<z.ZodString>;
6
+ action: z.ZodDefault<z.ZodOptional<z.ZodEnum<["goto", "back"]>>>;
7
+ settle_ms: z.ZodOptional<z.ZodNumber>;
8
+ }, "strip", z.ZodTypeAny, {
9
+ action: "goto" | "back";
10
+ url?: string | undefined;
11
+ settle_ms?: number | undefined;
12
+ }, {
13
+ url?: string | undefined;
14
+ action?: "goto" | "back" | undefined;
15
+ settle_ms?: number | undefined;
16
+ }>;
17
+ export type NavigateParams = z.infer<typeof navigateSchema>;
18
+ export declare function navigateHandler(params: NavigateParams, cdpClient: CdpClient, sessionId?: string): Promise<ToolResponse>;
@@ -0,0 +1,111 @@
1
+ import { z } from "zod";
2
+ import { settle } from "../cdp/settle.js";
3
+ import { wrapCdpError } from "./error-utils.js";
4
+ export const navigateSchema = z.object({
5
+ url: z.string().optional().describe("URL to navigate to (required for goto action)"),
6
+ action: z
7
+ .enum(["goto", "back"])
8
+ .optional()
9
+ .default("goto")
10
+ .describe("Navigation action: goto (default) or back"),
11
+ settle_ms: z
12
+ .number()
13
+ .optional()
14
+ .describe("Extra wait time in ms after page load (default: 500)"),
15
+ });
16
+ export async function navigateHandler(params, cdpClient, sessionId) {
17
+ const start = performance.now();
18
+ const method = "navigate";
19
+ try {
20
+ if (params.action === "back") {
21
+ return await handleBack(cdpClient, sessionId, params.settle_ms, start, method);
22
+ }
23
+ return await handleGoto(cdpClient, sessionId, params.url, params.settle_ms, start, method);
24
+ }
25
+ catch (err) {
26
+ const elapsedMs = Math.round(performance.now() - start);
27
+ return {
28
+ content: [{ type: "text", text: wrapCdpError(err, "navigate") }],
29
+ isError: true,
30
+ _meta: { elapsedMs, method },
31
+ };
32
+ }
33
+ }
34
+ async function handleGoto(cdpClient, sessionId, url, settleMs, start, method) {
35
+ if (!url) {
36
+ return {
37
+ content: [{ type: "text", text: "URL is required for goto action" }],
38
+ isError: true,
39
+ _meta: { elapsedMs: Math.round(performance.now() - start), method },
40
+ };
41
+ }
42
+ const navResult = await cdpClient.send("Page.navigate", { url }, sessionId);
43
+ if (navResult.errorText) {
44
+ return {
45
+ content: [{ type: "text", text: `Navigation failed: ${navResult.errorText} for ${url}` }],
46
+ isError: true,
47
+ _meta: { elapsedMs: Math.round(performance.now() - start), method },
48
+ };
49
+ }
50
+ const isSpa = !navResult.loaderId;
51
+ const settleResult = await settle({
52
+ cdpClient,
53
+ sessionId: sessionId,
54
+ frameId: navResult.frameId,
55
+ loaderId: navResult.loaderId,
56
+ spaNavigation: isSpa,
57
+ settleMs,
58
+ });
59
+ return await buildSuccessResponse(cdpClient, sessionId, start, method, settleResult);
60
+ }
61
+ async function handleBack(cdpClient, sessionId, settleMs, start, method) {
62
+ const history = await cdpClient.send("Page.getNavigationHistory", {}, sessionId);
63
+ if (history.currentIndex <= 0) {
64
+ return {
65
+ content: [{ type: "text", text: "No previous page in history" }],
66
+ isError: true,
67
+ _meta: { elapsedMs: Math.round(performance.now() - start), method },
68
+ };
69
+ }
70
+ const prevEntry = history.entries[history.currentIndex - 1];
71
+ const frameTree = await cdpClient.send("Page.getFrameTree", {}, sessionId);
72
+ const mainFrameId = frameTree.frameTree.frame.id;
73
+ await cdpClient.send("Page.navigateToHistoryEntry", { entryId: prevEntry.id }, sessionId);
74
+ // Back navigation: no loaderId available upfront — accept any lifecycle events for main frame
75
+ const settleResult = await settle({
76
+ cdpClient,
77
+ sessionId: sessionId,
78
+ frameId: mainFrameId,
79
+ settleMs,
80
+ });
81
+ return await buildSuccessResponse(cdpClient, sessionId, start, method, settleResult);
82
+ }
83
+ async function buildSuccessResponse(cdpClient, sessionId, start, method, settleResult) {
84
+ let finalUrl = "unknown";
85
+ let title = "";
86
+ try {
87
+ const urlResult = await cdpClient.send("Runtime.evaluate", { expression: "document.URL", returnByValue: true }, sessionId);
88
+ finalUrl = urlResult.result.value;
89
+ }
90
+ catch {
91
+ // URL retrieval failed — continue with "unknown"
92
+ }
93
+ try {
94
+ const titleResult = await cdpClient.send("Runtime.evaluate", { expression: "document.title", returnByValue: true }, sessionId);
95
+ title = titleResult.result.value;
96
+ }
97
+ catch {
98
+ // Title retrieval failed — continue with empty title
99
+ }
100
+ const elapsedMs = Math.round(performance.now() - start);
101
+ let text = title
102
+ ? `Navigated to ${finalUrl} — ${title}`
103
+ : `Navigated to ${finalUrl}`;
104
+ if (!settleResult.settled) {
105
+ text += " (page not fully settled)";
106
+ }
107
+ return {
108
+ content: [{ type: "text", text }],
109
+ _meta: { elapsedMs, method, settled: settleResult.settled, settleSignal: settleResult.signal },
110
+ };
111
+ }
@@ -0,0 +1,18 @@
1
+ import { z } from "zod";
2
+ import type { NetworkCollector } from "../cdp/network-collector.js";
3
+ import type { ToolResponse } from "../types.js";
4
+ export declare const networkMonitorSchema: z.ZodObject<{
5
+ action: z.ZodEnum<["start", "get", "stop"]>;
6
+ filter: z.ZodOptional<z.ZodEnum<["failed"]>>;
7
+ pattern: z.ZodOptional<z.ZodString>;
8
+ }, "strip", z.ZodTypeAny, {
9
+ action: "start" | "get" | "stop";
10
+ filter?: "failed" | undefined;
11
+ pattern?: string | undefined;
12
+ }, {
13
+ action: "start" | "get" | "stop";
14
+ filter?: "failed" | undefined;
15
+ pattern?: string | undefined;
16
+ }>;
17
+ export type NetworkMonitorParams = z.infer<typeof networkMonitorSchema>;
18
+ export declare function networkMonitorHandler(params: NetworkMonitorParams, networkCollector: NetworkCollector): Promise<ToolResponse>;
@@ -0,0 +1,66 @@
1
+ import { z } from "zod";
2
+ export const networkMonitorSchema = z.object({
3
+ action: z.enum(["start", "get", "stop"])
4
+ .describe("start: begin recording, get: retrieve recorded requests, stop: return and clear"),
5
+ filter: z.enum(["failed"])
6
+ .optional()
7
+ .describe("Filter results — 'failed': only requests with HTTP >= 400 or network errors"),
8
+ pattern: z.string()
9
+ .optional()
10
+ .describe("Regex pattern to match against request URLs"),
11
+ });
12
+ export async function networkMonitorHandler(params, networkCollector) {
13
+ const start = performance.now();
14
+ // action: "start"
15
+ if (params.action === "start") {
16
+ await networkCollector.start();
17
+ return {
18
+ content: [{ type: "text", text: JSON.stringify({
19
+ status: "monitoring",
20
+ since: networkCollector.monitoringSince,
21
+ }) }],
22
+ _meta: { elapsedMs: Math.round(performance.now() - start), method: "network_monitor" },
23
+ };
24
+ }
25
+ // action: "get"
26
+ if (params.action === "get") {
27
+ if (!networkCollector.isMonitoring) {
28
+ return {
29
+ content: [{ type: "text", text: "Network-Monitoring nicht aktiv — starte mit action: 'start'" }],
30
+ isError: true,
31
+ _meta: { elapsedMs: Math.round(performance.now() - start), method: "network_monitor" },
32
+ };
33
+ }
34
+ let requests;
35
+ try {
36
+ requests = (params.filter || params.pattern)
37
+ ? networkCollector.getFiltered(params.filter, params.pattern)
38
+ : networkCollector.getAll();
39
+ }
40
+ catch (err) {
41
+ return {
42
+ content: [{ type: "text", text: `Invalid regex pattern: ${err.message}` }],
43
+ isError: true,
44
+ _meta: { elapsedMs: Math.round(performance.now() - start), method: "network_monitor" },
45
+ };
46
+ }
47
+ return {
48
+ content: [{ type: "text", text: JSON.stringify(requests) }],
49
+ _meta: {
50
+ elapsedMs: Math.round(performance.now() - start),
51
+ method: "network_monitor",
52
+ count: requests.length,
53
+ },
54
+ };
55
+ }
56
+ // action: "stop"
57
+ const requests = await networkCollector.stop();
58
+ return {
59
+ content: [{ type: "text", text: JSON.stringify(requests) }],
60
+ _meta: {
61
+ elapsedMs: Math.round(performance.now() - start),
62
+ method: "network_monitor",
63
+ count: requests.length,
64
+ },
65
+ };
66
+ }
@@ -0,0 +1,44 @@
1
+ import { z } from "zod";
2
+ import type { CdpClient } from "../cdp/cdp-client.js";
3
+ import type { SessionManager } from "../cdp/session-manager.js";
4
+ import type { ToolResponse } from "../types.js";
5
+ export declare const observeSchema: z.ZodObject<{
6
+ selector: z.ZodString;
7
+ duration: z.ZodOptional<z.ZodNumber>;
8
+ until: z.ZodOptional<z.ZodString>;
9
+ then_click: z.ZodOptional<z.ZodString>;
10
+ click_first: z.ZodOptional<z.ZodString>;
11
+ collect: z.ZodDefault<z.ZodOptional<z.ZodEnum<["text", "attributes", "all"]>>>;
12
+ interval: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
13
+ timeout: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
14
+ }, "strip", z.ZodTypeAny, {
15
+ timeout: number;
16
+ selector: string;
17
+ collect: "text" | "all" | "attributes";
18
+ interval: number;
19
+ duration?: number | undefined;
20
+ until?: string | undefined;
21
+ then_click?: string | undefined;
22
+ click_first?: string | undefined;
23
+ }, {
24
+ selector: string;
25
+ timeout?: number | undefined;
26
+ duration?: number | undefined;
27
+ until?: string | undefined;
28
+ then_click?: string | undefined;
29
+ click_first?: string | undefined;
30
+ collect?: "text" | "all" | "attributes" | undefined;
31
+ interval?: number | undefined;
32
+ }>;
33
+ export type ObserveParams = z.infer<typeof observeSchema>;
34
+ /**
35
+ * Build the observer function for "collect" mode.
36
+ * Runs for `duration` ms, collects all text/attribute changes.
37
+ */
38
+ export declare function buildCollectFunction(duration: number, interval: number, collect: "text" | "attributes" | "all", clickFirstSelector?: string): string;
39
+ /**
40
+ * Build the observer function for "until" mode.
41
+ * Waits until a JS condition is met, optionally clicks a target element.
42
+ */
43
+ export declare function buildUntilFunction(untilExpression: string, timeout: number, interval: number, collect: "text" | "attributes" | "all", thenClickSelector?: string, clickFirstSelector?: string): string;
44
+ export declare function observeHandler(params: ObserveParams, cdpClient: CdpClient, sessionId: string, sessionManager?: SessionManager): Promise<ToolResponse>;