@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,172 @@
1
+ /**
2
+ * Design Audit System — systematic UI/UX flow auditing with vision.
3
+ *
4
+ * Navigates through UI flows, captures screenshots at checkpoints,
5
+ * evaluates visual quality, UX patterns, accessibility, and design
6
+ * consistency. Produces structured reports with findings.
7
+ */
8
+ import { Brain } from './brain/index.js';
9
+ import { AgentRunner } from './runner.js';
10
+ /**
11
+ * DesignAuditor — orchestrates flow navigation + screenshot capture + evaluation.
12
+ *
13
+ * Usage:
14
+ * ```ts
15
+ * const auditor = new DesignAuditor(driver, { model: 'gpt-4o', vision: true });
16
+ * const report = await auditor.audit([
17
+ * { name: 'login', startUrl: 'http://localhost:5173', goal: 'Navigate to the login page', checkpoints: ['Login form is visible'] },
18
+ * { name: 'chat', startUrl: 'http://localhost:5173/chat', goal: 'Send a message in chat', checkpoints: ['Chat input is visible', 'Message appears'] },
19
+ * ]);
20
+ * console.log(generateDesignAuditReport(report));
21
+ * ```
22
+ */
23
+ export class DesignAuditor {
24
+ driver;
25
+ brain;
26
+ config;
27
+ constructor(driver, config = {}) {
28
+ this.driver = driver;
29
+ this.config = { ...config, vision: true }; // Vision must be on for design audit
30
+ this.brain = new Brain(this.config);
31
+ }
32
+ /**
33
+ * Audit a single flow — agent navigates toward the goal, captures
34
+ * screenshots at checkpoints, and evaluates design quality.
35
+ */
36
+ async auditFlow(flow) {
37
+ const screenshots = [];
38
+ const allFindings = [];
39
+ // Use the runner to navigate the flow
40
+ const runner = new AgentRunner({
41
+ driver: this.driver,
42
+ config: this.config,
43
+ onTurn: (turn) => {
44
+ if (turn.state.screenshot) {
45
+ screenshots.push(turn.state.screenshot);
46
+ }
47
+ },
48
+ });
49
+ const result = await runner.run({
50
+ goal: flow.goal,
51
+ startUrl: flow.startUrl,
52
+ maxTurns: flow.maxTurns ?? 15,
53
+ });
54
+ // Evaluate checkpoints — capture + audit at the final state
55
+ const finalState = result.turns.length > 0
56
+ ? result.turns[result.turns.length - 1].state
57
+ : await this.driver.observe();
58
+ // Run design evaluation on the final state
59
+ const evaluation = await this.brain.auditDesign(finalState, flow.goal, flow.checkpoints);
60
+ allFindings.push(...evaluation.findings);
61
+ // Keep only key screenshots (first, middle, last) to avoid bloat
62
+ const keyScreenshots = [];
63
+ if (screenshots.length > 0)
64
+ keyScreenshots.push(screenshots[0]);
65
+ if (screenshots.length > 2)
66
+ keyScreenshots.push(screenshots[Math.floor(screenshots.length / 2)]);
67
+ if (screenshots.length > 1)
68
+ keyScreenshots.push(screenshots[screenshots.length - 1]);
69
+ return {
70
+ flow: flow.name,
71
+ steps: result.turns.length,
72
+ reachedGoal: result.success,
73
+ findings: allFindings,
74
+ screenshots: keyScreenshots,
75
+ score: evaluation.score,
76
+ };
77
+ }
78
+ /**
79
+ * Audit multiple flows and produce an aggregate report.
80
+ * Individual flow failures are caught and reported, not propagated.
81
+ *
82
+ * Flows run sequentially by default since they share a browser page.
83
+ * Pass `onFlowComplete` for progress reporting on long audits.
84
+ */
85
+ async audit(flows, options) {
86
+ const flowResults = [];
87
+ for (let i = 0; i < flows.length; i++) {
88
+ const flow = flows[i];
89
+ try {
90
+ const result = await this.auditFlow(flow);
91
+ flowResults.push(result);
92
+ }
93
+ catch (err) {
94
+ // Capture partial result for failed flows
95
+ flowResults.push({
96
+ flow: flow.name,
97
+ steps: 0,
98
+ reachedGoal: false,
99
+ findings: [],
100
+ screenshots: [],
101
+ score: 1,
102
+ error: err instanceof Error ? err.message : String(err),
103
+ });
104
+ }
105
+ options?.onFlowComplete?.(flow.name, i + 1, flows.length);
106
+ }
107
+ // Compute summary
108
+ const allFindings = flowResults.flatMap(f => f.findings);
109
+ const critical = allFindings.filter(f => f.severity === 'critical').length;
110
+ const major = allFindings.filter(f => f.severity === 'major').length;
111
+ const minor = allFindings.filter(f => f.severity === 'minor').length;
112
+ // Health score: 100 - (critical * 15 + major * 5 + minor * 1), clamped to 0-100
113
+ const deductions = critical * 15 + major * 5 + minor * 1;
114
+ const healthScore = Math.max(0, Math.min(100, 100 - deductions));
115
+ return {
116
+ timestamp: new Date().toISOString(),
117
+ flows: flowResults,
118
+ summary: {
119
+ healthScore,
120
+ totalFindings: allFindings.length,
121
+ critical,
122
+ major,
123
+ minor,
124
+ },
125
+ };
126
+ }
127
+ }
128
+ /**
129
+ * Generate a markdown report from a DesignAuditReport.
130
+ */
131
+ export function generateDesignAuditReport(report) {
132
+ const lines = [];
133
+ lines.push('# Design Audit Report');
134
+ lines.push(`**Date:** ${report.timestamp}`);
135
+ lines.push(`**Health Score:** ${report.summary.healthScore}/100`);
136
+ lines.push('');
137
+ // Summary
138
+ lines.push('## Summary');
139
+ lines.push('');
140
+ lines.push(`| Metric | Value |`);
141
+ lines.push(`|--------|-------|`);
142
+ lines.push(`| Total Findings | ${report.summary.totalFindings} |`);
143
+ lines.push(`| Critical | ${report.summary.critical} |`);
144
+ lines.push(`| Major | ${report.summary.major} |`);
145
+ lines.push(`| Minor | ${report.summary.minor} |`);
146
+ lines.push(`| Flows Audited | ${report.flows.length} |`);
147
+ lines.push('');
148
+ // Per-flow results
149
+ for (const flow of report.flows) {
150
+ lines.push(`## Flow: ${flow.flow}`);
151
+ const goalStatus = flow.reachedGoal ? 'Reached' : 'Not reached';
152
+ lines.push(`**Steps:** ${flow.steps} | **Score:** ${flow.score}/10 | **Goal:** ${goalStatus}`);
153
+ if (flow.error) {
154
+ lines.push(`**Error:** ${flow.error}`);
155
+ }
156
+ lines.push('');
157
+ if (flow.findings.length === 0) {
158
+ lines.push('No issues found.');
159
+ }
160
+ else {
161
+ lines.push('| Severity | Category | Description | Location | Suggestion |');
162
+ lines.push('|----------|----------|-------------|----------|------------|');
163
+ for (const f of flow.findings) {
164
+ const esc = (s) => s.replace(/\|/g, '\\|').replace(/\n/g, ' ');
165
+ lines.push(`| ${f.severity} | ${f.category} | ${esc(f.description)} | ${esc(f.location)} | ${esc(f.suggestion)} |`);
166
+ }
167
+ }
168
+ lines.push('');
169
+ }
170
+ return lines.join('\n');
171
+ }
172
+ //# sourceMappingURL=design-audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"design-audit.js","sourceRoot":"","sources":["../src/design-audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { GoalVerification } from './types.js';
2
+ export declare function buildFirstPartyBoundaryNote(goal: string, currentUrl: string): string | undefined;
3
+ export declare function shouldAcceptFirstPartyBoundaryCompletion(goal: string, currentUrl: string, verification: GoalVerification, claimedResult: string): boolean;
4
+ //# sourceMappingURL=domain-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain-policy.d.ts","sourceRoot":"","sources":["../src/domain-policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAqBnD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAYhG;AAED,wBAAgB,wCAAwC,CACtD,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,gBAAgB,EAC9B,aAAa,EAAE,MAAM,GACpB,OAAO,CAoCT"}
@@ -0,0 +1,69 @@
1
+ function safeHostname(url) {
2
+ try {
3
+ return new URL(url).hostname.toLowerCase();
4
+ }
5
+ catch {
6
+ return undefined;
7
+ }
8
+ }
9
+ function toRegistrableDomain(hostname) {
10
+ const parts = hostname.toLowerCase().split('.').filter(Boolean);
11
+ if (parts.length <= 2)
12
+ return hostname.toLowerCase();
13
+ return parts.slice(-2).join('.');
14
+ }
15
+ function extractGoalHosts(goal) {
16
+ const matches = goal.match(/\b(?:[a-z0-9-]+\.)+[a-z]{2,}\b/gi) ?? [];
17
+ return [...new Set(matches.map((host) => host.toLowerCase()))];
18
+ }
19
+ export function buildFirstPartyBoundaryNote(goal, currentUrl) {
20
+ const currentHost = safeHostname(currentUrl);
21
+ if (!currentHost)
22
+ return undefined;
23
+ const goalHosts = extractGoalHosts(goal);
24
+ if (goalHosts.length === 0 || goalHosts.includes(currentHost))
25
+ return undefined;
26
+ const currentRoot = toRegistrableDomain(currentHost);
27
+ const sameSiteHost = goalHosts.find((host) => toRegistrableDomain(host) === currentRoot);
28
+ if (!sameSiteHost)
29
+ return undefined;
30
+ return `SITE BOUNDARY NOTE: The current host "${currentHost}" is a first-party sibling subdomain of "${sameSiteHost}" (shared registrable domain "${currentRoot}"). If the user reached it through official in-site navigation, treat it as the same product/site for completion unless the task clearly depends on the exact host for security, auth, or compliance reasons. Do not fail solely because the subdomain differs.`;
31
+ }
32
+ export function shouldAcceptFirstPartyBoundaryCompletion(goal, currentUrl, verification, claimedResult) {
33
+ if (verification.achieved)
34
+ return false;
35
+ if (!buildFirstPartyBoundaryNote(goal, currentUrl))
36
+ return false;
37
+ const bulletCount = claimedResult
38
+ .split('\n')
39
+ .filter((line) => /^\s*[-*]\s+/.test(line))
40
+ .length;
41
+ if (bulletCount < 3)
42
+ return false;
43
+ const boundaryText = [...verification.evidence, ...verification.missing].join('\n').toLowerCase();
44
+ const boundarySignals = [
45
+ /subdomain/,
46
+ /host/,
47
+ /domain/,
48
+ /www\./,
49
+ /only use/,
50
+ /constraint/,
51
+ /same site/,
52
+ ];
53
+ const substantiveFailureSignals = [
54
+ /not visible/,
55
+ /not shown/,
56
+ /not displayed/,
57
+ /cannot find/,
58
+ /could not find/,
59
+ /missing categories?/,
60
+ /missing evidence/,
61
+ /error/,
62
+ /form/,
63
+ /button/,
64
+ /dialog/,
65
+ ];
66
+ return boundarySignals.some((pattern) => pattern.test(boundaryText))
67
+ && !substantiveFailureSignals.some((pattern) => pattern.test(boundaryText));
68
+ }
69
+ //# sourceMappingURL=domain-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain-policy.js","sourceRoot":"","sources":["../src/domain-policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Resource blocking patterns for analytics, tracking, ads, images, and media.
3
+ * Used by PlaywrightDriver.setupResourceBlocking() to abort unnecessary requests.
4
+ */
5
+ /** Analytics and tracking domain patterns (matched via URL.includes()) */
6
+ export declare const ANALYTICS_PATTERNS: string[];
7
+ /** Image file extension patterns */
8
+ export declare const IMAGE_PATTERNS: string[];
9
+ /** Media file extension patterns */
10
+ export declare const MEDIA_PATTERNS: string[];
11
+ //# sourceMappingURL=block-patterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block-patterns.d.ts","sourceRoot":"","sources":["../../src/drivers/block-patterns.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,0EAA0E;AAC1E,eAAO,MAAM,kBAAkB,EAAE,MAAM,EA4FtC,CAAC;AAEF,oCAAoC;AACpC,eAAO,MAAM,cAAc,EAAE,MAAM,EAUlC,CAAC;AAEF,oCAAoC;AACpC,eAAO,MAAM,cAAc,EAAE,MAAM,EAUlC,CAAC"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Resource blocking patterns for analytics, tracking, ads, images, and media.
3
+ * Used by PlaywrightDriver.setupResourceBlocking() to abort unnecessary requests.
4
+ */
5
+ /** Analytics and tracking domain patterns (matched via URL.includes()) */
6
+ export const ANALYTICS_PATTERNS = [
7
+ // Google
8
+ 'google-analytics.com',
9
+ 'googletagmanager.com',
10
+ 'googlesyndication.com',
11
+ 'googleadservices.com',
12
+ 'google.com/pagead',
13
+ 'doubleclick.net',
14
+ 'googleads.g.doubleclick.net',
15
+ // Facebook / Meta
16
+ 'facebook.com/tr',
17
+ 'connect.facebook.net',
18
+ 'facebook.net/signals',
19
+ 'fbcdn.net/signals',
20
+ // Analytics platforms
21
+ 'segment.io',
22
+ 'segment.com',
23
+ 'cdn.segment.com',
24
+ 'mixpanel.com',
25
+ 'amplitude.com',
26
+ 'api.amplitude.com',
27
+ 'cdn.amplitude.com',
28
+ 'heap.io',
29
+ 'heapanalytics.com',
30
+ 'fullstory.com',
31
+ 'rs.fullstory.com',
32
+ 'hotjar.com',
33
+ 'static.hotjar.com',
34
+ 'script.hotjar.com',
35
+ 'clarity.ms',
36
+ 'smartlook.com',
37
+ 'mouseflow.com',
38
+ 'logrocket.com',
39
+ 'cdn.logrocket.io',
40
+ 'posthog.com',
41
+ 'app.posthog.com',
42
+ 'plausible.io',
43
+ 'stats.wp.com',
44
+ // Ad networks
45
+ 'adroll.com',
46
+ 'adsrvr.org',
47
+ 'criteo.com',
48
+ 'static.criteo.net',
49
+ 'taboola.com',
50
+ 'outbrain.com',
51
+ 'amazon-adsystem.com',
52
+ 'ads-twitter.com',
53
+ 'ads.linkedin.com',
54
+ 'snap.licdn.com',
55
+ 'px.ads.linkedin.com',
56
+ // Tag managers & data
57
+ 'cdn.rudderlabs.com',
58
+ 'cdn.mxpnl.com',
59
+ 'js-agent.newrelic.com',
60
+ 'bam.nr-data.net',
61
+ 'browser.sentry-cdn.com',
62
+ 'sentry.io/api',
63
+ 'rum.datadog.com',
64
+ 'datadoghq.com',
65
+ 'bugsnag.com',
66
+ 'rollbar.com',
67
+ // Chat/support widgets
68
+ 'widget.intercom.io',
69
+ 'js.intercomcdn.com',
70
+ 'embed.tawk.to',
71
+ 'static.zdassets.com',
72
+ 'cdn.jsdelivr.net/npm/@drift',
73
+ // Marketing & tracking pixels
74
+ 'bat.bing.com',
75
+ 'ct.pinterest.com',
76
+ 'analytics.tiktok.com',
77
+ 'snap.licdn.com',
78
+ 'tr.snapchat.com',
79
+ 'sc-static.net/scevent',
80
+ // Survey/feedback
81
+ 'survicate.com',
82
+ 'qualtrics.com',
83
+ 'usabilla.com',
84
+ // A/B testing
85
+ 'optimizely.com',
86
+ 'cdn.optimizely.com',
87
+ 'cdn-pci.optimizely.com',
88
+ 'launchdarkly.com',
89
+ 'app.launchdarkly.com',
90
+ 'split.io',
91
+ 'cdn.split.io',
92
+ 'vwo.com',
93
+ 'd5nxst8fruw4z.cloudfront.net', // VWO
94
+ // Cookie consent (often blocks interaction)
95
+ 'cookiebot.com',
96
+ 'cdn.cookielaw.org',
97
+ 'consentmanager.net',
98
+ ];
99
+ /** Image file extension patterns */
100
+ export const IMAGE_PATTERNS = [
101
+ '.png',
102
+ '.jpg',
103
+ '.jpeg',
104
+ '.gif',
105
+ '.webp',
106
+ '.svg',
107
+ '.ico',
108
+ '.bmp',
109
+ '.avif',
110
+ ];
111
+ /** Media file extension patterns */
112
+ export const MEDIA_PATTERNS = [
113
+ '.mp4',
114
+ '.webm',
115
+ '.ogg',
116
+ '.mp3',
117
+ '.wav',
118
+ '.flac',
119
+ '.m4a',
120
+ '.avi',
121
+ '.mov',
122
+ ];
123
+ //# sourceMappingURL=block-patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block-patterns.js","sourceRoot":"","sources":["../../src/drivers/block-patterns.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,0EAA0E;AAC1E,MAAM,CAAC,MAAM,kBAAkB,GAAa;IAC1C,SAAS;IACT,sBAAsB;IACtB,sBAAsB;IACtB,uBAAuB;IACvB,sBAAsB;IACtB,mBAAmB;IACnB,iBAAiB;IACjB,6BAA6B;IAC7B,kBAAkB;IAClB,iBAAiB;IACjB,sBAAsB;IACtB,sBAAsB;IACtB,mBAAmB;IACnB,sBAAsB;IACtB,YAAY;IACZ,aAAa;IACb,iBAAiB;IACjB,cAAc;IACd,eAAe;IACf,mBAAmB;IACnB,mBAAmB;IACnB,SAAS;IACT,mBAAmB;IACnB,eAAe;IACf,kBAAkB;IAClB,YAAY;IACZ,mBAAmB;IACnB,mBAAmB;IACnB,YAAY;IACZ,eAAe;IACf,eAAe;IACf,eAAe;IACf,kBAAkB;IAClB,aAAa;IACb,iBAAiB;IACjB,cAAc;IACd,cAAc;IACd,cAAc;IACd,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,mBAAmB;IACnB,aAAa;IACb,cAAc;IACd,qBAAqB;IACrB,iBAAiB;IACjB,kBAAkB;IAClB,gBAAgB;IAChB,qBAAqB;IACrB,sBAAsB;IACtB,oBAAoB;IACpB,eAAe;IACf,uBAAuB;IACvB,iBAAiB;IACjB,wBAAwB;IACxB,eAAe;IACf,iBAAiB;IACjB,eAAe;IACf,aAAa;IACb,aAAa;IACb,uBAAuB;IACvB,oBAAoB;IACpB,oBAAoB;IACpB,eAAe;IACf,qBAAqB;IACrB,6BAA6B;IAC7B,8BAA8B;IAC9B,cAAc;IACd,kBAAkB;IAClB,sBAAsB;IACtB,gBAAgB;IAChB,iBAAiB;IACjB,uBAAuB;IACvB,kBAAkB;IAClB,eAAe;IACf,eAAe;IACf,cAAc;IACd,cAAc;IACd,gBAAgB;IAChB,oBAAoB;IACpB,wBAAwB;IACxB,kBAAkB;IAClB,sBAAsB;IACtB,UAAU;IACV,cAAc;IACd,SAAS;IACT,8BAA8B,EAAE,MAAM;IACtC,4CAA4C;IAC5C,eAAe;IACf,mBAAmB;IACnB,oBAAoB;CACrB,CAAC;AAEF,oCAAoC;AACpC,MAAM,CAAC,MAAM,cAAc,GAAa;IACtC,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;CACR,CAAC;AAEF,oCAAoC;AACpC,MAAM,CAAC,MAAM,cAAc,GAAa;IACtC,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;CACP,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * CDP-based batched page metadata retrieval.
3
+ *
4
+ * Replaces 3 separate Playwright calls (page.url(), page.title(),
5
+ * page.evaluate(testids)) with a single Runtime.evaluate via CDP.
6
+ */
7
+ import type { CDPSession } from 'playwright';
8
+ export interface PageMetadata {
9
+ url: string;
10
+ title: string;
11
+ testIds: Array<{
12
+ testId: string;
13
+ tag: string;
14
+ text: string;
15
+ disabled: boolean;
16
+ }>;
17
+ }
18
+ /**
19
+ * Get page URL, title, and data-testid elements in a single CDP call.
20
+ */
21
+ export declare function getPageMetadata(cdp: CDPSession): Promise<PageMetadata>;
22
+ //# sourceMappingURL=cdp-page-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp-page-state.d.ts","sourceRoot":"","sources":["../../src/drivers/cdp-page-state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,KAAK,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,OAAO,CAAC;KACnB,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CA6B5E"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * CDP-based batched page metadata retrieval.
3
+ *
4
+ * Replaces 3 separate Playwright calls (page.url(), page.title(),
5
+ * page.evaluate(testids)) with a single Runtime.evaluate via CDP.
6
+ */
7
+ /**
8
+ * Get page URL, title, and data-testid elements in a single CDP call.
9
+ */
10
+ export async function getPageMetadata(cdp) {
11
+ const { result } = await cdp.send('Runtime.evaluate', {
12
+ expression: `(() => {
13
+ const INTERACTIVE = new Set(['button', 'input', 'textarea', 'select', 'a']);
14
+ const elements = document.querySelectorAll('[data-testid]');
15
+ const testIds = Array.from(elements)
16
+ .filter(el => INTERACTIVE.has(el.tagName.toLowerCase()) || el.getAttribute('role'))
17
+ .slice(0, 30)
18
+ .map(el => ({
19
+ testId: el.getAttribute('data-testid') || '',
20
+ tag: el.tagName.toLowerCase(),
21
+ text: (el.textContent || '').trim().slice(0, 40),
22
+ disabled: el.disabled || false,
23
+ }));
24
+ return JSON.stringify({
25
+ url: location.href,
26
+ title: document.title,
27
+ testIds,
28
+ });
29
+ })()`,
30
+ returnByValue: true,
31
+ });
32
+ if (result.type === 'string') {
33
+ return JSON.parse(result.value);
34
+ }
35
+ // Fallback if evaluate returns unexpected format
36
+ return { url: '', title: '', testIds: [] };
37
+ }
38
+ //# sourceMappingURL=cdp-page-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp-page-state.js","sourceRoot":"","sources":["../../src/drivers/cdp-page-state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAeH;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAe;IACnD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE;QACpD,UAAU,EAAE;;;;;;;;;;;;;;;;;SAiBP;QACL,aAAa,EAAE,IAAI;KACpB,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAe,CAAiB,CAAC;IAC5D,CAAC;IAED,iDAAiD;IACjD,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * CDP-based accessibility tree snapshot.
3
+ *
4
+ * Uses Chrome DevTools Protocol `Accessibility.getFullAXTree` to get the
5
+ * accessibility tree directly as structured AXNode objects — bypassing
6
+ * Playwright's ariaSnapshot() which serializes to YAML then we regex-parse.
7
+ *
8
+ * Produces the same ref-annotated YAML format as the Playwright path so the
9
+ * rest of the system (Brain, resolveLocator) works unchanged.
10
+ */
11
+ import type { CDPSession } from 'playwright';
12
+ import type { ParsedElement } from './snapshot.js';
13
+ export interface CdpSnapshotResult {
14
+ /** Formatted snapshot (same YAML-like format as ariaSnapshot path) */
15
+ snapshot: string;
16
+ /** Ref map for resolveLocator integration */
17
+ refMap: Map<string, {
18
+ role: string;
19
+ name: string;
20
+ backendNodeId?: number;
21
+ }>;
22
+ /** Parsed elements for diff tracking */
23
+ elements: Map<string, ParsedElement>;
24
+ }
25
+ /**
26
+ * Build an accessibility tree snapshot via CDP.
27
+ *
28
+ * Calls `Accessibility.getFullAXTree`, reconstructs the tree structure,
29
+ * walks depth-first to produce indented YAML lines with stable ref IDs.
30
+ */
31
+ export declare function buildCdpSnapshot(cdp: CDPSession): Promise<CdpSnapshotResult>;
32
+ //# sourceMappingURL=cdp-snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp-snapshot.d.ts","sourceRoot":"","sources":["../../src/drivers/cdp-snapshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAgBnD,MAAM,WAAW,iBAAiB;IAChC,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5E,wCAAwC;IACxC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CACtC;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAoHlF"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * CDP-based accessibility tree snapshot.
3
+ *
4
+ * Uses Chrome DevTools Protocol `Accessibility.getFullAXTree` to get the
5
+ * accessibility tree directly as structured AXNode objects — bypassing
6
+ * Playwright's ariaSnapshot() which serializes to YAML then we regex-parse.
7
+ *
8
+ * Produces the same ref-annotated YAML format as the Playwright path so the
9
+ * rest of the system (Brain, resolveLocator) works unchanged.
10
+ */
11
+ import { stableHash, INTERACTIVE_ROLES } from './snapshot.js';
12
+ /**
13
+ * Build an accessibility tree snapshot via CDP.
14
+ *
15
+ * Calls `Accessibility.getFullAXTree`, reconstructs the tree structure,
16
+ * walks depth-first to produce indented YAML lines with stable ref IDs.
17
+ */
18
+ export async function buildCdpSnapshot(cdp) {
19
+ const { nodes } = await cdp.send('Accessibility.getFullAXTree');
20
+ if (!nodes || nodes.length === 0) {
21
+ return {
22
+ snapshot: '(empty page)',
23
+ refMap: new Map(),
24
+ elements: new Map(),
25
+ };
26
+ }
27
+ // Build lookup: nodeId -> AXNode
28
+ const nodeMap = new Map();
29
+ for (const node of nodes) {
30
+ nodeMap.set(node.nodeId, node);
31
+ }
32
+ // Find root nodes (nodes without parentId, or first node)
33
+ const rootIds = [];
34
+ for (const node of nodes) {
35
+ if (!node.parentId) {
36
+ rootIds.push(node.nodeId);
37
+ }
38
+ }
39
+ // Fallback: if no roots found, use first node
40
+ if (rootIds.length === 0 && nodes.length > 0) {
41
+ rootIds.push(nodes[0].nodeId);
42
+ }
43
+ const refMap = new Map();
44
+ const elements = new Map();
45
+ const hashCounts = new Map();
46
+ const lines = [];
47
+ // Structural/invisible roles — skip the node itself but recurse into children
48
+ const SKIP_ROLES = new Set([
49
+ 'none', 'generic', 'InlineTextBox', 'LineBreak',
50
+ 'StaticText', 'RootWebArea', 'WebArea',
51
+ ]);
52
+ function walk(nodeId, depth) {
53
+ const node = nodeMap.get(nodeId);
54
+ if (!node)
55
+ return;
56
+ // Ignored nodes: still recurse into children (Chrome marks structural
57
+ // nodes like <html>/<body> as ignored while their children are not)
58
+ if (node.ignored) {
59
+ if (node.childIds) {
60
+ for (const childId of node.childIds) {
61
+ walk(childId, depth);
62
+ }
63
+ }
64
+ return;
65
+ }
66
+ const role = node.role?.value;
67
+ if (!role || SKIP_ROLES.has(role)) {
68
+ // No role or structural role — recurse into children at same depth
69
+ if (node.childIds) {
70
+ for (const childId of node.childIds) {
71
+ walk(childId, depth);
72
+ }
73
+ }
74
+ return;
75
+ }
76
+ const name = node.name?.value || '';
77
+ const value = node.value?.value;
78
+ const indent = ' '.repeat(depth);
79
+ // Determine if this element gets a ref
80
+ const needsRef = INTERACTIVE_ROLES.has(role) || (name && role !== 'text');
81
+ let refStr = '';
82
+ if (needsRef) {
83
+ const baseHash = stableHash(role, name);
84
+ const count = hashCounts.get(baseHash) || 0;
85
+ hashCounts.set(baseHash, count + 1);
86
+ const refId = count === 0 ? baseHash : `${baseHash}_${count}`;
87
+ refMap.set(refId, { role, name, backendNodeId: node.backendDOMNodeId });
88
+ elements.set(refId, { ref: refId, role, name, value });
89
+ refStr = ` [ref=${refId}]`;
90
+ }
91
+ const nameStr = name ? ` "${name}"` : '';
92
+ const valueStr = value !== undefined ? ` [value="${value}"]` : '';
93
+ // Check if node has visible children (not just StaticText/InlineTextBox)
94
+ const hasVisibleChildren = node.childIds?.some((cid) => {
95
+ const child = nodeMap.get(cid);
96
+ if (!child)
97
+ return false;
98
+ if (child.ignored)
99
+ return child.childIds?.length ? true : false;
100
+ const cRole = child.role?.value;
101
+ return cRole && !SKIP_ROLES.has(cRole);
102
+ }) ?? false;
103
+ const colon = hasVisibleChildren ? ':' : '';
104
+ lines.push(`${indent}- ${role}${nameStr}${refStr}${valueStr}${colon}`);
105
+ if (node.childIds) {
106
+ for (const childId of node.childIds) {
107
+ walk(childId, depth + 1);
108
+ }
109
+ }
110
+ }
111
+ for (const rootId of rootIds) {
112
+ walk(rootId, 0);
113
+ }
114
+ return {
115
+ snapshot: lines.length > 0 ? lines.join('\n') : '(empty page)',
116
+ refMap,
117
+ elements,
118
+ };
119
+ }
120
+ //# sourceMappingURL=cdp-snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp-snapshot.js","sourceRoot":"","sources":["../../src/drivers/cdp-snapshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAwB9D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAe;IACpD,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,6BAA6B,CAAwB,CAAC;IAEvF,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO;YACL,QAAQ,EAAE,cAAc;YACxB,MAAM,EAAE,IAAI,GAAG,EAAE;YACjB,QAAQ,EAAE,IAAI,GAAG,EAAE;SACpB,CAAC;IACJ,CAAC;IAED,iCAAiC;IACjC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;IAED,0DAA0D;IAC1D,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,8CAA8C;IAC9C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7C,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkE,CAAC;IACzF,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAC;IAClD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC7C,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,8EAA8E;IAC9E,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;QACzB,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,WAAW;QAC/C,YAAY,EAAE,aAAa,EAAE,SAAS;KACvC,CAAC,CAAC;IAEH,SAAS,IAAI,CAAC,MAAc,EAAE,KAAa;QACzC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,IAAI;YAAE,OAAO;QAElB,sEAAsE;QACtE,oEAAoE;QACpE,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACpC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;gBACvB,CAAC;YACH,CAAC;YACD,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;QAC9B,IAAI,CAAC,IAAI,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,mEAAmE;YACnE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACpC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;gBACvB,CAAC;YACH,CAAC;YACD,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC;QAChC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAElC,uCAAuC;QACvC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,MAAM,CAAC,CAAC;QAE1E,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACxC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC5C,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YACpC,MAAM,KAAK,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,KAAK,EAAE,CAAC;YAE9D,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC;YACxE,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YACvD,MAAM,GAAG,SAAS,KAAK,GAAG,CAAC;QAC7B,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,MAAM,QAAQ,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAElE,yEAAyE;QACzE,MAAM,kBAAkB,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;YACrD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,CAAC,KAAK;gBAAE,OAAO,KAAK,CAAC;YACzB,IAAI,KAAK,CAAC,OAAO;gBAAE,OAAO,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;YAChE,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC;YAChC,OAAO,KAAK,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACzC,CAAC,CAAC,IAAI,KAAK,CAAC;QACZ,MAAM,KAAK,GAAG,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAE5C,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,KAAK,IAAI,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,EAAE,CAAC,CAAC;QAEvE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACpC,IAAI,CAAC,OAAO,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,cAAc;QAC9D,MAAM;QACN,QAAQ;KACT,CAAC;AACJ,CAAC"}