@dyyz1993/agent-browser 0.13.2 → 0.24.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 +108 -0
- package/bin/agent-browser-darwin-arm64 +0 -0
- package/bin/agent-browser-darwin-x64 +0 -0
- package/bin/agent-browser-linux-arm64 +0 -0
- package/bin/agent-browser-linux-x64 +0 -0
- package/bin/agent-browser-win32-x64.exe +0 -0
- package/dist/__tests__/e2e/utils/test-helpers.d.ts +1 -0
- package/dist/__tests__/e2e/utils/test-helpers.d.ts.map +1 -1
- package/dist/__tests__/e2e/utils/test-helpers.js +14 -1
- package/dist/__tests__/e2e/utils/test-helpers.js.map +1 -1
- package/dist/__tests__/utils/free-port.d.ts +2 -0
- package/dist/__tests__/utils/free-port.d.ts.map +1 -0
- package/dist/__tests__/utils/free-port.js +18 -0
- package/dist/__tests__/utils/free-port.js.map +1 -0
- package/dist/__tests__/utils/parseCli.d.ts.map +1 -1
- package/dist/__tests__/utils/parseCli.js +83 -9
- package/dist/__tests__/utils/parseCli.js.map +1 -1
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +298 -9
- package/dist/actions.js.map +1 -1
- package/dist/browser.d.ts +11 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +75 -19
- package/dist/browser.js.map +1 -1
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +172 -15
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/connection.d.ts +13 -0
- package/dist/cli/connection.d.ts.map +1 -1
- package/dist/cli/connection.js +137 -48
- package/dist/cli/connection.js.map +1 -1
- package/dist/cli/flags.d.ts.map +1 -1
- package/dist/cli/flags.js +0 -1
- package/dist/cli/flags.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +63 -22
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/cli/output.js +0 -32
- package/dist/cli/output.js.map +1 -1
- package/dist/cli.js +20 -2
- package/dist/cli.js.map +1 -1
- package/dist/daemon.d.ts +1 -0
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +291 -264
- package/dist/daemon.js.map +1 -1
- package/dist/diff.d.ts.map +1 -1
- package/dist/diff.js +1 -1
- package/dist/diff.js.map +1 -1
- package/dist/flow/exporters/cypress.d.ts +9 -0
- package/dist/flow/exporters/cypress.d.ts.map +1 -0
- package/dist/flow/exporters/cypress.js +256 -0
- package/dist/flow/exporters/cypress.js.map +1 -0
- package/dist/flow/exporters/index.d.ts +6 -0
- package/dist/flow/exporters/index.d.ts.map +1 -0
- package/dist/flow/exporters/index.js +5 -0
- package/dist/flow/exporters/index.js.map +1 -0
- package/dist/flow/exporters/playwright.d.ts +20 -0
- package/dist/flow/exporters/playwright.d.ts.map +1 -0
- package/dist/flow/exporters/playwright.js +175 -0
- package/dist/flow/exporters/playwright.js.map +1 -0
- package/dist/flow/exporters/python.d.ts +20 -0
- package/dist/flow/exporters/python.d.ts.map +1 -0
- package/dist/flow/exporters/python.js +163 -0
- package/dist/flow/exporters/python.js.map +1 -0
- package/dist/flow/exporters/selenium.d.ts +9 -0
- package/dist/flow/exporters/selenium.d.ts.map +1 -0
- package/dist/flow/exporters/selenium.js +298 -0
- package/dist/flow/exporters/selenium.js.map +1 -0
- package/dist/flow/exporters/types.d.ts +13 -0
- package/dist/flow/exporters/types.d.ts.map +1 -0
- package/dist/flow/exporters/types.js +2 -0
- package/dist/flow/exporters/types.js.map +1 -0
- package/dist/flow/flow-executor.d.ts +57 -0
- package/dist/flow/flow-executor.d.ts.map +1 -0
- package/dist/flow/flow-executor.js +1263 -0
- package/dist/flow/flow-executor.js.map +1 -0
- package/dist/flow/index.d.ts +15 -0
- package/dist/flow/index.d.ts.map +1 -0
- package/dist/flow/index.js +10 -0
- package/dist/flow/index.js.map +1 -0
- package/dist/flow/output.d.ts +11 -0
- package/dist/flow/output.d.ts.map +1 -0
- package/dist/flow/output.js +84 -0
- package/dist/flow/output.js.map +1 -0
- package/dist/flow/plugin-system.d.ts +48 -0
- package/dist/flow/plugin-system.d.ts.map +1 -0
- package/dist/flow/plugin-system.js +132 -0
- package/dist/flow/plugin-system.js.map +1 -0
- package/dist/flow/plugins/file-output-plugin.d.ts +8 -0
- package/dist/flow/plugins/file-output-plugin.d.ts.map +1 -0
- package/dist/flow/plugins/file-output-plugin.js +31 -0
- package/dist/flow/plugins/file-output-plugin.js.map +1 -0
- package/dist/flow/plugins/index.d.ts +4 -0
- package/dist/flow/plugins/index.d.ts.map +1 -0
- package/dist/flow/plugins/index.js +4 -0
- package/dist/flow/plugins/index.js.map +1 -0
- package/dist/flow/plugins/logging-plugin.d.ts +7 -0
- package/dist/flow/plugins/logging-plugin.d.ts.map +1 -0
- package/dist/flow/plugins/logging-plugin.js +40 -0
- package/dist/flow/plugins/logging-plugin.js.map +1 -0
- package/dist/flow/plugins/webhook-plugin.d.ts +7 -0
- package/dist/flow/plugins/webhook-plugin.d.ts.map +1 -0
- package/dist/flow/plugins/webhook-plugin.js +24 -0
- package/dist/flow/plugins/webhook-plugin.js.map +1 -0
- package/dist/flow/presets/index.d.ts +10 -0
- package/dist/flow/presets/index.d.ts.map +1 -0
- package/dist/flow/presets/index.js +29 -0
- package/dist/flow/presets/index.js.map +1 -0
- package/dist/flow/recorder-to-flow.d.ts +70 -0
- package/dist/flow/recorder-to-flow.d.ts.map +1 -0
- package/dist/flow/recorder-to-flow.js +392 -0
- package/dist/flow/recorder-to-flow.js.map +1 -0
- package/dist/flow/site-manager.d.ts +24 -0
- package/dist/flow/site-manager.d.ts.map +1 -0
- package/dist/flow/site-manager.js +125 -0
- package/dist/flow/site-manager.js.map +1 -0
- package/dist/flow/types.d.ts +196 -0
- package/dist/flow/types.d.ts.map +1 -0
- package/dist/flow/types.js +2 -0
- package/dist/flow/types.js.map +1 -0
- package/dist/flow/yaml-parser.d.ts +15 -0
- package/dist/flow/yaml-parser.d.ts.map +1 -0
- package/dist/flow/yaml-parser.js +216 -0
- package/dist/flow/yaml-parser.js.map +1 -0
- package/dist/human-mouse.d.ts.map +1 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +15 -11
- package/dist/protocol.js.map +1 -1
- package/dist/rc-config.d.ts.map +1 -1
- package/dist/rc-config.js +1 -2
- package/dist/rc-config.js.map +1 -1
- package/dist/recorder/inject.js +730 -332
- package/dist/snapshot-store.d.ts +83 -0
- package/dist/snapshot-store.d.ts.map +1 -0
- package/dist/snapshot-store.js +112 -0
- package/dist/snapshot-store.js.map +1 -0
- package/dist/snapshot.d.ts +6 -7
- package/dist/snapshot.d.ts.map +1 -1
- package/dist/snapshot.js +471 -17
- package/dist/snapshot.js.map +1 -1
- package/dist/stream-server-standalone.d.ts.map +1 -1
- package/dist/stream-server-standalone.js.map +1 -1
- package/dist/stream-server.d.ts.map +1 -1
- package/dist/stream-server.js +38 -13
- package/dist/stream-server.js.map +1 -1
- package/dist/test-live.js +5 -5
- package/dist/test-live.js.map +1 -1
- package/dist/types.d.ts +13 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/viewer-script.d.ts.map +1 -1
- package/dist/viewer-script.js +12 -6
- package/dist/viewer-script.js.map +1 -1
- package/package.json +18 -5
- package/skills/agent-browser/SKILL.md +151 -3
- package/dist/ios-actions.d.ts +0 -11
- package/dist/ios-actions.d.ts.map +0 -1
- package/dist/ios-actions.js +0 -228
- package/dist/ios-actions.js.map +0 -1
- package/dist/ios-manager.d.ts +0 -266
- package/dist/ios-manager.d.ts.map +0 -1
- package/dist/ios-manager.js +0 -1076
- package/dist/ios-manager.js.map +0 -1
package/dist/browser.js
CHANGED
|
@@ -4,7 +4,8 @@ import os from 'node:os';
|
|
|
4
4
|
import { existsSync, mkdirSync, rmSync, readFileSync, writeFileSync, statSync } from 'node:fs';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
-
import { getEnhancedSnapshot, parseRef } from './snapshot.js';
|
|
7
|
+
import { getEnhancedSnapshot, generateStableSelectors, parseRef, } from './snapshot.js';
|
|
8
|
+
import { SnapshotStore } from './snapshot-store.js';
|
|
8
9
|
import { getEventCallbacks } from './actions.js';
|
|
9
10
|
/**
|
|
10
11
|
* Manages the Playwright browser lifecycle with multiple tabs/windows
|
|
@@ -46,6 +47,7 @@ export class BrowserManager {
|
|
|
46
47
|
isRecordingHar = false;
|
|
47
48
|
refMap = {};
|
|
48
49
|
lastSnapshot = '';
|
|
50
|
+
snapshotStore = new SnapshotStore();
|
|
49
51
|
scopedHeaderRoutes = new Map();
|
|
50
52
|
commandHistory = [];
|
|
51
53
|
// CDP session for screencast and input injection
|
|
@@ -93,7 +95,63 @@ export class BrowserManager {
|
|
|
93
95
|
const snapshot = await getEnhancedSnapshot(frame, options);
|
|
94
96
|
this.refMap = snapshot.refs;
|
|
95
97
|
this.lastSnapshot = snapshot.tree;
|
|
96
|
-
|
|
98
|
+
let snapshotId;
|
|
99
|
+
const url = this.pages.length > 0 ? this.getPage().url() : '';
|
|
100
|
+
const elements = [];
|
|
101
|
+
let index = 1;
|
|
102
|
+
for (const [ref, data] of Object.entries(snapshot.refs)) {
|
|
103
|
+
elements.push({
|
|
104
|
+
ref,
|
|
105
|
+
index: index,
|
|
106
|
+
role: data.role,
|
|
107
|
+
name: data.name,
|
|
108
|
+
cssSelector: '',
|
|
109
|
+
xpath: '',
|
|
110
|
+
});
|
|
111
|
+
index++;
|
|
112
|
+
}
|
|
113
|
+
snapshotId = this.snapshotStore.create(url, elements, options?.framePath);
|
|
114
|
+
const elementCount = elements.length;
|
|
115
|
+
const header = `Snapshot #${snapshotId} (${elementCount} interactive elements)\n---`;
|
|
116
|
+
const tips = `---\nTips:\n Get selector: snapshot --selector-for ${snapshotId}:@e1\n Or by index: snapshot --selector-for ${snapshotId}:1\n List all: snapshot --selectors-of ${snapshotId}\n Validate: snapshot --validate ${snapshotId}`;
|
|
117
|
+
snapshot.tree = `${header}\n${snapshot.tree}\n${tips}`;
|
|
118
|
+
this.lastSnapshot = snapshot.tree;
|
|
119
|
+
return { ...snapshot, snapshotId };
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Ensure selectors have been lazily generated for a snapshot.
|
|
123
|
+
* Generates them on first call, then caches in the store.
|
|
124
|
+
*/
|
|
125
|
+
async ensureSelectorsGenerated(snapId) {
|
|
126
|
+
const store = this.snapshotStore;
|
|
127
|
+
if (store.isSelectorsGenerated(snapId))
|
|
128
|
+
return true;
|
|
129
|
+
const entry = store.get(snapId);
|
|
130
|
+
if (!entry)
|
|
131
|
+
return false;
|
|
132
|
+
const refs = {};
|
|
133
|
+
for (const [ref, el] of entry.elements) {
|
|
134
|
+
refs[ref] = {
|
|
135
|
+
selector: `getByRole('${el.role}'${el.name ? `, { name: "${el.name}", exact: true }` : ''})`,
|
|
136
|
+
role: el.role,
|
|
137
|
+
name: el.name,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
const frame = entry.framePath ? this.getFrame(entry.framePath) : this.getFrame();
|
|
141
|
+
let stableSelectors = {};
|
|
142
|
+
try {
|
|
143
|
+
stableSelectors = await generateStableSelectors(frame, refs);
|
|
144
|
+
}
|
|
145
|
+
catch { }
|
|
146
|
+
for (const [ref, sel] of Object.entries(stableSelectors)) {
|
|
147
|
+
const el = entry.elements.get(ref);
|
|
148
|
+
if (el) {
|
|
149
|
+
el.cssSelector = sel.cssSelector;
|
|
150
|
+
el.xpath = sel.xpath;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
store.markSelectorsGenerated(snapId);
|
|
154
|
+
return true;
|
|
97
155
|
}
|
|
98
156
|
/**
|
|
99
157
|
* Get the cached ref map from last snapshot
|
|
@@ -101,6 +159,9 @@ export class BrowserManager {
|
|
|
101
159
|
getRefMap() {
|
|
102
160
|
return this.refMap;
|
|
103
161
|
}
|
|
162
|
+
getSnapshotStore() {
|
|
163
|
+
return this.snapshotStore;
|
|
164
|
+
}
|
|
104
165
|
recordCommand(action, selector, value, success) {
|
|
105
166
|
this.commandHistory.push({ action, selector, value, success, timestamp: Date.now() });
|
|
106
167
|
}
|
|
@@ -133,7 +194,10 @@ export class BrowserManager {
|
|
|
133
194
|
}
|
|
134
195
|
let locator;
|
|
135
196
|
if (refData.name) {
|
|
136
|
-
locator = frame.getByRole(refData.role, {
|
|
197
|
+
locator = frame.getByRole(refData.role, {
|
|
198
|
+
name: refData.name,
|
|
199
|
+
exact: true,
|
|
200
|
+
});
|
|
137
201
|
}
|
|
138
202
|
else {
|
|
139
203
|
locator = frame.getByRole(refData.role);
|
|
@@ -2306,7 +2370,7 @@ export class BrowserManager {
|
|
|
2306
2370
|
// 这个会第一个执行(后添加的先执行)
|
|
2307
2371
|
// 注意:必须设置 xyzSessionId,否则 inject.js 会跳过初始化
|
|
2308
2372
|
// 使用时间戳来确保只有最新的会话 ID 被设置
|
|
2309
|
-
const sessionIdTimestamp = parseInt(this.recorderSessionId.replace('recorder-', '')) || Date.now();
|
|
2373
|
+
const sessionIdTimestamp = parseInt(this.recorderSessionId.replace('recorder-', ''), 10) || Date.now();
|
|
2310
2374
|
await context.addInitScript({
|
|
2311
2375
|
content: `
|
|
2312
2376
|
// 只有当新的会话 ID 更新时才设置
|
|
@@ -2455,7 +2519,7 @@ export class BrowserManager {
|
|
|
2455
2519
|
const pageIndex = this.getPageIndex(newPage);
|
|
2456
2520
|
const newTabIndex = pageIndex >= 0 ? pageIndex : this.pages.length;
|
|
2457
2521
|
this.recorderSteps.push({
|
|
2458
|
-
id: this.recorderSteps.length + 1
|
|
2522
|
+
id: `step-${this.recorderSteps.length + 1}`,
|
|
2459
2523
|
timestamp: Date.now(),
|
|
2460
2524
|
action: 'tab_new',
|
|
2461
2525
|
url: newPage.url(),
|
|
@@ -2464,7 +2528,7 @@ export class BrowserManager {
|
|
|
2464
2528
|
setTimeout(() => {
|
|
2465
2529
|
if (this.recorderSessionId && this.activePageIndex !== previousActiveIndex) {
|
|
2466
2530
|
this.recorderSteps.push({
|
|
2467
|
-
id: this.recorderSteps.length + 1
|
|
2531
|
+
id: `step-${this.recorderSteps.length + 1}`,
|
|
2468
2532
|
timestamp: Date.now(),
|
|
2469
2533
|
action: 'tab_switch',
|
|
2470
2534
|
index: this.activePageIndex,
|
|
@@ -2475,7 +2539,7 @@ export class BrowserManager {
|
|
|
2475
2539
|
if (this.recorderSessionId) {
|
|
2476
2540
|
const closeIndex = this.getPageIndex(newPage);
|
|
2477
2541
|
this.recorderSteps.push({
|
|
2478
|
-
id: this.recorderSteps.length + 1
|
|
2542
|
+
id: `step-${this.recorderSteps.length + 1}`,
|
|
2479
2543
|
timestamp: Date.now(),
|
|
2480
2544
|
action: 'tab_close',
|
|
2481
2545
|
index: closeIndex >= 0 ? closeIndex : -1,
|
|
@@ -2531,8 +2595,6 @@ export class BrowserManager {
|
|
|
2531
2595
|
const hasCloseFunc = typeof win.xyzClose === 'function';
|
|
2532
2596
|
const hasFlushFunc = typeof win.xyzFlushPending === 'function';
|
|
2533
2597
|
console.log('[stopRecorder] hasFlushFunc:', hasFlushFunc, 'hasCloseFunc:', hasCloseFunc, 'hasPanel:', hasPanel);
|
|
2534
|
-
// 重要:先调用 xyzFlushPending,再设置 xyzStopped
|
|
2535
|
-
// 因为 recordStep 会检查 xyzStopped,如果为 true 就不记录
|
|
2536
2598
|
if (hasFlushFunc) {
|
|
2537
2599
|
console.log('[stopRecorder] Calling xyzFlushPending');
|
|
2538
2600
|
win.xyzFlushPending();
|
|
@@ -2540,15 +2602,10 @@ export class BrowserManager {
|
|
|
2540
2602
|
else {
|
|
2541
2603
|
console.log('[stopRecorder] xyzFlushPending not found');
|
|
2542
2604
|
}
|
|
2543
|
-
// 然后再设置停止标志
|
|
2544
2605
|
win.xyzActive = false;
|
|
2545
2606
|
win.xyzStopped = true;
|
|
2546
|
-
// 重置初始化标志,允许新的录制会话重新初始化
|
|
2547
2607
|
win.xyzInited = false;
|
|
2548
2608
|
win.xyzInitializedSessionId = undefined;
|
|
2549
|
-
// 注意:不要清除 xyzSessionId,因为旧的监听器需要用它来检查是否应该跳过
|
|
2550
|
-
// 新的录制会话会设置新的 xyzSessionId,旧的监听器会检测到时间戳更新并跳过
|
|
2551
|
-
// win.xyzSessionId = undefined;
|
|
2552
2609
|
if (hasCloseFunc) {
|
|
2553
2610
|
win.xyzClose();
|
|
2554
2611
|
}
|
|
@@ -2665,13 +2722,13 @@ export class BrowserManager {
|
|
|
2665
2722
|
if (step.from && typeof step.from === 'string') {
|
|
2666
2723
|
lines.push(` from: "${step.from}"`);
|
|
2667
2724
|
}
|
|
2668
|
-
else if (step.from) {
|
|
2725
|
+
else if (step.from && typeof step.from === 'object') {
|
|
2669
2726
|
lines.push(` from: { width: ${step.from.width}, height: ${step.from.height} }`);
|
|
2670
2727
|
}
|
|
2671
2728
|
if (step.to && typeof step.to === 'string') {
|
|
2672
2729
|
lines.push(` to: "${step.to}"`);
|
|
2673
2730
|
}
|
|
2674
|
-
else if (step.to) {
|
|
2731
|
+
else if (step.to && typeof step.to === 'object') {
|
|
2675
2732
|
lines.push(` to: { width: ${step.to.width}, height: ${step.to.height} }`);
|
|
2676
2733
|
}
|
|
2677
2734
|
// 备注信息 - 添加重点提示
|
|
@@ -2702,7 +2759,7 @@ export class BrowserManager {
|
|
|
2702
2759
|
lines.push(` # User marked this as: "${step.annotation.label}"`);
|
|
2703
2760
|
}
|
|
2704
2761
|
// 只在特定操作类型时携带 URL
|
|
2705
|
-
if (step.url && urlRequiredActions.includes(step.action)) {
|
|
2762
|
+
if (step.url && step.action && urlRequiredActions.includes(step.action)) {
|
|
2706
2763
|
lines.push(` url: "${step.url}"`);
|
|
2707
2764
|
}
|
|
2708
2765
|
if (step.index !== undefined)
|
|
@@ -2758,6 +2815,7 @@ export class BrowserManager {
|
|
|
2758
2815
|
if (s.altKey)
|
|
2759
2816
|
parts.push('Alt');
|
|
2760
2817
|
if (s.shiftKey &&
|
|
2818
|
+
s.key &&
|
|
2761
2819
|
!['Shift', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(s.key)) {
|
|
2762
2820
|
parts.push('Shift');
|
|
2763
2821
|
}
|
|
@@ -2831,7 +2889,6 @@ export class BrowserManager {
|
|
|
2831
2889
|
sampled = step.points;
|
|
2832
2890
|
}
|
|
2833
2891
|
else {
|
|
2834
|
-
// 均匀采样
|
|
2835
2892
|
sampled = [];
|
|
2836
2893
|
const step_size = (step.points.length - 1) / (maxPoints - 1);
|
|
2837
2894
|
for (let i = 0; i < maxPoints; i++) {
|
|
@@ -2839,7 +2896,6 @@ export class BrowserManager {
|
|
|
2839
2896
|
sampled.push(step.points[idx]);
|
|
2840
2897
|
}
|
|
2841
2898
|
}
|
|
2842
|
-
// 格式化为 x:y:delay 字符串
|
|
2843
2899
|
const segments = sampled.map((p, i) => {
|
|
2844
2900
|
const x = Math.round(p.x);
|
|
2845
2901
|
const y = Math.round(p.y);
|