@tangle-network/browser-agent-driver 0.8.7 → 0.11.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.
- package/README.md +2 -2
- package/dist/brain/index.d.ts +2 -0
- package/dist/brain/index.d.ts.map +1 -1
- package/dist/brain/index.js +96 -10
- package/dist/brain/index.js.map +1 -1
- package/dist/browser-launch.d.ts +3 -0
- package/dist/browser-launch.d.ts.map +1 -1
- package/dist/browser-launch.js +12 -2
- package/dist/browser-launch.js.map +1 -1
- package/dist/cli-design-audit.d.ts.map +1 -1
- package/dist/cli-design-audit.js +250 -2
- package/dist/cli-design-audit.js.map +1 -1
- package/dist/cli-showcase.d.ts +28 -0
- package/dist/cli-showcase.d.ts.map +1 -0
- package/dist/cli-showcase.js +131 -0
- package/dist/cli-showcase.js.map +1 -0
- package/dist/cli-ui.d.ts.map +1 -1
- package/dist/cli-ui.js +35 -2
- package/dist/cli-ui.js.map +1 -1
- package/dist/cli.js +462 -217
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +5 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -2
- package/dist/config.js.map +1 -1
- package/dist/design/compare.d.ts +9 -0
- package/dist/design/compare.d.ts.map +1 -0
- package/dist/design/compare.js +339 -0
- package/dist/design/compare.js.map +1 -0
- package/dist/design/index.d.ts +6 -0
- package/dist/design/index.d.ts.map +1 -0
- package/dist/design/index.js +5 -0
- package/dist/design/index.js.map +1 -0
- package/dist/design/page-interaction.d.ts +24 -0
- package/dist/design/page-interaction.d.ts.map +1 -0
- package/dist/design/page-interaction.js +244 -0
- package/dist/design/page-interaction.js.map +1 -0
- package/dist/design/rip.d.ts +9 -0
- package/dist/design/rip.d.ts.map +1 -0
- package/dist/design/rip.js +362 -0
- package/dist/design/rip.js.map +1 -0
- package/dist/design/types.d.ts +126 -0
- package/dist/design/types.d.ts.map +1 -0
- package/dist/design/types.js +3 -0
- package/dist/design/types.js.map +1 -0
- package/dist/design-audit.js +2 -2
- package/dist/design-audit.js.map +1 -1
- package/dist/index.d.ts +10 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/memory/knowledge.d.ts +25 -9
- package/dist/memory/knowledge.d.ts.map +1 -1
- package/dist/memory/knowledge.js +94 -28
- package/dist/memory/knowledge.js.map +1 -1
- package/dist/memory/run-registry.d.ts +85 -0
- package/dist/memory/run-registry.d.ts.map +1 -0
- package/dist/memory/run-registry.js +144 -0
- package/dist/memory/run-registry.js.map +1 -0
- package/dist/multi-actor.d.ts +3 -3
- package/dist/multi-actor.d.ts.map +1 -1
- package/dist/multi-actor.js +3 -3
- package/dist/multi-actor.js.map +1 -1
- package/dist/runner/index.d.ts +2 -2
- package/dist/runner/index.d.ts.map +1 -1
- package/dist/runner/index.js +1 -1
- package/dist/runner/index.js.map +1 -1
- package/dist/runner/runner.d.ts +9 -5
- package/dist/runner/runner.d.ts.map +1 -1
- package/dist/runner/runner.js +95 -22
- package/dist/runner/runner.js.map +1 -1
- package/dist/runner.d.ts +2 -2
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +1 -1
- package/dist/runner.js.map +1 -1
- package/dist/showcase/annotate.d.ts +28 -0
- package/dist/showcase/annotate.d.ts.map +1 -0
- package/dist/showcase/annotate.js +95 -0
- package/dist/showcase/annotate.js.map +1 -0
- package/dist/showcase/assemble.d.ts +31 -0
- package/dist/showcase/assemble.d.ts.map +1 -0
- package/dist/showcase/assemble.js +107 -0
- package/dist/showcase/assemble.js.map +1 -0
- package/dist/showcase/demo-player.d.ts +53 -0
- package/dist/showcase/demo-player.d.ts.map +1 -0
- package/dist/showcase/demo-player.js +325 -0
- package/dist/showcase/demo-player.js.map +1 -0
- package/dist/showcase/index.d.ts +21 -0
- package/dist/showcase/index.d.ts.map +1 -0
- package/dist/showcase/index.js +289 -0
- package/dist/showcase/index.js.map +1 -0
- package/dist/showcase/types.d.ts +111 -0
- package/dist/showcase/types.d.ts.map +1 -0
- package/dist/showcase/types.js +3 -0
- package/dist/showcase/types.js.map +1 -0
- package/dist/test-runner.d.ts +1 -0
- package/dist/test-runner.d.ts.map +1 -1
- package/dist/test-runner.js +26 -2
- package/dist/test-runner.js.map +1 -1
- package/dist/types.d.ts +32 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +11 -1
package/dist/cli.js
CHANGED
|
@@ -21,6 +21,8 @@ import { isPersonaId, listPersonaIds, withPersonaDirective } from './personas.js
|
|
|
21
21
|
import { resolveProviderApiKey, resolveProviderModelName } from './provider-defaults.js';
|
|
22
22
|
import { loadLocalEnvFiles } from './env-loader.js';
|
|
23
23
|
import { CliRenderer, cliError, cliWarn, cliLog, printStyledHelp } from './cli-ui.js';
|
|
24
|
+
import { ProjectStore } from './memory/project-store.js';
|
|
25
|
+
import { RunRegistry } from './memory/run-registry.js';
|
|
24
26
|
const RUN_MODES = ['fast-explore', 'full-evidence'];
|
|
25
27
|
const DRIVER_PROFILES = ['default', 'stealth', 'benchmark-webbench', 'benchmark-webbench-stealth', 'benchmark-webvoyager'];
|
|
26
28
|
async function applyStorageStateToPersistentContext(context, storageStatePath) {
|
|
@@ -94,8 +96,23 @@ async function main() {
|
|
|
94
96
|
'storage-state': { type: 'string' },
|
|
95
97
|
concurrency: { type: 'string' },
|
|
96
98
|
'max-turns': { type: 'string' },
|
|
99
|
+
'session-id': { type: 'string' },
|
|
100
|
+
'resume-run': { type: 'string' },
|
|
101
|
+
'fork-run': { type: 'string' },
|
|
97
102
|
pages: { type: 'string' },
|
|
98
103
|
'extract-tokens': { type: 'boolean' },
|
|
104
|
+
rip: { type: 'boolean' },
|
|
105
|
+
'design-compare': { type: 'boolean' },
|
|
106
|
+
'compare-url': { type: 'string' },
|
|
107
|
+
// showcase
|
|
108
|
+
script: { type: 'string' },
|
|
109
|
+
capture: { type: 'string' },
|
|
110
|
+
crop: { type: 'string' },
|
|
111
|
+
highlight: { type: 'string' },
|
|
112
|
+
format: { type: 'string' },
|
|
113
|
+
viewport: { type: 'string' },
|
|
114
|
+
scale: { type: 'string' },
|
|
115
|
+
'color-scheme': { type: 'string' },
|
|
99
116
|
'llm-timeout': { type: 'string' },
|
|
100
117
|
retries: { type: 'string' },
|
|
101
118
|
'retry-delay-ms': { type: 'string' },
|
|
@@ -111,6 +128,8 @@ async function main() {
|
|
|
111
128
|
timeout: { type: 'string' },
|
|
112
129
|
extension: { type: 'string', multiple: true },
|
|
113
130
|
'user-data-dir': { type: 'string' },
|
|
131
|
+
'profile-dir': { type: 'string' },
|
|
132
|
+
'cdp-url': { type: 'string' },
|
|
114
133
|
wallet: { type: 'boolean' },
|
|
115
134
|
'wallet-auto-approve': { type: 'boolean' },
|
|
116
135
|
'wallet-password': { type: 'string' },
|
|
@@ -155,6 +174,32 @@ async function main() {
|
|
|
155
174
|
cliError('--url is required for design-audit.');
|
|
156
175
|
process.exit(1);
|
|
157
176
|
}
|
|
177
|
+
// --design-compare mode
|
|
178
|
+
if (values['design-compare']) {
|
|
179
|
+
if (!values['compare-url']) {
|
|
180
|
+
cliError('--compare-url is required with --design-compare.');
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
const { runDesignCompare } = await import('./design/compare.js');
|
|
184
|
+
await runDesignCompare({
|
|
185
|
+
urlA: values.url,
|
|
186
|
+
urlB: values['compare-url'],
|
|
187
|
+
headless: values.headless,
|
|
188
|
+
outputDir: values.sink,
|
|
189
|
+
});
|
|
190
|
+
process.exit(0);
|
|
191
|
+
}
|
|
192
|
+
// --rip mode
|
|
193
|
+
if (values.rip) {
|
|
194
|
+
const { ripSite } = await import('./design/rip.js');
|
|
195
|
+
await ripSite({
|
|
196
|
+
url: values.url,
|
|
197
|
+
pages: values.pages ? parseInt(values.pages) : undefined,
|
|
198
|
+
headless: values.headless,
|
|
199
|
+
outputDir: values.sink,
|
|
200
|
+
});
|
|
201
|
+
process.exit(0);
|
|
202
|
+
}
|
|
158
203
|
const { runDesignAudit } = await import('./cli-design-audit.js');
|
|
159
204
|
await runDesignAudit({
|
|
160
205
|
url: values.url,
|
|
@@ -171,13 +216,64 @@ async function main() {
|
|
|
171
216
|
});
|
|
172
217
|
process.exit(0);
|
|
173
218
|
}
|
|
219
|
+
if (command === 'runs') {
|
|
220
|
+
const store = new ProjectStore(values['memory-dir']);
|
|
221
|
+
const registry = new RunRegistry(store.getRoot());
|
|
222
|
+
const runs = registry.listRuns({
|
|
223
|
+
domain: values.url ? new URL(values.url).hostname : undefined,
|
|
224
|
+
sessionId: values['session-id'],
|
|
225
|
+
limit: 20,
|
|
226
|
+
});
|
|
227
|
+
if (runs.length === 0) {
|
|
228
|
+
console.log(' No runs found.');
|
|
229
|
+
}
|
|
230
|
+
else if (values.json) {
|
|
231
|
+
console.log(JSON.stringify(runs, null, 2));
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
for (const r of runs) {
|
|
235
|
+
const icon = r.status === 'completed' ? (r.success ? '\u2713' : '\u2717') : '\u25cb';
|
|
236
|
+
const ts = r.startedAt.slice(0, 16).replace('T', ' ');
|
|
237
|
+
const dur = r.completedAt
|
|
238
|
+
? `${Math.round((new Date(r.completedAt).getTime() - new Date(r.startedAt).getTime()) / 1000)}s`
|
|
239
|
+
: 'running';
|
|
240
|
+
const session = r.sessionId ? ` [${r.sessionId}]` : '';
|
|
241
|
+
const parent = r.parentRunId ? ` \u2190 ${r.parentRunId.slice(0, 20)}` : '';
|
|
242
|
+
console.log(` ${icon} ${r.runId.slice(0, 30)} ${ts} ${dur} ${r.goal.slice(0, 50)}${session}${parent}`);
|
|
243
|
+
if (r.summary)
|
|
244
|
+
console.log(` ${r.summary.slice(0, 80)}`);
|
|
245
|
+
if (r.finalUrl)
|
|
246
|
+
console.log(` ${r.finalUrl}`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
process.exit(0);
|
|
250
|
+
}
|
|
251
|
+
if (command === 'showcase') {
|
|
252
|
+
const { handleShowcase } = await import('./cli-showcase.js');
|
|
253
|
+
await handleShowcase({
|
|
254
|
+
url: values.url,
|
|
255
|
+
script: values.script,
|
|
256
|
+
capture: values.capture,
|
|
257
|
+
crop: values.crop,
|
|
258
|
+
highlight: values.highlight,
|
|
259
|
+
format: values.format,
|
|
260
|
+
viewport: values.viewport,
|
|
261
|
+
output: values.sink,
|
|
262
|
+
headless: values.headless ?? true,
|
|
263
|
+
colorScheme: values['color-scheme'],
|
|
264
|
+
scale: values.scale ? parseFloat(values.scale) : undefined,
|
|
265
|
+
storageState: values['storage-state'],
|
|
266
|
+
quality: values['quality-threshold'] ? parseInt(values['quality-threshold']) : undefined,
|
|
267
|
+
});
|
|
268
|
+
process.exit(0);
|
|
269
|
+
}
|
|
174
270
|
if (command !== 'run') {
|
|
175
|
-
cliError(`Unknown command: ${command}. Use "run"
|
|
271
|
+
cliError(`Unknown command: ${command}. Use "run", "runs", "design-audit", or "showcase".`);
|
|
176
272
|
process.exit(1);
|
|
177
273
|
}
|
|
178
274
|
// Validate inputs
|
|
179
|
-
if (!values.goal && !values.cases) {
|
|
180
|
-
cliError('provide --goal "..." --url "..." for a single task,
|
|
275
|
+
if (!values.goal && !values.cases && !values['resume-run'] && !values['fork-run']) {
|
|
276
|
+
cliError('provide --goal "..." --url "..." for a single task, --cases ./cases.json for a suite, or --resume-run / --fork-run <runId>.');
|
|
181
277
|
process.exit(1);
|
|
182
278
|
}
|
|
183
279
|
// Load config file, then overlay CLI flags
|
|
@@ -341,6 +437,10 @@ async function main() {
|
|
|
341
437
|
}
|
|
342
438
|
}
|
|
343
439
|
}
|
|
440
|
+
if (values['profile-dir'])
|
|
441
|
+
cliOverrides.profileDir = values['profile-dir'];
|
|
442
|
+
if (values['cdp-url'])
|
|
443
|
+
cliOverrides.cdpUrl = values['cdp-url'];
|
|
344
444
|
if (values.memory !== undefined || values['memory-dir']) {
|
|
345
445
|
cliOverrides.memory = {
|
|
346
446
|
...(cliOverrides.memory ?? {}),
|
|
@@ -401,12 +501,8 @@ async function main() {
|
|
|
401
501
|
cliOverrides.resourceBlocking = {
|
|
402
502
|
...(cliOverrides.resourceBlocking ?? {}),
|
|
403
503
|
blockAnalytics: true,
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
blockImages: true,
|
|
407
|
-
blockMedia: true,
|
|
408
|
-
}
|
|
409
|
-
: {}),
|
|
504
|
+
blockImages: true,
|
|
505
|
+
blockMedia: true,
|
|
410
506
|
};
|
|
411
507
|
}
|
|
412
508
|
cliOverrides.microPlan = {
|
|
@@ -517,9 +613,49 @@ async function main() {
|
|
|
517
613
|
walletMode: Boolean(driverConfig.wallet?.enabled),
|
|
518
614
|
walletAddress: driverConfig.wallet?.address,
|
|
519
615
|
};
|
|
616
|
+
// Create project store for memory + run registry
|
|
617
|
+
const memoryEnabled = driverConfig.memory?.enabled === true;
|
|
618
|
+
const projectStore = memoryEnabled
|
|
619
|
+
? new ProjectStore(driverConfig.memory?.dir)
|
|
620
|
+
: undefined;
|
|
621
|
+
const runRegistry = projectStore
|
|
622
|
+
? new RunRegistry(projectStore.getRoot())
|
|
623
|
+
: undefined;
|
|
520
624
|
// Build test cases
|
|
521
625
|
let cases;
|
|
522
|
-
if (values
|
|
626
|
+
if (values['resume-run'] || values['fork-run']) {
|
|
627
|
+
// Resume or fork from a previous run
|
|
628
|
+
if (!runRegistry) {
|
|
629
|
+
cliError('--resume-run and --fork-run require memory to be enabled');
|
|
630
|
+
process.exit(1);
|
|
631
|
+
}
|
|
632
|
+
const isResume = Boolean(values['resume-run']);
|
|
633
|
+
const sourceRunId = (values['resume-run'] || values['fork-run']);
|
|
634
|
+
const scenario = isResume
|
|
635
|
+
? runRegistry.buildResumeScenario(sourceRunId, values.goal)
|
|
636
|
+
: runRegistry.buildForkScenario(sourceRunId, values.goal || '');
|
|
637
|
+
if (!scenario) {
|
|
638
|
+
cliError(`run "${sourceRunId}" not found in registry`);
|
|
639
|
+
process.exit(1);
|
|
640
|
+
}
|
|
641
|
+
if (!isResume && !values.goal) {
|
|
642
|
+
cliError('--fork-run requires --goal');
|
|
643
|
+
process.exit(1);
|
|
644
|
+
}
|
|
645
|
+
cases = [{
|
|
646
|
+
id: `${isResume ? 'resume' : 'fork'}-${sourceRunId.slice(0, 20)}`,
|
|
647
|
+
name: scenario.goal.slice(0, 60),
|
|
648
|
+
startUrl: values.url || scenario.startUrl,
|
|
649
|
+
goal: scenario.goal,
|
|
650
|
+
allowedDomains: parseAllowedDomains(values['allowed-domains']),
|
|
651
|
+
maxTurns,
|
|
652
|
+
timeoutMs,
|
|
653
|
+
priority: 0,
|
|
654
|
+
sessionId: scenario.sessionId,
|
|
655
|
+
parentRunId: scenario.parentRunId,
|
|
656
|
+
}];
|
|
657
|
+
}
|
|
658
|
+
else if (values.cases) {
|
|
523
659
|
const raw = fs.readFileSync(path.resolve(values.cases), 'utf-8');
|
|
524
660
|
const parsed = JSON.parse(raw);
|
|
525
661
|
const rawCases = Array.isArray(parsed) ? parsed : [parsed];
|
|
@@ -547,8 +683,14 @@ async function main() {
|
|
|
547
683
|
maxTurns,
|
|
548
684
|
timeoutMs,
|
|
549
685
|
priority: 0,
|
|
686
|
+
sessionId: values['session-id'],
|
|
550
687
|
}];
|
|
551
688
|
}
|
|
689
|
+
// Apply --session-id to all cases from file too
|
|
690
|
+
if (values['session-id'] && cases.length > 0 && cases[0].id !== 'cli-task') {
|
|
691
|
+
const sid = values['session-id'];
|
|
692
|
+
cases = cases.map(c => ({ ...c, sessionId: c.sessionId || sid }));
|
|
693
|
+
}
|
|
552
694
|
const persona = values.persona;
|
|
553
695
|
if (persona) {
|
|
554
696
|
if (!isPersonaId(persona)) {
|
|
@@ -594,9 +736,9 @@ async function main() {
|
|
|
594
736
|
cliError(`storage state file not found: ${storageStatePath}`);
|
|
595
737
|
process.exit(1);
|
|
596
738
|
}
|
|
597
|
-
if (launchPlan.
|
|
598
|
-
|
|
599
|
-
|
|
739
|
+
if (launchPlan.persistentContext && !launchPlan.cdpUrl && browserName !== 'chromium') {
|
|
740
|
+
const feature = launchPlan.walletMode ? 'Wallet mode' : '--profile-dir';
|
|
741
|
+
throw new Error(`${feature} requires Chromium. Set --browser chromium.`);
|
|
600
742
|
}
|
|
601
743
|
// Ensure clean exit on interrupt
|
|
602
744
|
process.on('SIGINT', () => { renderer?.destroy(); process.exit(130); });
|
|
@@ -607,145 +749,179 @@ async function main() {
|
|
|
607
749
|
let persistentContext;
|
|
608
750
|
let stopWalletAutoApprover;
|
|
609
751
|
const launchDiagnostics = {};
|
|
610
|
-
|
|
752
|
+
// CDP connection — attach to an existing browser (Atlas, Chrome, Brave, etc.)
|
|
753
|
+
let cdpUrl = launchPlan.cdpUrl || process.env.BROWSER_ENDPOINT;
|
|
754
|
+
let cdpConnected = false;
|
|
755
|
+
if (cdpUrl) {
|
|
756
|
+
// Auto-discover WebSocket URL from HTTP endpoint
|
|
757
|
+
if (cdpUrl.startsWith('http://') || cdpUrl.startsWith('https://')) {
|
|
758
|
+
try {
|
|
759
|
+
const versionUrl = cdpUrl.replace(/\/$/, '') + '/json/version';
|
|
760
|
+
const res = await fetch(versionUrl);
|
|
761
|
+
const info = await res.json();
|
|
762
|
+
if (info.webSocketDebuggerUrl) {
|
|
763
|
+
if (info.Browser && !quiet)
|
|
764
|
+
cliLog('cdp', `connected to ${info.Browser}`);
|
|
765
|
+
cdpUrl = info.webSocketDebuggerUrl;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
catch {
|
|
769
|
+
// Fall through — try the URL as-is
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
const cdpStartedAt = Date.now();
|
|
773
|
+
if (cdpUrl.includes('/devtools/') || browserName === 'chromium') {
|
|
774
|
+
browser = await chromium.connectOverCDP(cdpUrl);
|
|
775
|
+
}
|
|
776
|
+
else {
|
|
777
|
+
const browserType = browserName === 'firefox' ? firefox : browserName === 'webkit' ? webkit : chromium;
|
|
778
|
+
browser = await browserType.connect(cdpUrl);
|
|
779
|
+
}
|
|
780
|
+
launchDiagnostics.browserLaunchMs = Date.now() - cdpStartedAt;
|
|
781
|
+
launchDiagnostics.cdpUrl = cdpUrl;
|
|
782
|
+
cdpConnected = true;
|
|
783
|
+
}
|
|
784
|
+
else if (launchPlan.persistentContext) {
|
|
611
785
|
for (const extensionPath of launchPlan.extensionPaths) {
|
|
612
786
|
if (!fs.existsSync(extensionPath)) {
|
|
613
787
|
throw new Error(`Wallet extension path does not exist: ${extensionPath}`);
|
|
614
788
|
}
|
|
615
789
|
}
|
|
616
|
-
const userDataDir = launchPlan.userDataDir ?? path.resolve('.agent-wallet-profile');
|
|
790
|
+
const userDataDir = launchPlan.userDataDir ?? path.resolve(launchPlan.walletMode ? '.agent-wallet-profile' : '.agent-profile');
|
|
617
791
|
fs.mkdirSync(userDataDir, { recursive: true });
|
|
618
792
|
const persistentLaunchStartedAt = Date.now();
|
|
619
793
|
persistentContext = await chromium.launchPersistentContext(userDataDir, {
|
|
620
794
|
channel: isStealthProfile ? 'chrome' : 'chromium',
|
|
621
|
-
headless:
|
|
795
|
+
headless: launchPlan.headless,
|
|
622
796
|
args: launchPlan.browserArgs,
|
|
623
797
|
viewport,
|
|
624
798
|
recordVideo: { dir: videoDir, size: viewport },
|
|
625
799
|
});
|
|
626
800
|
launchDiagnostics.browserLaunchMs = Date.now() - persistentLaunchStartedAt;
|
|
627
801
|
await applyStorageStateToPersistentContext(persistentContext, storageStatePath);
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
802
|
+
if (launchPlan.walletMode) {
|
|
803
|
+
const walletConfig = driverConfig.wallet ?? {};
|
|
804
|
+
// Intercept page-level JSON-RPC so dApps see wallet balances from the
|
|
805
|
+
// local Anvil fork. Only forward user-specific calls (eth_getBalance
|
|
806
|
+
// for the wallet, eth_call with wallet address in calldata). Pool data
|
|
807
|
+
// and protocol calls go to real endpoints for reliability.
|
|
808
|
+
const walletRpcUrl = walletConfig.preflight?.chain?.rpcUrl;
|
|
809
|
+
if (walletRpcUrl) {
|
|
810
|
+
// Default to Anvil's first derived address if no wallet address configured
|
|
811
|
+
const walletAddrFull = (walletConfig.address ?? '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266').toLowerCase();
|
|
812
|
+
const walletAddrHex = walletAddrFull.replace('0x', '');
|
|
813
|
+
await persistentContext.route('**/*', async (route) => {
|
|
814
|
+
try {
|
|
815
|
+
const frame = route.request().frame();
|
|
816
|
+
if (frame && frame.url().startsWith('chrome-extension://')) {
|
|
817
|
+
await route.continue();
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
catch {
|
|
642
822
|
await route.continue();
|
|
643
823
|
return;
|
|
644
824
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
const items = Array.isArray(body) ? body : [body];
|
|
667
|
-
// Check if any item involves the wallet (balance, contract call, simulation)
|
|
668
|
-
const isUserQuery = items.some((item) => {
|
|
669
|
-
const method = item.method;
|
|
670
|
-
if (!method)
|
|
671
|
-
return false;
|
|
672
|
-
if (method === 'eth_getBalance') {
|
|
673
|
-
const params = item.params;
|
|
674
|
-
return params?.[0]?.toLowerCase() === walletAddrFull;
|
|
675
|
-
}
|
|
676
|
-
if (method === 'eth_call' || method === 'eth_estimateGas') {
|
|
677
|
-
const params = item.params;
|
|
678
|
-
const txObj = params?.[0];
|
|
679
|
-
if (!txObj)
|
|
825
|
+
if (route.request().method() !== 'POST') {
|
|
826
|
+
await route.continue();
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
const ct = route.request().headers()['content-type'] ?? '';
|
|
830
|
+
if (!ct.includes('json')) {
|
|
831
|
+
await route.continue();
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
const postData = route.request().postData();
|
|
835
|
+
if (!postData) {
|
|
836
|
+
await route.continue();
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
try {
|
|
840
|
+
const body = JSON.parse(postData);
|
|
841
|
+
const items = Array.isArray(body) ? body : [body];
|
|
842
|
+
// Check if any item involves the wallet (balance, contract call, simulation)
|
|
843
|
+
const isUserQuery = items.some((item) => {
|
|
844
|
+
const method = item.method;
|
|
845
|
+
if (!method)
|
|
680
846
|
return false;
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
847
|
+
if (method === 'eth_getBalance') {
|
|
848
|
+
const params = item.params;
|
|
849
|
+
return params?.[0]?.toLowerCase() === walletAddrFull;
|
|
850
|
+
}
|
|
851
|
+
if (method === 'eth_call' || method === 'eth_estimateGas') {
|
|
852
|
+
const params = item.params;
|
|
853
|
+
const txObj = params?.[0];
|
|
854
|
+
if (!txObj)
|
|
855
|
+
return false;
|
|
856
|
+
const from = txObj.from?.toLowerCase() ?? '';
|
|
857
|
+
const data = txObj.data?.toLowerCase() ?? '';
|
|
858
|
+
return from === walletAddrFull || data.includes(walletAddrHex);
|
|
859
|
+
}
|
|
860
|
+
if (method === 'eth_getTransactionCount') {
|
|
861
|
+
const params = item.params;
|
|
862
|
+
return params?.[0]?.toLowerCase() === walletAddrFull;
|
|
863
|
+
}
|
|
864
|
+
return false;
|
|
865
|
+
});
|
|
866
|
+
if (!isUserQuery) {
|
|
867
|
+
await route.continue();
|
|
868
|
+
return;
|
|
688
869
|
}
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
870
|
+
// Normalize: some dApps (Aave) omit jsonrpc/id — Anvil requires them
|
|
871
|
+
let nextId = 1;
|
|
872
|
+
const normalized = items.map((item) => {
|
|
873
|
+
const out = { ...item, jsonrpc: '2.0', id: item.id ?? nextId++ };
|
|
874
|
+
delete out.chainId;
|
|
875
|
+
return out;
|
|
876
|
+
});
|
|
877
|
+
const payload = Array.isArray(body) ? normalized : normalized[0];
|
|
878
|
+
const res = await fetch(walletRpcUrl, {
|
|
879
|
+
method: 'POST',
|
|
880
|
+
headers: { 'Content-Type': 'application/json' },
|
|
881
|
+
body: JSON.stringify(payload),
|
|
882
|
+
});
|
|
883
|
+
await route.fulfill({
|
|
884
|
+
status: res.status,
|
|
885
|
+
contentType: 'application/json',
|
|
886
|
+
body: await res.text(),
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
catch {
|
|
692
890
|
await route.continue();
|
|
693
|
-
return;
|
|
694
891
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
const shouldAutoApprove = walletConfig.autoApprove ?? true;
|
|
895
|
+
if (shouldAutoApprove) {
|
|
896
|
+
stopWalletAutoApprover = await startWalletAutoApprover(persistentContext, {
|
|
897
|
+
password: walletConfig.password,
|
|
898
|
+
tickMs: walletConfig.tickMs,
|
|
899
|
+
actionSelectors: walletConfig.actionSelectors,
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
const preflightEnabled = walletConfig.preflight?.enabled ?? true;
|
|
903
|
+
const preflightSeedUrls = walletConfig.preflight?.seedUrls && walletConfig.preflight.seedUrls.length > 0
|
|
904
|
+
? walletConfig.preflight.seedUrls
|
|
905
|
+
: [...new Set(cases.map((testCase) => testCase.startUrl).filter(Boolean))];
|
|
906
|
+
if (preflightEnabled && preflightSeedUrls.length > 0) {
|
|
907
|
+
const preflight = await runWalletPreflight(persistentContext, {
|
|
908
|
+
seedUrls: preflightSeedUrls,
|
|
909
|
+
password: walletConfig.password,
|
|
910
|
+
actionSelectors: walletConfig.actionSelectors,
|
|
911
|
+
promptPaths: walletConfig.promptPaths,
|
|
912
|
+
connectSelectors: walletConfig.connectSelectors,
|
|
913
|
+
connectorSelectors: walletConfig.connectorSelectors,
|
|
914
|
+
requestAccounts: walletConfig.preflight?.requestAccounts,
|
|
915
|
+
accountsTimeoutMs: walletConfig.preflight?.accountsTimeoutMs,
|
|
916
|
+
maxChainSwitchAttempts: walletConfig.preflight?.maxChainSwitchAttempts,
|
|
917
|
+
chain: walletConfig.preflight?.chain,
|
|
918
|
+
log: quiet ? undefined : (message) => cliLog('wallet', message),
|
|
919
|
+
});
|
|
920
|
+
if (!preflight.ok) {
|
|
921
|
+
const failed = preflight.results.find((resultEntry) => !resultEntry.ready);
|
|
922
|
+
const details = failed?.details ?? 'unknown reason';
|
|
923
|
+
throw new Error(`Wallet preflight failed for ${preflight.failedUrl ?? 'unknown origin'} (${details})`);
|
|
716
924
|
}
|
|
717
|
-
});
|
|
718
|
-
}
|
|
719
|
-
const shouldAutoApprove = walletConfig.autoApprove ?? true;
|
|
720
|
-
if (shouldAutoApprove) {
|
|
721
|
-
stopWalletAutoApprover = await startWalletAutoApprover(persistentContext, {
|
|
722
|
-
password: walletConfig.password,
|
|
723
|
-
tickMs: walletConfig.tickMs,
|
|
724
|
-
actionSelectors: walletConfig.actionSelectors,
|
|
725
|
-
});
|
|
726
|
-
}
|
|
727
|
-
const preflightEnabled = walletConfig.preflight?.enabled ?? true;
|
|
728
|
-
const preflightSeedUrls = walletConfig.preflight?.seedUrls && walletConfig.preflight.seedUrls.length > 0
|
|
729
|
-
? walletConfig.preflight.seedUrls
|
|
730
|
-
: [...new Set(cases.map((testCase) => testCase.startUrl).filter(Boolean))];
|
|
731
|
-
if (preflightEnabled && preflightSeedUrls.length > 0) {
|
|
732
|
-
const preflight = await runWalletPreflight(persistentContext, {
|
|
733
|
-
seedUrls: preflightSeedUrls,
|
|
734
|
-
password: walletConfig.password,
|
|
735
|
-
actionSelectors: walletConfig.actionSelectors,
|
|
736
|
-
promptPaths: walletConfig.promptPaths,
|
|
737
|
-
connectSelectors: walletConfig.connectSelectors,
|
|
738
|
-
connectorSelectors: walletConfig.connectorSelectors,
|
|
739
|
-
requestAccounts: walletConfig.preflight?.requestAccounts,
|
|
740
|
-
accountsTimeoutMs: walletConfig.preflight?.accountsTimeoutMs,
|
|
741
|
-
maxChainSwitchAttempts: walletConfig.preflight?.maxChainSwitchAttempts,
|
|
742
|
-
chain: walletConfig.preflight?.chain,
|
|
743
|
-
log: quiet ? undefined : (message) => cliLog('wallet', message),
|
|
744
|
-
});
|
|
745
|
-
if (!preflight.ok) {
|
|
746
|
-
const failed = preflight.results.find((resultEntry) => !resultEntry.ready);
|
|
747
|
-
const details = failed?.details ?? 'unknown reason';
|
|
748
|
-
throw new Error(`Wallet preflight failed for ${preflight.failedUrl ?? 'unknown origin'} (${details})`);
|
|
749
925
|
}
|
|
750
926
|
}
|
|
751
927
|
}
|
|
@@ -755,94 +931,160 @@ async function main() {
|
|
|
755
931
|
: browserName === 'webkit'
|
|
756
932
|
? webkit
|
|
757
933
|
: chromium;
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
934
|
+
const browserLaunchStartedAt = Date.now();
|
|
935
|
+
browser = await browserType.launch({
|
|
936
|
+
headless: launchPlan.headless,
|
|
937
|
+
...(browserName === 'chromium' ? { args: launchPlan.browserArgs } : {}),
|
|
938
|
+
// Use system Chrome for stealth profiles — real TLS/JA3 fingerprint vs bundled Chromium
|
|
939
|
+
...(isStealthProfile && browserName === 'chromium' ? { channel: 'chrome' } : {}),
|
|
940
|
+
});
|
|
941
|
+
launchDiagnostics.browserLaunchMs = Date.now() - browserLaunchStartedAt;
|
|
942
|
+
}
|
|
943
|
+
// Headless Chromium sends "HeadlessChrome/..." in the default User-Agent.
|
|
944
|
+
// CDNs like Akamai reject this with ERR_HTTP2_PROTOCOL_ERROR before any JS
|
|
945
|
+
// stealth patches can run. Build a clean UA from the browser version.
|
|
946
|
+
const headlessUserAgent = launchPlan.headless && browser
|
|
947
|
+
? (() => {
|
|
948
|
+
const ver = browser.version();
|
|
949
|
+
const plat = process.platform;
|
|
950
|
+
const platformToken = plat === 'win32'
|
|
951
|
+
? 'Windows NT 10.0; Win64; x64'
|
|
952
|
+
: plat === 'linux'
|
|
953
|
+
? 'X11; Linux x86_64'
|
|
954
|
+
: 'Macintosh; Intel Mac OS X 10_15_7';
|
|
955
|
+
return `Mozilla/5.0 (${platformToken}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${ver} Safari/537.36`;
|
|
956
|
+
})()
|
|
957
|
+
: undefined;
|
|
958
|
+
const driverFactory = async () => {
|
|
959
|
+
const contextStartedAt = Date.now();
|
|
960
|
+
// CDP: reuse the browser's default context (preserves user cookies/sessions).
|
|
961
|
+
// Persistent context: use the already-opened persistent context.
|
|
962
|
+
// Default: create a fresh isolated context.
|
|
963
|
+
let context;
|
|
964
|
+
if (cdpConnected) {
|
|
965
|
+
// Reuse the user's existing browser context — cookies, localStorage, extensions intact
|
|
966
|
+
const contexts = browser.contexts();
|
|
967
|
+
context = contexts[0] ?? await browser.newContext({ viewport });
|
|
968
|
+
}
|
|
969
|
+
else if (persistentContext) {
|
|
970
|
+
context = persistentContext;
|
|
769
971
|
}
|
|
770
972
|
else {
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
973
|
+
context = await browser.newContext({
|
|
974
|
+
viewport,
|
|
975
|
+
recordVideo: { dir: videoDir, size: viewport },
|
|
976
|
+
storageState: storageStatePath,
|
|
977
|
+
locale: 'en-US',
|
|
978
|
+
timezoneId: 'America/New_York',
|
|
979
|
+
...(headlessUserAgent ? { userAgent: headlessUserAgent } : {}),
|
|
980
|
+
extraHTTPHeaders: {
|
|
981
|
+
'Accept-Language': 'en-US,en;q=0.9',
|
|
982
|
+
},
|
|
777
983
|
});
|
|
778
|
-
launchDiagnostics.browserLaunchMs = Date.now() - browserLaunchStartedAt;
|
|
779
984
|
}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
985
|
+
// Stealth patches: only for Playwright-controlled contexts (not real user browsers)
|
|
986
|
+
if (!cdpConnected) {
|
|
987
|
+
await context.addInitScript(`
|
|
988
|
+
// navigator.webdriver — explicit override (backup for --disable-blink-features)
|
|
989
|
+
Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
|
|
990
|
+
// navigator.plugins — empty in headless, non-empty in real browsers
|
|
991
|
+
Object.defineProperty(navigator, 'plugins', {
|
|
992
|
+
get: () => [
|
|
993
|
+
{ name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer', description: 'Portable Document Format' },
|
|
994
|
+
{ name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: '' },
|
|
995
|
+
{ name: 'Native Client', filename: 'internal-nacl-plugin', description: '' },
|
|
996
|
+
],
|
|
792
997
|
});
|
|
793
|
-
//
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
998
|
+
// navigator.languages — must match Accept-Language header
|
|
999
|
+
Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });
|
|
1000
|
+
// hardware signals — realistic desktop values
|
|
1001
|
+
Object.defineProperty(navigator, 'hardwareConcurrency', { get: () => 8 });
|
|
1002
|
+
Object.defineProperty(navigator, 'deviceMemory', { get: () => 8 });
|
|
1003
|
+
// window.chrome — full stub matching real Chrome
|
|
1004
|
+
if (!window.chrome) window.chrome = {};
|
|
1005
|
+
if (!window.chrome.runtime) window.chrome.runtime = { id: undefined };
|
|
1006
|
+
if (!window.chrome.app) window.chrome.app = { isInstalled: false, InstallState: { DISABLED: 'disabled', INSTALLED: 'installed', NOT_INSTALLED: 'not_installed' }, RunningState: { CANNOT_RUN: 'cannot_run', READY_TO_RUN: 'ready_to_run', RUNNING: 'running' } };
|
|
1007
|
+
if (!window.chrome.csi) window.chrome.csi = function() { return { onloadT: Date.now(), startE: Date.now(), pageT: Date.now() - performance.timing.navigationStart }; };
|
|
1008
|
+
if (!window.chrome.loadTimes) window.chrome.loadTimes = function() { return { commitLoadTime: Date.now() / 1000, connectionInfo: 'h2', finishDocumentLoadTime: Date.now() / 1000, finishLoadTime: Date.now() / 1000, firstPaintAfterLoadTime: 0, firstPaintTime: Date.now() / 1000, navigationType: 'Other', npnNegotiatedProtocol: 'h2', requestTime: Date.now() / 1000 - 0.16, startLoadTime: Date.now() / 1000 - 0.16, wasAlternateProtocolAvailable: false, wasFetchedViaSpdy: true, wasNpnNegotiated: true }; };
|
|
1009
|
+
// WebGL vendor/renderer — match real GPU values
|
|
1010
|
+
try {
|
|
1011
|
+
const getParameter = WebGLRenderingContext.prototype.getParameter;
|
|
1012
|
+
WebGLRenderingContext.prototype.getParameter = function(parameter) {
|
|
1013
|
+
if (parameter === 37445) return 'Intel Inc.';
|
|
1014
|
+
if (parameter === 37446) return 'Intel Iris OpenGL Engine';
|
|
1015
|
+
return getParameter.call(this, parameter);
|
|
1016
|
+
};
|
|
1017
|
+
} catch (_) {}
|
|
1018
|
+
try {
|
|
1019
|
+
const getParameter2 = WebGL2RenderingContext.prototype.getParameter;
|
|
1020
|
+
WebGL2RenderingContext.prototype.getParameter = function(parameter) {
|
|
1021
|
+
if (parameter === 37445) return 'Intel Inc.';
|
|
1022
|
+
if (parameter === 37446) return 'Intel Iris OpenGL Engine';
|
|
1023
|
+
return getParameter2.call(this, parameter);
|
|
1024
|
+
};
|
|
1025
|
+
} catch (_) {}
|
|
1026
|
+
// window.outerWidth/outerHeight — 0 in headless, match viewport in real browsers
|
|
1027
|
+
if (window.outerWidth === 0) Object.defineProperty(window, 'outerWidth', { get: () => window.innerWidth });
|
|
1028
|
+
if (window.outerHeight === 0) Object.defineProperty(window, 'outerHeight', { get: () => window.innerHeight + 85 });
|
|
1029
|
+
// Patch permissions API — cover all permission types bots commonly mis-handle
|
|
1030
|
+
try {
|
|
1031
|
+
const origQuery = navigator.permissions.query.bind(navigator.permissions);
|
|
1032
|
+
navigator.permissions.query = (params) => {
|
|
1033
|
+
const deny = ['notifications', 'geolocation', 'camera', 'microphone', 'payment-handler'];
|
|
1034
|
+
if (deny.includes(params.name))
|
|
1035
|
+
return Promise.resolve({ state: 'denied', onchange: null });
|
|
1036
|
+
return origQuery(params);
|
|
1037
|
+
};
|
|
1038
|
+
} catch (_) {}
|
|
1039
|
+
// Canvas fingerprint noise — add imperceptible per-session noise to canvas readback
|
|
1040
|
+
// so each session produces a unique fingerprint (defeats static fingerprint matching)
|
|
1041
|
+
try {
|
|
1042
|
+
const seed = Math.random() * 0xffff | 0;
|
|
1043
|
+
const noisify = (canvas) => {
|
|
1044
|
+
try {
|
|
1045
|
+
const ctx = canvas.getContext('2d');
|
|
1046
|
+
if (!ctx) return;
|
|
1047
|
+
const { width: w, height: h } = canvas;
|
|
1048
|
+
if (w === 0 || h === 0) return;
|
|
1049
|
+
const img = ctx.getImageData(0, 0, w, h);
|
|
1050
|
+
const d = img.data;
|
|
1051
|
+
for (let i = 0; i < d.length; i += 4) {
|
|
1052
|
+
// deterministic per-pixel noise from seed + position
|
|
1053
|
+
d[i] = d[i] ^ ((seed + i) & 1);
|
|
1054
|
+
}
|
|
1055
|
+
ctx.putImageData(img, 0, 0);
|
|
1056
|
+
} catch (_) {}
|
|
1057
|
+
};
|
|
1058
|
+
const origToDataURL = HTMLCanvasElement.prototype.toDataURL;
|
|
1059
|
+
HTMLCanvasElement.prototype.toDataURL = function(...args) {
|
|
1060
|
+
noisify(this);
|
|
1061
|
+
return origToDataURL.apply(this, args);
|
|
1062
|
+
};
|
|
1063
|
+
const origToBlob = HTMLCanvasElement.prototype.toBlob;
|
|
1064
|
+
HTMLCanvasElement.prototype.toBlob = function(...args) {
|
|
1065
|
+
noisify(this);
|
|
1066
|
+
return origToBlob.apply(this, args);
|
|
1067
|
+
};
|
|
1068
|
+
} catch (_) {}
|
|
1069
|
+
// Fix CDP screenX/screenY bug — CDP Input.dispatchMouseEvent sets
|
|
1070
|
+
// screenX=clientX, screenY=clientY which never happens in real browsers.
|
|
1071
|
+
// Cloudflare Turnstile actively checks this. Add a per-session window
|
|
1072
|
+
// offset so screenX/screenY are realistic and internally consistent.
|
|
1073
|
+
try {
|
|
1074
|
+
const winX = Math.floor(Math.random() * 200) + 50;
|
|
1075
|
+
const winY = Math.floor(Math.random() * 100) + 50;
|
|
1076
|
+
const chrome = 85;
|
|
1077
|
+
Object.defineProperty(MouseEvent.prototype, 'screenX', {
|
|
1078
|
+
get() { return this.clientX + winX; },
|
|
1079
|
+
configurable: true,
|
|
1080
|
+
});
|
|
1081
|
+
Object.defineProperty(MouseEvent.prototype, 'screenY', {
|
|
1082
|
+
get() { return this.clientY + winY + chrome; },
|
|
1083
|
+
configurable: true,
|
|
1084
|
+
});
|
|
1085
|
+
} catch (_) {}
|
|
1086
|
+
`);
|
|
1087
|
+
}
|
|
846
1088
|
const contextCreateMs = Date.now() - contextStartedAt;
|
|
847
1089
|
const pageStartedAt = Date.now();
|
|
848
1090
|
const page = await context.newPage();
|
|
@@ -874,8 +1116,9 @@ async function main() {
|
|
|
874
1116
|
contextCreateMs,
|
|
875
1117
|
pageCreateMs,
|
|
876
1118
|
resourceBlockingSetupMs,
|
|
877
|
-
storageStateApplied: Boolean(storageStatePath),
|
|
1119
|
+
storageStateApplied: Boolean(storageStatePath) && !cdpConnected,
|
|
878
1120
|
persistentContext: Boolean(persistentContext),
|
|
1121
|
+
cdpConnected,
|
|
879
1122
|
};
|
|
880
1123
|
// Wrap in a Driver that properly tears down context on close
|
|
881
1124
|
const wrappedDriver = {
|
|
@@ -887,7 +1130,7 @@ async function main() {
|
|
|
887
1130
|
async close() {
|
|
888
1131
|
await driver.close().catch(() => { });
|
|
889
1132
|
await page.close().catch(() => { });
|
|
890
|
-
if (!persistentContext) {
|
|
1133
|
+
if (!persistentContext && !cdpConnected) {
|
|
891
1134
|
await context.close().catch(() => { });
|
|
892
1135
|
}
|
|
893
1136
|
},
|
|
@@ -905,8 +1148,9 @@ async function main() {
|
|
|
905
1148
|
defaultTimeoutMs: timeoutMs,
|
|
906
1149
|
driver: singleDriver,
|
|
907
1150
|
driverFactory: concurrency > 1 ? driverFactory : undefined,
|
|
908
|
-
enableMemory:
|
|
1151
|
+
enableMemory: memoryEnabled,
|
|
909
1152
|
trajectoryStorePath: driverConfig.memory?.dir,
|
|
1153
|
+
projectStore,
|
|
910
1154
|
concurrency,
|
|
911
1155
|
screenshotInterval,
|
|
912
1156
|
artifactSink: sink,
|
|
@@ -983,9 +1227,10 @@ async function main() {
|
|
|
983
1227
|
if (runError) {
|
|
984
1228
|
throw runError;
|
|
985
1229
|
}
|
|
986
|
-
|
|
1230
|
+
const runLabel = values.cases
|
|
987
1231
|
? `${path.basename(values.cases)} · cli run`
|
|
988
|
-
: `${values.goal.slice(0, 80)} · cli run
|
|
1232
|
+
: `${(values.goal || values['resume-run'] || values['fork-run'] || 'run').slice(0, 80)} · cli run`;
|
|
1233
|
+
await syncLocalBenchmarkRun(path.resolve(sinkDir), runLabel);
|
|
989
1234
|
process.exit((result?.summary.failed ?? 1) > 0 ? 1 : 0);
|
|
990
1235
|
}
|
|
991
1236
|
function parseAllowedDomains(value) {
|