@tangle-network/browser-agent-driver 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/LICENSE +196 -0
  2. package/README.md +149 -0
  3. package/dist/artifacts/composite-sink.d.ts +15 -0
  4. package/dist/artifacts/composite-sink.d.ts.map +1 -0
  5. package/dist/artifacts/composite-sink.js +27 -0
  6. package/dist/artifacts/composite-sink.js.map +1 -0
  7. package/dist/artifacts/filesystem-sink.d.ts +26 -0
  8. package/dist/artifacts/filesystem-sink.d.ts.map +1 -0
  9. package/dist/artifacts/filesystem-sink.js +81 -0
  10. package/dist/artifacts/filesystem-sink.js.map +1 -0
  11. package/dist/artifacts/types.d.ts +97 -0
  12. package/dist/artifacts/types.d.ts.map +1 -0
  13. package/dist/artifacts/types.js +9 -0
  14. package/dist/artifacts/types.js.map +1 -0
  15. package/dist/artifacts/webhook-sink.d.ts +71 -0
  16. package/dist/artifacts/webhook-sink.d.ts.map +1 -0
  17. package/dist/artifacts/webhook-sink.js +117 -0
  18. package/dist/artifacts/webhook-sink.js.map +1 -0
  19. package/dist/brain/index.d.ts +149 -0
  20. package/dist/brain/index.d.ts.map +1 -0
  21. package/dist/brain/index.js +1030 -0
  22. package/dist/brain/index.js.map +1 -0
  23. package/dist/browser-launch.d.ts +27 -0
  24. package/dist/browser-launch.d.ts.map +1 -0
  25. package/dist/browser-launch.js +92 -0
  26. package/dist/browser-launch.js.map +1 -0
  27. package/dist/cli.d.ts +14 -0
  28. package/dist/cli.d.ts.map +1 -0
  29. package/dist/cli.js +1035 -0
  30. package/dist/cli.js.map +1 -0
  31. package/dist/config.d.ts +143 -0
  32. package/dist/config.d.ts.map +1 -0
  33. package/dist/config.js +205 -0
  34. package/dist/config.js.map +1 -0
  35. package/dist/context-budget.d.ts +14 -0
  36. package/dist/context-budget.d.ts.map +1 -0
  37. package/dist/context-budget.js +39 -0
  38. package/dist/context-budget.js.map +1 -0
  39. package/dist/design-audit.d.ts +48 -0
  40. package/dist/design-audit.d.ts.map +1 -0
  41. package/dist/design-audit.js +172 -0
  42. package/dist/design-audit.js.map +1 -0
  43. package/dist/domain-policy.d.ts +4 -0
  44. package/dist/domain-policy.d.ts.map +1 -0
  45. package/dist/domain-policy.js +69 -0
  46. package/dist/domain-policy.js.map +1 -0
  47. package/dist/drivers/block-patterns.d.ts +11 -0
  48. package/dist/drivers/block-patterns.d.ts.map +1 -0
  49. package/dist/drivers/block-patterns.js +123 -0
  50. package/dist/drivers/block-patterns.js.map +1 -0
  51. package/dist/drivers/cdp-page-state.d.ts +22 -0
  52. package/dist/drivers/cdp-page-state.d.ts.map +1 -0
  53. package/dist/drivers/cdp-page-state.js +38 -0
  54. package/dist/drivers/cdp-page-state.js.map +1 -0
  55. package/dist/drivers/cdp-snapshot.d.ts +32 -0
  56. package/dist/drivers/cdp-snapshot.d.ts.map +1 -0
  57. package/dist/drivers/cdp-snapshot.js +120 -0
  58. package/dist/drivers/cdp-snapshot.js.map +1 -0
  59. package/dist/drivers/playwright.d.ts +84 -0
  60. package/dist/drivers/playwright.d.ts.map +1 -0
  61. package/dist/drivers/playwright.js +385 -0
  62. package/dist/drivers/playwright.js.map +1 -0
  63. package/dist/drivers/snapshot.d.ts +134 -0
  64. package/dist/drivers/snapshot.d.ts.map +1 -0
  65. package/dist/drivers/snapshot.js +354 -0
  66. package/dist/drivers/snapshot.js.map +1 -0
  67. package/dist/drivers/types.d.ts +37 -0
  68. package/dist/drivers/types.d.ts.map +1 -0
  69. package/dist/drivers/types.js +5 -0
  70. package/dist/drivers/types.js.map +1 -0
  71. package/dist/env-loader.d.ts +2 -0
  72. package/dist/env-loader.d.ts.map +1 -0
  73. package/dist/env-loader.js +35 -0
  74. package/dist/env-loader.js.map +1 -0
  75. package/dist/formatters/slack.d.ts +37 -0
  76. package/dist/formatters/slack.d.ts.map +1 -0
  77. package/dist/formatters/slack.js +97 -0
  78. package/dist/formatters/slack.js.map +1 -0
  79. package/dist/index.d.ts +60 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +53 -0
  82. package/dist/index.js.map +1 -0
  83. package/dist/memory/analyzer.d.ts +67 -0
  84. package/dist/memory/analyzer.d.ts.map +1 -0
  85. package/dist/memory/analyzer.js +265 -0
  86. package/dist/memory/analyzer.js.map +1 -0
  87. package/dist/memory/knowledge.d.ts +55 -0
  88. package/dist/memory/knowledge.d.ts.map +1 -0
  89. package/dist/memory/knowledge.js +115 -0
  90. package/dist/memory/knowledge.js.map +1 -0
  91. package/dist/memory/project-store.d.ts +43 -0
  92. package/dist/memory/project-store.d.ts.map +1 -0
  93. package/dist/memory/project-store.js +119 -0
  94. package/dist/memory/project-store.js.map +1 -0
  95. package/dist/memory/selectors.d.ts +46 -0
  96. package/dist/memory/selectors.d.ts.map +1 -0
  97. package/dist/memory/selectors.js +89 -0
  98. package/dist/memory/selectors.js.map +1 -0
  99. package/dist/memory/store.d.ts +39 -0
  100. package/dist/memory/store.d.ts.map +1 -0
  101. package/dist/memory/store.js +193 -0
  102. package/dist/memory/store.js.map +1 -0
  103. package/dist/model-pricing.d.ts +41 -0
  104. package/dist/model-pricing.d.ts.map +1 -0
  105. package/dist/model-pricing.js +197 -0
  106. package/dist/model-pricing.js.map +1 -0
  107. package/dist/multi-actor.d.ts +108 -0
  108. package/dist/multi-actor.d.ts.map +1 -0
  109. package/dist/multi-actor.js +192 -0
  110. package/dist/multi-actor.js.map +1 -0
  111. package/dist/override-pipeline.d.ts +57 -0
  112. package/dist/override-pipeline.d.ts.map +1 -0
  113. package/dist/override-pipeline.js +26 -0
  114. package/dist/override-pipeline.js.map +1 -0
  115. package/dist/personas.d.ts +19 -0
  116. package/dist/personas.d.ts.map +1 -0
  117. package/dist/personas.js +86 -0
  118. package/dist/personas.js.map +1 -0
  119. package/dist/preview.d.ts +32 -0
  120. package/dist/preview.d.ts.map +1 -0
  121. package/dist/preview.js +138 -0
  122. package/dist/preview.js.map +1 -0
  123. package/dist/provider-defaults.d.ts +6 -0
  124. package/dist/provider-defaults.d.ts.map +1 -0
  125. package/dist/provider-defaults.js +40 -0
  126. package/dist/provider-defaults.js.map +1 -0
  127. package/dist/providers/sandbox-backend.d.ts +22 -0
  128. package/dist/providers/sandbox-backend.d.ts.map +1 -0
  129. package/dist/providers/sandbox-backend.js +259 -0
  130. package/dist/providers/sandbox-backend.js.map +1 -0
  131. package/dist/recovery.d.ts +91 -0
  132. package/dist/recovery.d.ts.map +1 -0
  133. package/dist/recovery.js +500 -0
  134. package/dist/recovery.js.map +1 -0
  135. package/dist/reporters/junit.d.ts +8 -0
  136. package/dist/reporters/junit.d.ts.map +1 -0
  137. package/dist/reporters/junit.js +99 -0
  138. package/dist/reporters/junit.js.map +1 -0
  139. package/dist/run-metrics.d.ts +4 -0
  140. package/dist/run-metrics.d.ts.map +1 -0
  141. package/dist/run-metrics.js +48 -0
  142. package/dist/run-metrics.js.map +1 -0
  143. package/dist/run-state.d.ts +22 -0
  144. package/dist/run-state.d.ts.map +1 -0
  145. package/dist/run-state.js +33 -0
  146. package/dist/run-state.js.map +1 -0
  147. package/dist/runner/goal-verification.d.ts +13 -0
  148. package/dist/runner/goal-verification.d.ts.map +1 -0
  149. package/dist/runner/goal-verification.js +152 -0
  150. package/dist/runner/goal-verification.js.map +1 -0
  151. package/dist/runner/index.d.ts +12 -0
  152. package/dist/runner/index.d.ts.map +1 -0
  153. package/dist/runner/index.js +18 -0
  154. package/dist/runner/index.js.map +1 -0
  155. package/dist/runner/overrides.d.ts +75 -0
  156. package/dist/runner/overrides.d.ts.map +1 -0
  157. package/dist/runner/overrides.js +385 -0
  158. package/dist/runner/overrides.js.map +1 -0
  159. package/dist/runner/page-analysis.d.ts +23 -0
  160. package/dist/runner/page-analysis.d.ts.map +1 -0
  161. package/dist/runner/page-analysis.js +91 -0
  162. package/dist/runner/page-analysis.js.map +1 -0
  163. package/dist/runner/runner.d.ts +66 -0
  164. package/dist/runner/runner.d.ts.map +1 -0
  165. package/dist/runner/runner.js +1314 -0
  166. package/dist/runner/runner.js.map +1 -0
  167. package/dist/runner/scout.d.ts +29 -0
  168. package/dist/runner/scout.d.ts.map +1 -0
  169. package/dist/runner/scout.js +81 -0
  170. package/dist/runner/scout.js.map +1 -0
  171. package/dist/runner/search-guidance.d.ts +31 -0
  172. package/dist/runner/search-guidance.d.ts.map +1 -0
  173. package/dist/runner/search-guidance.js +210 -0
  174. package/dist/runner/search-guidance.js.map +1 -0
  175. package/dist/runner/utils.d.ts +28 -0
  176. package/dist/runner/utils.d.ts.map +1 -0
  177. package/dist/runner/utils.js +119 -0
  178. package/dist/runner/utils.js.map +1 -0
  179. package/dist/runner.d.ts +8 -0
  180. package/dist/runner.d.ts.map +1 -0
  181. package/dist/runner.js +21 -0
  182. package/dist/runner.js.map +1 -0
  183. package/dist/supervisor/critic.d.ts +29 -0
  184. package/dist/supervisor/critic.d.ts.map +1 -0
  185. package/dist/supervisor/critic.js +320 -0
  186. package/dist/supervisor/critic.js.map +1 -0
  187. package/dist/supervisor/policy.d.ts +11 -0
  188. package/dist/supervisor/policy.d.ts.map +1 -0
  189. package/dist/supervisor/policy.js +118 -0
  190. package/dist/supervisor/policy.js.map +1 -0
  191. package/dist/test-report.d.ts +15 -0
  192. package/dist/test-report.d.ts.map +1 -0
  193. package/dist/test-report.js +241 -0
  194. package/dist/test-report.js.map +1 -0
  195. package/dist/test-runner.d.ts +99 -0
  196. package/dist/test-runner.d.ts.map +1 -0
  197. package/dist/test-runner.js +1075 -0
  198. package/dist/test-runner.js.map +1 -0
  199. package/dist/types.d.ts +493 -0
  200. package/dist/types.d.ts.map +1 -0
  201. package/dist/types.js +5 -0
  202. package/dist/types.js.map +1 -0
  203. package/dist/wallet/automation.d.ts +52 -0
  204. package/dist/wallet/automation.d.ts.map +1 -0
  205. package/dist/wallet/automation.js +507 -0
  206. package/dist/wallet/automation.js.map +1 -0
  207. package/package.json +101 -0
  208. package/scripts/postinstall-provider-patches.mjs +52 -0
