momentic 0.0.6 → 0.0.8

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 (4) hide show
  1. package/bin/cli.js +1279 -1432
  2. package/dist/index.js +1079 -1218
  3. package/package.json +3 -10
  4. package/dist/index.mjs +0 -2455
package/bin/cli.js CHANGED
@@ -1,89 +1,17 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
- var __create = Object.create;
4
- var __defProp = Object.defineProperty;
5
- var __defProps = Object.defineProperties;
6
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
8
- var __getOwnPropNames = Object.getOwnPropertyNames;
9
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
10
- var __getProtoOf = Object.getPrototypeOf;
11
- var __hasOwnProp = Object.prototype.hasOwnProperty;
12
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
13
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
14
- var __spreadValues = (a, b) => {
15
- for (var prop in b || (b = {}))
16
- if (__hasOwnProp.call(b, prop))
17
- __defNormalProp(a, prop, b[prop]);
18
- if (__getOwnPropSymbols)
19
- for (var prop of __getOwnPropSymbols(b)) {
20
- if (__propIsEnum.call(b, prop))
21
- __defNormalProp(a, prop, b[prop]);
22
- }
23
- return a;
24
- };
25
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
26
- var __objRest = (source, exclude) => {
27
- var target = {};
28
- for (var prop in source)
29
- if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
30
- target[prop] = source[prop];
31
- if (source != null && __getOwnPropSymbols)
32
- for (var prop of __getOwnPropSymbols(source)) {
33
- if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
34
- target[prop] = source[prop];
35
- }
36
- return target;
37
- };
38
- var __copyProps = (to, from, except, desc) => {
39
- if (from && typeof from === "object" || typeof from === "function") {
40
- for (let key of __getOwnPropNames(from))
41
- if (!__hasOwnProp.call(to, key) && key !== except)
42
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
43
- }
44
- return to;
45
- };
46
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
47
- // If the importer is in node compatibility mode or this is not an ESM
48
- // file that has been converted to a CommonJS file using a Babel-
49
- // compatible transform (i.e. "__esModule" has not been set), then set
50
- // "default" to the CommonJS "module.exports" for node compatibility.
51
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
52
- mod
53
- ));
54
- var __async = (__this, __arguments, generator) => {
55
- return new Promise((resolve, reject) => {
56
- var fulfilled = (value) => {
57
- try {
58
- step(generator.next(value));
59
- } catch (e) {
60
- reject(e);
61
- }
62
- };
63
- var rejected = (value) => {
64
- try {
65
- step(generator.throw(value));
66
- } catch (e) {
67
- reject(e);
68
- }
69
- };
70
- var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
71
- step((generator = generator.apply(__this, __arguments)).next());
72
- });
73
- };
74
2
 
75
3
  // src/cli.ts
76
- var import_chalk = __toESM(require("chalk"));
77
- var import_commander = require("commander");
78
- var import_execa = require("execa");
79
- var import_wait_on = __toESM(require("wait-on"));
4
+ import chalk from "chalk";
5
+ import { Command as Command4, Option } from "commander";
6
+ import { $ } from "execa";
7
+ import waitOnFn from "wait-on";
80
8
 
81
9
  // ../../packages/types/src/commands.ts
82
- var import_dedent = __toESM(require("dedent"), 1);
83
- var z2 = __toESM(require("zod"), 1);
10
+ import dedent from "dedent";
11
+ import * as z2 from "zod";
84
12
 
85
13
  // ../../packages/types/src/a11y-targets.ts
