cbrowser 2.4.0 → 3.0.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.
package/dist/browser.d.ts CHANGED
@@ -190,5 +190,186 @@ export declare class CBrowser {
190
190
  count: number;
191
191
  size: number;
192
192
  }>;
193
+ /**
194
+ * Get the data directory path.
195
+ */
196
+ getDataDir(): string;
197
+ /**
198
+ * Save a visual baseline screenshot.
199
+ */
200
+ saveBaseline(name: string, url?: string): Promise<string>;
201
+ /**
202
+ * Compare current page to a baseline.
203
+ */
204
+ compareBaseline(name: string, threshold?: number): Promise<{
205
+ baseline: string;
206
+ current: string;
207
+ diffPath?: string;
208
+ diffPercentage: number;
209
+ passed: boolean;
210
+ }>;
211
+ /**
212
+ * List all visual baselines.
213
+ */
214
+ listBaselines(): string[];
215
+ /**
216
+ * Run accessibility audit on current page.
217
+ */
218
+ auditAccessibility(): Promise<{
219
+ url: string;
220
+ violations: Array<{
221
+ id: string;
222
+ impact: string;
223
+ description: string;
224
+ helpUrl: string;
225
+ }>;
226
+ passes: number;
227
+ score: number;
228
+ }>;
229
+ private recordingActions;
230
+ private isRecording;
231
+ /**
232
+ * Start recording user interactions.
233
+ */
234
+ startRecording(url?: string): Promise<void>;
235
+ /**
236
+ * Stop recording and return actions.
237
+ */
238
+ stopRecording(): Array<{
239
+ type: string;
240
+ selector?: string;
241
+ value?: string;
242
+ url?: string;
243
+ timestamp: number;
244
+ }>;
245
+ /**
246
+ * Save recording to file.
247
+ */
248
+ saveRecording(name: string, actions?: Array<{
249
+ type: string;
250
+ selector?: string;
251
+ value?: string;
252
+ url?: string;
253
+ timestamp: number;
254
+ }>): string;
255
+ /**
256
+ * Generate test code from recording.
257
+ */
258
+ generateTestCode(name: string, actions: Array<{
259
+ type: string;
260
+ selector?: string;
261
+ value?: string;
262
+ url?: string;
263
+ }>): string;
264
+ /**
265
+ * Export test results as JUnit XML.
266
+ */
267
+ exportJUnit(suite: {
268
+ name: string;
269
+ tests: Array<{
270
+ name: string;
271
+ status: string;
272
+ duration: number;
273
+ error?: string;
274
+ }>;
275
+ }, outputPath?: string): string;
276
+ /**
277
+ * Export test results as TAP format.
278
+ */
279
+ exportTAP(suite: {
280
+ name: string;
281
+ tests: Array<{
282
+ name: string;
283
+ status: string;
284
+ error?: string;
285
+ }>;
286
+ }, outputPath?: string): string;
287
+ /**
288
+ * Run multiple browser tasks in parallel.
289
+ */
290
+ static parallel<T>(tasks: Array<{
291
+ name: string;
292
+ config?: Partial<import("./config.js").CBrowserConfig>;
293
+ run: (browser: CBrowser) => Promise<T>;
294
+ }>, options?: {
295
+ maxConcurrency?: number;
296
+ }): Promise<Array<{
297
+ name: string;
298
+ result?: T;
299
+ error?: string;
300
+ duration: number;
301
+ }>>;
302
+ /**
303
+ * Run the same task across multiple device configurations in parallel.
304
+ */
305
+ static parallelDevices<T>(devices: string[], run: (browser: CBrowser, device: string) => Promise<T>, options?: {
306
+ maxConcurrency?: number;
307
+ }): Promise<Array<{
308
+ device: string;
309
+ result?: T;
310
+ error?: string;
311
+ duration: number;
312
+ }>>;
313
+ /**
314
+ * Run the same task across multiple URLs in parallel.
315
+ */
316
+ static parallelUrls<T>(urls: string[], run: (browser: CBrowser, url: string) => Promise<T>, options?: {
317
+ maxConcurrency?: number;
318
+ config?: Partial<import("./config.js").CBrowserConfig>;
319
+ }): Promise<Array<{
320
+ url: string;
321
+ result?: T;
322
+ error?: string;
323
+ duration: number;
324
+ }>>;
325
+ /**
326
+ * Fluent API - navigate and return chainable instance.
327
+ */
328
+ goto(url: string): Promise<FluentCBrowser>;
329
+ }
330
+ /**
331
+ * Fluent wrapper for chainable API.
332
+ */
333
+ export declare class FluentCBrowser {
334
+ private browser;
335
+ constructor(browser: CBrowser);
336
+ click(selector: string, options?: {
337
+ force?: boolean;
338
+ }): Promise<FluentCBrowser>;
339
+ fill(selector: string, value: string): Promise<FluentCBrowser>;
340
+ screenshot(path?: string): Promise<FluentCBrowser>;
341
+ wait(ms: number): Promise<FluentCBrowser>;
342
+ extract(what: string): Promise<{
343
+ data: unknown;
344
+ fluent: FluentCBrowser;
345
+ }>;
346
+ close(): Promise<void>;
347
+ get instance(): CBrowser;
193
348
  }