@@ -0,0 +1,500 @@
1
+ /**
2
+ * Recovery strategies for common failure modes.
3
+ *
4
+ * Automatically triggered by the Runner when it detects patterns like:
5
+ * - Stuck (same URL + snapshot for multiple turns)
6
+ * - Consecutive selector failures
7
+ * - Loading states
8
+ * - Blocking overlays
9
+ */
10
+ /**
11
+ * Compute a simple hash of a snapshot string for change detection.
12
+ * Uses a fast DJB2-like hash — not cryptographic, just for equality checks.
13
+ */
14
+ export function snapshotHash(snapshot) {
15
+ let hash = 5381;
16
+ for (let i = 0; i < snapshot.length; i++) {
17
+ hash = ((hash << 5) + hash + snapshot.charCodeAt(i)) | 0;
18
+ }
19
+ return hash;
20
+ }
21
+ /**
22
+ * Detect if the agent is stuck (same URL + similar snapshot for N turns).
23
+ */
24
+ export function detectStuck(turns, threshold = 3) {
25
+ if (turns.length < threshold)
26
+ return false;
27
+ const recent = turns.slice(-threshold);
28
+ const firstUrl = recent[0].state.url;
29
+ const firstHash = snapshotHash(recent[0].state.snapshot);
30
+ // Classic stuck: identical state across all turns
31
+ if (recent.every((t) => t.state.url === firstUrl && snapshotHash(t.state.snapshot) === firstHash)) {
32
+ return true;
33
+ }
34
+ // Oscillating stuck: same URL, alternating between two states (e.g., menu open/close)
35
+ if (recent.length >= 4) {
36
+ const last4 = turns.slice(-4);
37
+ const sameUrl = last4.every((t) => t.state.url === firstUrl);
38
+ if (sameUrl) {
39
+ const hashes = last4.map((t) => snapshotHash(t.state.snapshot));
40
+ const isOscillating = hashes[0] === hashes[2] && hashes[1] === hashes[3] && hashes[0] !== hashes[1];
41
+ if (isOscillating)
42
+ return true;
43
+ }
44
+ }
45
+ // URL cycle detection: agent revisits the same URL sequence across different pages
46
+ // Catches A→B→C→A→B→C and A→B→A→B patterns across different URLs
47
+ if (turns.length >= 6) {
48
+ const recentUrls = turns.slice(-6).map((t) => t.state.url);
49
+ // Check for 2-cycle (A→B→A→B) across different URLs
50
+ if (recentUrls[2] === recentUrls[4] && recentUrls[3] === recentUrls[5] && recentUrls[2] !== recentUrls[3]) {
51
+ if (recentUrls[0] === recentUrls[2] && recentUrls[1] === recentUrls[3])
52
+ return true;
53
+ }
54
+ // Check for 3-cycle (A→B→C→A→B→C) across different URLs
55
+ if (recentUrls[0] === recentUrls[3] && recentUrls[1] === recentUrls[4] && recentUrls[2] === recentUrls[5]) {
56
+ const unique = new Set(recentUrls.slice(0, 3));
57
+ if (unique.size >= 2)
58
+ return true;
59
+ }
60
+ }
61
+ return false;
62
+ }
63
+ /**
64
+ * Detect consecutive action failures (selector not found, click intercepted, etc.)
65
+ */
66
+ export function detectSelectorFailures(turns, threshold = 2) {
67
+ if (turns.length < threshold)
68
+ return false;
69
+ const recent = turns.slice(-threshold);
70
+ return recent.every((t) => !!t.error);
71
+ }
72
+ /**
73
+ * Detect loading states in the snapshot.
74
+ * Patterns are anchored to avoid false-positives on words like "downloading" or
75
+ * "loading" appearing in regular page content (e.g., "Loading dock", "Processing fees").
76
+ */
77
+ export function detectLoadingState(snapshot) {
78
+ const loadingPatterns = [
79
+ /\bloading\.{2,3}/i, // "Loading..." or "Loading.." (ellipsis = spinner text)
80
+ /\bspinner\b/i, // explicit spinner element
81
+ /\bplease wait\b/i, // "Please wait"
82
+ /\bfetching data\b/i, // "Fetching data" (not just "fetching")
83
+ /\bProcessing\.\.\./i, // "Processing..." (with ellipsis)
84
+ /\bProvisioning\s+(?:your|the|a)\b/i, // "Provisioning your container" etc.
85
+ /\bCreating development environment\b/i,
86
+ ];
87
+ return loadingPatterns.some((p) => p.test(snapshot));
88
+ }
89
+ /** Parse interactive elements from a snapshot into role/name/ref triples. */
90
+ export function parseSnapshotElements(snapshot) {
91
+ const elements = [];
92
+ const lines = snapshot.split('\n');
93
+ for (const line of lines) {
94
+ const match = line.match(/^\s*-\s+([a-zA-Z0-9_-]+)(?:\s+"([^"]*)")?.*\[ref=([^\]]+)\]/);
95
+ if (!match)
96
+ continue;
97
+ const [, role, name = '', ref] = match;
98
+ elements.push({ role: role.toLowerCase(), name: name.trim(), ref: ref.trim() });
99
+ }
100
+ return elements;
101
+ }
102
+ function pickRefByName(elements, patterns) {
103
+ for (const pattern of patterns) {
104
+ const match = elements.find((el) => (el.role === 'button' || el.role === 'link' || el.role === 'menuitem') &&
105
+ pattern.test(el.name.toLowerCase()));
106
+ if (match)
107
+ return match.ref;
108
+ }
109
+ return undefined;
110
+ }
111
+ function detectQuotaLimitText(snapshotLower) {
112
+ const patterns = [
113
+ /project limit/,
114
+ /limit reached/,
115
+ /quota/,
116
+ /usage limit/,
117
+ /maximum .* reached/,
118
+ /too many .* projects/,
119
+ /upgrade .* plan/,
120
+ /free up .* project/,
121
+ ];
122
+ return patterns.some((p) => p.test(snapshotLower));
123
+ }
124
+ /**
125
+ * Detect blocking dialogs/modals and suggest an immediate remediation action.
126
+ * This is intentionally deterministic so common blockers are handled without
127
+ * waiting for the LLM to rediscover basic escape hatches every run.
128
+ */
129
+ export function detectBlockingModal(snapshot) {
130
+ const snapshotLower = snapshot.toLowerCase();
131
+ const hasDialog = /(?:^|\n)\s*-\s*(?:dialog|alertdialog)\b/i.test(snapshot);
132
+ const hasModalWord = /\bmodal\b/i.test(snapshot);
133
+ if (!hasDialog && !hasModalWord && !detectQuotaLimitText(snapshotLower)) {
134
+ return null;
135
+ }
136
+ const elements = parseSnapshotElements(snapshot);
137
+ const confirmDeleteRef = pickRefByName(elements, [
138
+ /^delete$/,
139
+ /^yes,\s*delete$/,
140
+ /^confirm$/,
141
+ /^remove$/,
142
+ ]);
143
+ const looksLikeProjectDeleteConfirm = /(?:delete|remove).*(?:project|item)/.test(snapshotLower) ||
144
+ /are you sure/.test(snapshotLower) ||
145
+ /permanently delete/.test(snapshotLower);
146
+ if (looksLikeProjectDeleteConfirm && confirmDeleteRef) {
147
+ return {
148
+ kind: 'blocking-modal',
149
+ strategy: 'modal-confirm-delete',
150
+ feedback: 'BLOCKER SUBSTEP: A delete-confirmation modal is present. Confirming deletion to complete quota cleanup, then continue the main goal.',
151
+ action: { action: 'click', selector: `@${confirmDeleteRef}` },
152
+ };
153
+ }
154
+ const verificationOverrideRef = pickRefByName(elements, [
155
+ /use personal credits/,
156
+ /continue with (?:your )?current project/,
157
+ /continue with personal credits/,
158
+ /continue anyway/,
159
+ /proceed anyway/,
160
+ ]);
161
+ const looksLikeVerificationOverride = /\bverification error\b/.test(snapshotLower) ||
162
+ /\bcouldn[’']t verify\b/.test(snapshotLower) ||
163
+ /\bpartner['’]s requirements\b/.test(snapshotLower) ||
164
+ /\buse personal credits\b/.test(snapshotLower);
165
+ if (looksLikeVerificationOverride && verificationOverrideRef) {
166
+ return {
167
+ kind: 'verification-override',
168
+ strategy: 'modal-use-personal-credits',
169
+ feedback: 'BLOCKER: A partner verification modal is blocking project start. Continue with the current project using personal credits, then resume the main goal.',
170
+ action: { action: 'click', selector: `@${verificationOverrideRef}` },
171
+ };
172
+ }
173
+ // Prefer non-destructive exits first, then cleanup actions if required.
174
+ if (detectQuotaLimitText(snapshotLower)) {
175
+ const manageRef = pickRefByName(elements, [
176
+ /manage projects?/,
177
+ /view projects?/,
178
+ /open projects?/,
179
+ /go to projects?/,
180
+ /existing projects?/,
181
+ /project settings/,
182
+ /billing/,
183
+ /upgrade/,
184
+ ]);
185
+ if (manageRef) {
186
+ return {
187
+ kind: 'quota-limit',
188
+ strategy: 'quota-limit-manage',
189
+ feedback: 'BLOCKER: A quota/limit dialog is blocking progress. Opening the project/plan management path. ' +
190
+ 'Resolve the limit (remove/archive old test items or upgrade) and then retry the original goal action.',
191
+ action: { action: 'click', selector: `@${manageRef}` },
192
+ };
193
+ }
194
+ const cleanupRef = pickRefByName(elements, [
195
+ /delete\s+(?:a\s+)?project/,
196
+ /remove\s+(?:an?\s+)?project/,
197
+ /archive\s+(?:an?\s+)?project/,
198
+ /free up .*project/,
199
+ /delete oldest project/,
200
+ /remove oldest project/,
201
+ /clear old projects?/,
202
+ ]);
203
+ if (cleanupRef) {
204
+ return {
205
+ kind: 'quota-limit',
206
+ strategy: 'quota-limit-cleanup',
207
+ feedback: 'BLOCKER: A quota/limit dialog is blocking progress. A cleanup action was selected to free capacity. ' +
208
+ 'After cleanup, confirm the blocker is gone and continue with the main goal.',
209
+ action: { action: 'click', selector: `@${cleanupRef}` },
210
+ };
211
+ }
212
+ return {
213
+ kind: 'quota-limit',
214
+ strategy: 'quota-limit-escape',
215
+ feedback: 'BLOCKER: Quota/limit dialog detected but no clear management button was found. ' +
216
+ 'Dismissing the dialog; then navigate to project/settings areas to free capacity and retry.',
217
+ forceAction: 'escape',
218
+ };
219
+ }
220
+ // Cookie / consent banners — dismiss deterministically before the LLM wastes a turn.
221
+ const isCookieConsent = /\bcookie/i.test(snapshotLower) ||
222
+ /\bconsent/i.test(snapshotLower) ||
223
+ /\bpersonalise your/i.test(snapshotLower) ||
224
+ /\bpersonalize your/i.test(snapshotLower) ||
225
+ /\bprivacy preference/i.test(snapshotLower);
226
+ if (isCookieConsent) {
227
+ const consentDismissRef = pickRefByName(elements, [
228
+ /^reject all$/,
229
+ /^decline all$/,
230
+ /^deny$/,
231
+ /^reject$/,
232
+ /^accept all$/,
233
+ /^allow all$/,
234
+ /^accept cookies?$/,
235
+ /^got it$/,
236
+ /^ok$/,
237
+ /^close$/,
238
+ /^continue$/,
239
+ ]);
240
+ if (consentDismissRef) {
241
+ return {
242
+ kind: 'blocking-modal',
243
+ strategy: 'cookie-consent-dismiss',
244
+ feedback: 'BLOCKER: A cookie/consent dialog was intercepting the page. It has been dismissed. ' +
245
+ 'If you submitted a form or search before this dialog appeared, the submission may have been blocked. ' +
246
+ 'Re-verify whether your last action took effect (check the URL and page content) and re-submit if needed.',
247
+ action: { action: 'click', selector: `@${consentDismissRef}` },
248
+ };
249
+ }
250
+ // Iframe-based consent dialogs (e.g., SP Consent Message, OneTrust):
251
+ // buttons are inside an iframe so pickRefByName can't find them.
252
+ // Use runScript to click the accept/reject button inside the consent iframe.
253
+ const hasConsentIframe = /iframe\s+"[^"]*consent/i.test(snapshot);
254
+ if (hasConsentIframe) {
255
+ return {
256
+ kind: 'blocking-modal',
257
+ strategy: 'cookie-consent-iframe-dismiss',
258
+ feedback: 'BLOCKER: A cookie/consent dialog inside an iframe was detected and is being dismissed via script.',
259
+ action: {
260
+ action: 'runScript',
261
+ script: `(function() {
262
+ const selectors = [
263
+ 'button[title*="Accept"]', 'button[title*="Agree"]', 'button[title*="OK"]',
264
+ 'button[title*="Reject"]', 'button[title*="Decline"]',
265
+ '.sp_choice_type_11', '.sp_choice_type_12', // SourcePoint accept/reject
266
+ '[class*="accept"]', '[class*="agree"]', '[class*="consent-accept"]',
267
+ 'button:not([class*="manage"]):not([class*="setting"])',
268
+ ];
269
+ for (const iframe of document.querySelectorAll('iframe')) {
270
+ try {
271
+ const doc = iframe.contentDocument;
272
+ if (!doc) continue;
273
+ for (const sel of selectors) {
274
+ const btn = doc.querySelector(sel);
275
+ if (btn && btn.offsetHeight > 0) { btn.click(); return 'dismissed:' + sel; }
276
+ }
277
+ } catch(e) { /* cross-origin iframe, skip */ }
278
+ }
279
+ return 'no-dismiss-target-found';
280
+ })()`,
281
+ },
282
+ };
283
+ }
284
+ }
285
+ const closeRef = pickRefByName(elements, [
286
+ /^close$/,
287
+ /dismiss/,
288
+ /cancel/,
289
+ /not now/,
290
+ /maybe later/,
291
+ /^ok$/,
292
+ /^got it$/,
293
+ /^continue$/,
294
+ /skip/,
295
+ ]);
296
+ if (closeRef) {
297
+ return {
298
+ kind: 'blocking-modal',
299
+ strategy: 'modal-dismiss-click',
300
+ feedback: 'BLOCKER: A dialog/modal is obstructing interaction. Dismiss it first, then continue with the goal.',
301
+ action: { action: 'click', selector: `@${closeRef}` },
302
+ };
303
+ }
304
+ return {
305
+ kind: 'blocking-modal',
306
+ strategy: 'modal-present-no-force',
307
+ feedback: 'BLOCKER: A dialog/modal is present. Do not interact with background page elements. ' +
308
+ 'Choose an explicit action inside this modal first (close, cancel, confirm, or required primary action).',
309
+ };
310
+ }
311
+ /**
312
+ * Detect blockers that should terminate the run immediately.
313
+ * These are conditions the agent cannot reliably resolve by trying more actions.
314
+ */
315
+ export function detectTerminalBlocker(state) {
316
+ const url = state.url || '';
317
+ const title = state.title || '';
318
+ const snapshot = state.snapshot || '';
319
+ const haystack = `${url}\n${title}\n${snapshot}`.toLowerCase();
320
+ const networkPatterns = [
321
+ ['chrome-error-url', /^chrome-error:\/\//i],
322
+ ['site-unreachable', /\bthis site can['’]t be reached\b/i],
323
+ ['name-not-resolved', /\berr_name_not_resolved\b/i],
324
+ ['connection-failed', /\berr_(?:connection|internet|address)_/i],
325
+ ['dns-failure', /\bdns_probe_finished\b/i],
326
+ ['network-error', /\bnetwork error\b/i],
327
+ ];
328
+ const networkHits = networkPatterns
329
+ .filter(([, pattern]) => pattern.test(haystack))
330
+ .map(([name]) => name);
331
+ if (networkHits.length > 0) {
332
+ return {
333
+ kind: 'network-unreachable',
334
+ strategy: 'terminal-network-error',
335
+ reason: 'Terminal blocker: destination is unreachable from the current browser environment.',
336
+ evidence: networkHits,
337
+ };
338
+ }
339
+ const botPatterns = [
340
+ ['verify-human', /\bverify you are human\b/i],
341
+ ['captcha', /\bcaptcha\b/i],
342
+ ['cloudflare-attention', /\battention required\b/i],
343
+ ['cloudflare-just-a-moment', /\bjust a moment\b/i],
344
+ ['cloudflare-security-verification', /\bperforming security verification\b/i],
345
+ ['cloudflare-secure-connection', /\bchecking if the site connection is secure\b/i],
346
+ ['cloudflare-checking', /\bchecking your browser before accessing\b/i],
347
+ ['cf-challenge', /\bcf[-_ ]challenge\b/i],
348
+ ['turnstile', /\bturnstile\b/i],
349
+ ];
350
+ const botHits = botPatterns.filter(([, pattern]) => pattern.test(haystack)).map(([name]) => name);
351
+ if (botHits.length > 0) {
352
+ return {
353
+ kind: 'bot-challenge',
354
+ strategy: 'terminal-bot-challenge',
355
+ reason: 'Terminal blocker: anti-bot challenge detected; automated completion is not supported for this flow.',
356
+ evidence: botHits,
357
+ };
358
+ }
359
+ return null;
360
+ }
361
+ /**
362
+ * Detect persistent app-native environment blockers that are unlikely to be fixed
363
+ * by more navigation attempts inside the same run.
364
+ */
365
+ export function detectPersistentTerminalBlocker(recentTurns, currentState) {
366
+ const appDevEnvPatterns = [
367
+ ['dev-environment', /\bdev environment\b/i],
368
+ ['orchestrator-offline', /\borchestrator\b.*\boffline\b/i],
369
+ ['websocket-disconnected', /\bwebsocket disconnected\b/i],
370
+ ['event-stream-connecting', /\bevent stream\b.*\bconnecting\b/i],
371
+ ['container-not-started', /\bcontainer\b.*\bnot started\b/i],
372
+ ['not-provisioned', /\bnot provisioned\b/i],
373
+ ['awaiting-provisioning', /\bawaiting provisioning\b/i],
374
+ ];
375
+ if (recentTurns.length < 3)
376
+ return null;
377
+ const currentSnapshot = currentState.snapshot || '';
378
+ const currentHaystack = `${currentState.url}\n${currentState.title}\n${currentSnapshot}`.toLowerCase();
379
+ const appDevEnvSignals = appDevEnvPatterns
380
+ .filter(([, pattern]) => pattern.test(currentHaystack))
381
+ .map(([name]) => name);
382
+ if (appDevEnvSignals.length < 3)
383
+ return null;
384
+ const recent = recentTurns.slice(-3);
385
+ const sameUrl = recent.every((turn) => turn.state.url === currentState.url);
386
+ const refreshOrInspectLoop = recent.every((turn) => {
387
+ const action = turn.action;
388
+ return action.action === 'click' || action.action === 'runScript' || action.action === 'wait';
389
+ });
390
+ const repeatedSignals = recent.every((turn) => {
391
+ const haystack = `${turn.state.url}\n${turn.state.title}\n${turn.state.snapshot}`.toLowerCase();
392
+ const matchedSignals = appDevEnvPatterns
393
+ .filter(([, pattern]) => pattern.test(haystack))
394
+ .map(([name]) => name);
395
+ return matchedSignals.length >= 3;
396
+ });
397
+ if (!sameUrl || !refreshOrInspectLoop || !repeatedSignals)
398
+ return null;
399
+ return {
400
+ kind: 'dev-environment-unavailable',
401
+ strategy: 'terminal-dev-environment-unavailable',
402
+ reason: 'Terminal blocker: the application dev environment is offline/not provisioned, so preview/start actions cannot complete within this run.',
403
+ evidence: appDevEnvSignals,
404
+ };
405
+ }
406
+ /**
407
+ * Analyze the current state and return a recovery action if needed.
408
+ * Returns null if no recovery is warranted.
409
+ */
410
+ export function analyzeRecovery(ctx) {
411
+ const { recentTurns, currentState, consecutiveErrors } = ctx;
412
+ // Strategy 0: Blocker modal/dialog handling — run before stuck detection.
413
+ // Without this, repeated blocked actions often look like generic "stuck".
414
+ const blockingModal = detectBlockingModal(currentState.snapshot);
415
+ if (blockingModal) {
416
+ return {
417
+ strategy: blockingModal.strategy,
418
+ feedback: blockingModal.feedback,
419
+ forceAction: blockingModal.forceAction,
420
+ forceBrowserAction: blockingModal.action,
421
+ waitMs: 500,
422
+ };
423
+ }
424
+ // Strategy 1: Stuck detection — same page for 3+ turns (check BEFORE loading,
425
+ // because a stuck loading state should escalate to reload, not just wait again)
426
+ if (detectStuck(recentTurns, 3)) {
427
+ const lastActions = recentTurns.slice(-3).map((t) => JSON.stringify(t.action));
428
+ const allSame = lastActions.every((a) => a === lastActions[0]);
429
+ // Check for oscillating stuck (menu open/close loop)
430
+ if (recentTurns.length >= 4) {
431
+ const last4 = recentTurns.slice(-4);
432
+ const hashes = last4.map((t) => snapshotHash(t.state.snapshot));
433
+ if (hashes[0] === hashes[2] && hashes[1] === hashes[3] && hashes[0] !== hashes[1]) {
434
+ return {
435
+ strategy: 'stuck-oscillating',
436
+ feedback: 'STUCK: You are toggling between two states (e.g., opening and closing a menu/dialog) without making progress. ' +
437
+ 'The URL has not changed. Stop repeating these actions. ' +
438
+ 'Try a completely different approach: use the search box if one is available, navigate directly via URL, ' +
439
+ 'or scroll to find alternative navigation elements.',
440
+ forceAction: 'escape',
441
+ };
442
+ }
443
+ }
444
+ // Check for URL cycle (navigating between the same 2-3 pages repeatedly)
445
+ if (recentTurns.length >= 6) {
446
+ const recentUrls = recentTurns.slice(-6).map((t) => t.state.url);
447
+ const is2Cycle = recentUrls[0] === recentUrls[2] && recentUrls[2] === recentUrls[4] &&
448
+ recentUrls[1] === recentUrls[3] && recentUrls[3] === recentUrls[5] && recentUrls[0] !== recentUrls[1];
449
+ const is3Cycle = recentUrls[0] === recentUrls[3] && recentUrls[1] === recentUrls[4] &&
450
+ recentUrls[2] === recentUrls[5] && new Set(recentUrls.slice(0, 3)).size >= 2;
451
+ if (is2Cycle || is3Cycle) {
452
+ return {
453
+ strategy: 'stuck-url-cycle',
454
+ feedback: 'STUCK: You are navigating in a circle between the same pages without making progress. ' +
455
+ 'You have visited the same URLs repeatedly. Stop this loop immediately. ' +
456
+ 'The information you need may already be on the current page — look at the ELEMENTS more carefully. ' +
457
+ 'If not, try a completely different approach: use a direct URL, extract data with runScript, ' +
458
+ 'or look for the answer in the current page content rather than navigating away.',
459
+ };
460
+ }
461
+ }
462
+ if (allSame) {
463
+ return {
464
+ strategy: 'stuck-same-action',
465
+ feedback: 'STUCK: You have repeated the same action 3 times with no effect. ' +
466
+ 'The page has not changed. The page has been reloaded to reset state. ' +
467
+ 'You MUST try a completely different approach.',
468
+ waitMs: 1000,
469
+ forceAction: 'reload',
470
+ };
471
+ }
472
+ return {
473
+ strategy: 'stuck-no-progress',
474
+ feedback: 'STUCK: The page has not changed for 3 turns despite different actions. ' +
475
+ 'Escape has been pressed to dismiss any overlays. ' +
476
+ 'Try a fundamentally different approach — scroll, use different selectors, or navigate elsewhere.',
477
+ forceAction: 'escape',
478
+ };
479
+ }
480
+ // Strategy 2: Loading state — wait and re-observe instead of acting
481
+ // (only if not already stuck — avoids masking stuck detection)
482
+ if (detectLoadingState(currentState.snapshot)) {
483
+ return {
484
+ strategy: 'loading-wait',
485
+ feedback: 'The page appears to be loading. Waiting for it to finish before taking action.',
486
+ waitMs: 3000,
487
+ };
488
+ }
489
+ // Strategy 3: Consecutive selector failures
490
+ if (consecutiveErrors >= 2 || detectSelectorFailures(recentTurns, 2)) {
491
+ return {
492
+ strategy: 'selector-failures',
493
+ feedback: 'Multiple actions have failed. The selectors may be stale or elements may be obscured. ' +
494
+ 'Look carefully at the current ELEMENTS list and choose a different element. ' +
495
+ 'If a dialog is present, dismiss or resolve it before retrying.',
496
+ };
497
+ }
498
+ return null;
499
+ }
500
+ //# sourceMappingURL=recovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery.js","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * JUnit XML Reporter — produces standard JUnit XML that GitHub Actions,
3
+ * Jenkins, and GitLab CI parse natively.
4
+ */
5
+ import type { TestSuiteResult } from '../types.js';
6
+ /** Generate JUnit XML from a test suite result */
7
+ export declare function generateJUnitXml(suite: TestSuiteResult): string;
8
+ //# sourceMappingURL=junit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"junit.d.ts","sourceRoot":"","sources":["../../src/reporters/junit.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAc,MAAM,aAAa,CAAC;AAY/D,kDAAkD;AAClD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CA8C/D"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * JUnit XML Reporter — produces standard JUnit XML that GitHub Actions,
3
+ * Jenkins, and GitLab CI parse natively.
4
+ */
5
+ /** Escape special XML characters */
6
+ function escapeXml(s) {
7
+ return s
8
+ .replace(/&/g, '&amp;')
9
+ .replace(/</g, '&lt;')
10
+ .replace(/>/g, '&gt;')
11
+ .replace(/"/g, '&quot;')
12
+ .replace(/'/g, '&apos;');
13
+ }
14
+ /** Generate JUnit XML from a test suite result */
15
+ export function generateJUnitXml(suite) {
16
+ const { summary, results } = suite;
17
+ const totalTimeSeconds = (summary.totalDurationMs / 1000).toFixed(3);
18
+ const lines = [];
19
+ lines.push('<?xml version="1.0" encoding="UTF-8"?>');
20
+ lines.push(`<testsuites name="browser-agent-driver" tests="${summary.total}" failures="${summary.failed}" errors="0" skipped="${summary.skipped}" time="${totalTimeSeconds}">`);
21
+ // Group by category (or "default" if none)
22
+ const groups = groupByCategory(results);
23
+ for (const [category, tests] of groups) {
24
+ const groupFailed = tests.filter((r) => !r.skipped && !r.verified).length;
25
+ const groupSkipped = tests.filter((r) => r.skipped).length;
26
+ const groupTime = tests.reduce((sum, r) => sum + r.durationMs, 0) / 1000;
27
+ lines.push(` <testsuite name="${escapeXml(category)}" tests="${tests.length}" failures="${groupFailed}" errors="0" skipped="${groupSkipped}" time="${groupTime.toFixed(3)}" timestamp="${suite.timestamp}">`);
28
+ for (const result of tests) {
29
+ const testTime = (result.durationMs / 1000).toFixed(3);
30
+ const classname = escapeXml(result.testCase.category || result.testCase.id);
31
+ const testName = escapeXml(result.testCase.name);
32
+ if (result.skipped) {
33
+ lines.push(` <testcase name="${testName}" classname="${classname}" time="0">`);
34
+ lines.push(` <skipped message="${escapeXml(result.skipReason || 'Unmet dependency')}"/>`);
35
+ lines.push(' </testcase>');
36
+ }
37
+ else if (!result.verified) {
38
+ lines.push(` <testcase name="${testName}" classname="${classname}" time="${testTime}">`);
39
+ lines.push(formatFailure(result));
40
+ lines.push(' </testcase>');
41
+ }
42
+ else {
43
+ lines.push(` <testcase name="${testName}" classname="${classname}" time="${testTime}">`);
44
+ lines.push(' </testcase>');
45
+ }
46
+ }
47
+ lines.push(' </testsuite>');
48
+ }
49
+ lines.push('</testsuites>');
50
+ return lines.join('\n');
51
+ }
52
+ function formatFailure(result) {
53
+ const message = escapeXml(result.verdict.slice(0, 200));
54
+ const bodyLines = [];
55
+ // Verdict
56
+ bodyLines.push(`Verdict: ${result.verdict}`);
57
+ // Criteria failures
58
+ if (result.criteriaResults?.length) {
59
+ const failed = result.criteriaResults.filter((c) => !c.passed);
60
+ if (failed.length > 0) {
61
+ bodyLines.push('Failed criteria:');
62
+ for (const c of failed) {
63
+ const desc = c.criterion.description || c.criterion.type;
64
+ bodyLines.push(` - ${desc}${c.detail ? ': ' + c.detail : ''}`);
65
+ }
66
+ }
67
+ }
68
+ // Last actions for debugging
69
+ const lastTurns = result.agentResult.turns.slice(-5);
70
+ if (lastTurns.length > 0) {
71
+ bodyLines.push('Last actions:');
72
+ for (const t of lastTurns) {
73
+ const actionStr = JSON.stringify(t.action).slice(0, 120);
74
+ bodyLines.push(` [turn ${t.turn}] ${actionStr}`);
75
+ }
76
+ }
77
+ // Escape the entire body text — it's XML CDATA content
78
+ const escapedBody = escapeXml(bodyLines.join('\n'));
79
+ const lines = [];
80
+ lines.push(` <failure message="${message}" type="verification">`);
81
+ lines.push(escapedBody);
82
+ lines.push(' </failure>');
83
+ return lines.join('\n');
84
+ }
85
+ function groupByCategory(results) {
86
+ const groups = new Map();
87
+ for (const result of results) {
88
+ const category = result.testCase.category || 'default';
89
+ const group = groups.get(category);
90
+ if (group) {
91
+ group.push(result);
92
+ }
93
+ else {
94
+ groups.set(category, [result]);
95
+ }
96
+ }
97
+ return groups;
98
+ }
99
+ //# sourceMappingURL=junit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"junit.js","sourceRoot":"","sources":["../../src/reporters/junit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Turn, RunWasteMetrics } from './types.js';
2
+ export declare function countRepeatedQueries(turns: Turn[]): number;
3
+ export declare function deriveWasteMetrics(turns: Turn[], verificationRejectionCount: number, firstSufficientEvidenceTurn?: number): RunWasteMetrics;
4
+ //# sourceMappingURL=run-metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-metrics.d.ts","sourceRoot":"","sources":["../src/run-metrics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,IAAI,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAqBhE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,CAe1D;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,IAAI,EAAE,EACb,0BAA0B,EAAE,MAAM,EAClC,2BAA2B,CAAC,EAAE,MAAM,GACnC,eAAe,CAajB"}