86
- var z = __toESM(require("zod"), 1);
14
+ import * as z from "zod";
87
15
  var A11yTargetWithCacheSchema = z.object({
88
16
  // a11y ID
89
17
  id: z.number().int(),
@@ -171,7 +99,7 @@ var ClickCommandSchema = CommonCommandSchema.merge(
171
99
  rightClick: z2.boolean().default(false)
172
100
  })
173
101
  ).describe(
174
- import_dedent.default`CLICK <id> - click on the element that has the specified id.
102
+ dedent`CLICK <id> - click on the element that has the specified id.
175
103
  You are NOT allowed to click on disabled, hidden or StaticText elements.
176
104
  Only click on elements on the Current Page.
177
105
  Only click on elements with the following tag names: button, input, link, image, generic.
@@ -273,7 +201,7 @@ var AICommandSchema = z2.discriminatedUnion("type", [
273
201
  ]);
274
202
 
275
203
  // ../../packages/types/src/steps.ts
276
- var z3 = __toESM(require("zod"), 1);
204
+ import * as z3 from "zod";
277
205
  var StepType = /* @__PURE__ */ ((StepType2) => {
278
206
  StepType2["AI_ACTION"] = "AI_ACTION";
279
207
  StepType2["PRESET_ACTION"] = "PRESET_ACTION";
@@ -316,18 +244,21 @@ var ResolvedStepSchema = z3.union([
316
244
  ]);
317
245
 
318
246
  // ../../packages/web-agent/src/browsers/chrome.ts
319
- var import_playwright = require("playwright");
247
+ import {
248
+ chromium,
249
+ devices
250
+ } from "playwright";
320
251
 
321
252
  // ../../packages/types/src/assertions.ts
322
- var import_zod = require("zod");
323
- var AIAssertionResultSchema = import_zod.z.object({
324
- thoughts: import_zod.z.string(),
325
- result: import_zod.z.boolean(),
326
- relevantElements: import_zod.z.array(import_zod.z.number()).optional()
253
+ import { z as z4 } from "zod";
254
+ var AIAssertionResultSchema = z4.object({
255
+ thoughts: z4.string(),
256
+ result: z4.boolean(),
257
+ relevantElements: z4.array(z4.number()).optional()
327
258
  });
328
259
 
329
260
  // ../../packages/types/src/ai-command-generation.ts
330
- var import_zod2 = require("zod");
261
+ import { z as z5 } from "zod";
331
262
 
332
263
  // ../../packages/types/src/errors.ts
333
264
  var BrowserExecutionError = class extends Error {
@@ -344,14 +275,14 @@ var EmptyA11yTreeError = class extends Error {
344
275
  };
345
276
 
346
277
  // ../../packages/types/src/ai-command-generation.ts
347
- var LLMOutputSchema = import_zod2.z.object({
348
- command: import_zod2.z.string(),
349
- thoughts: import_zod2.z.string()
278
+ var LLMOutputSchema = z5.object({
279
+ command: z5.string(),
280
+ thoughts: z5.string()
350
281
  });
351
- var NumericStringSchema = import_zod2.z.string().pipe(import_zod2.z.coerce.number());
282
+ var NumericStringSchema = z5.string().pipe(z5.coerce.number());
352
283
 
353
284
  // ../../packages/types/src/command-results.ts
354
- var z6 = __toESM(require("zod"), 1);
285
+ import * as z6 from "zod";
355
286
  var ResultStatus = /* @__PURE__ */ ((ResultStatus2) => {
356
287
  ResultStatus2["SUCCESS"] = "SUCCESS";
357
288
  ResultStatus2["FAILED"] = "FAILED";
@@ -423,9 +354,9 @@ var ResultSchema = z6.discriminatedUnion("type", [
423
354
  ]);
424
355
 
425
356
  // ../../packages/types/src/cookies.ts
426
- var import_set_cookie_parser = require("set-cookie-parser");
357
+ import { parseString } from "set-cookie-parser";
427
358
  function parseCookieString(cookie) {
428
- const parsedCookie = (0, import_set_cookie_parser.parseString)(cookie);
359
+ const parsedCookie = parseString(cookie);
429
360
  if (!parsedCookie.name) {
430
361
  throw new Error("Name missing from cookie");
431
362
  }
@@ -448,15 +379,16 @@ function parseCookieString(cookie) {
448
379
  if (!parsedCookie.path && parsedCookie.domain) {
449
380
  parsedCookie.path = "/";
450
381
  }
451
- const result = __spreadProps(__spreadValues({}, parsedCookie), {
382
+ const result = {
383
+ ...parsedCookie,
452
384
  expires: parsedCookie.expires ? parsedCookie.expires.getTime() / 1e3 : void 0,
453
385
  sameSite
454
- });
386
+ };
455
387
  return result;
456
388
  }
457
389
 
458
390
  // ../../packages/types/src/execute-results.ts
459
- var z7 = __toESM(require("zod"), 1);
391
+ import * as z7 from "zod";
460
392
  var ExecuteCommandHistoryEntrySchema = z7.object({
461
393
  // type of command executed
462
394
  type: z7.nativeEnum(StepType),
@@ -469,11 +401,11 @@ var ExecuteCommandHistoryEntrySchema = z7.object({
469
401
  });
470
402
 
471
403
  // ../../packages/types/src/goal-splitter.ts
472
- var import_zod3 = require("zod");
473
- var InstructionsSchema = import_zod3.z.string().array();
404
+ import { z as z8 } from "zod";
405
+ var InstructionsSchema = z8.string().array();
474
406
 
475
407
  // ../../packages/types/src/locator.ts
476
- var z9 = __toESM(require("zod"), 1);
408
+ import * as z9 from "zod";
477
409
  var AILocatorSchema = z9.object({
478
410
  thoughts: z9.string(),
479
411
  // a11y id
@@ -483,23 +415,23 @@ var AILocatorSchema = z9.object({
483
415
  });
484
416
 
485
417
  // ../../packages/types/src/modules.ts
486
- var import_zod4 = require("zod");
487
- var ModuleMetadataSchema = import_zod4.z.object({
488
- id: import_zod4.z.string(),
489
- createdAt: import_zod4.z.coerce.date(),
490
- createdBy: import_zod4.z.string(),
491
- organizationId: import_zod4.z.string().or(import_zod4.z.null()),
492
- name: import_zod4.z.string(),
493
- schemaVersion: import_zod4.z.string(),
418
+ import { z as z10 } from "zod";
419
+ var ModuleMetadataSchema = z10.object({
420
+ id: z10.string(),
421
+ createdAt: z10.coerce.date(),
422
+ createdBy: z10.string(),
423
+ organizationId: z10.string().or(z10.null()),
424
+ name: z10.string(),
425
+ schemaVersion: z10.string(),
494
426
  // this is only used in the client and is not stored in the db
495
- numSteps: import_zod4.z.number()
427
+ numSteps: z10.number()
496
428
  });
497
- var ModuleSchema = import_zod4.z.object({
429
+ var ModuleSchema = z10.object({
498
430
  steps: AllowedModuleStepSchema.array()
499
431
  }).merge(ModuleMetadataSchema.omit({ numSteps: true }));
500
432
 
501
433
  // ../../packages/types/src/runs.ts
502
- var import_zod5 = require("zod");
434
+ import { z as z11 } from "zod";
503
435
  var RunTrigger = {
504
436
  WEBHOOK: "WEBHOOK",
505
437
  CRON: "CRON",
@@ -512,31 +444,31 @@ var RunStatusEnum = {
512
444
  FAILED: "FAILED",
513
445
  CANCELLED: "CANCELLED"
514
446
  };
515
- var DateOrStringSchema = import_zod5.z.string().pipe(import_zod5.z.coerce.date()).or(import_zod5.z.date());
516
- var RunMetadataSchema = import_zod5.z.object({
517
- id: import_zod5.z.string(),
447
+ var DateOrStringSchema = z11.string().pipe(z11.coerce.date()).or(z11.date());
448
+ var RunMetadataSchema = z11.object({
449
+ id: z11.string(),
518
450
  createdAt: DateOrStringSchema,
519
- createdBy: import_zod5.z.string(),
520
- organizationId: import_zod5.z.string().or(import_zod5.z.null()),
521
- scheduledAt: DateOrStringSchema.or(import_zod5.z.null()),
522
- startedAt: DateOrStringSchema.or(import_zod5.z.null()),
523
- finishedAt: DateOrStringSchema.or(import_zod5.z.null()),
524
- testId: import_zod5.z.string().or(import_zod5.z.null()),
525
- status: import_zod5.z.nativeEnum(RunStatusEnum),
526
- trigger: import_zod5.z.nativeEnum(RunTrigger),
527
- test: import_zod5.z.object({
528
- name: import_zod5.z.string(),
529
- id: import_zod5.z.string()
530
- }).or(import_zod5.z.null())
451
+ createdBy: z11.string(),
452
+ organizationId: z11.string().or(z11.null()),
453
+ scheduledAt: DateOrStringSchema.or(z11.null()),
454
+ startedAt: DateOrStringSchema.or(z11.null()),
455
+ finishedAt: DateOrStringSchema.or(z11.null()),
456
+ testId: z11.string().or(z11.null()),
457
+ status: z11.nativeEnum(RunStatusEnum),
458
+ trigger: z11.nativeEnum(RunTrigger),
459
+ test: z11.object({
460
+ name: z11.string(),
461
+ id: z11.string()
462
+ }).or(z11.null())
531
463
  });
532
464
  var RunWithTestSchema = RunMetadataSchema.merge(
533
- import_zod5.z.object({
465
+ z11.object({
534
466
  results: ResultSchema.array(),
535
- test: import_zod5.z.object({
536
- name: import_zod5.z.string(),
537
- id: import_zod5.z.string(),
538
- baseUrl: import_zod5.z.string()
539
- }).or(import_zod5.z.null())
467
+ test: z11.object({
468
+ name: z11.string(),
469
+ id: z11.string(),
470
+ baseUrl: z11.string()
471
+ }).or(z11.null())
540
472
  })
541
473
  );
542
474
 
@@ -641,56 +573,56 @@ var CARD_DESCRIPTIONS = {
641
573
  };
642
574
 
643
575
  // ../../packages/types/src/test.ts
644
- var import_zod7 = require("zod");
576
+ import { z as z13 } from "zod";
645
577
 
646
578
  // ../../packages/types/src/test-settings.ts
647
- var import_cron_validator = require("cron-validator");
648
- var import_zod6 = require("zod");
649
- var TestAdvancedSettingsSchema = import_zod6.z.object({
650
- availableAsModule: import_zod6.z.boolean().default(false),
651
- disableAICaching: import_zod6.z.boolean().default(false)
579
+ import { isValidCron } from "cron-validator";
580
+ import { z as z12 } from "zod";
581
+ var TestAdvancedSettingsSchema = z12.object({
582
+ availableAsModule: z12.boolean().default(false),
583
+ disableAICaching: z12.boolean().default(false)
652
584
  });
653
- var ScheduleSettingsSchema = import_zod6.z.object({
654
- cron: import_zod6.z.string().refine(
585
+ var ScheduleSettingsSchema = z12.object({
586
+ cron: z12.string().refine(
655
587
  (v) => {
656
- return (0, import_cron_validator.isValidCron)(v);
588
+ return isValidCron(v);
657
589
  },
658
590
  { message: "Invalid cron expression." }
659
591
  ).default("0 0 */1 * *"),
660
- enabled: import_zod6.z.boolean().default(false),
661
- timeZone: import_zod6.z.string().default("America/Los_Angeles"),
592
+ enabled: z12.boolean().default(false),
593
+ timeZone: z12.string().default("America/Los_Angeles"),
662
594
  // this is used for removing repeatable jobs (not set by user)
663
- jobKey: import_zod6.z.string().optional()
595
+ jobKey: z12.string().optional()
664
596
  });
665
- var WebhookSchema = import_zod6.z.object({
666
- lastStatus: import_zod6.z.number().optional(),
667
- url: import_zod6.z.string().url()
597
+ var WebhookSchema = z12.object({
598
+ lastStatus: z12.number().optional(),
599
+ url: z12.string().url()
668
600
  });
669
- var WebhookSettingsSchema = import_zod6.z.array(WebhookSchema).default([]);
670
- var TestSettingsSchema = import_zod6.z.object({
671
- name: import_zod6.z.string().min(1),
672
- baseUrl: import_zod6.z.string().url(),
601
+ var WebhookSettingsSchema = z12.array(WebhookSchema).default([]);
602
+ var TestSettingsSchema = z12.object({
603
+ name: z12.string().min(1),
604
+ baseUrl: z12.string().url(),
673
605
  advanced: TestAdvancedSettingsSchema
674
606
  });
675
607
 
676
608
  // ../../packages/types/src/test.ts
677
- var ResolvedTestSchema = import_zod7.z.object({
678
- id: import_zod7.z.string(),
679
- name: import_zod7.z.string(),
680
- baseUrl: import_zod7.z.string(),
681
- steps: import_zod7.z.array(ResolvedStepSchema),
682
- createdAt: import_zod7.z.coerce.date(),
683
- updatedAt: import_zod7.z.coerce.date(),
684
- createdBy: import_zod7.z.string(),
685
- organizationId: import_zod7.z.string().or(import_zod7.z.null()),
686
- schemaVersion: import_zod7.z.string(),
609
+ var ResolvedTestSchema = z13.object({
610
+ id: z13.string(),
611
+ name: z13.string(),
612
+ baseUrl: z13.string(),
613
+ steps: z13.array(ResolvedStepSchema),
614
+ createdAt: z13.coerce.date(),
615
+ updatedAt: z13.coerce.date(),
616
+ createdBy: z13.string(),
617
+ organizationId: z13.string().or(z13.null()),
618
+ schemaVersion: z13.string(),
687
619
  advanced: TestAdvancedSettingsSchema,
688
620
  schedule: ScheduleSettingsSchema,
689
621
  webhooks: WebhookSettingsSchema
690
622
  });
691
623
 
692
624
  // ../../packages/types/src/context.ts
693
- var z14 = __toESM(require("zod"), 1);
625
+ import * as z14 from "zod";
694
626
  var DynamicContextSchema = z14.object({
695
627
  // user goal or instruction
696
628
  goal: z14.string(),
@@ -707,7 +639,7 @@ var DynamicContextSchema = z14.object({
707
639
  });
708
640
 
709
641
  // ../../packages/types/src/public-api.ts
710
- var z15 = __toESM(require("zod"), 1);
642
+ import * as z15 from "zod";
711
643
  var GeneratorOptionsSchema = z15.object({
712
644
  disableCache: z15.boolean()
713
645
  });
@@ -788,6 +720,18 @@ var defaultA11yNodeSerializeParams = {
788
720
  noProperties: false
789
721
  };
790
722
  var ProcessedA11yNode = class {
723
+ id;
724
+ role;
725
+ name;
726
+ content;
727
+ properties;
728
+ // css-like selector from the root of the tree to the current node
729
+ pathFromRoot;
730
+ parent;
731
+ // md5 hash - set lazily in most cases (not used at the moment)
732
+ // md5Sum: string;
733
+ children;
734
+ backendNodeID;
791
735
  constructor(params) {
792
736
  this.id = params.id;
793
737
  this.role = params.role;
@@ -799,11 +743,10 @@ var ProcessedA11yNode = class {
799
743
  this.backendNodeID = params.backendNodeID;
800
744
  }
801
745
  getLogForm() {
802
- var _a, _b;
803
746
  return JSON.stringify({
804
747
  id: this.id,
805
- name: (_a = this.name) != null ? _a : "",
806
- role: (_b = this.role) != null ? _b : "",
748
+ name: this.name ?? "",
749
+ role: this.role ?? "",
807
750
  backendNodeId: this.backendNodeID
808
751
  });
809
752
  }
@@ -896,7 +839,7 @@ function getNodePathIdentifier(node) {
896
839
  return `"${node.nodeId}"`;
897
840
  }
898
841
  function processA11yTreeDFS(node, parent, inputNodeMap, outputNodeMap) {
899
- var _a, _b, _c, _d, _e, _f, _g;
842
+ var _a, _b, _c, _d, _e, _f;
900
843
  if (!parent && node.parentId) {
901
844
  throw new Error(
902
845
  `Got no parent for accessibility node ${node.nodeId}: ${JSON.stringify(
@@ -924,7 +867,7 @@ function processA11yTreeDFS(node, parent, inputNodeMap, outputNodeMap) {
924
867
  });
925
868
  }
926
869
  outputNodeMap.set(processedNode.id, processedNode);
927
- const children = (_f = node.childIds) != null ? _f : [];
870
+ const children = node.childIds ?? [];
928
871
  for (const childId of children) {
929
872
  if (!childId) {
930
873
  continue;
@@ -949,7 +892,7 @@ function processA11yTreeDFS(node, parent, inputNodeMap, outputNodeMap) {
949
892
  }
950
893
  if (processedNode.children.length === 1 && processedNode.children[0].role === "StaticText") {
951
894
  const currentName = processedNode.name;
952
- const childName = (_g = processedNode.children[0]) == null ? void 0 : _g.name;
895
+ const childName = (_f = processedNode.children[0]) == null ? void 0 : _f.name;
953
896
  if (currentName === childName || !childName) {
954
897
  processedNode.children = [];
955
898
  }
@@ -1152,14 +1095,20 @@ function isRequestRelevantForPageLoad(request, currentURL) {
1152
1095
  }
1153
1096
 
1154
1097
  // ../../packages/web-agent/src/browsers/chrome.ts
1155
- function initCDPSession(cdpClient) {
1156
- return __async(this, null, function* () {
1157
- yield cdpClient.send("Accessibility.enable");
1158
- yield cdpClient.send("DOM.enable");
1159
- yield cdpClient.send("Overlay.enable");
1160
- });
1098
+ async function initCDPSession(cdpClient) {
1099
+ await cdpClient.send("Accessibility.enable");
1100
+ await cdpClient.send("DOM.enable");
1101
+ await cdpClient.send("Overlay.enable");
1161
1102
  }
1162
- var _ChromeBrowser = class _ChromeBrowser {
1103
+ var ChromeBrowser = class _ChromeBrowser {
1104
+ browser;
1105
+ context;
1106
+ page;
1107
+ // key is nodeId, according to the a11y tree
1108
+ nodeMap = /* @__PURE__ */ new Map();
1109
+ cdpClient;
1110
+ logger;
1111
+ baseURL;
1163
1112
  constructor({
1164
1113
  browser,
1165
1114
  context,
@@ -1168,8 +1117,6 @@ var _ChromeBrowser = class _ChromeBrowser {
1168
1117
  cdpClient,
1169
1118
  logger
1170
1119
  }) {
1171
- // key is nodeId, according to the a11y tree
1172
- this.nodeMap = /* @__PURE__ */ new Map();
1173
1120
  this.browser = browser;
1174
1121
  this.context = context;
1175
1122
  this.page = page;
@@ -1177,117 +1124,106 @@ var _ChromeBrowser = class _ChromeBrowser {
1177
1124
  this.cdpClient = cdpClient;
1178
1125
  this.logger = logger;
1179
1126
  }
1127
+ static USER_AGENT = devices["Desktop Chrome"].userAgent;
1180
1128
  /**
1181
1129
  * Creates a new browser and waits for navigation to the given test URL.
1182
1130
  */
1183
- static init(_0, _1, _2) {
1184
- return __async(this, arguments, function* (baseURL, logger, onScreenshot, timeout = MAX_LOAD_TIMEOUT_MS) {
1185
- const browser = yield import_playwright.chromium.launch({ headless: true });
1186
- const context = yield browser.newContext({
1187
- viewport: {
1188
- width: 1920,
1189
- height: 1080
1190
- },
1191
- // comment out the below if you are on Mac OS but you're using a monitor
1192
- deviceScaleFactor: process.platform === "darwin" ? RETINA_WINDOW_SCALE_FACTOR : 1,
1193
- userAgent: import_playwright.devices["Desktop Chrome"].userAgent,
1194
- geolocation: { latitude: 37.7749, longitude: -122.4194 },
1195
- // san francisco
1196
- locale: "en-US",
1197
- timezoneId: "America/Los_Angeles"
1198
- });
1199
- const page = yield context.newPage();
1200
- const cdpClient = yield context.newCDPSession(page);
1201
- const chrome = new _ChromeBrowser({
1202
- browser,
1203
- context,
1204
- page,
1205
- baseURL,
1206
- cdpClient,
1207
- logger
1208
- });
1209
- let completed = false;
1210
- const navigateAndInitCDP = () => __async(this, null, function* () {
1211
- try {
1212
- yield chrome.navigate(baseURL, false);
1213
- yield initCDPSession(cdpClient);
1214
- } catch (err) {
1215
- logger.error({ err }, "Failed to initialize chrome browser");
1216
- } finally {
1217
- completed = true;
1218
- }
1219
- });
1220
- void navigateAndInitCDP();
1221
- const sendScreenshot = () => __async(this, null, function* () {
1222
- if (!onScreenshot) {
1223
- return;
1224
- }
1225
- try {
1226
- onScreenshot({
1227
- viewport: chrome.viewport,
1228
- buffer: yield chrome.screenshot()
1229
- });
1230
- } catch (err) {
1231
- logger.error({ err }, "Failed to take screenshot");
1232
- }
1233
- });
1234
- void sendScreenshot();
1235
- const screenshotInterval = setInterval(() => {
1236
- void sendScreenshot();
1237
- }, 250);
1238
- const startTime = Date.now();
1239
- while (!completed && Date.now() - startTime < timeout) {
1240
- yield sleep(CHECK_INTERVAL_MS);
1131
+ static async init(baseURL, logger, onScreenshot, timeout = MAX_LOAD_TIMEOUT_MS) {
1132
+ const browser = await chromium.launch({ headless: true });
1133
+ const context = await browser.newContext({
1134
+ viewport: {
1135
+ width: 1920,
1136
+ height: 1080
1137
+ },
1138
+ // comment out the below if you are on Mac OS but you're using a monitor
1139
+ deviceScaleFactor: process.platform === "darwin" ? RETINA_WINDOW_SCALE_FACTOR : 1,
1140
+ userAgent: devices["Desktop Chrome"].userAgent,
1141
+ geolocation: { latitude: 37.7749, longitude: -122.4194 },
1142
+ // san francisco
1143
+ locale: "en-US",
1144
+ timezoneId: "America/Los_Angeles"
1145
+ });
1146
+ const page = await context.newPage();
1147
+ const cdpClient = await context.newCDPSession(page);
1148
+ const chrome = new _ChromeBrowser({
1149
+ browser,
1150
+ context,
1151
+ page,
1152
+ baseURL,
1153
+ cdpClient,
1154
+ logger
1155
+ });
1156
+ let completed = false;
1157
+ const navigateAndInitCDP = async () => {
1158
+ try {
1159
+ await chrome.navigate(baseURL, false);
1160
+ await initCDPSession(cdpClient);
1161
+ } catch (err) {
1162
+ logger.error({ err }, "Failed to initialize chrome browser");
1163
+ } finally {
1164
+ completed = true;
1241
1165
  }
1242
- clearInterval(screenshotInterval);
1243
- if (!completed) {
1244
- logger.warn(
1245
- "Timeout elapsed waiting for browser to initialize - are you sure this page is accessible?"
1246
- );
1166
+ };
1167
+ void navigateAndInitCDP();
1168
+ const sendScreenshot = async () => {
1169
+ if (!onScreenshot) {
1170
+ return;
1247
1171
  }
1248
- return chrome;
1249
- });
1172
+ try {
1173
+ onScreenshot({
1174
+ viewport: chrome.viewport,
1175
+ buffer: await chrome.screenshot()
1176
+ });
1177
+ } catch (err) {
1178
+ logger.error({ err }, "Failed to take screenshot");
1179
+ }
1180
+ };
1181
+ void sendScreenshot();
1182
+ const screenshotInterval = setInterval(() => {
1183
+ void sendScreenshot();
1184
+ }, 250);
1185
+ const startTime = Date.now();
1186
+ while (!completed && Date.now() - startTime < timeout) {
1187
+ await sleep(CHECK_INTERVAL_MS);
1188
+ }
1189
+ clearInterval(screenshotInterval);
1190
+ if (!completed) {
1191
+ logger.warn(
1192
+ "Timeout elapsed waiting for browser to initialize - are you sure this page is accessible?"
1193
+ );
1194
+ }
1195
+ return chrome;
1250
1196
  }
1251
1197
  // Things to do on every page load
1252
- pageSetup() {
1253
- return __async(this, null, function* () {
1254
- yield this.page.evaluate(addCursorScript);
1255
- yield this.page.evaluate(addIDsScript);
1256
- });
1198
+ async pageSetup() {
1199
+ await this.page.evaluate(addCursorScript);
1200
+ await this.page.evaluate(addIDsScript);
1257
1201
  }
1258
- wait(timeoutMs) {
1259
- return __async(this, null, function* () {
1260
- yield this.page.waitForTimeout(timeoutMs);
1261
- });
1202
+ async wait(timeoutMs) {
1203
+ await this.page.waitForTimeout(timeoutMs);
1262
1204
  }
1263
- cleanup() {
1264
- return __async(this, null, function* () {
1265
- yield this.page.close();
1266
- yield this.context.close();
1267
- yield this.browser.close();
1268
- });
1205
+ async cleanup() {
1206
+ await this.page.close();
1207
+ await this.context.close();
1208
+ await this.browser.close();
1269
1209
  }
1270
1210
  get closed() {
1271
1211
  return this.page.isClosed() || !this.browser.isConnected();
1272
1212
  }
1273
- html() {
1274
- return __async(this, null, function* () {
1275
- return yield this.page.content();
1276
- });
1213
+ async html() {
1214
+ return await this.page.content();
1277
1215
  }
1278
1216
  get url() {
1279
1217
  return this.page.url();
1280
1218
  }
1281
- screenshot(quality = 100, scale = "device") {
1282
- return __async(this, null, function* () {
1283
- return yield this.page.screenshot({
1284
- fullPage: false,
1285
- quality,
1286
- scale,
1287
- type: "jpeg",
1288
- // allow the blinking text cursor thing to remain there
1289
- caret: "initial"
1290
- });
1219
+ async screenshot(quality = 100, scale = "device") {
1220
+ return await this.page.screenshot({
1221
+ fullPage: false,
1222
+ quality,
1223
+ scale,
1224
+ type: "jpeg",
1225
+ // allow the blinking text cursor thing to remain there
1226
+ caret: "initial"
1291
1227
  });
1292
1228
  }
1293
1229
  get viewport() {
@@ -1297,595 +1233,539 @@ var _ChromeBrowser = class _ChromeBrowser {
1297
1233
  }
1298
1234
  return viewport;
1299
1235
  }
1300
- navigate(url, wrapPossibleNavigation = true) {
1301
- return __async(this, null, function* () {
1302
- this.logger.debug(`Navigating to ${url}`);
1303
- const startTime = Date.now();
1304
- const doNav = () => __async(this, null, function* () {
1305
- try {
1306
- yield this.page.goto(url, {
1307
- timeout: MAX_LOAD_TIMEOUT_MS
1308
- });
1309
- this.logger.debug(
1310
- { url },
1311
- `Got load event in ${Math.floor(Date.now() - startTime)}ms`
1312
- );
1313
- } catch (e) {
1314
- this.logger.warn(
1315
- { url, type: "navigate", err: e },
1316
- "Timeout elapsed waiting for page to load, continuing anyways..."
1317
- );
1318
- }
1319
- });
1320
- if (wrapPossibleNavigation) {
1321
- yield this.wrapPossibleNavigation(doNav);
1322
- } else {
1323
- yield doNav();
1324
- }
1325
- if (CHROME_INTERNAL_URLS.has(this.url) && process.env.NODE_ENV === "production") {
1326
- throw new Error(
1327
- `${url} took too long to load \u{1F61E}. Please ensure the site and your internet are working.`
1236
+ async navigate(url, wrapPossibleNavigation = true) {
1237
+ this.logger.debug(`Navigating to ${url}`);
1238
+ const startTime = Date.now();
1239
+ const doNav = async () => {
1240
+ try {
1241
+ await this.page.goto(url, {
1242
+ timeout: MAX_LOAD_TIMEOUT_MS
1243
+ });
1244
+ this.logger.debug(
1245
+ { url },
1246
+ `Got load event in ${Math.floor(Date.now() - startTime)}ms`
1247
+ );
1248
+ } catch (e) {
1249
+ this.logger.warn(
1250
+ { url, type: "navigate", err: e },
1251
+ "Timeout elapsed waiting for page to load, continuing anyways..."
1328
1252
  );
1329
1253
  }
1330
- yield this.pageSetup();
1331
- this.logger.debug({ url }, "Navigation complete");
1332
- });
1254
+ };
1255
+ if (wrapPossibleNavigation) {
1256
+ await this.wrapPossibleNavigation(doNav);
1257
+ } else {
1258
+ await doNav();
1259
+ }
1260
+ if (CHROME_INTERNAL_URLS.has(this.url) && process.env.NODE_ENV === "production") {
1261
+ throw new Error(
1262
+ `${url} took too long to load \u{1F61E}. Please ensure the site and your internet are working.`
1263
+ );
1264
+ }
1265
+ await this.pageSetup();
1266
+ this.logger.debug({ url }, "Navigation complete");
1267
+ }
1268
+ async fill(target, text, options = {}) {
1269
+ const element = await this.click(target, {
1270
+ doubleClick: false,
1271
+ rightClick: false
1272
+ });
1273
+ await this.type(text, options);
1274
+ return element;
1275
+ }
1276
+ async type(text, options = {}) {
1277
+ const { clearContent = true, pressKeysSequentially = false } = options;
1278
+ if (clearContent) {
1279
+ await this.page.keyboard.press("Meta+A");
1280
+ await this.page.keyboard.press("Backspace");
1281
+ }
1282
+ if (pressKeysSequentially) {
1283
+ await this.page.keyboard.type(text);
1284
+ } else {
1285
+ await this.page.keyboard.insertText(text);
1286
+ }
1333
1287
  }
1334
- fill(_0, _1) {
1335
- return __async(this, arguments, function* (target, text, options = {}) {
1336
- const element = yield this.click(target, {
1337
- doubleClick: false,
1338
- rightClick: false
1339
- });
1340
- yield this.type(text, options);
1341
- return element;
1288
+ async clickByA11yID(index, options = {}) {
1289
+ const node = this.nodeMap.get(`${index}`);
1290
+ if (!node) {
1291
+ throw new Error(`Could not find node in DOM with index: ${index}`);
1292
+ }
1293
+ const nodeClicked = await this.clickUsingCDP(node, options);
1294
+ await this.highlightNode(nodeClicked);
1295
+ return node.serialize({ noChildren: true, noProperties: true, noID: true });
1296
+ }
1297
+ async selectOptionByA11yID(index, option) {
1298
+ const node = this.nodeMap.get(`${index}`);
1299
+ if (!node) {
1300
+ throw new Error(`Could not find node in DOM with index: ${index}`);
1301
+ }
1302
+ if (!node.backendNodeID) {
1303
+ throw new Error(
1304
+ `Select target missing backend node id: ${node.getLogForm()}`
1305
+ );
1306
+ }
1307
+ const locator = await this.getLocatorFromBackendID(node.backendNodeID);
1308
+ await locator.selectOption(option, {
1309
+ timeout: COMPLICATED_BROWSER_ACTION_TIMEOUT_MS
1342
1310
  });
1311
+ await this.highlightNode(node);
1312
+ return node.serialize({ noChildren: true, noProperties: true, noID: true });
1343
1313
  }
1344
- type(_0) {
1345
- return __async(this, arguments, function* (text, options = {}) {
1346
- const { clearContent = true, pressKeysSequentially = false } = options;
1347
- if (clearContent) {
1348
- yield this.page.keyboard.press("Meta+A");
1349
- yield this.page.keyboard.press("Backspace");
1350
- }
1351
- if (pressKeysSequentially) {
1352
- yield this.page.keyboard.type(text);
1353
- } else {
1354
- yield this.page.keyboard.insertText(text);
1355
- }
1356
- });
1314
+ async highlight(target) {
1315
+ try {
1316
+ await this.highlightByA11yID(target.id);
1317
+ } catch (err) {
1318
+ this.logger.warn({ err, target }, "Failed to highlight target");
1319
+ }
1357
1320
  }
1358
- clickByA11yID(_0) {
1359
- return __async(this, arguments, function* (index, options = {}) {
1360
- const node = this.nodeMap.get(`${index}`);
1361
- if (!node) {
1362
- throw new Error(`Could not find node in DOM with index: ${index}`);
1363
- }
1364
- const nodeClicked = yield this.clickUsingCDP(node, options);
1365
- yield this.highlightNode(nodeClicked);
1366
- return node.serialize({ noChildren: true, noProperties: true, noID: true });
1367
- });
1321
+ async highlightByA11yID(index) {
1322
+ const node = this.nodeMap.get(`${index}`);
1323
+ if (!node) {
1324
+ throw new Error(`Could not find node in DOM with index: ${index}`);
1325
+ }
1326
+ if (!node.backendNodeID) {
1327
+ throw new Error(
1328
+ `Select target missing backend node id: ${node.getLogForm()}`
1329
+ );
1330
+ }
1331
+ await this.highlightNode(node);
1368
1332
  }
1369
- selectOptionByA11yID(index, option) {
1370
- return __async(this, null, function* () {
1371
- const node = this.nodeMap.get(`${index}`);
1372
- if (!node) {
1373
- throw new Error(`Could not find node in DOM with index: ${index}`);
1374
- }
1375
- if (!node.backendNodeID) {
1376
- throw new Error(
1377
- `Select target missing backend node id: ${node.getLogForm()}`
1378
- );
1379
- }
1380
- const locator = yield this.getLocatorFromBackendID(node.backendNodeID);
1381
- yield locator.selectOption(option, {
1382
- timeout: COMPLICATED_BROWSER_ACTION_TIMEOUT_MS
1333
+ async highlightNode(node) {
1334
+ try {
1335
+ await this.cdpClient.send("Overlay.highlightNode", {
1336
+ highlightConfig: NODE_HIGHLIGHT_CONFIG,
1337
+ backendNodeId: node.backendNodeID
1383
1338
  });
1384
- yield this.highlightNode(node);
1385
- return node.serialize({ noChildren: true, noProperties: true, noID: true });
1386
- });
1387
- }
1388
- highlight(target) {
1389
- return __async(this, null, function* () {
1390
- try {
1391
- yield this.highlightByA11yID(target.id);
1392
- } catch (err) {
1393
- this.logger.warn({ err, target }, "Failed to highlight target");
1394
- }
1395
- });
1396
- }
1397
- highlightByA11yID(index) {
1398
- return __async(this, null, function* () {
1399
- const node = this.nodeMap.get(`${index}`);
1400
- if (!node) {
1401
- throw new Error(`Could not find node in DOM with index: ${index}`);
1402
- }
1403
- if (!node.backendNodeID) {
1404
- throw new Error(
1405
- `Select target missing backend node id: ${node.getLogForm()}`
1406
- );
1407
- }
1408
- yield this.highlightNode(node);
1409
- });
1410
- }
1411
- highlightNode(node) {
1412
- return __async(this, null, function* () {
1339
+ } catch (err) {
1340
+ this.logger.warn({ err }, "Failed to add node highlight");
1341
+ }
1342
+ const hideHighlight = async () => {
1413
1343
  try {
1414
- yield this.cdpClient.send("Overlay.highlightNode", {
1415
- highlightConfig: NODE_HIGHLIGHT_CONFIG,
1344
+ await this.cdpClient.send("Overlay.hideHighlight", {
1416
1345
  backendNodeId: node.backendNodeID
1417
1346
  });
1418
1347
  } catch (err) {
1419
- this.logger.warn({ err }, "Failed to add node highlight");
1348
+ this.logger.debug({ err }, "Failed to remove node highlight");
1420
1349
  }
1421
- const hideHighlight = () => __async(this, null, function* () {
1422
- try {
1423
- yield this.cdpClient.send("Overlay.hideHighlight", {
1424
- backendNodeId: node.backendNodeID
1425
- });
1426
- } catch (err) {
1427
- this.logger.debug({ err }, "Failed to remove node highlight");
1428
- }
1429
- });
1430
- setTimeout(() => {
1431
- void hideHighlight();
1432
- }, HIGHLIGHT_DURATION_MS);
1433
- });
1434
- }
1435
- wrapPossibleNavigation(_0) {
1436
- return __async(this, arguments, function* (fn, timeoutMS = MAX_LOAD_TIMEOUT_MS) {
1437
- const startTime = Date.now();
1438
- const startURL = this.url;
1439
- let lastRequestReceived = Date.now();
1440
- const firedRequests = /* @__PURE__ */ new Map();
1441
- const finishedRequests = /* @__PURE__ */ new Map();
1442
- const requestFinishedListener = (request) => {
1443
- var _a;
1444
- const key = serializeRequest(request);
1445
- finishedRequests.set(key, ((_a = finishedRequests.get(key)) != null ? _a : 0) + 1);
1446
- };
1447
- const requestFiredListener = (request) => {
1448
- var _a;
1449
- if (!isRequestRelevantForPageLoad(request, this.url)) {
1450
- this.logger.debug(
1451
- {
1452
- uri: serializeRequest(request)
1453
- },
1454
- "Ignoring request for page load network stability"
1455
- );
1456
- return;
1457
- }
1458
- const key = serializeRequest(request);
1350
+ };
1351
+ setTimeout(() => {
1352
+ void hideHighlight();
1353
+ }, HIGHLIGHT_DURATION_MS);
1354
+ }
1355
+ async wrapPossibleNavigation(fn, timeoutMS = MAX_LOAD_TIMEOUT_MS) {
1356
+ const startTime = Date.now();
1357
+ const startURL = this.url;
1358
+ let lastRequestReceived = Date.now();
1359
+ const firedRequests = /* @__PURE__ */ new Map();
1360
+ const finishedRequests = /* @__PURE__ */ new Map();
1361
+ const requestFinishedListener = (request) => {
1362
+ const key = serializeRequest(request);
1363
+ finishedRequests.set(key, (finishedRequests.get(key) ?? 0) + 1);
1364
+ };
1365
+ const requestFiredListener = (request) => {
1366
+ if (!isRequestRelevantForPageLoad(request, this.url)) {
1459
1367
  this.logger.debug(
1460
1368
  {
1461
- uri: key
1369
+ uri: serializeRequest(request)
1462
1370
  },
1463
- "Request fired on page load, delaying network stability"
1371
+ "Ignoring request for page load network stability"
1464
1372
  );
1465
- firedRequests.set(key, ((_a = firedRequests.get(key)) != null ? _a : 0) + 1);
1466
- lastRequestReceived = Date.now();
1467
- };
1468
- this.page.on("requestfinished", requestFinishedListener);
1469
- this.page.on("request", requestFiredListener);
1470
- let rejected = false;
1471
- const retPromise = fn().catch((e) => {
1472
- rejected = true;
1473
- if (e instanceof Error)
1474
- return e;
1475
- return new Error(`${e}`);
1476
- });
1477
- yield sleep(CHECK_INTERVAL_MS);
1478
- const unwrapAndThrowError = (p) => __async(this, null, function* () {
1479
- const v = yield p;
1480
- if (v instanceof Error) {
1481
- throw v;
1373
+ return;
1374
+ }
1375
+ const key = serializeRequest(request);
1376
+ this.logger.debug(
1377
+ {
1378
+ uri: key
1379
+ },
1380
+ "Request fired on page load, delaying network stability"
1381
+ );
1382
+ firedRequests.set(key, (firedRequests.get(key) ?? 0) + 1);
1383
+ lastRequestReceived = Date.now();
1384
+ };
1385
+ this.page.on("requestfinished", requestFinishedListener);
1386
+ this.page.on("request", requestFiredListener);
1387
+ let rejected = false;
1388
+ const retPromise = fn().catch((e) => {
1389
+ rejected = true;
1390
+ if (e instanceof Error)
1391
+ return e;
1392
+ return new Error(`${e}`);
1393
+ });
1394
+ await sleep(CHECK_INTERVAL_MS);
1395
+ const unwrapAndThrowError = async (p) => {
1396
+ const v = await p;
1397
+ if (v instanceof Error) {
1398
+ throw v;
1399
+ }
1400
+ return v;
1401
+ };
1402
+ let unfinishedRequests = /* @__PURE__ */ new Set();
1403
+ const waitForNetworkIdle = async () => {
1404
+ while (!rejected && Date.now() - startTime < timeoutMS) {
1405
+ unfinishedRequests = /* @__PURE__ */ new Set();
1406
+ await sleep(CHECK_INTERVAL_MS);
1407
+ if (Date.now() - lastRequestReceived <= NETWORK_STABLE_DURATION_MS) {
1408
+ continue;
1482
1409
  }
1483
- return v;
1484
- });
1485
- let unfinishedRequests = /* @__PURE__ */ new Set();
1486
- const waitForNetworkIdle = () => __async(this, null, function* () {
1487
- while (!rejected && Date.now() - startTime < timeoutMS) {
1488
- unfinishedRequests = /* @__PURE__ */ new Set();
1489
- yield sleep(CHECK_INTERVAL_MS);
1490
- if (Date.now() - lastRequestReceived <= NETWORK_STABLE_DURATION_MS) {
1491
- continue;
1492
- }
1493
- let anyDifference = false;
1494
- for (const key of firedRequests.keys()) {
1495
- if (firedRequests.get(key) !== finishedRequests.get(key)) {
1496
- this.logger.debug({ uri: key }, "Waiting on request to finish");
1497
- anyDifference = true;
1498
- unfinishedRequests.add(key);
1499
- }
1500
- }
1501
- if (!anyDifference) {
1502
- this.logger.debug(
1503
- {
1504
- url: this.url,
1505
- requests: JSON.stringify(Array.from(firedRequests.entries()))
1506
- },
1507
- `Network idle in ${Math.floor(Date.now() - startTime)}ms`
1508
- );
1509
- return true;
1410
+ let anyDifference = false;
1411
+ for (const key of firedRequests.keys()) {
1412
+ if (firedRequests.get(key) !== finishedRequests.get(key)) {
1413
+ this.logger.debug({ uri: key }, "Waiting on request to finish");
1414
+ anyDifference = true;
1415
+ unfinishedRequests.add(key);
1510
1416
  }
1511
1417
  }
1512
- if (!rejected) {
1513
- this.logger.warn(
1418
+ if (!anyDifference) {
1419
+ this.logger.debug(
1514
1420
  {
1515
1421
  url: this.url,
1516
- requests: JSON.stringify(Array.from(unfinishedRequests.entries()))
1422
+ requests: JSON.stringify(Array.from(firedRequests.entries()))
1517
1423
  },
1518
- "Timeout elapsed waiting for network idle, continuing anyways..."
1424
+ `Network idle in ${Math.floor(Date.now() - startTime)}ms`
1519
1425
  );
1426
+ return true;
1520
1427
  }
1521
- return false;
1522
- });
1523
- const waitResult = yield waitForNetworkIdle();
1524
- this.page.off("requestfinished", requestFinishedListener);
1525
- this.page.off("request", requestFiredListener);
1526
- if (!waitResult) {
1527
- return unwrapAndThrowError(retPromise);
1528
1428
  }
1529
- if (!rejected && urlChanged(this.url, startURL)) {
1530
- this.logger.debug(
1531
- `Detected url change in wrapPossibleNavigation, waiting for load state`
1429
+ if (!rejected) {
1430
+ this.logger.warn(
1431
+ {
1432
+ url: this.url,
1433
+ requests: JSON.stringify(Array.from(unfinishedRequests.entries()))
1434
+ },
1435
+ "Timeout elapsed waiting for network idle, continuing anyways..."
1532
1436
  );
1533
- try {
1534
- yield this.page.waitForLoadState("load", {
1535
- timeout: timeoutMS - (Date.now() - startTime)
1536
- });
1537
- } catch (e) {
1538
- this.logger.warn(
1539
- { url: this.url },
1540
- "Timeout elapsed waiting for load state to fire, continuing anyways..."
1541
- );
1542
- }
1543
1437
  }
1438
+ return false;
1439
+ };
1440
+ const waitResult = await waitForNetworkIdle();
1441
+ this.page.off("requestfinished", requestFinishedListener);
1442
+ this.page.off("request", requestFiredListener);
1443
+ if (!waitResult) {
1544
1444
  return unwrapAndThrowError(retPromise);
1545
- });
1546
- }
1547
- click(_0) {
1548
- return __async(this, arguments, function* (target, options = {}) {
1549
- const elementInteracted = yield this.wrapPossibleNavigation(
1550
- () => this.clickByA11yID(target.id, options)
1445
+ }
1446
+ if (!rejected && urlChanged(this.url, startURL)) {
1447
+ this.logger.debug(
1448
+ `Detected url change in wrapPossibleNavigation, waiting for load state`
1551
1449
  );
1552
- return elementInteracted;
1553
- });
1450
+ try {
1451
+ await this.page.waitForLoadState("load", {
1452
+ timeout: timeoutMS - (Date.now() - startTime)
1453
+ });
1454
+ } catch (e) {
1455
+ this.logger.warn(
1456
+ { url: this.url },
1457
+ "Timeout elapsed waiting for load state to fire, continuing anyways..."
1458
+ );
1459
+ }
1460
+ }
1461
+ return unwrapAndThrowError(retPromise);
1554
1462
  }
1555
- selectOption(target, option) {
1556
- return __async(this, null, function* () {
1557
- return this.selectOptionByA11yID(target.id, option);
1558
- });
1463
+ async click(target, options = {}) {
1464
+ const elementInteracted = await this.wrapPossibleNavigation(
1465
+ () => this.clickByA11yID(target.id, options)
1466
+ );
1467
+ return elementInteracted;
1559
1468
  }
1560
- press(key) {
1561
- return __async(this, null, function* () {
1562
- yield this.wrapPossibleNavigation(() => this.page.keyboard.press(key));
1563
- });
1469
+ async selectOption(target, option) {
1470
+ return this.selectOptionByA11yID(target.id, option);
1564
1471
  }
1565
- refresh() {
1566
- return __async(this, null, function* () {
1567
- yield this.page.reload();
1568
- yield this.pageSetup();
1569
- });
1472
+ async press(key) {
1473
+ await this.wrapPossibleNavigation(() => this.page.keyboard.press(key));
1570
1474
  }
1571
- getA11yTree() {
1572
- return __async(this, null, function* () {
1573
- let processedTree = null;
1574
- let attempt = 0;
1575
- const url = this.url;
1576
- while (!processedTree) {
1577
- try {
1578
- this.logger.debug(`Getting a11y tree at ${url}`);
1579
- const graph = yield this.getRawA11yTree();
1580
- if (!graph.root || graph.allNodes.length === 0) {
1581
- throw new Error("No a11y tree found on page");
1582
- }
1583
- processedTree = processA11yTree(graph);
1584
- } catch (e) {
1585
- this.logger.error({ err: e, url }, "Error fetching a11y tree");
1586
- if (attempt === 0) {
1587
- yield sleep(1e3);
1588
- attempt++;
1589
- } else {
1590
- throw new Error(`Max retries exceeded fetching a11y tree: ${e}`);
1591
- }
1475
+ async refresh() {
1476
+ await this.page.reload();
1477
+ await this.pageSetup();
1478
+ }
1479
+ async getA11yTree() {
1480
+ let processedTree = null;
1481
+ let attempt = 0;
1482
+ const url = this.url;
1483
+ while (!processedTree) {
1484
+ try {
1485
+ this.logger.debug(`Getting a11y tree at ${url}`);
1486
+ const graph = await this.getRawA11yTree();
1487
+ if (!graph.root || graph.allNodes.length === 0) {
1488
+ throw new Error("No a11y tree found on page");
1489
+ }
1490
+ processedTree = processA11yTree(graph);
1491
+ } catch (e) {
1492
+ this.logger.error({ err: e, url }, "Error fetching a11y tree");
1493
+ if (attempt === 0) {
1494
+ await sleep(1e3);
1495
+ attempt++;
1496
+ } else {
1497
+ throw new Error(`Max retries exceeded fetching a11y tree: ${e}`);
1592
1498
  }
1593
1499
  }
1594
- if (!processedTree.root) {
1595
- this.logger.warn("A11y tree was pruned entirely");
1500
+ }
1501
+ if (!processedTree.root) {
1502
+ this.logger.warn("A11y tree was pruned entirely");
1503
+ }
1504
+ this.nodeMap = processedTree.nodeMap;
1505
+ return processedTree;
1506
+ }
1507
+ async getRawA11yTree() {
1508
+ const url = this.page.url();
1509
+ let lastTreeUpdateTimestamp = Date.now();
1510
+ const treeUpdateListener = () => {
1511
+ lastTreeUpdateTimestamp = Date.now();
1512
+ };
1513
+ this.cdpClient.addListener(
1514
+ "Accessibility.nodesUpdated",
1515
+ treeUpdateListener
1516
+ );
1517
+ let accessibilityTreeLoadFired = false;
1518
+ const accessibilityLoadListener = () => {
1519
+ this.logger.info({ url }, `A11y tree load event fired`);
1520
+ accessibilityTreeLoadFired = true;
1521
+ };
1522
+ this.cdpClient.addListener(
1523
+ "Accessibility.loadComplete",
1524
+ accessibilityLoadListener
1525
+ );
1526
+ const a11yLoadStart = Date.now();
1527
+ let timeoutTriggered = true;
1528
+ while (Date.now() - a11yLoadStart < A11Y_STABLE_TIMEOUT_MS) {
1529
+ await sleep(CHECK_INTERVAL_MS);
1530
+ if (!accessibilityTreeLoadFired && Date.now() - a11yLoadStart < A11Y_LOAD_TIMEOUT_MS) {
1531
+ this.logger.debug({ url }, `A11y tree not loaded yet, waiting...`);
1532
+ continue;
1533
+ }
1534
+ if (Date.now() - lastTreeUpdateTimestamp >= A11Y_STABLE_DURATION_MS) {
1535
+ this.logger.debug({ url }, `A11y tree not stable yet, waiting...`);
1536
+ continue;
1596
1537
  }
1597
- this.nodeMap = processedTree.nodeMap;
1598
- return processedTree;
1538
+ timeoutTriggered = false;
1539
+ break;
1540
+ }
1541
+ this.logger.debug(
1542
+ {
1543
+ duration: Date.now() - a11yLoadStart,
1544
+ eventReceived: accessibilityTreeLoadFired,
1545
+ timeoutTriggered
1546
+ },
1547
+ "A11y wait phase completed"
1548
+ );
1549
+ const { node: root } = await this.cdpClient.send(
1550
+ "Accessibility.getRootAXNode"
1551
+ );
1552
+ const { nodes } = await this.cdpClient.send("Accessibility.queryAXTree", {
1553
+ backendNodeId: root.backendDOMNodeId
1599
1554
  });
1555
+ this.cdpClient.removeListener(
1556
+ "Accessibility.loadComplete",
1557
+ accessibilityLoadListener
1558
+ );
1559
+ this.cdpClient.removeListener(
1560
+ "Accessibility.nodesUpdated",
1561
+ treeUpdateListener
1562
+ );
1563
+ return {
1564
+ root,
1565
+ allNodes: nodes
1566
+ };
1600
1567
  }
1601
- getRawA11yTree() {
1602
- return __async(this, null, function* () {
1603
- const url = this.page.url();
1604
- let lastTreeUpdateTimestamp = Date.now();
1605
- const treeUpdateListener = () => {
1606
- lastTreeUpdateTimestamp = Date.now();
1607
- };
1608
- this.cdpClient.addListener(
1609
- "Accessibility.nodesUpdated",
1610
- treeUpdateListener
1568
+ async clickUsingVisualCoordinates(backendNodeId) {
1569
+ const location = await this.getElementLocation(backendNodeId);
1570
+ if (!location) {
1571
+ throw new Error(
1572
+ `Could not find element location with backend node id: ${backendNodeId}`
1611
1573
  );
1612
- let accessibilityTreeLoadFired = false;
1613
- const accessibilityLoadListener = () => {
1614
- this.logger.info({ url }, `A11y tree load event fired`);
1615
- accessibilityTreeLoadFired = true;
1616
- };
1617
- this.cdpClient.addListener(
1618
- "Accessibility.loadComplete",
1619
- accessibilityLoadListener
1574
+ }
1575
+ this.logger.debug({ location }, "Executing mouse click");
1576
+ await this.page.mouse.click(location.centerX, location.centerY);
1577
+ }
1578
+ // Get the "id" attribute value from an HTML element.
1579
+ async getIDAttributeUsingCDP(objectId) {
1580
+ await this.cdpClient.send("DOM.getDocument", { depth: 0 });
1581
+ const cdpNodeResult = await this.cdpClient.send("DOM.requestNode", {
1582
+ objectId
1583
+ });
1584
+ const attrResult = await this.cdpClient.send("DOM.getAttributes", {
1585
+ nodeId: cdpNodeResult.nodeId
1586
+ });
1587
+ const attributes = attrResult.attributes;
1588
+ const indexAttr = attributes.findIndex((s) => s === "data-momentic-id");
1589
+ if (indexAttr === -1) {
1590
+ return "";
1591
+ }
1592
+ return attributes[indexAttr + 1] || "";
1593
+ }
1594
+ async getLocatorFromBackendID(backendNodeId) {
1595
+ await this.page.evaluate(addIDsScript);
1596
+ const cdpResolveResult = await this.cdpClient.send("DOM.resolveNode", {
1597
+ backendNodeId
1598
+ });
1599
+ if (!cdpResolveResult || !cdpResolveResult.object.objectId) {
1600
+ throw new Error(`Could not resolve backend node ${backendNodeId}`);
1601
+ }
1602
+ try {
1603
+ const id = await this.getIDAttributeUsingCDP(
1604
+ cdpResolveResult.object.objectId
1620
1605
  );
1621
- const a11yLoadStart = Date.now();
1622
- let timeoutTriggered = true;
1623
- while (Date.now() - a11yLoadStart < A11Y_STABLE_TIMEOUT_MS) {
1624
- yield sleep(CHECK_INTERVAL_MS);
1625
- if (!accessibilityTreeLoadFired && Date.now() - a11yLoadStart < A11Y_LOAD_TIMEOUT_MS) {
1626
- this.logger.debug({ url }, `A11y tree not loaded yet, waiting...`);
1627
- continue;
1628
- }
1629
- if (Date.now() - lastTreeUpdateTimestamp >= A11Y_STABLE_DURATION_MS) {
1630
- this.logger.debug({ url }, `A11y tree not stable yet, waiting...`);
1631
- continue;
1632
- }
1633
- timeoutTriggered = false;
1634
- break;
1606
+ if (!id) {
1607
+ throw new Error("Failed getting data-momentic-id attribute using CDP");
1635
1608
  }
1636
- this.logger.debug(
1609
+ return this.page.locator(`[data-momentic-id="${id}"]`);
1610
+ } catch (err) {
1611
+ this.logger.error(
1637
1612
  {
1638
- duration: Date.now() - a11yLoadStart,
1639
- eventReceived: accessibilityTreeLoadFired,
1640
- timeoutTriggered
1613
+ err
1641
1614
  },
1642
- "A11y wait phase completed"
1615
+ "Failed to get ID attribute"
1643
1616
  );
1644
- const { node: root } = yield this.cdpClient.send(
1645
- "Accessibility.getRootAXNode"
1646
- );
1647
- const { nodes } = yield this.cdpClient.send("Accessibility.queryAXTree", {
1648
- backendNodeId: root.backendDOMNodeId
1649
- });
1650
- this.cdpClient.removeListener(
1651
- "Accessibility.loadComplete",
1652
- accessibilityLoadListener
1653
- );
1654
- this.cdpClient.removeListener(
1655
- "Accessibility.nodesUpdated",
1656
- treeUpdateListener
1657
- );
1658
- return {
1659
- root,
1660
- allNodes: nodes
1661
- };
1662
- });
1617
+ throw err;
1618
+ }
1663
1619
  }
1664
- clickUsingVisualCoordinates(backendNodeId) {
1665
- return __async(this, null, function* () {
1666
- const location = yield this.getElementLocation(backendNodeId);
1667
- if (!location) {
1620
+ async clickUsingCDP(originalNode, options = {}) {
1621
+ let clickAttempts = 0;
1622
+ let candidateNode = originalNode;
1623
+ while (clickAttempts < MAX_BROWSER_ACTION_ATTEMPTS) {
1624
+ if (!candidateNode || candidateNode.role === "RootWebArea") {
1668
1625
  throw new Error(
1669
- `Could not find element location with backend node id: ${backendNodeId}`
1626
+ `Attempted to click node with no clickable surrounding elements: ${originalNode.getLogForm()}`
1670
1627
  );
1671
1628
  }
1672
- this.logger.debug({ location }, "Executing mouse click");
1673
- yield this.page.mouse.click(location.centerX, location.centerY);
1674
- });
1675
- }
1676
- // Get the "id" attribute value from an HTML element.
1677
- getIDAttributeUsingCDP(objectId) {
1678
- return __async(this, null, function* () {
1679
- yield this.cdpClient.send("DOM.getDocument", { depth: 0 });
1680
- const cdpNodeResult = yield this.cdpClient.send("DOM.requestNode", {
1681
- objectId
1682
- });
1683
- const attrResult = yield this.cdpClient.send("DOM.getAttributes", {
1684
- nodeId: cdpNodeResult.nodeId
1685
- });
1686
- const attributes = attrResult.attributes;
1687
- const indexAttr = attributes.findIndex((s) => s === "data-momentic-id");
1688
- if (indexAttr === -1) {
1689
- return "";
1629
+ if (candidateNode.role === "StaticText") {
1630
+ candidateNode = candidateNode.parent;
1631
+ continue;
1690
1632
  }
1691
- return attributes[indexAttr + 1] || "";
1692
- });
1693
- }
1694
- getLocatorFromBackendID(backendNodeId) {
1695
- return __async(this, null, function* () {
1696
- yield this.page.evaluate(addIDsScript);
1697
- const cdpResolveResult = yield this.cdpClient.send("DOM.resolveNode", {
1698
- backendNodeId
1699
- });
1700
- if (!cdpResolveResult || !cdpResolveResult.object.objectId) {
1701
- throw new Error(`Could not resolve backend node ${backendNodeId}`);
1633
+ const candidateNodeID = candidateNode.backendNodeID;
1634
+ if (!candidateNodeID) {
1635
+ this.logger.warn(
1636
+ { node: candidateNode.getLogForm() },
1637
+ "Click candidate had no backend node ID"
1638
+ );
1639
+ candidateNode = candidateNode.parent;
1640
+ continue;
1702
1641
  }
1703
1642
  try {
1704
- const id = yield this.getIDAttributeUsingCDP(
1705
- cdpResolveResult.object.objectId
1706
- );
1707
- if (!id) {
1708
- throw new Error("Failed getting data-momentic-id attribute using CDP");
1643
+ const locator = await this.getLocatorFromBackendID(candidateNodeID);
1644
+ if (options.doubleClick) {
1645
+ await locator.dblclick({
1646
+ timeout: BROWSER_ACTION_TIMEOUT_MS
1647
+ });
1648
+ } else {
1649
+ await locator.click({
1650
+ timeout: BROWSER_ACTION_TIMEOUT_MS,
1651
+ button: options.rightClick ? "right" : "left"
1652
+ });
1653
+ }
1654
+ if (candidateNode.id !== originalNode.id) {
1655
+ this.logger.info(
1656
+ {
1657
+ oldNode: originalNode.getLogForm(),
1658
+ newNode: candidateNode.getLogForm()
1659
+ },
1660
+ `Redirected click successfully to new element`
1661
+ );
1709
1662
  }
1710
- return this.page.locator(`[data-momentic-id="${id}"]`);
1663
+ return candidateNode;
1711
1664
  } catch (err) {
1712
1665
  this.logger.error(
1713
- {
1714
- err
1715
- },
1716
- "Failed to get ID attribute"
1666
+ { err, node: candidateNode.getLogForm() },
1667
+ "Failed click or click timed out"
1717
1668
  );
1718
- throw err;
1669
+ clickAttempts++;
1670
+ candidateNode = candidateNode.parent;
1671
+ }
1672
+ }
1673
+ throw new Error(
1674
+ `Max click redirection attempts exhausted on original element: ${originalNode.getLogForm()}`
1675
+ );
1676
+ }
1677
+ /**
1678
+ * Currently unused, but could be useful for vision model integration.
1679
+ * Gets x/y position of an a11y node.
1680
+ */
1681
+ async getElementLocation(backendNodeId) {
1682
+ const tree = await this.cdpClient.send("DOMSnapshot.captureSnapshot", {
1683
+ computedStyles: [],
1684
+ includeDOMRects: true,
1685
+ includePaintOrder: true
1686
+ });
1687
+ let devicePixelRatio = await this.page.evaluate(
1688
+ () => window.devicePixelRatio
1689
+ );
1690
+ if (process.platform === "darwin" && devicePixelRatio === 1) {
1691
+ devicePixelRatio = RETINA_WINDOW_SCALE_FACTOR;
1692
+ }
1693
+ const document2 = tree["documents"][0];
1694
+ const layout = document2["layout"];
1695
+ const nodes = document2["nodes"];
1696
+ const nodeNames = nodes["nodeName"] || [];
1697
+ const backendNodeIds = nodes["backendNodeId"] || [];
1698
+ const layoutNodeIndex = layout["nodeIndex"];
1699
+ const bounds = layout["bounds"];
1700
+ let cursor2 = -1;
1701
+ for (let i = 0; i < nodeNames.length; i++) {
1702
+ if (backendNodeIds[i] === backendNodeId) {
1703
+ cursor2 = layoutNodeIndex.indexOf(i);
1704
+ break;
1719
1705
  }
1706
+ }
1707
+ if (cursor2 === -1) {
1708
+ throw new Error(
1709
+ `Could not find any backend node with ID ${backendNodeId}`
1710
+ );
1711
+ }
1712
+ let [x = 0, y = 0, width = 0, height = 0] = bounds[cursor2];
1713
+ x /= devicePixelRatio;
1714
+ y /= devicePixelRatio;
1715
+ width /= devicePixelRatio;
1716
+ height /= devicePixelRatio;
1717
+ const centerX = x + width / 2;
1718
+ const centerY = y + height / 2;
1719
+ return { centerX, centerY };
1720
+ }
1721
+ async scrollUp() {
1722
+ await this.page.evaluate(() => {
1723
+ (document.scrollingElement || document.body).scrollTop = (document.scrollingElement || document.body).scrollTop - window.innerHeight;
1724
+ });
1725
+ await this.page.evaluate(() => {
1726
+ (document.scrollingElement || document.body).scrollTop = (document.scrollingElement || document.body).scrollTop + window.innerHeight;
1720
1727
  });
1721
1728
  }
1722
- clickUsingCDP(_0) {
1723
- return __async(this, arguments, function* (originalNode, options = {}) {
1724
- let clickAttempts = 0;
1725
- let candidateNode = originalNode;
1726
- while (clickAttempts < MAX_BROWSER_ACTION_ATTEMPTS) {
1727
- if (!candidateNode || candidateNode.role === "RootWebArea") {
1728
- throw new Error(
1729
- `Attempted to click node with no clickable surrounding elements: ${originalNode.getLogForm()}`
1730
- );
1731
- }
1732
- if (candidateNode.role === "StaticText") {
1733
- candidateNode = candidateNode.parent;
1734
- continue;
1735
- }
1736
- const candidateNodeID = candidateNode.backendNodeID;
1737
- if (!candidateNodeID) {
1738
- this.logger.warn(
1739
- { node: candidateNode.getLogForm() },
1740
- "Click candidate had no backend node ID"
1741
- );
1742
- candidateNode = candidateNode.parent;
1743
- continue;
1744
- }
1745
- try {
1746
- const locator = yield this.getLocatorFromBackendID(candidateNodeID);
1747
- if (options.doubleClick) {
1748
- yield locator.dblclick({
1749
- timeout: BROWSER_ACTION_TIMEOUT_MS
1750
- });
1751
- } else {
1752
- yield locator.click({
1753
- timeout: BROWSER_ACTION_TIMEOUT_MS,
1754
- button: options.rightClick ? "right" : "left"
1755
- });
1756
- }
1757
- if (candidateNode.id !== originalNode.id) {
1758
- this.logger.info(
1759
- {
1760
- oldNode: originalNode.getLogForm(),
1761
- newNode: candidateNode.getLogForm()
1762
- },
1763
- `Redirected click successfully to new element`
1764
- );
1765
- }
1766
- return candidateNode;
1767
- } catch (err) {
1768
- this.logger.error(
1769
- { err, node: candidateNode.getLogForm() },
1770
- "Failed click or click timed out"
1771
- );
1772
- clickAttempts++;
1773
- candidateNode = candidateNode.parent;
1774
- }
1775
- }
1776
- throw new Error(
1777
- `Max click redirection attempts exhausted on original element: ${originalNode.getLogForm()}`
1778
- );
1729
+ async scrollDown() {
1730
+ await this.page.evaluate(() => {
1731
+ (document.scrollingElement || document.body).scrollTop = (document.scrollingElement || document.body).scrollTop + window.innerHeight;
1779
1732
  });
1780
1733
  }
1781
- /**
1782
- * Currently unused, but could be useful for vision model integration.
1783
- * Gets x/y position of an a11y node.
1784
- */
1785
- getElementLocation(backendNodeId) {
1786
- return __async(this, null, function* () {
1787
- const tree = yield this.cdpClient.send("DOMSnapshot.captureSnapshot", {
1788
- computedStyles: [],
1789
- includeDOMRects: true,
1790
- includePaintOrder: true
1791
- });
1792
- let devicePixelRatio = yield this.page.evaluate(
1793
- () => window.devicePixelRatio
1794
- );
1795
- if (process.platform === "darwin" && devicePixelRatio === 1) {
1796
- devicePixelRatio = RETINA_WINDOW_SCALE_FACTOR;
1797
- }
1798
- const document2 = tree["documents"][0];
1799
- const layout = document2["layout"];
1800
- const nodes = document2["nodes"];
1801
- const nodeNames = nodes["nodeName"] || [];
1802
- const backendNodeIds = nodes["backendNodeId"] || [];
1803
- const layoutNodeIndex = layout["nodeIndex"];
1804
- const bounds = layout["bounds"];
1805
- let cursor2 = -1;
1806
- for (let i = 0; i < nodeNames.length; i++) {
1807
- if (backendNodeIds[i] === backendNodeId) {
1808
- cursor2 = layoutNodeIndex.indexOf(i);
1809
- break;
1810
- }
1811
- }
1812
- if (cursor2 === -1) {
1813
- throw new Error(
1814
- `Could not find any backend node with ID ${backendNodeId}`
1815
- );
1816
- }
1817
- let [x = 0, y = 0, width = 0, height = 0] = bounds[cursor2];
1818
- x /= devicePixelRatio;
1819
- y /= devicePixelRatio;
1820
- width /= devicePixelRatio;
1821
- height /= devicePixelRatio;
1822
- const centerX = x + width / 2;
1823
- const centerY = y + height / 2;
1824
- return { centerX, centerY };
1825
- });
1826
- }
1827
- scrollUp() {
1828
- return __async(this, null, function* () {
1829
- yield this.page.evaluate(() => {
1830
- (document.scrollingElement || document.body).scrollTop = (document.scrollingElement || document.body).scrollTop - window.innerHeight;
1831
- });
1832
- yield this.page.evaluate(() => {
1833
- (document.scrollingElement || document.body).scrollTop = (document.scrollingElement || document.body).scrollTop + window.innerHeight;
1834
- });
1835
- });
1836
- }
1837
- scrollDown() {
1838
- return __async(this, null, function* () {
1839
- yield this.page.evaluate(() => {
1840
- (document.scrollingElement || document.body).scrollTop = (document.scrollingElement || document.body).scrollTop + window.innerHeight;
1841
- });
1842
- });
1843
- }
1844
- goForward() {
1845
- return __async(this, null, function* () {
1846
- yield this.wrapPossibleNavigation(
1847
- () => this.page.goForward({ timeout: MAX_LOAD_TIMEOUT_MS })
1848
- );
1849
- yield this.pageSetup();
1850
- });
1851
- }
1852
- goBack() {
1853
- return __async(this, null, function* () {
1854
- yield this.wrapPossibleNavigation(
1855
- () => this.page.goBack({ timeout: MAX_LOAD_TIMEOUT_MS })
1856
- );
1857
- yield this.pageSetup();
1858
- });
1734
+ async goForward() {
1735
+ await this.wrapPossibleNavigation(
1736
+ () => this.page.goForward({ timeout: MAX_LOAD_TIMEOUT_MS })
1737
+ );
1738
+ await this.pageSetup();
1859
1739
  }
1860
- switchToPage(urlSubstring) {
1861
- return __async(this, null, function* () {
1862
- const allPages = yield this.context.pages();
1863
- for (let i = 0; i < allPages.length; i++) {
1864
- const page = allPages[i];
1865
- if (page.url().includes(urlSubstring)) {
1866
- this.page = page;
1867
- yield page.waitForLoadState("load", {
1868
- timeout: MAX_LOAD_TIMEOUT_MS
1869
- });
1870
- yield this.pageSetup();
1871
- this.cdpClient = yield this.context.newCDPSession(page);
1872
- yield initCDPSession(this.cdpClient);
1873
- this.logger.info(`Switching to tab ${i} with url ${page.url()}`);
1874
- return;
1875
- }
1740
+ async goBack() {
1741
+ await this.wrapPossibleNavigation(
1742
+ () => this.page.goBack({ timeout: MAX_LOAD_TIMEOUT_MS })
1743
+ );
1744
+ await this.pageSetup();
1745
+ }
1746
+ async switchToPage(urlSubstring) {
1747
+ const allPages = await this.context.pages();
1748
+ for (let i = 0; i < allPages.length; i++) {
1749
+ const page = allPages[i];
1750
+ if (page.url().includes(urlSubstring)) {
1751
+ this.page = page;
1752
+ await page.waitForLoadState("load", {
1753
+ timeout: MAX_LOAD_TIMEOUT_MS
1754
+ });
1755
+ await this.pageSetup();
1756
+ this.cdpClient = await this.context.newCDPSession(page);
1757
+ await initCDPSession(this.cdpClient);
1758
+ this.logger.info(`Switching to tab ${i} with url ${page.url()}`);
1759
+ return;
1876
1760
  }
1877
- throw new Error(`Could not find page with url containing ${urlSubstring}`);
1878
- });
1761
+ }
1762
+ throw new Error(`Could not find page with url containing ${urlSubstring}`);
1879
1763
  }
1880
- setCookie(cookie) {
1881
- return __async(this, null, function* () {
1882
- const cookieSettings = parseCookieString(cookie);
1883
- yield this.context.addCookies([cookieSettings]);
1884
- });
1764
+ async setCookie(cookie) {
1765
+ const cookieSettings = parseCookieString(cookie);
1766
+ await this.context.addCookies([cookieSettings]);
1885
1767
  }
1886
1768
  };
1887
- _ChromeBrowser.USER_AGENT = import_playwright.devices["Desktop Chrome"].userAgent;
1888
- var ChromeBrowser = _ChromeBrowser;
1889
1769
 
1890
1770
  // ../../packages/web-agent/src/configs/controller.ts
1891
1771
  var A11Y_CONTROLLER_CONFIG = {
@@ -1897,10 +1777,22 @@ var A11Y_CONTROLLER_CONFIG = {
1897
1777
  var DEFAULT_CONTROLLER_CONFIG = A11Y_CONTROLLER_CONFIG;
1898
1778
 
1899
1779
  // ../../packages/web-agent/src/controller.ts
1900
- var import_dedent2 = __toESM(require("dedent"), 1);
1901
- var import_diff_lines = __toESM(require("diff-lines"), 1);
1780
+ import dedent2 from "dedent";
1781
+ import diffLines from "diff-lines";
1902
1782
  var MAX_HISTORY_CHAR_LENGTH = 1e4;
1903
1783
  var AgentController = class {
1784
+ // Instance of browser to interact with
1785
+ browser;
1786
+ // Stack of queued-up instructions
1787
+ pendingInstructions;
1788
+ // manager for all AI generation
1789
+ generator;
1790
+ // Stack of commands previously executed.
1791
+ // Top of stack can be a pending command that hasn't been executed yet.
1792
+ // Should not contain intermediate successes due to granular commands.
1793
+ commandHistory;
1794
+ config;
1795
+ logger;
1904
1796
  constructor({ browser, config, generator, logger }) {
1905
1797
  this.browser = browser;
1906
1798
  this.generator = generator;
@@ -1935,20 +1827,16 @@ var AgentController = class {
1935
1827
  /**
1936
1828
  * Reset controller and browser state.
1937
1829
  */
1938
- resetState() {
1939
- return __async(this, null, function* () {
1940
- this.resetHistory();
1941
- yield this.browser.navigate(this.browser.baseURL);
1942
- });
1830
+ async resetState() {
1831
+ this.resetHistory();
1832
+ await this.browser.navigate(this.browser.baseURL);
1943
1833
  }
1944
1834
  /**
1945
1835
  * Get the browser state as a string
1946
1836
  */
1947
- getBrowserState() {
1948
- return __async(this, null, function* () {
1949
- const a11yTree = yield this.browser.getA11yTree();
1950
- return a11yTree.serialize();
1951
- });
1837
+ async getBrowserState() {
1838
+ const a11yTree = await this.browser.getA11yTree();
1839
+ return a11yTree.serialize();
1952
1840
  }
1953
1841
  getSerializedHistory(url, currentBrowserState) {
1954
1842
  let history;
@@ -1959,105 +1847,99 @@ var AgentController = class {
1959
1847
  }
1960
1848
  return history;
1961
1849
  }
1962
- splitUserGoal(type, goal, disableCache) {
1963
- return __async(this, null, function* () {
1964
- if (type === "AI_ACTION" /* AI_ACTION */ && goal.match(/[,!;.]|(?:and)|(?:then)/) && this.config.useGoalSplitter) {
1965
- const granularInstructions = yield this.generator.getGranularGoals(
1966
- { goal, url: this.browser.url },
1967
- disableCache
1968
- );
1969
- this.pendingInstructions = granularInstructions.reverse();
1970
- } else {
1971
- this.pendingInstructions = [goal];
1972
- }
1973
- });
1850
+ async splitUserGoal(type, goal, disableCache) {
1851
+ if (type === "AI_ACTION" /* AI_ACTION */ && goal.match(/[,!;.]|(?:and)|(?:then)/) && this.config.useGoalSplitter) {
1852
+ const granularInstructions = await this.generator.getGranularGoals(
1853
+ { goal, url: this.browser.url },
1854
+ disableCache
1855
+ );
1856
+ this.pendingInstructions = granularInstructions.reverse();
1857
+ } else {
1858
+ this.pendingInstructions = [goal];
1859
+ }
1974
1860
  }
1975
1861
  /**
1976
1862
  * Given previously executed commands, generate command for the current prompt.
1977
1863
  * Should only be used for AI action.
1978
1864
  */
1979
- promptToCommand(type, goal, disableCache) {
1980
- return __async(this, null, function* () {
1981
- if (this.pendingInstructions.length === 0) {
1982
- yield this.splitUserGoal(type, goal, disableCache);
1983
- }
1984
- const currInstruction = this.pendingInstructions[this.pendingInstructions.length - 1];
1985
- this.logger.info({ goal: currInstruction }, "Starting prompt translation");
1986
- const getBrowserStateStart = Date.now();
1987
- const url = this.browser.url;
1988
- const browserState = yield this.getBrowserState();
1865
+ async promptToCommand(type, goal, disableCache) {
1866
+ if (this.pendingInstructions.length === 0) {
1867
+ await this.splitUserGoal(type, goal, disableCache);
1868
+ }
1869
+ const currInstruction = this.pendingInstructions[this.pendingInstructions.length - 1];
1870
+ this.logger.info({ goal: currInstruction }, "Starting prompt translation");
1871
+ const getBrowserStateStart = Date.now();
1872
+ const url = this.browser.url;
1873
+ const browserState = await this.getBrowserState();
1874
+ this.logger.info(
1875
+ {
1876
+ duration: Date.now() - getBrowserStateStart,
1877
+ url
1878
+ },
1879
+ "Got browser state"
1880
+ );
1881
+ const numPrevious = this.commandHistory.length;
1882
+ this.commandHistory.push({
1883
+ state: "PENDING",
1884
+ browserStateBeforeCommand: browserState,
1885
+ urlBeforeCommand: url,
1886
+ type
1887
+ });
1888
+ const history = this.getSerializedHistory(url, browserState);
1889
+ const getCommandProposalStart = Date.now();
1890
+ const proposedCommand = await this.generator.getProposedCommand(
1891
+ {
1892
+ url,
1893
+ numPrevious,
1894
+ browserState,
1895
+ history,
1896
+ goal: currInstruction,
1897
+ lastCommand: this.lastExecutedCommand
1898
+ },
1899
+ disableCache
1900
+ );
1901
+ this.logger.info(
1902
+ { duration: Date.now() - getCommandProposalStart },
1903
+ "Got proposed command"
1904
+ );
1905
+ if (proposedCommand.type === "SUCCESS" /* SUCCESS */) {
1906
+ const finishedInstruction = this.pendingInstructions.pop();
1989
1907
  this.logger.info(
1990
1908
  {
1991
- duration: Date.now() - getBrowserStateStart,
1992
- url
1909
+ finishedInstruction,
1910
+ remainingInstructions: this.pendingInstructions
1993
1911
  },
1994
- "Got browser state"
1912
+ "Removing pending instruction due to SUCCESS"
1995
1913
  );
1996
- const numPrevious = this.commandHistory.length;
1997
- this.commandHistory.push({
1998
- state: "PENDING",
1999
- browserStateBeforeCommand: browserState,
2000
- urlBeforeCommand: url,
2001
- type
2002
- });
2003
- const history = this.getSerializedHistory(url, browserState);
2004
- const getCommandProposalStart = Date.now();
2005
- const proposedCommand = yield this.generator.getProposedCommand(
1914
+ if (this.pendingInstructions.length !== 0) {
1915
+ this.commandHistory.pop();
1916
+ return this.promptToCommand(type, "", disableCache);
1917
+ }
1918
+ } else if (
1919
+ // on failure, we don't continue to execute
1920
+ proposedCommand.type === "FAILURE"
1921
+ ) {
1922
+ this.logger.info(
2006
1923
  {
2007
- url,
2008
- numPrevious,
2009
- browserState,
2010
- history,
2011
- goal: currInstruction,
2012
- lastCommand: this.lastExecutedCommand
1924
+ remainingInstructions: this.pendingInstructions
2013
1925
  },
2014
- disableCache
2015
- );
2016
- this.logger.info(
2017
- { duration: Date.now() - getCommandProposalStart },
2018
- "Got proposed command"
1926
+ "Removing pending instructions due to FAILURE"
2019
1927
  );
2020
- if (proposedCommand.type === "SUCCESS" /* SUCCESS */) {
2021
- const finishedInstruction = this.pendingInstructions.pop();
2022
- this.logger.info(
2023
- {
2024
- finishedInstruction,
2025
- remainingInstructions: this.pendingInstructions
2026
- },
2027
- "Removing pending instruction due to SUCCESS"
2028
- );
2029
- if (this.pendingInstructions.length !== 0) {
2030
- this.commandHistory.pop();
2031
- return this.promptToCommand(type, "", disableCache);
2032
- }
2033
- } else if (
2034
- // on failure, we don't continue to execute
2035
- proposedCommand.type === "FAILURE"
2036
- ) {
2037
- this.logger.info(
2038
- {
2039
- remainingInstructions: this.pendingInstructions
2040
- },
2041
- "Removing pending instructions due to FAILURE"
2042
- );
2043
- this.pendingInstructions = [];
2044
- }
2045
- return proposedCommand;
2046
- });
1928
+ this.pendingInstructions = [];
1929
+ }
1930
+ return proposedCommand;
2047
1931
  }
2048
- locateElement(description, disableCache) {
2049
- return __async(this, null, function* () {
2050
- const locator = yield this.generator.getElementLocation(
2051
- { browserState: yield this.getBrowserState(), goal: description },
2052
- disableCache
1932
+ async locateElement(description, disableCache) {
1933
+ const locator = await this.generator.getElementLocation(
1934
+ { browserState: await this.getBrowserState(), goal: description },
1935
+ disableCache
1936
+ );
1937
+ if (locator.id < 0) {
1938
+ throw new Error(
1939
+ `Unable to locate element with description: ${description}`
2053
1940
  );
2054
- if (locator.id < 0) {
2055
- throw new Error(
2056
- `Unable to locate element with description: ${description}`
2057
- );
2058
- }
2059
- return locator;
2060
- });
1941
+ }
1942
+ return locator;
2061
1943
  }
2062
1944
  /**
2063
1945
  * Construct a detailed history that can be passed to the LLM.
@@ -2084,7 +1966,7 @@ var AgentController = class {
2084
1966
  ` URL CHANGE: '${log.urlBeforeCommand}' -> '${currentURL}'`
2085
1967
  );
2086
1968
  } else {
2087
- const browserStateDiff = (0, import_diff_lines.default)(
1969
+ const browserStateDiff = diffLines(
2088
1970
  log.browserStateBeforeCommand,
2089
1971
  currentPageState,
2090
1972
  {
@@ -2107,7 +1989,7 @@ var AgentController = class {
2107
1989
  return historyLines.join("\n");
2108
1990
  }
2109
1991
  getListHistory() {
2110
- return import_dedent2.default`Here are the commands that you have successfully executed:
1992
+ return dedent2`Here are the commands that you have successfully executed:
2111
1993
  ${this.commandHistory.filter((cmd) => cmd.type === "AI_ACTION" /* AI_ACTION */).map((cmd) => `- ${cmd.serializedCommand}`).join("\n")}`;
2112
1994
  }
2113
1995
  /**
@@ -2115,108 +1997,104 @@ var AgentController = class {
2115
1997
  * @param [stateless=false] Execute this command in a stateless fashion, without modifying any controller state such as
2116
1998
  * pending instructions. Useful when executing cached instructions.
2117
1999
  */
2118
- executeCommand(command, disableCache, stateless = false) {
2119
- return __async(this, null, function* () {
2120
- const pendingHistory = this.commandHistory[this.commandHistory.length - 1];
2121
- if (!stateless) {
2122
- if (!pendingHistory || pendingHistory.state !== "PENDING") {
2123
- throw new Error(
2124
- "Executing command but there is no pending entry in the history"
2125
- );
2126
- }
2127
- } else {
2128
- yield this.browser.getA11yTree();
2129
- }
2130
- let result;
2131
- try {
2132
- const executionStart = Date.now();
2133
- result = yield this.executePresetStep(
2134
- command,
2135
- disableCache
2136
- );
2137
- this.logger.info(
2138
- { result, duration: Date.now() - executionStart },
2139
- "Got execution result"
2140
- );
2141
- } catch (e) {
2142
- if (e instanceof Error) {
2143
- throw new BrowserExecutionError(`Failed to execute command: ${e}`, {
2144
- cause: e
2145
- });
2146
- }
2147
- throw new BrowserExecutionError(
2148
- `Unexpected throw from executing command`,
2149
- {
2150
- cause: new Error(`${e}`)
2151
- }
2000
+ async executeCommand(command, disableCache, stateless = false) {
2001
+ const pendingHistory = this.commandHistory[this.commandHistory.length - 1];
2002
+ if (!stateless) {
2003
+ if (!pendingHistory || pendingHistory.state !== "PENDING") {
2004
+ throw new Error(
2005
+ "Executing command but there is no pending entry in the history"
2152
2006
  );
2153
2007
  }
2154
- if (result.succeedImmediately && !stateless) {
2155
- this.pendingInstructions.pop();
2156
- if (this.pendingInstructions.length > 0) {
2157
- result.succeedImmediately = false;
2158
- }
2159
- }
2160
- if (result.elementInteracted && "target" in command && !command.target.elementDescriptor) {
2161
- command.target.elementDescriptor = result.elementInteracted.trim();
2162
- }
2163
- if (!stateless) {
2164
- pendingHistory.generatedStep = command;
2165
- pendingHistory.serializedCommand = serializeCommand(command);
2166
- pendingHistory.state = "DONE";
2167
- }
2168
- return result;
2169
- });
2170
- }
2171
- executeAssertion(urlBeforeCommand, command) {
2172
- return __async(this, null, function* () {
2173
- let params;
2174
- if (command.useVision) {
2175
- params = {
2176
- goal: command.assertion,
2177
- url: urlBeforeCommand,
2178
- // used for vision only
2179
- screenshot: yield this.browser.screenshot(),
2180
- // unused for visual assertion
2181
- browserState: "",
2182
- history: "",
2183
- numPrevious: -1,
2184
- lastCommand: null
2185
- };
2186
- } else {
2187
- const browserState = yield this.getBrowserState();
2188
- const history = this.getSerializedHistory(urlBeforeCommand, browserState);
2189
- params = {
2190
- goal: command.assertion,
2191
- url: urlBeforeCommand,
2192
- // used for text only
2193
- browserState,
2194
- history,
2195
- lastCommand: this.lastExecutedCommand,
2196
- numPrevious: this.commandHistory.length
2197
- };
2198
- }
2199
- const assertionEval = yield this.generator.getAssertionResult(
2200
- params,
2201
- command.useVision,
2202
- command.disableCache
2008
+ } else {
2009
+ await this.browser.getA11yTree();
2010
+ }
2011
+ let result;
2012
+ try {
2013
+ const executionStart = Date.now();
2014
+ result = await this.executePresetStep(
2015
+ command,
2016
+ disableCache
2203
2017
  );
2204
- if (assertionEval.relevantElements) {
2205
- void Promise.all(
2206
- assertionEval.relevantElements.map(
2207
- (id) => this.browser.highlight({ id })
2208
- )
2209
- );
2018
+ this.logger.info(
2019
+ { result, duration: Date.now() - executionStart },
2020
+ "Got execution result"
2021
+ );
2022
+ } catch (e) {
2023
+ if (e instanceof Error) {
2024
+ throw new BrowserExecutionError(`Failed to execute command: ${e}`, {
2025
+ cause: e
2026
+ });
2210
2027
  }
2211
- if (!assertionEval.result) {
2212
- throw new Error(assertionEval.thoughts);
2028
+ throw new BrowserExecutionError(
2029
+ `Unexpected throw from executing command`,
2030
+ {
2031
+ cause: new Error(`${e}`)
2032
+ }
2033
+ );
2034
+ }
2035
+ if (result.succeedImmediately && !stateless) {
2036
+ this.pendingInstructions.pop();
2037
+ if (this.pendingInstructions.length > 0) {
2038
+ result.succeedImmediately = false;
2213
2039
  }
2214
- return {
2215
- succeedImmediately: false,
2216
- thoughts: assertionEval.thoughts,
2217
- urlAfterCommand: urlBeforeCommand
2040
+ }
2041
+ if (result.elementInteracted && "target" in command && !command.target.elementDescriptor) {
2042
+ command.target.elementDescriptor = result.elementInteracted.trim();
2043
+ }
2044
+ if (!stateless) {
2045
+ pendingHistory.generatedStep = command;
2046
+ pendingHistory.serializedCommand = serializeCommand(command);
2047
+ pendingHistory.state = "DONE";
2048
+ }
2049
+ return result;
2050
+ }
2051
+ async executeAssertion(urlBeforeCommand, command) {
2052
+ let params;
2053
+ if (command.useVision) {
2054
+ params = {
2055
+ goal: command.assertion,
2056
+ url: urlBeforeCommand,
2057
+ // used for vision only
2058
+ screenshot: await this.browser.screenshot(),
2059
+ // unused for visual assertion
2060
+ browserState: "",
2061
+ history: "",
2062
+ numPrevious: -1,
2063
+ lastCommand: null
2218
2064
  };
2219
- });
2065
+ } else {
2066
+ const browserState = await this.getBrowserState();
2067
+ const history = this.getSerializedHistory(urlBeforeCommand, browserState);
2068
+ params = {
2069
+ goal: command.assertion,
2070
+ url: urlBeforeCommand,
2071
+ // used for text only
2072
+ browserState,
2073
+ history,
2074
+ lastCommand: this.lastExecutedCommand,
2075
+ numPrevious: this.commandHistory.length
2076
+ };
2077
+ }
2078
+ const assertionEval = await this.generator.getAssertionResult(
2079
+ params,
2080
+ command.useVision,
2081
+ command.disableCache
2082
+ );
2083
+ if (assertionEval.relevantElements) {
2084
+ void Promise.all(
2085
+ assertionEval.relevantElements.map(
2086
+ (id) => this.browser.highlight({ id })
2087
+ )
2088
+ );
2089
+ }
2090
+ if (!assertionEval.result) {
2091
+ throw new Error(assertionEval.thoughts);
2092
+ }
2093
+ return {
2094
+ succeedImmediately: false,
2095
+ thoughts: assertionEval.thoughts,
2096
+ urlAfterCommand: urlBeforeCommand
2097
+ };
2220
2098
  }
2221
2099
  /**
2222
2100
  * Executes a preset command.
@@ -2224,265 +2102,255 @@ var AgentController = class {
2224
2102
  * For assertions, an AssertionResult with thoughts is returned.
2225
2103
  * Throws on failure.
2226
2104
  */
2227
- executePresetStep(command, disableCache) {
2228
- return __async(this, null, function* () {
2229
- var _a, _b, _c;
2230
- const urlBeforeCommand = this.browser.url;
2231
- switch (command.type) {
2232
- case "SUCCESS" /* SUCCESS */:
2233
- if ((_a = command.condition) == null ? void 0 : _a.assertion.trim()) {
2234
- return this.executeAssertion(urlBeforeCommand, command.condition);
2235
- }
2236
- return {
2237
- succeedImmediately: false,
2238
- urlAfterCommand: this.browser.url
2239
- };
2240
- case "AI_ASSERTION" /* AI_ASSERTION */: {
2241
- return this.executeAssertion(urlBeforeCommand, command);
2105
+ async executePresetStep(command, disableCache) {
2106
+ var _a, _b, _c;
2107
+ const urlBeforeCommand = this.browser.url;
2108
+ switch (command.type) {
2109
+ case "SUCCESS" /* SUCCESS */:
2110
+ if ((_a = command.condition) == null ? void 0 : _a.assertion.trim()) {
2111
+ return this.executeAssertion(urlBeforeCommand, command.condition);
2242
2112
  }
2243
- case "NAVIGATE" /* NAVIGATE */:
2244
- yield this.browser.navigate(command.url);
2245
- break;
2246
- case "GO_BACK" /* GO_BACK */:
2247
- yield this.browser.goBack();
2248
- break;
2249
- case "GO_FORWARD" /* GO_FORWARD */:
2250
- yield this.browser.goForward();
2251
- break;
2252
- case "SCROLL_DOWN" /* SCROLL_DOWN */:
2253
- yield this.browser.scrollDown();
2254
- break;
2255
- case "SCROLL_UP" /* SCROLL_UP */:
2256
- yield this.browser.scrollUp();
2257
- break;
2258
- case "WAIT" /* WAIT */:
2259
- yield this.browser.wait(command.delay * 1e3);
2260
- break;
2261
- case "REFRESH" /* REFRESH */:
2262
- yield this.browser.refresh();
2263
- break;
2264
- case "CLICK" /* CLICK */: {
2265
- let id;
2266
- if (command.target.a11yData) {
2267
- id = (_b = command.target.a11yData) == null ? void 0 : _b.id;
2268
- } else {
2269
- const locator = yield this.locateElement(
2270
- command.target.elementDescriptor,
2271
- disableCache
2272
- );
2273
- id = locator.id;
2274
- }
2275
- const elementInteracted = yield this.browser.click(
2276
- {
2277
- id
2278
- },
2279
- {
2280
- doubleClick: command.doubleClick,
2281
- rightClick: command.rightClick
2282
- }
2113
+ return {
2114
+ succeedImmediately: false,
2115
+ urlAfterCommand: this.browser.url
2116
+ };
2117
+ case "AI_ASSERTION" /* AI_ASSERTION */: {
2118
+ return this.executeAssertion(urlBeforeCommand, command);
2119
+ }
2120
+ case "NAVIGATE" /* NAVIGATE */:
2121
+ await this.browser.navigate(command.url);
2122
+ break;
2123
+ case "GO_BACK" /* GO_BACK */:
2124
+ await this.browser.goBack();
2125
+ break;
2126
+ case "GO_FORWARD" /* GO_FORWARD */:
2127
+ await this.browser.goForward();
2128
+ break;
2129
+ case "SCROLL_DOWN" /* SCROLL_DOWN */:
2130
+ await this.browser.scrollDown();
2131
+ break;
2132
+ case "SCROLL_UP" /* SCROLL_UP */:
2133
+ await this.browser.scrollUp();
2134
+ break;
2135
+ case "WAIT" /* WAIT */:
2136
+ await this.browser.wait(command.delay * 1e3);
2137
+ break;
2138
+ case "REFRESH" /* REFRESH */:
2139
+ await this.browser.refresh();
2140
+ break;
2141
+ case "CLICK" /* CLICK */: {
2142
+ let id;
2143
+ if (command.target.a11yData) {
2144
+ id = (_b = command.target.a11yData) == null ? void 0 : _b.id;
2145
+ } else {
2146
+ const locator = await this.locateElement(
2147
+ command.target.elementDescriptor,
2148
+ disableCache
2283
2149
  );
2284
- const result2 = {
2285
- urlAfterCommand: this.browser.url,
2286
- succeedImmediately: false,
2287
- elementInteracted
2288
- };
2289
- if (urlChanged(urlBeforeCommand, result2.urlAfterCommand)) {
2290
- result2.succeedImmediately = true;
2291
- result2.succeedImmediatelyReason = "URL changed";
2292
- }
2293
- return result2;
2150
+ id = locator.id;
2294
2151
  }
2295
- case "SELECT_OPTION" /* SELECT_OPTION */: {
2296
- let id;
2297
- if (command.target.a11yData) {
2298
- id = (_c = command.target.a11yData) == null ? void 0 : _c.id;
2299
- } else {
2300
- const locator = yield this.locateElement(
2301
- command.target.elementDescriptor,
2302
- disableCache
2303
- );
2304
- id = locator.id;
2152
+ const elementInteracted = await this.browser.click(
2153
+ {
2154
+ id
2155
+ },
2156
+ {
2157
+ doubleClick: command.doubleClick,
2158
+ rightClick: command.rightClick
2305
2159
  }
2306
- const elementInteracted = yield this.browser.selectOption(
2307
- {
2308
- id
2309
- },
2310
- command.option
2160
+ );
2161
+ const result2 = {
2162
+ urlAfterCommand: this.browser.url,
2163
+ succeedImmediately: false,
2164
+ elementInteracted
2165
+ };
2166
+ if (urlChanged(urlBeforeCommand, result2.urlAfterCommand)) {
2167
+ result2.succeedImmediately = true;
2168
+ result2.succeedImmediatelyReason = "URL changed";
2169
+ }
2170
+ return result2;
2171
+ }
2172
+ case "SELECT_OPTION" /* SELECT_OPTION */: {
2173
+ let id;
2174
+ if (command.target.a11yData) {
2175
+ id = (_c = command.target.a11yData) == null ? void 0 : _c.id;
2176
+ } else {
2177
+ const locator = await this.locateElement(
2178
+ command.target.elementDescriptor,
2179
+ disableCache
2311
2180
  );
2312
- return {
2313
- succeedImmediately: false,
2314
- urlAfterCommand: this.browser.url,
2315
- elementInteracted
2316
- };
2181
+ id = locator.id;
2317
2182
  }
2318
- case "TAB" /* TAB */:
2319
- yield this.browser.switchToPage(command.url);
2320
- break;
2321
- case "COOKIE" /* COOKIE */:
2322
- yield this.browser.setCookie(command.value);
2323
- break;
2324
- case "TYPE" /* TYPE */: {
2325
- let elementInteracted;
2326
- const target = command.target;
2327
- if (target.a11yData) {
2328
- elementInteracted = yield this.browser.click({
2329
- id: target.a11yData.id
2330
- });
2331
- } else if (target.elementDescriptor.length > 0) {
2332
- const locator = yield this.locateElement(
2333
- command.target.elementDescriptor,
2334
- disableCache
2335
- );
2336
- elementInteracted = yield this.browser.click({
2337
- id: locator.id
2338
- });
2339
- }
2340
- yield this.browser.type(command.value, {
2341
- clearContent: command.clearContent,
2342
- pressKeysSequentially: command.pressKeysSequentially
2183
+ const elementInteracted = await this.browser.selectOption(
2184
+ {
2185
+ id
2186
+ },
2187
+ command.option
2188
+ );
2189
+ return {
2190
+ succeedImmediately: false,
2191
+ urlAfterCommand: this.browser.url,
2192
+ elementInteracted
2193
+ };
2194
+ }
2195
+ case "TAB" /* TAB */:
2196
+ await this.browser.switchToPage(command.url);
2197
+ break;
2198
+ case "COOKIE" /* COOKIE */:
2199
+ await this.browser.setCookie(command.value);
2200
+ break;
2201
+ case "TYPE" /* TYPE */: {
2202
+ let elementInteracted;
2203
+ const target = command.target;
2204
+ if (target.a11yData) {
2205
+ elementInteracted = await this.browser.click({
2206
+ id: target.a11yData.id
2207
+ });
2208
+ } else if (target.elementDescriptor.length > 0) {
2209
+ const locator = await this.locateElement(
2210
+ command.target.elementDescriptor,
2211
+ disableCache
2212
+ );
2213
+ elementInteracted = await this.browser.click({
2214
+ id: locator.id
2343
2215
  });
2344
- if (command.pressEnter) {
2345
- yield this.browser.press("Enter");
2346
- }
2347
- const result2 = {
2348
- urlAfterCommand: this.browser.url,
2349
- succeedImmediately: false,
2350
- elementInteracted
2351
- };
2352
- if (urlChanged(urlBeforeCommand, result2.urlAfterCommand)) {
2353
- result2.succeedImmediately = true;
2354
- result2.succeedImmediatelyReason = "URL changed";
2355
- }
2356
- return result2;
2357
2216
  }
2358
- case "PRESS" /* PRESS */:
2359
- yield this.browser.press(command.value);
2360
- const result = {
2361
- urlAfterCommand: this.browser.url,
2362
- succeedImmediately: false
2363
- };
2364
- if (urlChanged(urlBeforeCommand, result.urlAfterCommand)) {
2365
- result.succeedImmediately = true;
2366
- result.succeedImmediatelyReason = "URL changed";
2367
- }
2368
- return result;
2369
- default:
2370
- const assertUnreachable = (_x) => {
2371
- throw "If Typescript complains about the line below, you missed a case or break in the switch above";
2372
- };
2373
- return assertUnreachable(command);
2217
+ await this.browser.type(command.value, {
2218
+ clearContent: command.clearContent,
2219
+ pressKeysSequentially: command.pressKeysSequentially
2220
+ });
2221
+ if (command.pressEnter) {
2222
+ await this.browser.press("Enter");
2223
+ }
2224
+ const result2 = {
2225
+ urlAfterCommand: this.browser.url,
2226
+ succeedImmediately: false,
2227
+ elementInteracted
2228
+ };
2229
+ if (urlChanged(urlBeforeCommand, result2.urlAfterCommand)) {
2230
+ result2.succeedImmediately = true;
2231
+ result2.succeedImmediatelyReason = "URL changed";
2232
+ }
2233
+ return result2;
2374
2234
  }
2375
- return {
2376
- succeedImmediately: false,
2377
- urlAfterCommand: this.browser.url
2378
- };
2379
- });
2235
+ case "PRESS" /* PRESS */:
2236
+ await this.browser.press(command.value);
2237
+ const result = {
2238
+ urlAfterCommand: this.browser.url,
2239
+ succeedImmediately: false
2240
+ };
2241
+ if (urlChanged(urlBeforeCommand, result.urlAfterCommand)) {
2242
+ result.succeedImmediately = true;
2243
+ result.succeedImmediatelyReason = "URL changed";
2244
+ }
2245
+ return result;
2246
+ default:
2247
+ const assertUnreachable = (_x) => {
2248
+ throw "If Typescript complains about the line below, you missed a case or break in the switch above";
2249
+ };
2250
+ return assertUnreachable(command);
2251
+ }
2252
+ return {
2253
+ succeedImmediately: false,
2254
+ urlAfterCommand: this.browser.url
2255
+ };
2380
2256
  }
2381
2257
  };
2382
2258
 
2383
2259
  // ../../packages/web-agent/src/generators/api-generator.ts
2384
- var import_fetch_retry = __toESM(require("fetch-retry"), 1);
2385
- var fetch2 = (0, import_fetch_retry.default)(global.fetch);
2260
+ import fetchRetry from "fetch-retry";
2261
+ var fetch2 = fetchRetry(global.fetch);
2386
2262
  var API_VERSION = "v1";
2387
2263
  var APIGenerator = class {
2264
+ baseURL;
2265
+ apiKey;
2388
2266
  constructor(params) {
2389
2267
  this.baseURL = params.baseURL;
2390
2268
  this.apiKey = params.apiKey;
2391
2269
  }
2392
- getElementLocation(context, disableCache) {
2393
- return __async(this, null, function* () {
2394
- const result = yield this.sendRequest(
2395
- `/${API_VERSION}/web-agent/locate-element`,
2396
- {
2397
- browserState: context.browserState,
2398
- goal: context.goal,
2399
- disableCache
2400
- }
2401
- );
2402
- return LocateResponseSchema.parse(result);
2403
- });
2404
- }
2405
- getAssertionResult(context, useVision, disableCache) {
2406
- return __async(this, null, function* () {
2407
- var _a;
2408
- if (useVision) {
2409
- const result2 = yield this.sendRequest(
2410
- `/${API_VERSION}/web-agent/assertion`,
2411
- {
2412
- url: context.url,
2413
- goal: context.goal,
2414
- screenshot: (_a = context.screenshot) == null ? void 0 : _a.toString("base64"),
2415
- disableCache,
2416
- vision: true
2417
- }
2418
- );
2419
- return GetAssertionResponseSchema.parse(result2);
2270
+ async getElementLocation(context, disableCache) {
2271
+ const result = await this.sendRequest(
2272
+ `/${API_VERSION}/web-agent/locate-element`,
2273
+ {
2274
+ browserState: context.browserState,
2275
+ goal: context.goal,
2276
+ disableCache
2420
2277
  }
2421
- const result = yield this.sendRequest(
2278
+ );
2279
+ return LocateResponseSchema.parse(result);
2280
+ }
2281
+ async getAssertionResult(context, useVision, disableCache) {
2282
+ var _a;
2283
+ if (useVision) {
2284
+ const result2 = await this.sendRequest(
2422
2285
  `/${API_VERSION}/web-agent/assertion`,
2423
2286
  {
2424
2287
  url: context.url,
2425
- browserState: context.browserState,
2426
2288
  goal: context.goal,
2427
- history: context.history,
2428
- numPrevious: context.numPrevious,
2429
- lastCommand: context.lastCommand,
2289
+ screenshot: (_a = context.screenshot) == null ? void 0 : _a.toString("base64"),
2430
2290
  disableCache,
2431
- vision: false
2432
- }
2433
- );
2434
- return GetAssertionResponseSchema.parse(result);
2435
- });
2436
- }
2437
- getProposedCommand(context, disableCache) {
2438
- return __async(this, null, function* () {
2439
- const result = yield this.sendRequest(
2440
- `/${API_VERSION}/web-agent/next-command`,
2441
- {
2442
- url: context.url,
2443
- browserState: context.browserState,
2444
- goal: context.goal,
2445
- history: context.history,
2446
- numPrevious: context.numPrevious,
2447
- lastCommand: context.lastCommand,
2448
- disableCache
2449
- }
2450
- );
2451
- return GetNextCommandResponseSchema.parse(result);
2452
- });
2453
- }
2454
- getGranularGoals(context, disableCache) {
2455
- return __async(this, null, function* () {
2456
- const result = yield this.sendRequest(
2457
- `/${API_VERSION}/web-agent/split-goal`,
2458
- {
2459
- url: context.url,
2460
- goal: context.goal,
2461
- disableCache
2291
+ vision: true
2462
2292
  }
2463
2293
  );
2464
- return SplitGoalResponseSchema.parse(result);
2465
- });
2466
- }
2467
- sendRequest(path, body) {
2468
- return __async(this, null, function* () {
2469
- const response = yield fetch2(`${this.baseURL}${path}`, {
2470
- retries: 3,
2471
- retryDelay: 1e3,
2472
- method: "POST",
2473
- body: JSON.stringify(body),
2474
- headers: {
2475
- "Content-Type": "application/json",
2476
- Authorization: `Bearer ${this.apiKey}`
2477
- }
2478
- });
2479
- if (!response.ok) {
2480
- throw new Error(
2481
- `Request to ${path} failed with status ${response.status}: ${yield response.text()}`
2482
- );
2294
+ return GetAssertionResponseSchema.parse(result2);
2295
+ }
2296
+ const result = await this.sendRequest(
2297
+ `/${API_VERSION}/web-agent/assertion`,
2298
+ {
2299
+ url: context.url,
2300
+ browserState: context.browserState,
2301
+ goal: context.goal,
2302
+ history: context.history,
2303
+ numPrevious: context.numPrevious,
2304
+ lastCommand: context.lastCommand,
2305
+ disableCache,
2306
+ vision: false
2307
+ }
2308
+ );
2309
+ return GetAssertionResponseSchema.parse(result);
2310
+ }
2311
+ async getProposedCommand(context, disableCache) {
2312
+ const result = await this.sendRequest(
2313
+ `/${API_VERSION}/web-agent/next-command`,
2314
+ {
2315
+ url: context.url,
2316
+ browserState: context.browserState,
2317
+ goal: context.goal,
2318
+ history: context.history,
2319
+ numPrevious: context.numPrevious,
2320
+ lastCommand: context.lastCommand,
2321
+ disableCache
2322
+ }
2323
+ );
2324
+ return GetNextCommandResponseSchema.parse(result);
2325
+ }
2326
+ async getGranularGoals(context, disableCache) {
2327
+ const result = await this.sendRequest(
2328
+ `/${API_VERSION}/web-agent/split-goal`,
2329
+ {
2330
+ url: context.url,
2331
+ goal: context.goal,
2332
+ disableCache
2333
+ }
2334
+ );
2335
+ return SplitGoalResponseSchema.parse(result);
2336
+ }
2337
+ async sendRequest(path, body) {
2338
+ const response = await fetch2(`${this.baseURL}${path}`, {
2339
+ retries: 3,
2340
+ retryDelay: 1e3,
2341
+ method: "POST",
2342
+ body: JSON.stringify(body),
2343
+ headers: {
2344
+ "Content-Type": "application/json",
2345
+ Authorization: `Bearer ${this.apiKey}`
2483
2346
  }
2484
- return response.json();
2485
2347
  });
2348
+ if (!response.ok) {
2349
+ throw new Error(
2350
+ `Request to ${path} failed with status ${response.status}: ${await response.text()}`
2351
+ );
2352
+ }
2353
+ return response.json();
2486
2354
  }
2487
2355
  };
2488
2356
 
@@ -2492,72 +2360,62 @@ var version = "1.0.0";
2492
2360
  // src/api-client.ts
2493
2361
  var API_VERSION2 = "v1";
2494
2362
  var APIClient = class {
2363
+ baseURL;
2364
+ apiKey;
2495
2365
  constructor(params) {
2496
2366
  this.baseURL = params.baseURL;
2497
2367
  this.apiKey = params.apiKey;
2498
2368
  }
2499
- getRun(runId) {
2500
- return __async(this, null, function* () {
2501
- const result = yield this.sendRequest(`/${API_VERSION2}/runs/${runId}`, {
2502
- method: "GET"
2503
- });
2504
- return GetRunResponseSchema.parse(result);
2369
+ async getRun(runId) {
2370
+ const result = await this.sendRequest(`/${API_VERSION2}/runs/${runId}`, {
2371
+ method: "GET"
2505
2372
  });
2373
+ return GetRunResponseSchema.parse(result);
2506
2374
  }
2507
- createRun(body) {
2508
- return __async(this, null, function* () {
2509
- const result = yield this.sendRequest(`/${API_VERSION2}/runs`, {
2510
- method: "POST",
2511
- body
2512
- });
2513
- return CreateRunResponseSchema.parse(result);
2375
+ async createRun(body) {
2376
+ const result = await this.sendRequest(`/${API_VERSION2}/runs`, {
2377
+ method: "POST",
2378
+ body
2514
2379
  });
2380
+ return CreateRunResponseSchema.parse(result);
2515
2381
  }
2516
- updateRun(runId, body) {
2517
- return __async(this, null, function* () {
2518
- yield this.sendRequest(`/${API_VERSION2}/runs/${runId}`, {
2519
- method: "PATCH",
2520
- body
2521
- });
2382
+ async updateRun(runId, body) {
2383
+ await this.sendRequest(`/${API_VERSION2}/runs/${runId}`, {
2384
+ method: "PATCH",
2385
+ body
2522
2386
  });
2523
2387
  }
2524
- getTest(testId) {
2525
- return __async(this, null, function* () {
2526
- const result = yield this.sendRequest(`/${API_VERSION2}/tests/${testId}`, {
2527
- method: "GET"
2528
- });
2529
- return GetTestResponseSchema.parse(result);
2388
+ async getTest(testId) {
2389
+ const result = await this.sendRequest(`/${API_VERSION2}/tests/${testId}`, {
2390
+ method: "GET"
2530
2391
  });
2392
+ return GetTestResponseSchema.parse(result);
2531
2393
  }
2532
- uploadScreenshot(body) {
2533
- return __async(this, null, function* () {
2534
- const result = yield this.sendRequest(`/${API_VERSION2}/screenshots`, {
2535
- method: "POST",
2536
- body
2537
- });
2538
- return CreateScreenshotResponseSchema.parse(result);
2394
+ async uploadScreenshot(body) {
2395
+ const result = await this.sendRequest(`/${API_VERSION2}/screenshots`, {
2396
+ method: "POST",
2397
+ body
2539
2398
  });
2399
+ return CreateScreenshotResponseSchema.parse(result);
2540
2400
  }
2541
- sendRequest(path, options) {
2542
- return __async(this, null, function* () {
2543
- const response = yield fetch(`${this.baseURL}${path}`, {
2544
- method: options.method,
2545
- body: options.body ? JSON.stringify(options.body) : void 0,
2546
- headers: {
2547
- "Content-Type": "application/json",
2548
- Authorization: `Bearer ${this.apiKey}`
2549
- }
2550
- });
2551
- if (!response.ok) {
2552
- throw new Error(
2553
- `Request to ${path} failed with status ${response.status}: ${yield response.text()}`
2554
- );
2555
- }
2556
- if (response.status === 204) {
2557
- return response.text();
2401
+ async sendRequest(path, options) {
2402
+ const response = await fetch(`${this.baseURL}${path}`, {
2403
+ method: options.method,
2404
+ body: options.body ? JSON.stringify(options.body) : void 0,
2405
+ headers: {
2406
+ "Content-Type": "application/json",
2407
+ Authorization: `Bearer ${this.apiKey}`
2558
2408
  }
2559
- return response.json();
2560
2409
  });
2410
+ if (!response.ok) {
2411
+ throw new Error(
2412
+ `Request to ${path} failed with status ${response.status}: ${await response.text()}`
2413
+ );
2414
+ }
2415
+ if (response.status === 204) {
2416
+ return response.text();
2417
+ }
2418
+ return response.json();
2561
2419
  }
2562
2420
  };
2563
2421
 
@@ -2565,29 +2423,25 @@ var APIClient = class {
2565
2423
  var MAX_COMMANDS_PER_STEP = 20;
2566
2424
 
2567
2425
  // ../../packages/execute/src/steps/ai.ts
2568
- var executeAIStep = (_a) => __async(void 0, null, function* () {
2569
- var _b = _a, {
2570
- controller,
2571
- step,
2572
- logger,
2573
- advanced
2574
- } = _b, callbacks = __objRest(_b, [
2575
- "controller",
2576
- "step",
2577
- "logger",
2578
- "advanced"
2579
- ]);
2580
- var _a2, _b2, _c, _d, _e, _f, _g;
2581
- (_a2 = callbacks.onStarted) == null ? void 0 : _a2.call(callbacks);
2426
+ var executeAIStep = async ({
2427
+ controller,
2428
+ step,
2429
+ logger,
2430
+ advanced,
2431
+ ...callbacks
2432
+ }) => {
2433
+ var _a, _b, _c, _d, _e, _f;
2434
+ (_a = callbacks.onStarted) == null ? void 0 : _a.call(callbacks);
2582
2435
  controller.resetHistory();
2583
- const result = __spreadProps(__spreadValues({}, step), {
2436
+ const result = {
2437
+ ...step,
2584
2438
  startedAt: /* @__PURE__ */ new Date(),
2585
2439
  userAgent: ChromeBrowser.USER_AGENT,
2586
2440
  // placeholder values
2587
2441
  finishedAt: /* @__PURE__ */ new Date(),
2588
2442
  results: [],
2589
2443
  status: "SUCCESS" /* SUCCESS */
2590
- });
2444
+ };
2591
2445
  try {
2592
2446
  let commandIndex = 0;
2593
2447
  let useSavedCommands = step.commands && step.commands.length > 0;
@@ -2599,8 +2453,8 @@ var executeAIStep = (_a) => __async(void 0, null, function* () {
2599
2453
  }
2600
2454
  let command;
2601
2455
  const startedAt = /* @__PURE__ */ new Date();
2602
- const beforeScreenshotBuffer = yield controller.browser.screenshot();
2603
- const beforeScreenshot = yield callbacks.onSaveScreenshot(
2456
+ const beforeScreenshotBuffer = await controller.browser.screenshot();
2457
+ const beforeScreenshot = await callbacks.onSaveScreenshot(
2604
2458
  beforeScreenshotBuffer
2605
2459
  );
2606
2460
  if (useSavedCommands) {
@@ -2611,7 +2465,7 @@ var executeAIStep = (_a) => __async(void 0, null, function* () {
2611
2465
  );
2612
2466
  }
2613
2467
  } else {
2614
- command = yield controller.promptToCommand(
2468
+ command = await controller.promptToCommand(
2615
2469
  step.type,
2616
2470
  step.text,
2617
2471
  advanced.disableAICaching
@@ -2623,7 +2477,7 @@ var executeAIStep = (_a) => __async(void 0, null, function* () {
2623
2477
  result.message = command.thoughts;
2624
2478
  break;
2625
2479
  }
2626
- (_b2 = callbacks.onCommandGenerated) == null ? void 0 : _b2.call(callbacks, {
2480
+ (_b = callbacks.onCommandGenerated) == null ? void 0 : _b.call(callbacks, {
2627
2481
  commandIndex,
2628
2482
  message: CARD_DISPLAY_NAMES[command.type] || `Unknown command (${command.type})`
2629
2483
  });
@@ -2640,7 +2494,7 @@ var executeAIStep = (_a) => __async(void 0, null, function* () {
2640
2494
  `Executing command ${commandIndex}: ${serializeCommand(command)}`
2641
2495
  );
2642
2496
  try {
2643
- const executionResult = yield controller.executeCommand(
2497
+ const executionResult = await controller.executeCommand(
2644
2498
  command,
2645
2499
  advanced.disableAICaching,
2646
2500
  useSavedCommands
@@ -2651,8 +2505,8 @@ var executeAIStep = (_a) => __async(void 0, null, function* () {
2651
2505
  message: serializeCommand(command),
2652
2506
  command
2653
2507
  });
2654
- const afterScreenshotBuffer = yield controller.browser.screenshot();
2655
- const afterScreenshot = yield callbacks.onSaveScreenshot(
2508
+ const afterScreenshotBuffer = await controller.browser.screenshot();
2509
+ const afterScreenshot = await callbacks.onSaveScreenshot(
2656
2510
  afterScreenshotBuffer
2657
2511
  );
2658
2512
  cmdResult.afterScreenshot = afterScreenshot;
@@ -2670,7 +2524,7 @@ var executeAIStep = (_a) => __async(void 0, null, function* () {
2670
2524
  if (command.type === "SUCCESS" /* SUCCESS */) {
2671
2525
  result.finishedAt = /* @__PURE__ */ new Date();
2672
2526
  result.status = "SUCCESS" /* SUCCESS */;
2673
- result.message = (_d = executionResult.thoughts) != null ? _d : "All commands completed.";
2527
+ result.message = executionResult.thoughts ?? "All commands completed.";
2674
2528
  break;
2675
2529
  }
2676
2530
  if (executionResult.succeedImmediately && !useSavedCommands) {
@@ -2680,14 +2534,15 @@ var executeAIStep = (_a) => __async(void 0, null, function* () {
2680
2534
  command = {
2681
2535
  type: "SUCCESS" /* SUCCESS */
2682
2536
  };
2683
- (_e = callbacks.onCommandExecuted) == null ? void 0 : _e.call(callbacks, {
2537
+ (_d = callbacks.onCommandExecuted) == null ? void 0 : _d.call(callbacks, {
2684
2538
  commandIndex: commandIndex + 1,
2685
2539
  message: serializeCommand(command),
2686
2540
  command
2687
2541
  });
2688
- result.results.push(__spreadProps(__spreadValues({}, presetActionResult), {
2542
+ result.results.push({
2543
+ ...presetActionResult,
2689
2544
  command
2690
- }));
2545
+ });
2691
2546
  break;
2692
2547
  }
2693
2548
  } catch (err) {
@@ -2724,57 +2579,54 @@ var executeAIStep = (_a) => __async(void 0, null, function* () {
2724
2579
  result.status = "FAILED" /* FAILED */;
2725
2580
  }
2726
2581
  if (result.status === "SUCCESS" /* SUCCESS */) {
2727
- (_f = callbacks.onSuccess) == null ? void 0 : _f.call(callbacks, {
2582
+ (_e = callbacks.onSuccess) == null ? void 0 : _e.call(callbacks, {
2728
2583
  message: result.message || "AI step succeeded.",
2729
2584
  startedAt: result.startedAt.getTime(),
2730
2585
  durationMs: result.finishedAt.getTime() - result.startedAt.getTime()
2731
2586
  });
2732
2587
  } else {
2733
- (_g = callbacks.onFailure) == null ? void 0 : _g.call(callbacks, {
2588
+ (_f = callbacks.onFailure) == null ? void 0 : _f.call(callbacks, {
2734
2589
  message: result.message || "AI step errored.",
2735
2590
  startedAt: result.startedAt.getTime(),
2736
2591
  durationMs: result.finishedAt.getTime() - result.startedAt.getTime()
2737
2592
  });
2738
2593
  }
2739
2594
  return result;
2740
- });
2595
+ };
2741
2596
 
2742
2597
  // ../../packages/execute/src/steps/preset.ts
2743
- var executePresetStep = (_a) => __async(void 0, null, function* () {
2744
- var _b = _a, {
2745
- controller,
2746
- step,
2747
- advanced
2748
- } = _b, callbacks = __objRest(_b, [
2749
- "controller",
2750
- "step",
2751
- "advanced"
2752
- ]);
2753
- var _a2, _b2, _c;
2754
- (_a2 = callbacks.onStarted) == null ? void 0 : _a2.call(callbacks);
2598
+ var executePresetStep = async ({
2599
+ controller,
2600
+ step,
2601
+ advanced,
2602
+ ...callbacks
2603
+ }) => {
2604
+ var _a, _b, _c;
2605
+ (_a = callbacks.onStarted) == null ? void 0 : _a.call(callbacks);
2755
2606
  const startedAt = /* @__PURE__ */ new Date();
2756
2607
  const beforeUrl = controller.browser.url;
2757
- const beforeScreenshotBuffer = yield controller.browser.screenshot();
2758
- const beforeScreenshot = yield callbacks.onSaveScreenshot(
2608
+ const beforeScreenshotBuffer = await controller.browser.screenshot();
2609
+ const beforeScreenshot = await callbacks.onSaveScreenshot(
2759
2610
  beforeScreenshotBuffer
2760
2611
  );
2761
2612
  try {
2762
- const execResult = yield controller.executePresetStep(
2613
+ const execResult = await controller.executePresetStep(
2763
2614
  step.command,
2764
2615
  advanced.disableAICaching
2765
2616
  );
2766
- const afterScreenshotBuffer = yield controller.browser.screenshot();
2767
- const afterScreenshot = yield callbacks.onSaveScreenshot(
2617
+ const afterScreenshotBuffer = await controller.browser.screenshot();
2618
+ const afterScreenshot = await callbacks.onSaveScreenshot(
2768
2619
  afterScreenshotBuffer
2769
2620
  );
2770
2621
  const finishedAt = /* @__PURE__ */ new Date();
2771
- const result = __spreadProps(__spreadValues({}, step), {
2622
+ const result = {
2623
+ ...step,
2772
2624
  startedAt,
2773
2625
  finishedAt,
2774
2626
  // placeholder values
2775
2627
  status: "SUCCESS" /* SUCCESS */,
2776
2628
  results: []
2777
- });
2629
+ };
2778
2630
  let message = "Successfully executed preset action.";
2779
2631
  if (step.command.type === "AI_ASSERTION" /* AI_ASSERTION */) {
2780
2632
  message = execResult.thoughts || "Assertion passed.";
@@ -2792,7 +2644,7 @@ var executePresetStep = (_a) => __async(void 0, null, function* () {
2792
2644
  result.status = "SUCCESS" /* SUCCESS */;
2793
2645
  result.results = [cmdMetadata];
2794
2646
  result.message = message;
2795
- (_b2 = callbacks.onSuccess) == null ? void 0 : _b2.call(callbacks, {
2647
+ (_b = callbacks.onSuccess) == null ? void 0 : _b.call(callbacks, {
2796
2648
  message,
2797
2649
  startedAt: startedAt.getTime(),
2798
2650
  durationMs: finishedAt.getTime() - startedAt.getTime()
@@ -2800,7 +2652,8 @@ var executePresetStep = (_a) => __async(void 0, null, function* () {
2800
2652
  return result;
2801
2653
  } catch (err) {
2802
2654
  const finishedAt = /* @__PURE__ */ new Date();
2803
- const result = __spreadProps(__spreadValues({}, step), {
2655
+ const result = {
2656
+ ...step,
2804
2657
  startedAt,
2805
2658
  finishedAt,
2806
2659
  status: "FAILED" /* FAILED */,
@@ -2818,7 +2671,7 @@ var executePresetStep = (_a) => __async(void 0, null, function* () {
2818
2671
  message: `${err}`
2819
2672
  }
2820
2673
  ]
2821
- });
2674
+ };
2822
2675
  (_c = callbacks.onFailure) == null ? void 0 : _c.call(callbacks, {
2823
2676
  message: `${err}`,
2824
2677
  startedAt: startedAt.getTime(),
@@ -2826,23 +2679,18 @@ var executePresetStep = (_a) => __async(void 0, null, function* () {
2826
2679
  });
2827
2680
  return result;
2828
2681
  }
2829
- });
2682
+ };
2830
2683
 
2831
2684
  // ../../packages/execute/src/steps/module.ts
2832
- var executeModuleStep = (_a) => __async(void 0, null, function* () {
2833
- var _b = _a, {
2834
- controller,
2835
- step,
2836
- advanced,
2837
- logger
2838
- } = _b, callbacks = __objRest(_b, [
2839
- "controller",
2840
- "step",
2841
- "advanced",
2842
- "logger"
2843
- ]);
2844
- var _a2, _b2, _c;
2845
- (_a2 = callbacks.onStarted) == null ? void 0 : _a2.call(callbacks);
2685
+ var executeModuleStep = async ({
2686
+ controller,
2687
+ step,
2688
+ advanced,
2689
+ logger,
2690
+ ...callbacks
2691
+ }) => {
2692
+ var _a, _b, _c;
2693
+ (_a = callbacks.onStarted) == null ? void 0 : _a.call(callbacks);
2846
2694
  const result = {
2847
2695
  type: "MODULE" /* MODULE */,
2848
2696
  moduleId: step.moduleId,
@@ -2859,19 +2707,19 @@ var executeModuleStep = (_a) => __async(void 0, null, function* () {
2859
2707
  let moduleStepResult;
2860
2708
  switch (moduleStep.type) {
2861
2709
  case "PRESET_ACTION" /* PRESET_ACTION */:
2862
- moduleStepResult = yield executePresetStep({
2710
+ moduleStepResult = await executePresetStep({
2863
2711
  controller,
2864
2712
  step: moduleStep,
2865
2713
  advanced,
2866
2714
  logger,
2867
2715
  onSaveScreenshot: callbacks.onSaveScreenshot,
2868
2716
  onStarted() {
2869
- var _a3;
2870
- (_a3 = callbacks.onStepStarted) == null ? void 0 : _a3.call(callbacks, { index: i });
2717
+ var _a2;
2718
+ (_a2 = callbacks.onStepStarted) == null ? void 0 : _a2.call(callbacks, { index: i });
2871
2719
  },
2872
2720
  onSuccess({ message, startedAt, durationMs }) {
2873
- var _a3;
2874
- (_a3 = callbacks.onStepSuccess) == null ? void 0 : _a3.call(callbacks, {
2721
+ var _a2;
2722
+ (_a2 = callbacks.onStepSuccess) == null ? void 0 : _a2.call(callbacks, {
2875
2723
  index: i,
2876
2724
  message,
2877
2725
  startedAt,
@@ -2879,8 +2727,8 @@ var executeModuleStep = (_a) => __async(void 0, null, function* () {
2879
2727
  });
2880
2728
  },
2881
2729
  onFailure({ message, startedAt, durationMs }) {
2882
- var _a3;
2883
- (_a3 = callbacks.onStepFailure) == null ? void 0 : _a3.call(callbacks, {
2730
+ var _a2;
2731
+ (_a2 = callbacks.onStepFailure) == null ? void 0 : _a2.call(callbacks, {
2884
2732
  index: i,
2885
2733
  message,
2886
2734
  startedAt,
@@ -2890,19 +2738,19 @@ var executeModuleStep = (_a) => __async(void 0, null, function* () {
2890
2738
  });
2891
2739
  break;
2892
2740
  case "AI_ACTION" /* AI_ACTION */:
2893
- moduleStepResult = yield executeAIStep({
2741
+ moduleStepResult = await executeAIStep({
2894
2742
  controller,
2895
2743
  step: moduleStep,
2896
2744
  advanced,
2897
2745
  logger,
2898
2746
  onSaveScreenshot: callbacks.onSaveScreenshot,
2899
2747
  onStarted() {
2900
- var _a3;
2901
- (_a3 = callbacks.onStepStarted) == null ? void 0 : _a3.call(callbacks, { index: i });
2748
+ var _a2;
2749
+ (_a2 = callbacks.onStepStarted) == null ? void 0 : _a2.call(callbacks, { index: i });
2902
2750
  },
2903
2751
  onSuccess({ message, startedAt, durationMs }) {
2904
- var _a3;
2905
- (_a3 = callbacks.onStepSuccess) == null ? void 0 : _a3.call(callbacks, {
2752
+ var _a2;
2753
+ (_a2 = callbacks.onStepSuccess) == null ? void 0 : _a2.call(callbacks, {
2906
2754
  index: i,
2907
2755
  message,
2908
2756
  startedAt,
@@ -2910,8 +2758,8 @@ var executeModuleStep = (_a) => __async(void 0, null, function* () {
2910
2758
  });
2911
2759
  },
2912
2760
  onFailure({ message, startedAt, durationMs }) {
2913
- var _a3;
2914
- (_a3 = callbacks.onStepFailure) == null ? void 0 : _a3.call(callbacks, {
2761
+ var _a2;
2762
+ (_a2 = callbacks.onStepFailure) == null ? void 0 : _a2.call(callbacks, {
2915
2763
  index: i,
2916
2764
  message,
2917
2765
  startedAt,
@@ -2919,12 +2767,12 @@ var executeModuleStep = (_a) => __async(void 0, null, function* () {
2919
2767
  });
2920
2768
  },
2921
2769
  onCommandGenerated({ commandIndex, message }) {
2922
- var _a3;
2923
- (_a3 = callbacks.onCommandGenerated) == null ? void 0 : _a3.call(callbacks, { index: i, commandIndex, message });
2770
+ var _a2;
2771
+ (_a2 = callbacks.onCommandGenerated) == null ? void 0 : _a2.call(callbacks, { index: i, commandIndex, message });
2924
2772
  },
2925
2773
  onCommandExecuted({ commandIndex, message, command }) {
2926
- var _a3;
2927
- (_a3 = callbacks.onCommandExecuted) == null ? void 0 : _a3.call(callbacks, {
2774
+ var _a2;
2775
+ (_a2 = callbacks.onCommandExecuted) == null ? void 0 : _a2.call(callbacks, {
2928
2776
  index: i,
2929
2777
  commandIndex,
2930
2778
  message,
@@ -2945,21 +2793,22 @@ var executeModuleStep = (_a) => __async(void 0, null, function* () {
2945
2793
  result.finishedAt = /* @__PURE__ */ new Date();
2946
2794
  for (let j = i + 1; j < step.steps.length; j++) {
2947
2795
  const skippedStep = step.steps[j];
2948
- const skippedResult = __spreadProps(__spreadValues({}, skippedStep), {
2796
+ const skippedResult = {
2797
+ ...skippedStep,
2949
2798
  status: "CANCELLED" /* CANCELLED */,
2950
2799
  startedAt: /* @__PURE__ */ new Date(),
2951
2800
  finishedAt: /* @__PURE__ */ new Date(),
2952
2801
  userAgent: ChromeBrowser.USER_AGENT,
2953
2802
  results: [],
2954
2803
  message: "Cancelled due to previous failure."
2955
- });
2804
+ };
2956
2805
  result.results.push(skippedResult);
2957
2806
  }
2958
2807
  break;
2959
2808
  }
2960
2809
  }
2961
2810
  if (result.status === "SUCCESS" /* SUCCESS */) {
2962
- (_b2 = callbacks.onSuccess) == null ? void 0 : _b2.call(callbacks, {
2811
+ (_b = callbacks.onSuccess) == null ? void 0 : _b.call(callbacks, {
2963
2812
  message: "Executed module step.",
2964
2813
  startedAt: result.startedAt.getTime(),
2965
2814
  durationMs: result.finishedAt.getTime() - result.startedAt.getTime()
@@ -2972,20 +2821,20 @@ var executeModuleStep = (_a) => __async(void 0, null, function* () {
2972
2821
  });
2973
2822
  }
2974
2823
  return result;
2975
- });
2824
+ };
2976
2825
 
2977
2826
  // ../../packages/execute/src/test.ts
2978
- var executeTest = (_0) => __async(void 0, [_0], function* ({
2827
+ var executeTest = async ({
2979
2828
  test,
2980
2829
  runId,
2981
2830
  controller,
2982
2831
  logger,
2983
2832
  onUpdateRun,
2984
2833
  onSaveScreenshot
2985
- }) {
2834
+ }) => {
2986
2835
  const advanced = TestAdvancedSettingsSchema.parse(test.advanced);
2987
2836
  logger.info(`Starting run ${runId} for test ${test.id}`);
2988
- yield onUpdateRun({
2837
+ await onUpdateRun({
2989
2838
  status: "RUNNING",
2990
2839
  startedAt: /* @__PURE__ */ new Date()
2991
2840
  });
@@ -2996,7 +2845,7 @@ var executeTest = (_0) => __async(void 0, [_0], function* ({
2996
2845
  let result;
2997
2846
  switch (step.type) {
2998
2847
  case "PRESET_ACTION" /* PRESET_ACTION */:
2999
- result = yield executePresetStep({
2848
+ result = await executePresetStep({
3000
2849
  controller,
3001
2850
  step,
3002
2851
  advanced,
@@ -3005,7 +2854,7 @@ var executeTest = (_0) => __async(void 0, [_0], function* ({
3005
2854
  });
3006
2855
  break;
3007
2856
  case "AI_ACTION" /* AI_ACTION */:
3008
- result = yield executeAIStep({
2857
+ result = await executeAIStep({
3009
2858
  controller,
3010
2859
  step,
3011
2860
  advanced,
@@ -3014,7 +2863,7 @@ var executeTest = (_0) => __async(void 0, [_0], function* ({
3014
2863
  });
3015
2864
  break;
3016
2865
  case "RESOLVED_MODULE":
3017
- result = yield executeModuleStep({
2866
+ result = await executeModuleStep({
3018
2867
  controller,
3019
2868
  step,
3020
2869
  advanced,
@@ -3029,7 +2878,7 @@ var executeTest = (_0) => __async(void 0, [_0], function* ({
3029
2878
  return assertUnreachable(step);
3030
2879
  }
3031
2880
  results.push(result);
3032
- yield onUpdateRun({
2881
+ await onUpdateRun({
3033
2882
  results
3034
2883
  });
3035
2884
  if (result.status === "FAILED" /* FAILED */) {
@@ -3043,26 +2892,28 @@ var executeTest = (_0) => __async(void 0, [_0], function* ({
3043
2892
  startedAt: /* @__PURE__ */ new Date(),
3044
2893
  userAgent: ChromeBrowser.USER_AGENT,
3045
2894
  results: skippedStep.steps.map((s) => {
3046
- return __spreadProps(__spreadValues({}, s), {
2895
+ return {
2896
+ ...s,
3047
2897
  status: "CANCELLED" /* CANCELLED */,
3048
2898
  startedAt: /* @__PURE__ */ new Date(),
3049
2899
  finishedAt: /* @__PURE__ */ new Date(),
3050
2900
  userAgent: ChromeBrowser.USER_AGENT,
3051
2901
  results: []
3052
- });
2902
+ };
3053
2903
  }),
3054
2904
  finishedAt: /* @__PURE__ */ new Date(),
3055
2905
  status: "CANCELLED" /* CANCELLED */
3056
2906
  };
3057
2907
  results.push(skippedResult);
3058
2908
  } else {
3059
- const skippedResult = __spreadProps(__spreadValues({}, skippedStep), {
2909
+ const skippedResult = {
2910
+ ...skippedStep,
3060
2911
  status: "CANCELLED" /* CANCELLED */,
3061
2912
  startedAt: /* @__PURE__ */ new Date(),
3062
2913
  finishedAt: /* @__PURE__ */ new Date(),
3063
2914
  userAgent: ChromeBrowser.USER_AGENT,
3064
2915
  results: []
3065
- });
2916
+ };
3066
2917
  results.push(skippedResult);
3067
2918
  }
3068
2919
  }
@@ -3071,14 +2922,14 @@ var executeTest = (_0) => __async(void 0, [_0], function* ({
3071
2922
  break;
3072
2923
  }
3073
2924
  }
3074
- yield onUpdateRun({
2925
+ await onUpdateRun({
3075
2926
  status: failed ? "FAILED" : "PASSED",
3076
2927
  finishedAt: /* @__PURE__ */ new Date(),
3077
2928
  results
3078
2929
  });
3079
- yield controller.browser.cleanup();
2930
+ await controller.browser.cleanup();
3080
2931
  return failed;
3081
- });
2932
+ };
3082
2933
 
3083
2934
  // src/run-test.ts
3084
2935
  var consoleLogger = {
@@ -3090,79 +2941,77 @@ var consoleLogger = {
3090
2941
  flush: () => {
3091
2942
  }
3092
2943
  };
3093
- function runTest(_0) {
3094
- return __async(this, arguments, function* ({
3095
- testId,
3096
- apiClient,
3097
- generator
3098
- }) {
3099
- const test = yield apiClient.getTest(testId);
3100
- const browser = yield ChromeBrowser.init(test.baseUrl, consoleLogger);
3101
- const controller = new AgentController({
3102
- browser,
3103
- generator,
3104
- config: DEFAULT_CONTROLLER_CONFIG,
3105
- logger: consoleLogger
2944
+ async function runTest({
2945
+ testId,
2946
+ apiClient,
2947
+ generator
2948
+ }) {
2949
+ const test = await apiClient.getTest(testId);
2950
+ const browser = await ChromeBrowser.init(test.baseUrl, consoleLogger);
2951
+ const controller = new AgentController({
2952
+ browser,
2953
+ generator,
2954
+ config: DEFAULT_CONTROLLER_CONFIG,
2955
+ logger: consoleLogger
2956
+ });
2957
+ const run = await apiClient.createRun({
2958
+ testId
2959
+ });
2960
+ let failed = true;
2961
+ try {
2962
+ failed = await executeTest({
2963
+ test,
2964
+ runId: run.id,
2965
+ controller,
2966
+ logger: consoleLogger,
2967
+ onSaveScreenshot: async (buffer) => {
2968
+ const { key } = await apiClient.uploadScreenshot({
2969
+ screenshot: buffer.toString("base64")
2970
+ });
2971
+ return key;
2972
+ },
2973
+ onUpdateRun: async (data) => {
2974
+ await apiClient.updateRun(run.id, data);
2975
+ }
3106
2976
  });
3107
- const run = yield apiClient.createRun({
3108
- testId
2977
+ } catch (err) {
2978
+ await apiClient.updateRun(run.id, {
2979
+ status: "FAILED",
2980
+ finishedAt: /* @__PURE__ */ new Date()
3109
2981
  });
3110
- let failed = true;
3111
- try {
3112
- failed = yield executeTest({
3113
- test,
3114
- runId: run.id,
3115
- controller,
3116
- logger: consoleLogger,
3117
- onSaveScreenshot: (buffer) => __async(this, null, function* () {
3118
- const { key } = yield apiClient.uploadScreenshot({
3119
- screenshot: buffer.toString("base64")
3120
- });
3121
- return key;
3122
- }),
3123
- onUpdateRun: (data) => __async(this, null, function* () {
3124
- yield apiClient.updateRun(run.id, data);
3125
- })
3126
- });
3127
- } catch (err) {
3128
- yield apiClient.updateRun(run.id, {
3129
- status: "FAILED",
3130
- finishedAt: /* @__PURE__ */ new Date()
3131
- });
3132
- }
3133
- return failed;
3134
- });
2982
+ }
2983
+ return failed;
3135
2984
  }
3136
2985
 
3137
2986
  // src/cli.ts
3138
- var program = new import_commander.Command();
2987
+ var program = new Command4();
3139
2988
  program.name("momentic").description("Momentic CLI").version(version);
3140
2989
  program.command("run-tests").addOption(
3141
- new import_commander.Option(
2990
+ new Option(
3142
2991
  "--tests <tests...>",
3143
2992
  "specify tests to run"
3144
2993
  ).makeOptionMandatory(true)
3145
2994
  ).addOption(
3146
- new import_commander.Option(
2995
+ new Option(
3147
2996
  "--start <command>",
3148
2997
  "specify start command"
3149
2998
  ).makeOptionMandatory(true)
3150
2999
  ).addOption(
3151
- new import_commander.Option("--wait-on <url>", "specify url to wait on").makeOptionMandatory(
3000
+ new Option("--wait-on <url>", "specify url to wait on").makeOptionMandatory(
3152
3001
  true
3153
3002
  )
3154
3003
  ).addOption(
3155
- new import_commander.Option(
3004
+ new Option(
3156
3005
  "--wait-on-timeout <timeout>",
3157
3006
  "specify how long to wait on url"
3158
3007
  ).default(60, "one minute")
3159
3008
  ).addOption(
3160
- new import_commander.Option("--api-key <key>", "API key for authenticating").env("MOMENTIC_API_KEY").makeOptionMandatory(true)
3161
- ).action((options) => __async(exports, null, function* () {
3009
+ new Option("--api-key <key>", "API key for authenticating").env("MOMENTIC_API_KEY").makeOptionMandatory(true)
3010
+ ).action(async (options) => {
3162
3011
  const { tests, start, waitOn, waitOnTimeout, apiKey } = options;
3163
3012
  console.log({ tests, start, waitOn, waitOnTimeout, apiKey });
3164
- void (0, import_execa.execa)(start);
3165
- yield (0, import_wait_on.default)({
3013
+ void $`${start}`;
3014
+ await waitOnFn({
3166
3015
  resources: [waitOn],
3167
3016
  timeout: waitOnTimeout * 1e3
3168
3017
  });
@@ -3182,24 +3031,22 @@ program.command("run-tests").addOption(
3182
3031
  });
3183
3032
  return { failed, testId };
3184
3033
  });
3185
- const results = yield Promise.all(promises);
3034
+ const results = await Promise.all(promises);
3186
3035
  const failedResults = results.filter((result) => result.failed);
3187
3036
  if (failedResults.length > 0) {
3188
3037
  console.log(
3189
- import_chalk.default.red(
3038
+ chalk.red(
3190
3039
  `Failed ${failedResults.length} out of ${results.length} tests`
3191
3040
  )
3192
3041
  );
3193
3042
  failedResults.forEach((result) => {
3194
- console.log(import_chalk.default.red(`- ${result.testId}`));
3043
+ console.log(chalk.red(`- ${result.testId}`));
3195
3044
  });
3196
3045
  process.exit(1);
3197
3046
  }
3198
- console.log(import_chalk.default.green(`All ${results.length} tests passed!`));
3199
- }));
3200
- function main() {
3201
- return __async(this, null, function* () {
3202
- yield program.parseAsync(process.argv);
3203
- });
3047
+ console.log(chalk.green(`All ${results.length} tests passed!`));
3048
+ });
3049
+ async function main() {
3050
+ await program.parseAsync(process.argv);
3204
3051
  }
3205
3052
  void main();