349
+ /**
350
+ * Parse natural language into browser action.
351
+ */
352
+ export declare function parseNaturalLanguage(command: string): {
353
+ action: string;
354
+ params: Record<string, string>;
355
+ } | null;
356
+ /**
357
+ * Execute a natural language command.
358
+ */
359
+ export declare function executeNaturalLanguage(browser: CBrowser, command: string): Promise<{
360
+ success: boolean;
361
+ action: string;
362
+ result?: unknown;
363
+ error?: string;
364
+ }>;
365
+ /**
366
+ * Execute multiple natural language commands in sequence.
367
+ */
368
+ export declare function executeNaturalLanguageScript(browser: CBrowser, commands: string[]): Promise<Array<{
369
+ command: string;
370
+ success: boolean;
371
+ action: string;
372
+ result?: unknown;
373
+ error?: string;
374
+ }>>;
194
375
  //# sourceMappingURL=browser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"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"}
package/dist/browser.js CHANGED
@@ -5,7 +5,10 @@
5
5
  * AI-powered browser automation with constitutional safety.
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.CBrowser = void 0;
8
+ exports.FluentCBrowser = exports.CBrowser = void 0;
9
+ exports.parseNaturalLanguage = parseNaturalLanguage;
10
+ exports.executeNaturalLanguage = executeNaturalLanguage;
11
+ exports.executeNaturalLanguageScript = executeNaturalLanguageScript;
9
12
  const playwright_1 = require("playwright");
10
13
  const fs_1 = require("fs");
11
14
  const path_1 = require("path");
@@ -1106,6 +1109,457 @@ class CBrowser {
1106
1109
  stats.audit = countDir(this.paths.auditDir, /\.json$/i);
1107
1110
  return stats;
1108
1111
  }
