@dyyz1993/agent-browser 0.25.0 → 0.26.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 (217) hide show
  1. package/dist/__tests__/e2e/utils/test-helpers.d.ts +2 -2
  2. package/dist/__tests__/e2e/utils/test-helpers.d.ts.map +1 -1
  3. package/dist/__tests__/e2e/utils/test-helpers.js +6 -4
  4. package/dist/__tests__/e2e/utils/test-helpers.js.map +1 -1
  5. package/dist/actions/advanced.d.ts +73 -0
  6. package/dist/actions/advanced.d.ts.map +1 -0
  7. package/dist/actions/advanced.js +390 -0
  8. package/dist/actions/advanced.js.map +1 -0
  9. package/dist/actions/context.d.ts +36 -0
  10. package/dist/actions/context.d.ts.map +1 -0
  11. package/dist/actions/context.js +164 -0
  12. package/dist/actions/context.js.map +1 -0
  13. package/dist/actions/crawl.d.ts +8 -0
  14. package/dist/actions/crawl.d.ts.map +1 -0
  15. package/dist/actions/crawl.js +290 -0
  16. package/dist/actions/crawl.js.map +1 -0
  17. package/dist/actions/elements.d.ts +11 -0
  18. package/dist/actions/elements.d.ts.map +1 -0
  19. package/dist/actions/elements.js +78 -0
  20. package/dist/actions/elements.js.map +1 -0
  21. package/dist/actions/flow.d.ts +4 -0
  22. package/dist/actions/flow.d.ts.map +1 -0
  23. package/dist/actions/flow.js +170 -0
  24. package/dist/actions/flow.js.map +1 -0
  25. package/dist/actions/index.d.ts +7 -0
  26. package/dist/actions/index.d.ts.map +1 -0
  27. package/dist/actions/index.js +323 -0
  28. package/dist/actions/index.js.map +1 -0
  29. package/dist/actions/interact.d.ts +4 -0
  30. package/dist/actions/interact.d.ts.map +1 -0
  31. package/dist/actions/interact.js +162 -0
  32. package/dist/actions/interact.js.map +1 -0
  33. package/dist/actions/interaction.d.ts +31 -0
  34. package/dist/actions/interaction.d.ts.map +1 -0
  35. package/dist/actions/interaction.js +477 -0
  36. package/dist/actions/interaction.js.map +1 -0
  37. package/dist/actions/locators.d.ts +14 -0
  38. package/dist/actions/locators.d.ts.map +1 -0
  39. package/dist/actions/locators.js +310 -0
  40. package/dist/actions/locators.js.map +1 -0
  41. package/dist/actions/map.d.ts +4 -0
  42. package/dist/actions/map.d.ts.map +1 -0
  43. package/dist/actions/map.js +79 -0
  44. package/dist/actions/map.js.map +1 -0
  45. package/dist/actions/meta.d.ts +44 -0
  46. package/dist/actions/meta.d.ts.map +1 -0
  47. package/dist/actions/meta.js +190 -0
  48. package/dist/actions/meta.js.map +1 -0
  49. package/dist/actions/mouse.d.ts +8 -0
  50. package/dist/actions/mouse.d.ts.map +1 -0
  51. package/dist/actions/mouse.js +52 -0
  52. package/dist/actions/mouse.js.map +1 -0
  53. package/dist/actions/recorder.d.ts +20 -0
  54. package/dist/actions/recorder.d.ts.map +1 -0
  55. package/dist/actions/recorder.js +231 -0
  56. package/dist/actions/recorder.js.map +1 -0
  57. package/dist/actions/recording.d.ts +6 -0
  58. package/dist/actions/recording.d.ts.map +1 -0
  59. package/dist/actions/recording.js +22 -0
  60. package/dist/actions/recording.js.map +1 -0
  61. package/dist/actions/scrape.d.ts +10 -0
  62. package/dist/actions/scrape.d.ts.map +1 -0
  63. package/dist/actions/scrape.js +39 -0
  64. package/dist/actions/scrape.js.map +1 -0
  65. package/dist/actions/screencast.d.ts +8 -0
  66. package/dist/actions/screencast.d.ts.map +1 -0
  67. package/dist/actions/screencast.js +56 -0
  68. package/dist/actions/screencast.js.map +1 -0
  69. package/dist/actions/search.d.ts +4 -0
  70. package/dist/actions/search.d.ts.map +1 -0
  71. package/dist/actions/search.js +129 -0
  72. package/dist/actions/search.js.map +1 -0
  73. package/dist/actions/storage.d.ts +14 -0
  74. package/dist/actions/storage.d.ts.map +1 -0
  75. package/dist/actions/storage.js +63 -0
  76. package/dist/actions/storage.js.map +1 -0
  77. package/dist/actions/tabs.d.ts +16 -0
  78. package/dist/actions/tabs.d.ts.map +1 -0
  79. package/dist/actions/tabs.js +47 -0
  80. package/dist/actions/tabs.js.map +1 -0
  81. package/dist/actions/utils.d.ts +15 -0
  82. package/dist/actions/utils.d.ts.map +1 -0
  83. package/dist/actions/utils.js +234 -0
  84. package/dist/actions/utils.js.map +1 -0
  85. package/dist/browser/browser-manager.d.ts +249 -0
  86. package/dist/browser/browser-manager.d.ts.map +1 -0
  87. package/dist/browser/browser-manager.js +1251 -0
  88. package/dist/browser/browser-manager.js.map +1 -0
  89. package/dist/browser/index.d.ts +3 -0
  90. package/dist/browser/index.d.ts.map +1 -0
  91. package/dist/browser/index.js +2 -0
  92. package/dist/browser/index.js.map +1 -0
  93. package/dist/browser/network-tracker.d.ts +39 -0
  94. package/dist/browser/network-tracker.d.ts.map +1 -0
  95. package/dist/browser/network-tracker.js +287 -0
  96. package/dist/browser/network-tracker.js.map +1 -0
  97. package/dist/browser/providers.d.ts +27 -0
  98. package/dist/browser/providers.d.ts.map +1 -0
  99. package/dist/browser/providers.js +293 -0
  100. package/dist/browser/providers.js.map +1 -0
  101. package/dist/browser/recorder-manager.d.ts +69 -0
  102. package/dist/browser/recorder-manager.d.ts.map +1 -0
  103. package/dist/browser/recorder-manager.js +755 -0
  104. package/dist/browser/recorder-manager.js.map +1 -0
  105. package/dist/browser/recording-manager.d.ts +46 -0
  106. package/dist/browser/recording-manager.d.ts.map +1 -0
  107. package/dist/browser/recording-manager.js +156 -0
  108. package/dist/browser/recording-manager.js.map +1 -0
  109. package/dist/browser/screencast-manager.d.ts +49 -0
  110. package/dist/browser/screencast-manager.d.ts.map +1 -0
  111. package/dist/browser/screencast-manager.js +131 -0
  112. package/dist/browser/screencast-manager.js.map +1 -0
  113. package/dist/browser/types.d.ts +101 -0
  114. package/dist/browser/types.d.ts.map +1 -0
  115. package/dist/browser/types.js +2 -0
  116. package/dist/browser/types.js.map +1 -0
  117. package/dist/browser-events.d.ts +25 -0
  118. package/dist/browser-events.d.ts.map +1 -0
  119. package/dist/browser-events.js +15 -0
  120. package/dist/browser-events.js.map +1 -0
  121. package/dist/cli/commands.d.ts.map +1 -1
  122. package/dist/cli/commands.js +140 -1
  123. package/dist/cli/commands.js.map +1 -1
  124. package/dist/cli/connection.d.ts.map +1 -1
  125. package/dist/cli/connection.js +15 -22
  126. package/dist/cli/connection.js.map +1 -1
  127. package/dist/cli/help.d.ts.map +1 -1
  128. package/dist/cli/help.js +153 -3
  129. package/dist/cli/help.js.map +1 -1
  130. package/dist/cli/output.d.ts.map +1 -1
  131. package/dist/cli/output.js +72 -0
  132. package/dist/cli/output.js.map +1 -1
  133. package/dist/cli.js +3 -4
  134. package/dist/cli.js.map +1 -1
  135. package/dist/daemon.d.ts +1 -1
  136. package/dist/daemon.d.ts.map +1 -1
  137. package/dist/daemon.js +12 -13
  138. package/dist/daemon.js.map +1 -1
  139. package/dist/flow/exporters/playwright.d.ts +23 -1
  140. package/dist/flow/exporters/playwright.d.ts.map +1 -1
  141. package/dist/flow/exporters/playwright.js +333 -85
  142. package/dist/flow/exporters/playwright.js.map +1 -1
  143. package/dist/flow/exporters/python.d.ts +22 -0
  144. package/dist/flow/exporters/python.d.ts.map +1 -1
  145. package/dist/flow/exporters/python.js +325 -74
  146. package/dist/flow/exporters/python.js.map +1 -1
  147. package/dist/flow/exporters/selenium.d.ts.map +1 -1
  148. package/dist/flow/exporters/selenium.js +0 -1
  149. package/dist/flow/exporters/selenium.js.map +1 -1
  150. package/dist/flow/flow-executor.d.ts +1 -1
  151. package/dist/flow/flow-executor.d.ts.map +1 -1
  152. package/dist/flow/flow-executor.js +11 -11
  153. package/dist/flow/flow-executor.js.map +1 -1
  154. package/dist/flow/output.js.map +1 -1
  155. package/dist/flow/plugin-system.d.ts +1 -1
  156. package/dist/flow/plugin-system.d.ts.map +1 -1
  157. package/dist/flow/plugin-system.js +2 -2
  158. package/dist/flow/plugin-system.js.map +1 -1
  159. package/dist/flow/plugins/logging-plugin.js +1 -1
  160. package/dist/flow/plugins/logging-plugin.js.map +1 -1
  161. package/dist/flow/presets/console-capture.js +33 -14
  162. package/dist/flow/presets/fetch-capture.js +52 -23
  163. package/dist/flow/presets/sse-stream.js +35 -17
  164. package/dist/flow/presets/xhr-only.js +22 -12
  165. package/dist/flow/recorder-to-flow.d.ts.map +1 -1
  166. package/dist/flow/recorder-to-flow.js +1 -3
  167. package/dist/flow/recorder-to-flow.js.map +1 -1
  168. package/dist/flow/site-manager.d.ts.map +1 -1
  169. package/dist/flow/site-manager.js +6 -2
  170. package/dist/flow/site-manager.js.map +1 -1
  171. package/dist/human-mouse.d.ts +1 -1
  172. package/dist/human-mouse.d.ts.map +1 -1
  173. package/dist/human-mouse.js +2 -2
  174. package/dist/human-mouse.js.map +1 -1
  175. package/dist/protocol.d.ts.map +1 -1
  176. package/dist/protocol.js +90 -0
  177. package/dist/protocol.js.map +1 -1
  178. package/dist/rc-config.js +4 -4
  179. package/dist/rc-config.js.map +1 -1
  180. package/dist/recorder/inject.js +31 -5
  181. package/dist/snapshot.d.ts.map +1 -1
  182. package/dist/snapshot.js +3 -4
  183. package/dist/snapshot.js.map +1 -1
  184. package/dist/stream-server-standalone.d.ts +1 -1
  185. package/dist/stream-server-standalone.d.ts.map +1 -1
  186. package/dist/stream-server-standalone.js +42 -23
  187. package/dist/stream-server-standalone.js.map +1 -1
  188. package/dist/stream-server.d.ts +1 -1
  189. package/dist/stream-server.d.ts.map +1 -1
  190. package/dist/stream-server.js +26 -21
  191. package/dist/stream-server.js.map +1 -1
  192. package/dist/test-live.js +9 -3
  193. package/dist/test-live.js.map +1 -1
  194. package/dist/types.d.ts +122 -1
  195. package/dist/types.d.ts.map +1 -1
  196. package/dist/types.js.map +1 -1
  197. package/package.json +4 -3
  198. package/scripts/README.md +66 -0
  199. package/scripts/copy-flow-presets.js +25 -0
  200. package/scripts/douyin-flow-test.sh +72 -0
  201. package/scripts/douyin-test.sh +101 -0
  202. package/dist/actions.d.ts +0 -51
  203. package/dist/actions.d.ts.map +0 -1
  204. package/dist/actions.js +0 -2662
  205. package/dist/actions.js.map +0 -1
  206. package/dist/browser.d.ts +0 -651
  207. package/dist/browser.d.ts.map +0 -1
  208. package/dist/browser.js +0 -3088
  209. package/dist/browser.js.map +0 -1
  210. package/dist/ios-actions.d.ts +0 -11
  211. package/dist/ios-actions.d.ts.map +0 -1
  212. package/dist/ios-actions.js +0 -228
  213. package/dist/ios-actions.js.map +0 -1
  214. package/dist/ios-manager.d.ts +0 -266
  215. package/dist/ios-manager.d.ts.map +0 -1
  216. package/dist/ios-manager.js +0 -1076
  217. package/dist/ios-manager.js.map +0 -1