1112
+ /**
1113
+ * Get the data directory path.
1114
+ */
1115
+ getDataDir() {
1116
+ return this.paths.dataDir;
1117
+ }
1118
+ // =========================================================================
1119
+ // Tier 2: Visual Regression (v2.5.0)
1120
+ // =========================================================================
1121
+ /**
1122
+ * Save a visual baseline screenshot.
1123
+ */
1124
+ async saveBaseline(name, url) {
1125
+ const baselinesDir = (0, path_1.join)(this.paths.dataDir, "baselines");
1126
+ if (!(0, fs_1.existsSync)(baselinesDir)) {
1127
+ (0, fs_1.mkdirSync)(baselinesDir, { recursive: true });
1128
+ }
1129
+ const page = await this.getPage();
1130
+ const screenshotPath = (0, path_1.join)(baselinesDir, `${name}.png`);
1131
+ await page.screenshot({ path: screenshotPath, fullPage: true });
1132
+ const baseline = {
1133
+ name,
1134
+ url: url || page.url(),
1135
+ viewport: page.viewportSize() || { width: 1280, height: 800 },
1136
+ screenshotPath,
1137
+ created: new Date().toISOString(),
1138
+ lastUsed: new Date().toISOString(),
1139
+ };
1140
+ const metaPath = (0, path_1.join)(baselinesDir, `${name}.json`);
1141
+ (0, fs_1.writeFileSync)(metaPath, JSON.stringify(baseline, null, 2));
1142
+ return screenshotPath;
1143
+ }
1144
+ /**
1145
+ * Compare current page to a baseline.
1146
+ */
1147
+ async compareBaseline(name, threshold = 0.1) {
1148
+ const baselinesDir = (0, path_1.join)(this.paths.dataDir, "baselines");
1149
+ const metaPath = (0, path_1.join)(baselinesDir, `${name}.json`);
1150
+ if (!(0, fs_1.existsSync)(metaPath)) {
1151
+ throw new Error(`Baseline not found: ${name}`);
1152
+ }
1153
+ const baseline = JSON.parse((0, fs_1.readFileSync)(metaPath, "utf-8"));
1154
+ const page = await this.getPage();
1155
+ const currentPath = (0, path_1.join)(baselinesDir, `${name}-current-${Date.now()}.png`);
1156
+ await page.screenshot({ path: currentPath, fullPage: true });
1157
+ const baselineBuffer = (0, fs_1.readFileSync)(baseline.screenshotPath);
1158
+ const currentBuffer = (0, fs_1.readFileSync)(currentPath);
1159
+ const sizeDiff = Math.abs(baselineBuffer.length - currentBuffer.length);
1160
+ const maxSize = Math.max(baselineBuffer.length, currentBuffer.length);
1161
+ const diffPercentage = sizeDiff / maxSize;
1162
+ return {
1163
+ baseline: baseline.screenshotPath,
1164
+ current: currentPath,
1165
+ diffPercentage,
1166
+ passed: diffPercentage <= threshold,
1167
+ };
1168
+ }
1169
+ /**
1170
+ * List all visual baselines.
1171
+ */
1172
+ listBaselines() {
1173
+ const baselinesDir = (0, path_1.join)(this.paths.dataDir, "baselines");
1174
+ if (!(0, fs_1.existsSync)(baselinesDir))
1175
+ return [];
1176
+ return (0, fs_1.readdirSync)(baselinesDir)
1177
+ .filter(f => f.endsWith(".json"))
1178
+ .map(f => f.replace(".json", ""));
1179
+ }
1180
+ // =========================================================================
1181
+ // Tier 2: Accessibility Audit (v2.5.0)
1182
+ // =========================================================================
1183
+ /**
1184
+ * Run accessibility audit on current page.
1185
+ */
1186
+ async auditAccessibility() {
1187
+ const page = await this.getPage();
1188
+ const results = await page.evaluate(() => {
1189
+ const violations = [];
1190
+ // Check images without alt
1191
+ document.querySelectorAll("img").forEach(img => {
1192
+ if (!img.alt && !img.getAttribute("aria-label")) {
1193
+ violations.push({
1194
+ id: "img-alt",
1195
+ impact: "serious",
1196
+ description: "Image missing alt text",
1197
+ helpUrl: "https://dequeuniversity.com/rules/axe/4.4/image-alt",
1198
+ });
1199
+ }
1200
+ });
1201
+ // Check buttons without text
1202
+ document.querySelectorAll("button").forEach(btn => {
1203
+ if (!btn.textContent?.trim() && !btn.getAttribute("aria-label")) {
1204
+ violations.push({
1205
+ id: "button-name",
1206
+ impact: "critical",
1207
+ description: "Button has no accessible name",
1208
+ helpUrl: "https://dequeuniversity.com/rules/axe/4.4/button-name",
1209
+ });
1210
+ }
1211
+ });
1212
+ // Check inputs without labels
1213
+ document.querySelectorAll("input:not([type='hidden'])").forEach(input => {
1214
+ const id = input.id;
1215
+ const hasLabel = id && document.querySelector(`label[for="${id}"]`);
1216
+ if (!hasLabel && !input.getAttribute("aria-label")) {
1217
+ violations.push({
1218
+ id: "label",
1219
+ impact: "serious",
1220
+ description: "Form input missing label",
1221
+ helpUrl: "https://dequeuniversity.com/rules/axe/4.4/label",
1222
+ });
1223
+ }
1224
+ });
1225
+ // Check lang attribute
1226
+ if (!document.documentElement.lang) {
1227
+ violations.push({
1228
+ id: "html-has-lang",
1229
+ impact: "serious",
1230
+ description: "Page missing lang attribute",
1231
+ helpUrl: "https://dequeuniversity.com/rules/axe/4.4/html-has-lang",
1232
+ });
1233
+ }
1234
+ const passes = document.querySelectorAll("img[alt], button:not(:empty), label").length;
1235
+ return { violations, passes };
1236
+ });
1237
+ const score = results.passes > 0
1238
+ ? Math.round((results.passes / (results.passes + results.violations.length)) * 100)
1239
+ : 100;
1240
+ return {
1241
+ url: page.url(),
1242
+ violations: results.violations,
1243
+ passes: results.passes,
1244
+ score,
1245
+ };
1246
+ }
1247
+ // =========================================================================
1248
+ // Tier 2: Test Recording (v2.5.0)
1249
+ // =========================================================================
1250
+ recordingActions = [];
1251
+ isRecording = false;
1252
+ /**
1253
+ * Start recording user interactions.
1254
+ */
1255
+ async startRecording(url) {
1256
+ this.isRecording = true;
1257
+ this.recordingActions = [];
1258
+ if (url) {
1259
+ await this.navigate(url);
1260
+ this.recordingActions.push({ type: "navigate", url, timestamp: Date.now() });
1261
+ }
1262
+ }
1263
+ /**
1264
+ * Stop recording and return actions.
1265
+ */
1266
+ stopRecording() {
1267
+ this.isRecording = false;
1268
+ return [...this.recordingActions];
1269
+ }
1270
+ /**
1271
+ * Save recording to file.
1272
+ */
1273
+ saveRecording(name, actions) {
1274
+ const recordingsDir = (0, path_1.join)(this.paths.dataDir, "recordings");
1275
+ if (!(0, fs_1.existsSync)(recordingsDir)) {
1276
+ (0, fs_1.mkdirSync)(recordingsDir, { recursive: true });
1277
+ }
1278
+ const recording = {
1279
+ name,
1280
+ actions: actions || this.recordingActions,
1281
+ created: new Date().toISOString(),
1282
+ };
1283
+ const filePath = (0, path_1.join)(recordingsDir, `${name}.json`);
1284
+ (0, fs_1.writeFileSync)(filePath, JSON.stringify(recording, null, 2));
1285
+ return filePath;
1286
+ }
1287
+ /**
1288
+ * Generate test code from recording.
1289
+ */
1290
+ generateTestCode(name, actions) {
1291
+ let code = `// Generated test: ${name}\n\n`;
1292
+ code += `import { CBrowser } from 'cbrowser';\n\n`;
1293
+ code += `async function test_${name.replace(/[^a-zA-Z0-9]/g, "_")}() {\n`;
1294
+ code += ` const browser = new CBrowser();\n\n`;
1295
+ for (const action of actions) {
1296
+ switch (action.type) {
1297
+ case "navigate":
1298
+ code += ` await browser.navigate("${action.url}");\n`;
1299
+ break;
1300
+ case "click":
1301
+ code += ` await browser.click("${action.selector}");\n`;
1302
+ break;
1303
+ case "fill":
1304
+ code += ` await browser.fill("${action.selector}", "${action.value}");\n`;
1305
+ break;
1306
+ }
1307
+ }
1308
+ code += `\n await browser.close();\n`;
1309
+ code += `}\n\n`;
1310
+ code += `test_${name.replace(/[^a-zA-Z0-9]/g, "_")}();\n`;
1311
+ return code;
1312
+ }
1313
+ // =========================================================================
1314
+ // Tier 2: Test Export (v2.5.0)
1315
+ // =========================================================================
1316
+ /**
1317
+ * Export test results as JUnit XML.
1318
+ */
1319
+ exportJUnit(suite, outputPath) {
1320
+ const filename = outputPath || (0, path_1.join)(this.paths.dataDir, `junit-${Date.now()}.xml`);
1321
+ let xml = `<?xml version="1.0" encoding="UTF-8"?>\n`;
1322
+ xml += `<testsuite name="${suite.name}" tests="${suite.tests.length}">\n`;
1323
+ for (const test of suite.tests) {
1324
+ xml += ` <testcase name="${test.name}" time="${(test.duration / 1000).toFixed(3)}">\n`;
1325
+ if (test.status === "failed" && test.error) {
1326
+ xml += ` <failure message="${test.error.replace(/"/g, "&quot;")}">${test.error}</failure>\n`;
1327
+ }
1328
+ xml += ` </testcase>\n`;
1329
+ }
1330
+ xml += `</testsuite>\n`;
1331
+ (0, fs_1.writeFileSync)(filename, xml);
1332
+ return filename;
1333
+ }
1334
+ /**
1335
+ * Export test results as TAP format.
1336
+ */
1337
+ exportTAP(suite, outputPath) {
1338
+ const filename = outputPath || (0, path_1.join)(this.paths.dataDir, `tap-${Date.now()}.tap`);
1339
+ let tap = `TAP version 13\n`;
1340
+ tap += `1..${suite.tests.length}\n`;
1341
+ suite.tests.forEach((test, i) => {
1342
+ const status = test.status === "passed" ? "ok" : "not ok";
1343
+ tap += `${status} ${i + 1} ${test.name}\n`;
1344
+ });
1345
+ (0, fs_1.writeFileSync)(filename, tap);
1346
+ return filename;
1347
+ }
1348
+ // =========================================================================
1349
+ // Tier 2: Parallel Execution (v2.5.0)
1350
+ // =========================================================================
1351
+ /**
1352
+ * Run multiple browser tasks in parallel.
1353
+ */
1354
+ static async parallel(tasks, options = {}) {
1355
+ const maxConcurrency = options.maxConcurrency || tasks.length;
1356
+ const results = [];
1357
+ // Process tasks in batches
1358
+ for (let i = 0; i < tasks.length; i += maxConcurrency) {
1359
+ const batch = tasks.slice(i, i + maxConcurrency);
1360
+ const batchResults = await Promise.all(batch.map(async (task) => {
1361
+ const startTime = Date.now();
1362
+ const browser = new CBrowser(task.config || {});
1363
+ try {
1364
+ const result = await task.run(browser);
1365
+ return {
1366
+ name: task.name,
1367
+ result,
1368
+ duration: Date.now() - startTime,
1369
+ };
1370
+ }
1371
+ catch (e) {
1372
+ return {
1373
+ name: task.name,
1374
+ error: e.message,
1375
+ duration: Date.now() - startTime,
1376
+ };
1377
+ }
1378
+ finally {
1379
+ await browser.close();
1380
+ }
1381
+ }));
1382
+ results.push(...batchResults);
1383
+ }
1384
+ return results;
1385
+ }
1386
+ /**
1387
+ * Run the same task across multiple device configurations in parallel.
1388
+ */
1389
+ static async parallelDevices(devices, run, options = {}) {
1390
+ const tasks = devices.map(device => ({
1391
+ name: device,
1392
+ config: { device },
1393
+ run: (browser) => run(browser, device),
1394
+ }));
1395
+ const results = await CBrowser.parallel(tasks, options);
1396
+ return results.map(r => ({ device: r.name, ...r }));
1397
+ }
1398
+ /**
1399
+ * Run the same task across multiple URLs in parallel.
1400
+ */
1401
+ static async parallelUrls(urls, run, options = {}) {
1402
+ const tasks = urls.map(url => ({
1403
+ name: url,
1404
+ config: options.config,
1405
+ run: (browser) => run(browser, url),
1406
+ }));
1407
+ const results = await CBrowser.parallel(tasks, options);
1408
+ return results.map(r => ({ url: r.name, ...r }));
1409
+ }
1410
+ // =========================================================================
1411
+ // Tier 3: Fluent API (v3.0.0)
1412
+ // =========================================================================
1413
+ /**
1414
+ * Fluent API - navigate and return chainable instance.
1415
+ */
1416
+ async goto(url) {
1417
+ await this.navigate(url);
1418
+ return new FluentCBrowser(this);
1419
+ }
1109
1420
  }
1110
1421
  exports.CBrowser = CBrowser;
1422
+ /**
1423
+ * Fluent wrapper for chainable API.
1424
+ */
1425
+ class FluentCBrowser {
1426
+ browser;
1427
+ constructor(browser) {
1428
+ this.browser = browser;
1429
+ }
1430
+ async click(selector, options) {
1431
+ await this.browser.click(selector, options);
1432
+ return this;
1433
+ }
1434
+ async fill(selector, value) {
1435
+ await this.browser.fill(selector, value);
1436
+ return this;
1437
+ }
1438
+ async screenshot(path) {
1439
+ await this.browser.screenshot(path);
1440
+ return this;
1441
+ }
1442
+ async wait(ms) {
1443
+ await new Promise(resolve => setTimeout(resolve, ms));
1444
+ return this;
1445
+ }
1446
+ async extract(what) {
1447
+ const result = await this.browser.extract(what);
1448
+ return { data: result.data, fluent: this };
1449
+ }
1450
+ async close() {
1451
+ await this.browser.close();
1452
+ }
1453
+ get instance() {
1454
+ return this.browser;
1455
+ }
1456
+ }
1457
+ exports.FluentCBrowser = FluentCBrowser;
1458
+ // ============================================================================
1459
+ // Tier 3: Natural Language API (v3.0.0)
1460
+ // ============================================================================
1461
+ /**
1462
+ * Natural language command patterns.
1463
+ */
1464
+ const NL_PATTERNS = [
1465
+ // Navigation
1466
+ { pattern: /^(?:go to|navigate to|open|visit)\s+(.+)$/i, action: "navigate", extract: (m) => ({ url: m[1] }) },
1467
+ { pattern: /^(?:go\s+)?back$/i, action: "back", extract: () => ({}) },
1468
+ { pattern: /^(?:go\s+)?forward$/i, action: "forward", extract: () => ({}) },
1469
+ { pattern: /^refresh|reload$/i, action: "reload", extract: () => ({}) },
1470
+ // Clicking
1471
+ { pattern: /^click(?:\s+on)?\s+(?:the\s+)?["']?(.+?)["']?$/i, action: "click", extract: (m) => ({ selector: m[1] }) },
1472
+ { pattern: /^press(?:\s+the)?\s+["']?(.+?)["']?(?:\s+button)?$/i, action: "click", extract: (m) => ({ selector: m[1] }) },
1473
+ { pattern: /^tap(?:\s+on)?\s+["']?(.+?)["']?$/i, action: "click", extract: (m) => ({ selector: m[1] }) },
1474
+ // Form filling
1475
+ { pattern: /^(?:type|enter|input|fill(?:\s+in)?)\s+["'](.+?)["']\s+(?:in(?:to)?|on)\s+(?:the\s+)?["']?(.+?)["']?$/i, action: "fill", extract: (m) => ({ value: m[1], selector: m[2] }) },
1476
+ { pattern: /^(?:fill(?:\s+in)?|set)\s+(?:the\s+)?["']?(.+?)["']?\s+(?:to|with|as)\s+["'](.+?)["']$/i, action: "fill", extract: (m) => ({ selector: m[1], value: m[2] }) },
1477
+ // Selecting
1478
+ { pattern: /^select\s+["'](.+?)["']\s+(?:from|in)\s+(?:the\s+)?["']?(.+?)["']?$/i, action: "select", extract: (m) => ({ value: m[1], selector: m[2] }) },
1479
+ { pattern: /^choose\s+["'](.+?)["']$/i, action: "click", extract: (m) => ({ selector: m[1] }) },
1480
+ // Screenshots
1481
+ { pattern: /^(?:take\s+a?\s*)?screenshot(?:\s+as\s+["']?(.+?)["']?)?$/i, action: "screenshot", extract: (m) => ({ path: m[1] || "" }) },
1482
+ { pattern: /^capture(?:\s+the)?\s+(?:page|screen)$/i, action: "screenshot", extract: () => ({}) },
1483
+ // Waiting
1484
+ { pattern: /^wait(?:\s+for)?\s+(\d+)\s*(?:ms|milliseconds?)?$/i, action: "wait", extract: (m) => ({ ms: m[1] }) },
1485
+ { pattern: /^wait(?:\s+for)?\s+(\d+)\s*(?:s|seconds?)$/i, action: "waitSeconds", extract: (m) => ({ seconds: m[1] }) },
1486
+ { pattern: /^wait(?:\s+for)?\s+["']?(.+?)["']?(?:\s+to\s+appear)?$/i, action: "waitFor", extract: (m) => ({ selector: m[1] }) },
1487
+ // Scrolling
1488
+ { pattern: /^scroll\s+(?:to\s+)?(?:the\s+)?(top|bottom)$/i, action: "scroll", extract: (m) => ({ direction: m[1] }) },
1489
+ { pattern: /^scroll\s+(up|down)(?:\s+(\d+))?$/i, action: "scrollBy", extract: (m) => ({ direction: m[1], amount: m[2] || "300" }) },
1490
+ // Extraction
1491
+ { pattern: /^(?:get|extract|find)\s+(?:all\s+)?(?:the\s+)?(.+)$/i, action: "extract", extract: (m) => ({ what: m[1] }) },
1492
+ ];
1493
+ /**
1494
+ * Parse natural language into browser action.
1495
+ */
1496
+ function parseNaturalLanguage(command) {
1497
+ const trimmed = command.trim();
1498
+ for (const { pattern, action, extract } of NL_PATTERNS) {
1499
+ const match = trimmed.match(pattern);
1500
+ if (match) {
1501
+ return { action, params: extract(match) };
1502
+ }
1503
+ }
1504
+ return null;
1505
+ }
1506
+ /**
1507
+ * Execute a natural language command.
1508
+ */
1509
+ async function executeNaturalLanguage(browser, command) {
1510
+ const parsed = parseNaturalLanguage(command);
1511
+ if (!parsed) {
1512
+ return { success: false, action: "unknown", error: `Could not parse command: "${command}"` };
1513
+ }
1514
+ const { action, params } = parsed;
1515
+ try {
1516
+ let result;
1517
+ switch (action) {
1518
+ case "navigate":
1519
+ result = await browser.navigate(params.url);
1520
+ break;
1521
+ case "click":
1522
+ result = await browser.click(params.selector);
1523
+ break;
1524
+ case "fill":
1525
+ result = await browser.fill(params.selector, params.value);
1526
+ break;
1527
+ case "screenshot":
1528
+ result = await browser.screenshot(params.path || undefined);
1529
+ break;
1530
+ case "wait":
1531
+ await new Promise(r => setTimeout(r, parseInt(params.ms)));
1532
+ result = { waited: parseInt(params.ms) };
1533
+ break;
1534
+ case "waitSeconds":
1535
+ await new Promise(r => setTimeout(r, parseInt(params.seconds) * 1000));
1536
+ result = { waited: parseInt(params.seconds) * 1000 };
1537
+ break;
1538
+ case "extract":
1539
+ result = await browser.extract(params.what);
1540
+ break;
1541
+ default:
1542
+ return { success: false, action, error: `Unsupported action: ${action}` };
1543
+ }
1544
+ return { success: true, action, result };
1545
+ }
1546
+ catch (e) {
1547
+ return { success: false, action, error: e.message };
1548
+ }
1549
+ }
1550
+ /**
1551
+ * Execute multiple natural language commands in sequence.
1552
+ */
1553
+ async function executeNaturalLanguageScript(browser, commands) {
1554
+ const results = [];
1555
+ for (const command of commands) {
1556
+ if (!command.trim() || command.startsWith("#"))
1557
+ continue; // Skip empty lines and comments
1558
+ const result = await executeNaturalLanguage(browser, command);
1559
+ results.push({ command, ...result });
1560
+ if (!result.success)
1561
+ break; // Stop on first error
1562
+ }
1563
+ return results;
1564
+ }
1111
1565
  //# sourceMappingURL=browser.js.map