@@ -0,0 +1,755 @@
1
+ import path from 'node:path';
2
+ import { readFileSync } from 'node:fs';
3
+ import { fileURLToPath } from 'node:url';
4
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
5
+ export class RecorderManager {
6
+ recorderSessionId = null;
7
+ recorderBindingName = null;
8
+ recorderStartTime = 0;
9
+ recorderSteps = [];
10
+ recorderPages = [];
11
+ recorderPageHandler = null;
12
+ navigationHistory = [];
13
+ navigationHistoryIndex = -1;
14
+ lastNavigationUrl = '';
15
+ lastNavigationTime = 0;
16
+ recorderNavigatedHandler = null;
17
+ recorderFrameAttachedHandler = null;
18
+ recorderPaused = false;
19
+ getPage;
20
+ getPages;
21
+ getActivePageIndex;
22
+ setActivePageIndex;
23
+ getCDPSession;
24
+ getCdpEndpoint;
25
+ constructor(deps) {
26
+ this.getPage = deps.getPage;
27
+ this.getPages = deps.getPages;
28
+ this.getActivePageIndex = deps.getActivePageIndex;
29
+ this.setActivePageIndex = deps.setActivePageIndex;
30
+ this.getCDPSession = deps.getCDPSession;
31
+ this.getCdpEndpoint = deps.getCdpEndpoint;
32
+ }
33
+ isRecordingSession() {
34
+ return this.recorderSessionId !== null;
35
+ }
36
+ pauseRecording() {
37
+ this.recorderPaused = true;
38
+ }
39
+ resumeRecording() {
40
+ this.recorderPaused = false;
41
+ }
42
+ recordStep(step) {
43
+ if (this.recorderSessionId && !this.recorderPaused) {
44
+ this.recorderSteps.push({
45
+ id: `step-${Date.now()}`,
46
+ timestamp: Date.now(),
47
+ action: step.action,
48
+ index: step.index,
49
+ key: step.key,
50
+ code: step.code,
51
+ ctrlKey: step.ctrlKey,
52
+ metaKey: step.metaKey,
53
+ altKey: step.altKey,
54
+ shiftKey: step.shiftKey,
55
+ selector: step.selector,
56
+ value: step.value,
57
+ });
58
+ }
59
+ }
60
+ addStep(step) {
61
+ this.recorderSteps.push(step);
62
+ }
63
+ getSteps() {
64
+ return this.recorderSteps;
65
+ }
66
+ getSessionId() {
67
+ return this.recorderSessionId;
68
+ }
69
+ async injectRecorderIfNeeded() {
70
+ if (!this.recorderSessionId)
71
+ return;
72
+ const page = this.getPage();
73
+ if (!page)
74
+ return;
75
+ try {
76
+ await page.evaluate(() => {
77
+ window.xyzActive = true;
78
+ window.xyzStopped = false;
79
+ window.xyzInited = false;
80
+ });
81
+ const injectScript = this.getRecorderInjectScript(false, this.recorderBindingName || 'xyzTrack', this.recorderSessionId);
82
+ await page.evaluate(injectScript);
83
+ }
84
+ catch {
85
+ /* empty */
86
+ }
87
+ }
88
+ getRecorderInjectScript(hide = false, bindingName = 'xyzTrack', sessionId) {
89
+ const injectScriptPath = path.join(__dirname, '..', 'recorder', 'inject.js');
90
+ const script = readFileSync(injectScriptPath, 'utf-8');
91
+ const config = `window.xyzHide = ${hide}; window.xyzBindingName = '${bindingName}'; window.xyzInjectedSessionId = '${sessionId || ''}';`;
92
+ const fullScript = config + '\n' + script;
93
+ return fullScript;
94
+ }
95
+ async startRecorder(url, hide = false) {
96
+ console.log('[BrowserManager] startRecorder called, url:', url, 'hide:', hide);
97
+ if (this.recorderSessionId) {
98
+ throw new Error(`Recording already in progress (session: ${this.recorderSessionId}). Use 'recorder stop' to stop current recording first.`);
99
+ }
100
+ const page = this.getPage();
101
+ if (!page) {
102
+ throw new Error('No page available. Launch browser first.');
103
+ }
104
+ this.recorderSessionId = 'recorder-' + Date.now();
105
+ this.recorderStartTime = Date.now();
106
+ this.recorderSteps = [];
107
+ this.recorderPages = [];
108
+ this.navigationHistory = [];
109
+ this.navigationHistoryIndex = -1;
110
+ this.lastNavigationUrl = '';
111
+ this.lastNavigationTime = 0;
112
+ const context = page.context();
113
+ const bindingName = `xyzTrack_${this.recorderSessionId}`;
114
+ this.recorderBindingName = bindingName;
115
+ const injectScript = this.getRecorderInjectScript(hide, bindingName, this.recorderSessionId);
116
+ if (this.getCdpEndpoint() !== null) {
117
+ await this.getCDPSession();
118
+ }
119
+ try {
120
+ await context.exposeBinding(bindingName, async (source, payload) => {
121
+ if (!this.recorderSessionId) {
122
+ return false;
123
+ }
124
+ if (!payload)
125
+ return true;
126
+ const targetPage = source.page;
127
+ try {
128
+ const step = JSON.parse(payload);
129
+ if (step && step.action) {
130
+ if (step.action === 'xyzPoll') {
131
+ await targetPage
132
+ ?.evaluate((steps) => {
133
+ window.xyzQueue = steps;
134
+ window.dispatchEvent(new CustomEvent('xyzEvt', { detail: steps }));
135
+ }, this.recorderSteps)
136
+ .catch(() => { });
137
+ }
138
+ else if (step.action === 'xyzClear') {
139
+ this.recorderSteps = [];
140
+ }
141
+ else if (step.action === 'xyzUpdate') {
142
+ if (step.id && step.data) {
143
+ const updateIndex = this.recorderSteps.findIndex((s) => s.id === step.id);
144
+ if (updateIndex >= 0) {
145
+ this.recorderSteps[updateIndex] = {
146
+ ...this.recorderSteps[updateIndex],
147
+ ...step.data,
148
+ };
149
+ await targetPage
150
+ ?.evaluate((steps) => {
151
+ window.xyzQueue = steps;
152
+ window.dispatchEvent(new CustomEvent('xyzEvt', { detail: steps }));
153
+ }, this.recorderSteps)
154
+ .catch(() => { });
155
+ }
156
+ }
157
+ }
158
+ else {
159
+ this.recorderSteps.push(step);
160
+ await targetPage
161
+ ?.evaluate((steps) => {
162
+ window.xyzQueue = steps;
163
+ window.dispatchEvent(new CustomEvent('xyzEvt', { detail: steps }));
164
+ }, this.recorderSteps)
165
+ .catch(() => { });
166
+ }
167
+ }
168
+ }
169
+ catch {
170
+ /* empty */
171
+ }
172
+ return true;
173
+ });
174
+ }
175
+ catch {
176
+ // Binding already exists, ignore
177
+ }
178
+ try {
179
+ await page.evaluate((sessionId) => {
180
+ window.xyzActive = true;
181
+ window.xyzStopped = false;
182
+ window.xyzInited = false;
183
+ window.xyzSessionId = sessionId;
184
+ }, this.recorderSessionId);
185
+ }
186
+ catch {
187
+ /* empty */
188
+ }
189
+ await context.addInitScript(injectScript);
190
+ const sessionIdTimestamp = parseInt(this.recorderSessionId.replace('recorder-', ''), 10) || Date.now();
191
+ await context.addInitScript({
192
+ content: `
193
+ const currentTimestamp = parseInt((window.xyzSessionId || '').replace('recorder-', '')) || 0;
194
+ const newTimestamp = ${sessionIdTimestamp};
195
+ if (newTimestamp > currentTimestamp) {
196
+ window.xyzActive = true;
197
+ window.xyzStopped = false;
198
+ window.xyzInited = false;
199
+ window.xyzSessionId = '${this.recorderSessionId}';
200
+ }
201
+ `,
202
+ });
203
+ try {
204
+ await page.evaluate(`
205
+ const currentTimestamp = parseInt((window.xyzSessionId || '').replace('recorder-', '')) || 0;
206
+ const newTimestamp = ${sessionIdTimestamp};
207
+ if (newTimestamp > currentTimestamp) {
208
+ window.xyzActive = true;
209
+ window.xyzStopped = false;
210
+ window.xyzInited = false;
211
+ window.xyzSessionId = '${this.recorderSessionId}';
212
+ window.xyzQueue = [];
213
+ }
214
+ `);
215
+ }
216
+ catch {
217
+ /* empty */
218
+ }
219
+ try {
220
+ await page.addScriptTag({ content: injectScript, type: 'text/javascript' });
221
+ }
222
+ catch {
223
+ try {
224
+ await page.evaluate((scriptContent) => {
225
+ const script = document.createElement('script');
226
+ script.textContent = scriptContent;
227
+ script.type = 'text/javascript';
228
+ (document.head || document.documentElement).appendChild(script);
229
+ }, injectScript);
230
+ }
231
+ catch {
232
+ /* empty */
233
+ }
234
+ }
235
+ this.recorderNavigatedHandler = async (frame) => {
236
+ if (!this.recorderSessionId)
237
+ return;
238
+ if (frame !== page.mainFrame())
239
+ return;
240
+ const currentUrl = frame.url();
241
+ const now = Date.now();
242
+ if (currentUrl === this.lastNavigationUrl)
243
+ return;
244
+ const timeSinceLastNav = now - this.lastNavigationTime;
245
+ if (timeSinceLastNav < 300 && currentUrl === this.lastNavigationUrl) {
246
+ this.recorderSteps.push({
247
+ id: `step-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
248
+ timestamp: now,
249
+ action: 'reload',
250
+ });
251
+ return;
252
+ }
253
+ const existingIndex = this.navigationHistory.indexOf(currentUrl);
254
+ if (existingIndex !== -1 && existingIndex < this.navigationHistoryIndex) {
255
+ this.recorderSteps.push({
256
+ id: `step-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
257
+ timestamp: now,
258
+ action: 'back',
259
+ from: this.navigationHistory[this.navigationHistoryIndex],
260
+ to: currentUrl,
261
+ });
262
+ this.navigationHistoryIndex = existingIndex;
263
+ }
264
+ else if (existingIndex !== -1 && existingIndex > this.navigationHistoryIndex) {
265
+ this.recorderSteps.push({
266
+ id: `step-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
267
+ timestamp: now,
268
+ action: 'forward',
269
+ from: this.navigationHistory[this.navigationHistoryIndex],
270
+ to: currentUrl,
271
+ });
272
+ this.navigationHistoryIndex = existingIndex;
273
+ }
274
+ else {
275
+ if (this.navigationHistoryIndex >= 0 &&
276
+ this.navigationHistoryIndex < this.navigationHistory.length - 1) {
277
+ this.navigationHistory = this.navigationHistory.slice(0, this.navigationHistoryIndex + 1);
278
+ }
279
+ this.navigationHistory.push(currentUrl);
280
+ this.navigationHistoryIndex = this.navigationHistory.length - 1;
281
+ }
282
+ this.lastNavigationUrl = currentUrl;
283
+ this.lastNavigationTime = now;
284
+ };
285
+ page.on('framenavigated', this.recorderNavigatedHandler);
286
+ const injectScriptToFrame = async (frame) => {
287
+ if (!this.recorderSessionId)
288
+ return;
289
+ if (frame === page.mainFrame())
290
+ return;
291
+ try {
292
+ const alreadyInjected = await frame
293
+ .evaluate(() => {
294
+ return !!window.xyzInjectedSessionId;
295
+ })
296
+ .catch(() => false);
297
+ if (alreadyInjected)
298
+ return;
299
+ const frameInjectScript = this.getRecorderInjectScript(false, this.recorderBindingName || 'xyzTrack', this.recorderSessionId);
300
+ await frame.evaluate(frameInjectScript).catch(() => {
301
+ // Cross-origin iframe, ignore
302
+ });
303
+ }
304
+ catch {
305
+ // Ignore errors, likely cross-origin iframe
306
+ }
307
+ };
308
+ const injectToAllFrames = async () => {
309
+ const frames = page.frames();
310
+ for (const frame of frames) {
311
+ await injectScriptToFrame(frame);
312
+ }
313
+ };
314
+ await injectToAllFrames();
315
+ this.recorderFrameAttachedHandler = async (frame) => {
316
+ await new Promise((resolve) => setTimeout(resolve, 100));
317
+ await injectScriptToFrame(frame);
318
+ };
319
+ page.on('frameattached', this.recorderFrameAttachedHandler);
320
+ const pages = this.getPages();
321
+ const getActivePageIndex = this.getActivePageIndex;
322
+ this.recorderPageHandler = async (newPage) => {
323
+ if (this.recorderSessionId) {
324
+ const previousActiveIndex = getActivePageIndex();
325
+ const pageIndex = pages.indexOf(newPage);
326
+ const newTabIndex = pageIndex >= 0 ? pageIndex : pages.length;
327
+ this.recorderSteps.push({
328
+ id: `step-${this.recorderSteps.length + 1}`,
329
+ timestamp: Date.now(),
330
+ action: 'tab_new',
331
+ url: newPage.url(),
332
+ index: newTabIndex,
333
+ });
334
+ setTimeout(() => {
335
+ if (this.recorderSessionId && getActivePageIndex() !== previousActiveIndex) {
336
+ this.recorderSteps.push({
337
+ id: `step-${this.recorderSteps.length + 1}`,
338
+ timestamp: Date.now(),
339
+ action: 'tab_switch',
340
+ index: getActivePageIndex(),
341
+ });
342
+ }
343
+ }, 100);
344
+ newPage.on('close', () => {
345
+ if (this.recorderSessionId) {
346
+ const closeIndex = pages.indexOf(newPage);
347
+ this.recorderSteps.push({
348
+ id: `step-${this.recorderSteps.length + 1}`,
349
+ timestamp: Date.now(),
350
+ action: 'tab_close',
351
+ index: closeIndex >= 0 ? closeIndex : -1,
352
+ });
353
+ }
354
+ });
355
+ await newPage.waitForLoadState('domcontentloaded').catch(() => { });
356
+ try {
357
+ const newPageInjectScript = this.getRecorderInjectScript(false, 'xyzTrack', this.recorderSessionId);
358
+ await newPage.evaluate(newPageInjectScript);
359
+ }
360
+ catch (e) {
361
+ console.log('[recorderPageHandler] Error injecting script:', e);
362
+ }
363
+ await newPage
364
+ .evaluate((steps) => {
365
+ window.__recorderSteps = steps;
366
+ window.dispatchEvent(new CustomEvent('recorder:steps', { detail: steps }));
367
+ }, this.recorderSteps)
368
+ .catch(() => { });
369
+ this.recorderPages.push({
370
+ url: newPage.url(),
371
+ title: await newPage.title().catch(() => ''),
372
+ firstVisitTime: Date.now(),
373
+ });
374
+ }
375
+ };
376
+ context.on('page', this.recorderPageHandler);
377
+ if (url) {
378
+ await page.goto(url, { waitUntil: 'load' });
379
+ }
380
+ this.recorderPages.push({
381
+ url: page.url(),
382
+ title: await page.title(),
383
+ firstVisitTime: Date.now(),
384
+ });
385
+ return { started: true, sessionId: this.recorderSessionId };
386
+ }
387
+ async stopRecorder() {
388
+ if (!this.recorderSessionId) {
389
+ console.log('[stopRecorder] No active recording session');
390
+ return { yaml: '', steps: 0, wasRecording: false };
391
+ }
392
+ const page = this.getPage();
393
+ if (page) {
394
+ try {
395
+ await page.evaluate(() => {
396
+ const win = window;
397
+ const hasPanel = !!document.getElementById('xyzPnl');
398
+ const hasCloseFunc = typeof win.xyzClose === 'function';
399
+ const hasFlushFunc = typeof win.xyzFlushPending === 'function';
400
+ console.log('[stopRecorder] hasFlushFunc:', hasFlushFunc, 'hasCloseFunc:', hasCloseFunc, 'hasPanel:', hasPanel);
401
+ if (hasFlushFunc) {
402
+ console.log('[stopRecorder] Calling xyzFlushPending');
403
+ win.xyzFlushPending();
404
+ }
405
+ else {
406
+ console.log('[stopRecorder] xyzFlushPending not found');
407
+ }
408
+ win.xyzActive = false;
409
+ win.xyzStopped = true;
410
+ win.xyzInited = false;
411
+ win.xyzInitializedSessionId = undefined;
412
+ if (hasCloseFunc) {
413
+ win.xyzClose();
414
+ }
415
+ return {
416
+ hadPanel: hasPanel,
417
+ hadCloseFunc: hasCloseFunc,
418
+ stillHasPanel: !!document.getElementById('xyzPnl'),
419
+ };
420
+ });
421
+ }
422
+ catch (e) {
423
+ console.error('[stopRecorder] Error:', e);
424
+ }
425
+ if (this.recorderNavigatedHandler) {
426
+ page.off('framenavigated', this.recorderNavigatedHandler);
427
+ this.recorderNavigatedHandler = null;
428
+ }
429
+ if (this.recorderFrameAttachedHandler) {
430
+ page.off('frameattached', this.recorderFrameAttachedHandler);
431
+ this.recorderFrameAttachedHandler = null;
432
+ }
433
+ if (this.recorderPageHandler) {
434
+ page.context().off('page', this.recorderPageHandler);
435
+ this.recorderPageHandler = null;
436
+ }
437
+ try {
438
+ await page.context().exposeBinding(this.recorderBindingName || 'xyzTrack', () => { });
439
+ }
440
+ catch {
441
+ // Ignore errors, binding may already be removed
442
+ }
443
+ }
444
+ await new Promise((resolve) => setTimeout(resolve, 100));
445
+ const yaml = this.generateRecorderYaml();
446
+ const steps = this.recorderSteps.length;
447
+ this.recorderSessionId = null;
448
+ this.recorderSteps = [];
449
+ this.navigationHistory = [];
450
+ this.navigationHistoryIndex = -1;
451
+ this.lastNavigationUrl = '';
452
+ this.lastNavigationTime = 0;
453
+ return { yaml, steps };
454
+ }
455
+ getRecorderStatus() {
456
+ return {
457
+ isRecording: this.recorderSessionId !== null,
458
+ sessionId: this.recorderSessionId || undefined,
459
+ steps: this.recorderSteps.length,
460
+ };
461
+ }
462
+ generateRecorderYaml() {
463
+ const lines = [];
464
+ const formatTime = (ts) => {
465
+ if (!ts)
466
+ return 'unknown';
467
+ const d = new Date(ts);
468
+ return d.toTimeString().split(' ')[0];
469
+ };
470
+ lines.push('session:');
471
+ lines.push(` id: ${this.recorderSessionId || 'unknown'}`);
472
+ lines.push(` startTime: ${formatTime(this.recorderStartTime)}`);
473
+ lines.push(` endTime: ${formatTime(Date.now())}`);
474
+ lines.push(` steps: ${this.recorderSteps.length}`);
475
+ lines.push('');
476
+ if (this.recorderPages.length > 0) {
477
+ lines.push('pages:');
478
+ for (const page of this.recorderPages) {
479
+ lines.push(` - url: ${page.url}`);
480
+ lines.push(` title: ${page.title || 'N/A'}`);
481
+ lines.push(` firstVisitTime: ${formatTime(page.firstVisitTime)}`);
482
+ }
483
+ lines.push('');
484
+ }
485
+ const urlRequiredActions = [
486
+ 'open',
487
+ 'goto',
488
+ 'back',
489
+ 'forward',
490
+ 'reload',
491
+ 'tab_new',
492
+ 'tab_switch',
493
+ 'link_click',
494
+ ];
495
+ lines.push('steps:');
496
+ for (const step of this.recorderSteps) {
497
+ lines.push(` - id: ${step.id}`);
498
+ lines.push(` time: ${formatTime(step.timestamp)}`);
499
+ lines.push(` action: ${step.action}`);
500
+ if (step.selector)
501
+ lines.push(` selector: "${step.selector}"`);
502
+ if (step.xpath)
503
+ lines.push(` xpath: "${step.xpath}"`);
504
+ if (step.value)
505
+ lines.push(` value: "${step.value}"`);
506
+ if (step.points && Array.isArray(step.points) && step.points.length > 0) {
507
+ lines.push(` points: ${JSON.stringify(step.points)}`);
508
+ const trajectoryCmd = this.generateStepCliCommand(step);
509
+ if (trajectoryCmd) {
510
+ lines.push(` # Replay: ${trajectoryCmd}`);
511
+ }
512
+ }
513
+ if (step.x !== undefined)
514
+ lines.push(` x: ${step.x}`);
515
+ if (step.y !== undefined)
516
+ lines.push(` y: ${step.y}`);
517
+ if (step.from && typeof step.from === 'string') {
518
+ lines.push(` from: "${step.from}"`);
519
+ }
520
+ else if (step.from && typeof step.from === 'object') {
521
+ lines.push(` from: { width: ${step.from.width}, height: ${step.from.height} }`);
522
+ }
523
+ if (step.to && typeof step.to === 'string') {
524
+ lines.push(` to: "${step.to}"`);
525
+ }
526
+ else if (step.to && typeof step.to === 'object') {
527
+ lines.push(` to: { width: ${step.to.width}, height: ${step.to.height} }`);
528
+ }
529
+ if (step.annotation) {
530
+ lines.push(` annotation:`);
531
+ lines.push(` type: ${step.annotation.type}`);
532
+ lines.push(` label: "${step.annotation.label}"`);
533
+ if (step.annotation.selector) {
534
+ lines.push(` selector: "${step.annotation.selector}"`);
535
+ }
536
+ if (step.annotation.itemSelector) {
537
+ lines.push(` itemSelector: "${step.annotation.itemSelector}"`);
538
+ }
539
+ if (step.annotation.nextSelector) {
540
+ lines.push(` nextSelector: "${step.annotation.nextSelector}"`);
541
+ }
542
+ if (step.annotation.fields && step.annotation.fields.length > 0) {
543
+ lines.push(` fields: [${step.annotation.fields.map((f) => `"${f}"`).join(', ')}]`);
544
+ }
545
+ if (step.annotation.waitTimeout !== undefined) {
546
+ lines.push(` waitTimeout: ${step.annotation.waitTimeout}`);
547
+ }
548
+ if (step.annotation.customNote) {
549
+ lines.push(` customNote: "${step.annotation.customNote}"`);
550
+ }
551
+ lines.push(` # \u26A0\uFE0F IMPORTANT: This step requires special attention`);
552
+ lines.push(` # User marked this as: "${step.annotation.label}"`);
553
+ }
554
+ if (step.url && step.action && urlRequiredActions.includes(step.action)) {
555
+ lines.push(` url: "${step.url}"`);
556
+ }
557
+ if (step.index !== undefined)
558
+ lines.push(` index: ${step.index}`);
559
+ if (step.key)
560
+ lines.push(` key: "${step.key}"`);
561
+ if (step.code)
562
+ lines.push(` code: "${step.code}"`);
563
+ if (step.ctrlKey)
564
+ lines.push(` ctrlKey: true`);
565
+ if (step.metaKey)
566
+ lines.push(` metaKey: true`);
567
+ if (step.altKey)
568
+ lines.push(` altKey: true`);
569
+ if (step.shiftKey)
570
+ lines.push(` shiftKey: true`);
571
+ lines.push('');
572
+ }
573
+ lines.push('# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550');
574
+ lines.push('# CLI Commands (Copy & Execute)');
575
+ lines.push('# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550');
576
+ lines.push('');
577
+ lines.push('# \u542F\u7528\u6A21\u62DF\u4EBA\u7C7B\u9F20\u6807\u79FB\u52A8\uFF08\u63A8\u8350\uFF09');
578
+ lines.push('# Enable human-like mouse movement (recommended)');
579
+ lines.push('export AGENT_BROWSER_HUMAN=bezier');
580
+ lines.push('');
581
+ for (const step of this.recorderSteps) {
582
+ const cmd = this.generateStepCliCommand(step);
583
+ if (cmd) {
584
+ lines.push(`# ${step.id}: ${step.action}`);
585
+ lines.push(cmd);
586
+ lines.push('');
587
+ }
588
+ }
589
+ return lines.join('\n');
590
+ }
591
+ generateStepCliCommand(step) {
592
+ const escapeShell = (str) => {
593
+ return str.replace(/"/g, '\\"').replace(/\$/g, '\\$').replace(/`/g, '\\`');
594
+ };
595
+ const formatKeyCombo = (s) => {
596
+ const parts = [];
597
+ if (s.ctrlKey)
598
+ parts.push('Control');
599
+ if (s.metaKey)
600
+ parts.push('Meta');
601
+ if (s.altKey)
602
+ parts.push('Alt');
603
+ if (s.shiftKey &&
604
+ s.key &&
605
+ !['Shift', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(s.key)) {
606
+ parts.push('Shift');
607
+ }
608
+ if (s.key)
609
+ parts.push(s.key);
610
+ return parts.join('+');
611
+ };
612
+ switch (step.action) {
613
+ case 'click':
614
+ case 'link_click':
615
+ if (step.selector) {
616
+ return `agent-browser click "${escapeShell(step.selector)}"`;
617
+ }
618
+ if (step.xpath) {
619
+ return `agent-browser click "xpath=${escapeShell(step.xpath)}"`;
620
+ }
621
+ return null;
622
+ case 'check':
623
+ if (step.selector) {
624
+ return `agent-browser check "${escapeShell(step.selector)}"`;
625
+ }
626
+ if (step.xpath) {
627
+ return `agent-browser check "xpath=${escapeShell(step.xpath)}"`;
628
+ }
629
+ return null;
630
+ case 'uncheck':
631
+ if (step.selector) {
632
+ return `agent-browser uncheck "${escapeShell(step.selector)}"`;
633
+ }
634
+ if (step.xpath) {
635
+ return `agent-browser uncheck "xpath=${escapeShell(step.xpath)}"`;
636
+ }
637
+ return null;
638
+ case 'fill':
639
+ if (step.value !== undefined) {
640
+ if (step.selector) {
641
+ return `agent-browser fill "${escapeShell(step.selector)}" "${escapeShell(String(step.value))}"`;
642
+ }
643
+ if (step.xpath) {
644
+ return `agent-browser fill "xpath=${escapeShell(step.xpath)}" "${escapeShell(String(step.value))}"`;
645
+ }
646
+ }
647
+ return null;
648
+ case 'select':
649
+ if (step.value !== undefined) {
650
+ if (step.selector) {
651
+ return `agent-browser select "${escapeShell(step.selector)}" "${escapeShell(String(step.value))}"`;
652
+ }
653
+ if (step.xpath) {
654
+ return `agent-browser select "xpath=${escapeShell(step.xpath)}" "${escapeShell(String(step.value))}"`;
655
+ }
656
+ }
657
+ return null;
658
+ case 'keyboard':
659
+ const key = formatKeyCombo(step);
660
+ if (key) {
661
+ return `agent-browser press "${key}"`;
662
+ }
663
+ return null;
664
+ case 'scroll':
665
+ if (step.x !== undefined && step.y !== undefined) {
666
+ return `agent-browser mouse wheel ${step.y} ${step.x}`;
667
+ }
668
+ return null;
669
+ case 'trajectory':
670
+ if (step.points && Array.isArray(step.points) && step.points.length > 0) {
671
+ const maxPoints = 5;
672
+ let sampled;
673
+ if (step.points.length <= maxPoints) {
674
+ sampled = step.points;
675
+ }
676
+ else {
677
+ sampled = [];
678
+ const step_size = (step.points.length - 1) / (maxPoints - 1);
679
+ for (let i = 0; i < maxPoints; i++) {
680
+ const idx = Math.round(i * step_size);
681
+ sampled.push(step.points[idx]);
682
+ }
683
+ }
684
+ const segments = sampled.map((p, i) => {
685
+ const x = Math.round(p.x);
686
+ const y = Math.round(p.y);
687
+ const delay = i === 0 ? 0 : Math.round(p.t - sampled[i - 1].t);
688
+ return `${x}:${y}:${delay}`;
689
+ });
690
+ return `AGENT_BROWSER_HUMAN=bezier agent-browser mouse trajectory "${segments.join(';')}"`;
691
+ }
692
+ return null;
693
+ case 'open':
694
+ case 'goto':
695
+ if (step.url) {
696
+ return `agent-browser open "${step.url}"`;
697
+ }
698
+ return null;
699
+ case 'back':
700
+ return 'agent-browser back';
701
+ case 'forward':
702
+ return 'agent-browser forward';
703
+ case 'reload':
704
+ return 'agent-browser reload';
705
+ case 'tab_new':
706
+ if (step.url) {
707
+ return `agent-browser tab new "${step.url}"`;
708
+ }
709
+ return 'agent-browser tab new';
710
+ case 'tab_switch':
711
+ if (step.index !== undefined) {
712
+ return `agent-browser tab ${step.index}`;
713
+ }
714
+ return null;
715
+ case 'resize':
716
+ if (step.to && typeof step.to === 'object') {
717
+ return `agent-browser set viewport ${step.to.width} ${step.to.height}`;
718
+ }
719
+ return null;
720
+ case 'hover':
721
+ if (step.xpath) {
722
+ return `agent-browser hover "xpath=${escapeShell(step.xpath)}"`;
723
+ }
724
+ if (step.selector) {
725
+ return `agent-browser hover "${escapeShell(step.selector)}"`;
726
+ }
727
+ return null;
728
+ default:
729
+ return null;
730
+ }
731
+ }
732
+ cleanup(page) {
733
+ if (page) {
734
+ if (this.recorderNavigatedHandler) {
735
+ page.off('framenavigated', this.recorderNavigatedHandler);
736
+ this.recorderNavigatedHandler = null;
737
+ }
738
+ if (this.recorderFrameAttachedHandler) {
739
+ page.off('frameattached', this.recorderFrameAttachedHandler);
740
+ this.recorderFrameAttachedHandler = null;
741
+ }
742
+ if (this.recorderPageHandler) {
743
+ page.context().off('page', this.recorderPageHandler);
744
+ this.recorderPageHandler = null;
745
+ }
746
+ }
747
+ this.recorderSessionId = null;
748
+ this.recorderSteps = [];
749
+ this.navigationHistory = [];
750
+ this.navigationHistoryIndex = -1;
751
+ this.lastNavigationUrl = '';
752
+ this.lastNavigationTime = 0;
753
+ }
754
+ }
755
+ //# sourceMappingURL=recorder-manager.js.map