@dyyz1993/agent-browser 0.9.2

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 (187) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +907 -0
  3. package/bin/agent-browser-darwin-arm64 +0 -0
  4. package/bin/agent-browser.js +120 -0
  5. package/dist/__tests__/e2e/utils/test-helpers.d.ts +5 -0
  6. package/dist/__tests__/e2e/utils/test-helpers.d.ts.map +1 -0
  7. package/dist/__tests__/e2e/utils/test-helpers.js +22 -0
  8. package/dist/__tests__/e2e/utils/test-helpers.js.map +1 -0
  9. package/dist/__tests__/test-iframe.d.ts +2 -0
  10. package/dist/__tests__/test-iframe.d.ts.map +1 -0
  11. package/dist/__tests__/test-iframe.js +52 -0
  12. package/dist/__tests__/test-iframe.js.map +1 -0
  13. package/dist/__tests__/utils/parseCli.d.ts +20 -0
  14. package/dist/__tests__/utils/parseCli.d.ts.map +1 -0
  15. package/dist/__tests__/utils/parseCli.js +1086 -0
  16. package/dist/__tests__/utils/parseCli.js.map +1 -0
  17. package/dist/actions.d.ts +50 -0
  18. package/dist/actions.d.ts.map +1 -0
  19. package/dist/actions.js +2164 -0
  20. package/dist/actions.js.map +1 -0
  21. package/dist/browser.d.ts +556 -0
  22. package/dist/browser.d.ts.map +1 -0
  23. package/dist/browser.js +2599 -0
  24. package/dist/browser.js.map +1 -0
  25. package/dist/cli/commands.d.ts +8 -0
  26. package/dist/cli/commands.d.ts.map +1 -0
  27. package/dist/cli/commands.js +1038 -0
  28. package/dist/cli/commands.js.map +1 -0
  29. package/dist/cli/connection.d.ts +50 -0
  30. package/dist/cli/connection.d.ts.map +1 -0
  31. package/dist/cli/connection.js +595 -0
  32. package/dist/cli/connection.js.map +1 -0
  33. package/dist/cli/flags.d.ts +36 -0
  34. package/dist/cli/flags.d.ts.map +1 -0
  35. package/dist/cli/flags.js +206 -0
  36. package/dist/cli/flags.js.map +1 -0
  37. package/dist/cli/help.d.ts +4 -0
  38. package/dist/cli/help.d.ts.map +1 -0
  39. package/dist/cli/help.js +1024 -0
  40. package/dist/cli/help.js.map +1 -0
  41. package/dist/cli/output.d.ts +14 -0
  42. package/dist/cli/output.d.ts.map +1 -0
  43. package/dist/cli/output.js +456 -0
  44. package/dist/cli/output.js.map +1 -0
  45. package/dist/cli-new.d.ts +3 -0
  46. package/dist/cli-new.d.ts.map +1 -0
  47. package/dist/cli-new.js +308 -0
  48. package/dist/cli-new.js.map +1 -0
  49. package/dist/cli-old.d.ts +3 -0
  50. package/dist/cli-old.d.ts.map +1 -0
  51. package/dist/cli-old.js +1101 -0
  52. package/dist/cli-old.js.map +1 -0
  53. package/dist/cli.d.ts +3 -0
  54. package/dist/cli.d.ts.map +1 -0
  55. package/dist/cli.js +403 -0
  56. package/dist/cli.js.map +1 -0
  57. package/dist/content-detection.d.ts +18 -0
  58. package/dist/content-detection.d.ts.map +1 -0
  59. package/dist/content-detection.js +68 -0
  60. package/dist/content-detection.js.map +1 -0
  61. package/dist/daemon.d.ts +55 -0
  62. package/dist/daemon.d.ts.map +1 -0
  63. package/dist/daemon.js +426 -0
  64. package/dist/daemon.js.map +1 -0
  65. package/dist/diff.d.ts +42 -0
  66. package/dist/diff.d.ts.map +1 -0
  67. package/dist/diff.js +166 -0
  68. package/dist/diff.js.map +1 -0
  69. package/dist/human-mouse.d.ts +31 -0
  70. package/dist/human-mouse.d.ts.map +1 -0
  71. package/dist/human-mouse.js +184 -0
  72. package/dist/human-mouse.js.map +1 -0
  73. package/dist/ios-actions.d.ts +11 -0
  74. package/dist/ios-actions.d.ts.map +1 -0
  75. package/dist/ios-actions.js +228 -0
  76. package/dist/ios-actions.js.map +1 -0
  77. package/dist/ios-manager.d.ts +266 -0
  78. package/dist/ios-manager.d.ts.map +1 -0
  79. package/dist/ios-manager.js +1076 -0
  80. package/dist/ios-manager.js.map +1 -0
  81. package/dist/message-bridge.d.ts +10 -0
  82. package/dist/message-bridge.d.ts.map +1 -0
  83. package/dist/message-bridge.js +60 -0
  84. package/dist/message-bridge.js.map +1 -0
  85. package/dist/protocol.d.ts +26 -0
  86. package/dist/protocol.d.ts.map +1 -0
  87. package/dist/protocol.js +912 -0
  88. package/dist/protocol.js.map +1 -0
  89. package/dist/recorder/binding.d.ts +24 -0
  90. package/dist/recorder/binding.d.ts.map +1 -0
  91. package/dist/recorder/binding.js +215 -0
  92. package/dist/recorder/binding.js.map +1 -0
  93. package/dist/recorder/index.d.ts +4 -0
  94. package/dist/recorder/index.d.ts.map +1 -0
  95. package/dist/recorder/index.js +4 -0
  96. package/dist/recorder/index.js.map +1 -0
  97. package/dist/recorder/inject.js +1913 -0
  98. package/dist/recorder/recorder.d.ts +19 -0
  99. package/dist/recorder/recorder.d.ts.map +1 -0
  100. package/dist/recorder/recorder.js +101 -0
  101. package/dist/recorder/recorder.js.map +1 -0
  102. package/dist/recorder/store.d.ts +22 -0
  103. package/dist/recorder/store.d.ts.map +1 -0
  104. package/dist/recorder/store.js +150 -0
  105. package/dist/recorder/store.js.map +1 -0
  106. package/dist/recorder/types.d.ts +73 -0
  107. package/dist/recorder/types.d.ts.map +1 -0
  108. package/dist/recorder/types.js +5 -0
  109. package/dist/recorder/types.js.map +1 -0
  110. package/dist/snapshot.d.ts +81 -0
  111. package/dist/snapshot.d.ts.map +1 -0
  112. package/dist/snapshot.js +1348 -0
  113. package/dist/snapshot.js.map +1 -0
  114. package/dist/stream-server-standalone.d.ts +38 -0
  115. package/dist/stream-server-standalone.d.ts.map +1 -0
  116. package/dist/stream-server-standalone.js +494 -0
  117. package/dist/stream-server-standalone.js.map +1 -0
  118. package/dist/stream-server.d.ts +214 -0
  119. package/dist/stream-server.d.ts.map +1 -0
  120. package/dist/stream-server.js +811 -0
  121. package/dist/stream-server.js.map +1 -0
  122. package/dist/types.d.ts +914 -0
  123. package/dist/types.d.ts.map +1 -0
  124. package/dist/types.js +4 -0
  125. package/dist/types.js.map +1 -0
  126. package/dist/viewer-html.d.ts +2 -0
  127. package/dist/viewer-html.d.ts.map +1 -0
  128. package/dist/viewer-html.js +185 -0
  129. package/dist/viewer-html.js.map +1 -0
  130. package/dist/viewer-script.d.ts +47 -0
  131. package/dist/viewer-script.d.ts.map +1 -0
  132. package/dist/viewer-script.js +586 -0
  133. package/dist/viewer-script.js.map +1 -0
  134. package/package.json +86 -0
  135. package/scripts/build-all-platforms.sh +68 -0
  136. package/scripts/check-version-sync.js +39 -0
  137. package/scripts/check_goods_container.js +35 -0
  138. package/scripts/check_page_content.js +36 -0
  139. package/scripts/click_applause_rate.js +30 -0
  140. package/scripts/copy-native.js +36 -0
  141. package/scripts/copy-recorder.js +21 -0
  142. package/scripts/e2e-test-recorder.ts +584 -0
  143. package/scripts/explore_jd_page.js +31 -0
  144. package/scripts/extract_all_jd_data.js +80 -0
  145. package/scripts/extract_jd_product_detail.js +62 -0
  146. package/scripts/extract_jd_products_correct_links.js +78 -0
  147. package/scripts/extract_jd_products_final.js +80 -0
  148. package/scripts/extract_jd_reviews.js +48 -0
  149. package/scripts/extract_jd_seafood_final.js +78 -0
  150. package/scripts/extract_multiple_products.js +77 -0
  151. package/scripts/extract_products_no_scroll.js +68 -0
  152. package/scripts/extract_products_simple.js +68 -0
  153. package/scripts/find_applause_rate.js +26 -0
  154. package/scripts/find_jd_links.js +28 -0
  155. package/scripts/find_main_content.js +20 -0
  156. package/scripts/find_product_cards.js +38 -0
  157. package/scripts/find_root_content.js +26 -0
  158. package/scripts/find_unique_products.js +55 -0
  159. package/scripts/get_jd_product_detail.js +16 -0
  160. package/scripts/get_jd_products.js +23 -0
  161. package/scripts/get_jd_seafood_products.js +44 -0
  162. package/scripts/get_product_details_from_images.js +54 -0
  163. package/scripts/postinstall.js +235 -0
  164. package/scripts/scroll_and_get_products.js +47 -0
  165. package/scripts/scroll_deep_and_find.js +45 -0
  166. package/scripts/sync-version.js +69 -0
  167. package/scripts/verify-baidu-enter.ts +116 -0
  168. package/skills/agent-browser/SKILL.md +310 -0
  169. package/skills/agent-browser/references/authentication.md +198 -0
  170. package/skills/agent-browser/references/commands.md +471 -0
  171. package/skills/agent-browser/references/data-extraction.md +377 -0
  172. package/skills/agent-browser/references/proxy-support.md +188 -0
  173. package/skills/agent-browser/references/session-management.md +197 -0
  174. package/skills/agent-browser/references/snapshot-refs.md +379 -0
  175. package/skills/agent-browser/references/video-recording.md +173 -0
  176. package/skills/agent-browser/templates/api-interception.sh +53 -0
  177. package/skills/agent-browser/templates/authenticated-session.sh +97 -0
  178. package/skills/agent-browser/templates/capture-workflow.sh +69 -0
  179. package/skills/agent-browser/templates/data-extraction.sh +210 -0
  180. package/skills/agent-browser/templates/form-automation.sh +62 -0
  181. package/skills/skill-creator/LICENSE.txt +202 -0
  182. package/skills/skill-creator/SKILL.md +356 -0
  183. package/skills/skill-creator/references/output-patterns.md +82 -0
  184. package/skills/skill-creator/references/workflows.md +28 -0
  185. package/skills/skill-creator/scripts/init_skill.py +303 -0
  186. package/skills/skill-creator/scripts/package_skill.py +113 -0
  187. package/skills/skill-creator/scripts/quick_validate.py +95 -0
@@ -0,0 +1,1038 @@
1
+ export class CliError extends Error {
2
+ usage;
3
+ constructor(message, usage) {
4
+ super(message);
5
+ this.usage = usage;
6
+ this.name = 'CliError';
7
+ }
8
+ }
9
+ function error(message, usage) {
10
+ throw new CliError(message, usage);
11
+ }
12
+ function genId() {
13
+ return `n${Date.now() % 1000000}`;
14
+ }
15
+ function parseInFrame(args) {
16
+ let inFrame;
17
+ const remaining = [];
18
+ for (let i = 0; i < args.length; i++) {
19
+ if (args[i] === '--in-frame' || args[i] === '-f') {
20
+ inFrame = args[i + 1];
21
+ i++;
22
+ }
23
+ else {
24
+ remaining.push(args[i]);
25
+ }
26
+ }
27
+ return { inFrame, remaining };
28
+ }
29
+ function parseDiff(args) {
30
+ const diffIdx = args.indexOf('--diff');
31
+ if (diffIdx === -1) {
32
+ return { remaining: args };
33
+ }
34
+ const remaining = [...args];
35
+ remaining.splice(diffIdx, 1);
36
+ const nextArg = remaining[diffIdx];
37
+ if (nextArg === 'full') {
38
+ remaining.splice(diffIdx, 1);
39
+ return { diffScope: 'full', remaining };
40
+ }
41
+ if (nextArg && /^\d+$/.test(nextArg)) {
42
+ remaining.splice(diffIdx, 1);
43
+ return { diffScope: parseInt(nextArg, 10), remaining };
44
+ }
45
+ if (nextArg && !nextArg.startsWith('-') && !nextArg.startsWith('@')) {
46
+ remaining.splice(diffIdx, 1);
47
+ return { diffScope: nextArg, remaining };
48
+ }
49
+ return { diffScope: 3, remaining };
50
+ }
51
+ export function parseCommand(args, flags) {
52
+ if (args.length === 0) {
53
+ error('No command provided', 'agent-browser <command> [args...]');
54
+ }
55
+ const cmd = args[0];
56
+ const rest = args.slice(1);
57
+ const id = genId();
58
+ switch (cmd) {
59
+ case 'open':
60
+ case 'goto':
61
+ case 'navigate': {
62
+ const url = rest[0];
63
+ if (!url)
64
+ error('Missing URL', 'agent-browser open <url>');
65
+ const urlLower = url.toLowerCase();
66
+ const formattedUrl = urlLower.startsWith('http://') ||
67
+ urlLower.startsWith('https://') ||
68
+ urlLower.startsWith('about:') ||
69
+ urlLower.startsWith('data:') ||
70
+ urlLower.startsWith('file:')
71
+ ? url
72
+ : `https://${url}`;
73
+ const navCmd = { id, action: 'navigate', url: formattedUrl };
74
+ if (flags.headers) {
75
+ try {
76
+ navCmd.headers = JSON.parse(flags.headers);
77
+ }
78
+ catch { }
79
+ }
80
+ if (flags.timeout) {
81
+ navCmd.timeout = parseInt(flags.timeout, 10);
82
+ }
83
+ if (flags.provider === 'ios' && flags.device) {
84
+ navCmd.iosDevice = flags.device;
85
+ }
86
+ return navCmd;
87
+ }
88
+ case 'back':
89
+ return { id, action: 'back' };
90
+ case 'forward':
91
+ return { id, action: 'forward' };
92
+ case 'reload':
93
+ return { id, action: 'reload' };
94
+ case 'click': {
95
+ const { inFrame, remaining: r1 } = parseInFrame(rest);
96
+ const { diffScope, remaining } = parseDiff(r1);
97
+ const selector = remaining[0];
98
+ if (!selector)
99
+ error('Missing selector', 'agent-browser click <selector> [--diff [scope]] [--in-frame <path>]');
100
+ const cmd = { id, action: 'click', selector, inFrame, diffScope };
101
+ if (flags.human.enabled)
102
+ cmd.human = flags.human;
103
+ return cmd;
104
+ }
105
+ case 'dblclick': {
106
+ const { inFrame, remaining: r1 } = parseInFrame(rest);
107
+ const { diffScope, remaining } = parseDiff(r1);
108
+ const selector = remaining[0];
109
+ if (!selector)
110
+ error('Missing selector', 'agent-browser dblclick <selector> [--diff [scope]] [--in-frame <path>]');
111
+ const cmd = { id, action: 'dblclick', selector, inFrame, diffScope };
112
+ if (flags.human.enabled)
113
+ cmd.human = flags.human;
114
+ return cmd;
115
+ }
116
+ case 'fill': {
117
+ const { inFrame, remaining: r1 } = parseInFrame(rest);
118
+ const { diffScope, remaining } = parseDiff(r1);
119
+ const selector = remaining[0];
120
+ const value = remaining.slice(1).join(' ');
121
+ if (!selector || !value)
122
+ error('Missing selector or value', 'agent-browser fill <selector> <text> [--diff [scope]] [--in-frame <path>]');
123
+ const cmd = { id, action: 'fill', selector, value, inFrame, diffScope };
124
+ if (flags.human.enabled)
125
+ cmd.human = flags.human;
126
+ return cmd;
127
+ }
128
+ case 'type': {
129
+ const { inFrame, remaining: r1 } = parseInFrame(rest);
130
+ const { diffScope, remaining } = parseDiff(r1);
131
+ const selector = remaining[0];
132
+ const text = remaining.slice(1).join(' ');
133
+ if (!selector || !text)
134
+ error('Missing selector or text', 'agent-browser type <selector> <text> [--diff [scope]] [--in-frame <path>]');
135
+ const cmd = { id, action: 'type', selector, text, inFrame, diffScope };
136
+ if (flags.human.enabled)
137
+ cmd.human = flags.human;
138
+ return cmd;
139
+ }
140
+ case 'hover': {
141
+ const { inFrame, remaining: r1 } = parseInFrame(rest);
142
+ const { diffScope, remaining } = parseDiff(r1);
143
+ const selector = remaining[0];
144
+ if (!selector)
145
+ error('Missing selector', 'agent-browser hover <selector> [--diff [scope]] [--in-frame <path>]');
146
+ const cmd = { id, action: 'hover', selector, inFrame, diffScope };
147
+ if (flags.human.enabled)
148
+ cmd.human = flags.human;
149
+ return cmd;
150
+ }
151
+ case 'focus': {
152
+ const { inFrame, remaining: r1 } = parseInFrame(rest);
153
+ const { diffScope, remaining } = parseDiff(r1);
154
+ const selector = remaining[0];
155
+ if (!selector)
156
+ error('Missing selector', 'agent-browser focus <selector> [--diff [scope]] [--in-frame <path>]');
157
+ return { id, action: 'focus', selector, inFrame, diffScope };
158
+ }
159
+ case 'check': {
160
+ const { inFrame, remaining: r1 } = parseInFrame(rest);
161
+ const { diffScope, remaining } = parseDiff(r1);
162
+ const selector = remaining[0];
163
+ if (!selector)
164
+ error('Missing selector', 'agent-browser check <selector> [--diff [scope]] [--in-frame <path>]');
165
+ return { id, action: 'check', selector, inFrame, diffScope };
166
+ }
167
+ case 'uncheck': {
168
+ const { inFrame, remaining: r1 } = parseInFrame(rest);
169
+ const { diffScope, remaining } = parseDiff(r1);
170
+ const selector = remaining[0];
171
+ if (!selector)
172
+ error('Missing selector', 'agent-browser uncheck <selector> [--diff [scope]] [--in-frame <path>]');
173
+ return { id, action: 'uncheck', selector, inFrame, diffScope };
174
+ }
175
+ case 'select': {
176
+ const { inFrame, remaining: r1 } = parseInFrame(rest);
177
+ const { diffScope, remaining } = parseDiff(r1);
178
+ const selector = remaining[0];
179
+ const values = remaining.slice(1);
180
+ if (!selector || values.length === 0)
181
+ error('Missing selector or values', 'agent-browser select <selector> <value...> [--diff [scope]] [--in-frame <path>]');
182
+ return {
183
+ id,
184
+ action: 'select',
185
+ selector,
186
+ values: values.length === 1 ? values[0] : values,
187
+ inFrame,
188
+ diffScope,
189
+ };
190
+ }
191
+ case 'drag': {
192
+ const source = rest[0];
193
+ const target = rest[1];
194
+ if (!source || !target)
195
+ error('Missing source or target', 'agent-browser drag <source> <target>');
196
+ return { id, action: 'drag', source, target };
197
+ }
198
+ case 'upload': {
199
+ const selector = rest[0];
200
+ const files = rest.slice(1);
201
+ if (!selector || files.length === 0)
202
+ error('Missing selector or files', 'agent-browser upload <selector> <files...>');
203
+ return { id, action: 'upload', selector, files };
204
+ }
205
+ case 'download': {
206
+ const selector = rest[0];
207
+ const path = rest[1];
208
+ if (!selector || !path)
209
+ error('Missing selector or path', 'agent-browser download <selector> <path>');
210
+ return { id, action: 'download', selector, path };
211
+ }
212
+ case 'press':
213
+ case 'key': {
214
+ const { diffScope, remaining } = parseDiff(rest);
215
+ const key = remaining[0];
216
+ if (!key)
217
+ error('Missing key', 'agent-browser press <key> [--diff [scope]]');
218
+ return { id, action: 'press', key, diffScope };
219
+ }
220
+ case 'keydown': {
221
+ const key = rest[0];
222
+ if (!key)
223
+ error('Missing key', 'agent-browser keydown <key>');
224
+ return { id, action: 'keydown', key };
225
+ }
226
+ case 'keyup': {
227
+ const key = rest[0];
228
+ if (!key)
229
+ error('Missing key', 'agent-browser keyup <key>');
230
+ return { id, action: 'keyup', key };
231
+ }
232
+ case 'scroll': {
233
+ const direction = rest[0] || 'down';
234
+ const amount = rest[1] ? parseInt(rest[1], 10) : 300;
235
+ return { id, action: 'scroll', direction, amount };
236
+ }
237
+ case 'scrollintoview':
238
+ case 'scrollinto': {
239
+ const selector = rest[0];
240
+ if (!selector)
241
+ error('Missing selector', 'agent-browser scrollintoview <selector>');
242
+ return { id, action: 'scrollintoview', selector };
243
+ }
244
+ case 'wait': {
245
+ if (rest.includes('--url') || rest.includes('-u')) {
246
+ const urlIdx = rest.includes('--url') ? rest.indexOf('--url') : rest.indexOf('-u');
247
+ const url = rest[urlIdx + 1];
248
+ if (!url)
249
+ error('Missing URL pattern', 'agent-browser wait --url <pattern>');
250
+ return { id, action: 'waitforurl', url };
251
+ }
252
+ if (rest.includes('--load') || rest.includes('-l')) {
253
+ const loadIdx = rest.includes('--load') ? rest.indexOf('--load') : rest.indexOf('-l');
254
+ const state = rest[loadIdx + 1];
255
+ if (!state)
256
+ error('Missing load state', 'agent-browser wait --load <state>');
257
+ return { id, action: 'waitforloadstate', state };
258
+ }
259
+ if (rest.includes('--fn') || rest.includes('-f')) {
260
+ const fnIdx = rest.includes('--fn') ? rest.indexOf('--fn') : rest.indexOf('-f');
261
+ const expression = rest[fnIdx + 1];
262
+ if (!expression)
263
+ error('Missing expression', 'agent-browser wait --fn <expression>');
264
+ return { id, action: 'waitforfunction', expression };
265
+ }
266
+ if (rest.includes('--text') || rest.includes('-t')) {
267
+ const textIdx = rest.includes('--text') ? rest.indexOf('--text') : rest.indexOf('-t');
268
+ const text = rest[textIdx + 1];
269
+ if (!text)
270
+ error('Missing text', 'agent-browser wait --text <text>');
271
+ return { id, action: 'wait', selector: `text=${text}` };
272
+ }
273
+ if (rest.includes('--download') || rest.includes('-d')) {
274
+ const cmd = { id, action: 'waitfordownload' };
275
+ const dlIdx = rest.includes('--download') ? rest.indexOf('--download') : rest.indexOf('-d');
276
+ if (rest[dlIdx + 1] && !rest[dlIdx + 1].startsWith('--'))
277
+ cmd.path = rest[dlIdx + 1];
278
+ const timeoutIdx = rest.indexOf('--timeout');
279
+ if (timeoutIdx !== -1 && rest[timeoutIdx + 1])
280
+ cmd.timeout = parseInt(rest[timeoutIdx + 1], 10);
281
+ return cmd;
282
+ }
283
+ if (rest.includes('--request') || rest.includes('-r')) {
284
+ const reqIdx = rest.includes('--request') ? rest.indexOf('--request') : rest.indexOf('-r');
285
+ const url = rest[reqIdx + 1];
286
+ if (!url)
287
+ error('Missing URL pattern', 'agent-browser wait --request <pattern>');
288
+ const cmd = { id, action: 'responsebody', url };
289
+ const timeoutIdx = rest.indexOf('--timeout');
290
+ if (timeoutIdx !== -1 && rest[timeoutIdx + 1])
291
+ cmd.timeout = parseInt(rest[timeoutIdx + 1], 10);
292
+ return cmd;
293
+ }
294
+ if (rest[0]) {
295
+ const timeout = parseInt(rest[0], 10);
296
+ if (!isNaN(timeout))
297
+ return { id, action: 'wait', timeout };
298
+ return { id, action: 'wait', selector: rest[0] };
299
+ }
300
+ error('Missing arguments', 'agent-browser wait <selector|ms|--url|--load|--fn|--text|--download|--request>');
301
+ }
302
+ case 'screenshot': {
303
+ const fullPage = rest.includes('--full') || rest.includes('-f');
304
+ const filtered = rest.filter((r) => r !== '--full' && r !== '-f');
305
+ let selector;
306
+ let path;
307
+ if (filtered.length === 2) {
308
+ selector = filtered[0];
309
+ path = filtered[1];
310
+ }
311
+ else if (filtered.length === 1) {
312
+ const arg = filtered[0];
313
+ const isPath = arg.includes('/') ||
314
+ arg.endsWith('.png') ||
315
+ arg.endsWith('.jpg') ||
316
+ arg.endsWith('.jpeg') ||
317
+ arg.endsWith('.webp');
318
+ if (isPath)
319
+ path = arg;
320
+ else
321
+ selector = arg;
322
+ }
323
+ return { id, action: 'screenshot', selector, path, fullPage: fullPage || undefined };
324
+ }
325
+ case 'pdf': {
326
+ const path = rest[0];
327
+ if (!path)
328
+ error('Missing path', 'agent-browser pdf <path>');
329
+ return { id, action: 'pdf', path };
330
+ }
331
+ case 'snapshot': {
332
+ const command = { id, action: 'snapshot' };
333
+ for (let i = 0; i < rest.length; i++) {
334
+ switch (rest[i]) {
335
+ case '-i':
336
+ case '--interactive':
337
+ command.interactive = true;
338
+ break;
339
+ case '-c':
340
+ case '--compact':
341
+ command.compact = true;
342
+ break;
343
+ case '-C':
344
+ case '--cursor':
345
+ command.cursor = true;
346
+ break;
347
+ case '-d':
348
+ case '--depth':
349
+ if (rest[i + 1]) {
350
+ command.maxDepth = parseInt(rest[i + 1], 10);
351
+ i++;
352
+ }
353
+ break;
354
+ case '-s':
355
+ case '--selector':
356
+ if (rest[i + 1]) {
357
+ command.selector = rest[i + 1];
358
+ i++;
359
+ }
360
+ break;
361
+ case '-f':
362
+ case '--in-frame':
363
+ if (rest[i + 1]) {
364
+ command.inFrame = rest[i + 1];
365
+ i++;
366
+ }
367
+ break;
368
+ case '--path':
369
+ command.path = true;
370
+ break;
371
+ case '--attrs':
372
+ command.attrs = true;
373
+ break;
374
+ }
375
+ }
376
+ return command;
377
+ }
378
+ case 'eval': {
379
+ let script;
380
+ let file;
381
+ if (rest.includes('--file')) {
382
+ const fileIdx = rest.indexOf('--file');
383
+ file = rest[fileIdx + 1];
384
+ if (!file)
385
+ error('Missing file path', 'agent-browser eval --file <path>');
386
+ }
387
+ else if (rest.includes('--stdin')) {
388
+ const fd = process.stdin.fd;
389
+ const buffer = Buffer.allocUnsafe(1024);
390
+ const chunks = [];
391
+ const fs = require('fs');
392
+ let bytesRead;
393
+ while ((bytesRead = fs.readSync(fd, buffer, 0, buffer.length)) > 0) {
394
+ chunks.push(Buffer.from(buffer.subarray(0, bytesRead)));
395
+ }
396
+ script = Buffer.concat(chunks).toString('utf8');
397
+ }
398
+ else if (rest.includes('-b') || rest.includes('--base64')) {
399
+ const bIdx = rest.includes('-b') ? rest.indexOf('-b') : rest.indexOf('--base64');
400
+ const encoded = rest[bIdx + 1];
401
+ if (!encoded)
402
+ error('Missing base64 script', 'agent-browser eval -b <base64-script>');
403
+ script = Buffer.from(encoded, 'base64').toString('utf8');
404
+ }
405
+ else {
406
+ script = rest.join(' ');
407
+ if (!script)
408
+ error('Missing script', 'agent-browser eval <script>');
409
+ }
410
+ return { id, action: 'evaluate', script, file };
411
+ }
412
+ case 'close':
413
+ case 'quit':
414
+ case 'exit':
415
+ return { id, action: 'close' };
416
+ case 'get': {
417
+ const subcmd = rest[0];
418
+ if (!subcmd)
419
+ error('Missing subcommand', 'agent-browser get <text|html|value|attr|url|title|count|box|styles> [args...]');
420
+ switch (subcmd) {
421
+ case 'text': {
422
+ const selector = rest[1];
423
+ if (!selector)
424
+ error('Missing selector', 'agent-browser get text <selector>');
425
+ return { id, action: 'gettext', selector };
426
+ }
427
+ case 'html': {
428
+ const selector = rest[1];
429
+ if (!selector)
430
+ error('Missing selector', 'agent-browser get html <selector>');
431
+ return { id, action: 'innerhtml', selector };
432
+ }
433
+ case 'value': {
434
+ const selector = rest[1];
435
+ if (!selector)
436
+ error('Missing selector', 'agent-browser get value <selector>');
437
+ return { id, action: 'inputvalue', selector };
438
+ }
439
+ case 'attr': {
440
+ const selector = rest[1];
441
+ const attribute = rest[2];
442
+ if (!selector || !attribute)
443
+ error('Missing selector or attribute', 'agent-browser get attr <selector> <attribute>');
444
+ return { id, action: 'getattribute', selector, attribute };
445
+ }
446
+ case 'url':
447
+ return { id, action: 'url' };
448
+ case 'title':
449
+ return { id, action: 'title' };
450
+ case 'count': {
451
+ const selector = rest[1];
452
+ if (!selector)
453
+ error('Missing selector', 'agent-browser get count <selector>');
454
+ return { id, action: 'count', selector };
455
+ }
456
+ case 'box': {
457
+ const selector = rest[1];
458
+ if (!selector)
459
+ error('Missing selector', 'agent-browser get box <selector>');
460
+ return { id, action: 'boundingbox', selector };
461
+ }
462
+ case 'styles': {
463
+ const selector = rest[1];
464
+ if (!selector)
465
+ error('Missing selector', 'agent-browser get styles <selector>');
466
+ return { id, action: 'styles', selector };
467
+ }
468
+ default:
469
+ error(`Unknown get subcommand: ${subcmd}`, 'agent-browser get <text|html|value|attr|url|title|count|box|styles> [args...]');
470
+ }
471
+ }
472
+ case 'is': {
473
+ const subcmd = rest[0];
474
+ if (!subcmd)
475
+ error('Missing subcommand', 'agent-browser is <visible|enabled|checked> <selector>');
476
+ const selector = rest[1];
477
+ if (!selector)
478
+ error('Missing selector', `agent-browser is ${subcmd} <selector>`);
479
+ switch (subcmd) {
480
+ case 'visible':
481
+ return { id, action: 'isvisible', selector };
482
+ case 'enabled':
483
+ return { id, action: 'isenabled', selector };
484
+ case 'checked':
485
+ return { id, action: 'ischecked', selector };
486
+ default:
487
+ error(`Unknown is subcommand: ${subcmd}`, 'agent-browser is <visible|enabled|checked> <selector>');
488
+ }
489
+ }
490
+ case 'find': {
491
+ const { inFrame, remaining: findRest } = parseInFrame(rest);
492
+ const locator = findRest[0];
493
+ if (!locator)
494
+ error('Missing locator type', 'agent-browser find <locator> <value> [action] [text] [--in-frame <path>]');
495
+ const nameIdx = findRest.indexOf('--name');
496
+ const name = nameIdx !== -1 ? findRest[nameIdx + 1] : undefined;
497
+ const exact = findRest.includes('--exact');
498
+ switch (locator) {
499
+ case 'role': {
500
+ const role = findRest[1];
501
+ if (!role)
502
+ error('Missing role', 'agent-browser find role <role> [action] [--name <name>] [--exact] [--in-frame <path>]');
503
+ const subaction = findRest[2] || 'click';
504
+ const value = findRest
505
+ .slice(3)
506
+ .filter((a) => !a.startsWith('--'))
507
+ .join(' ');
508
+ const cmd = { id, action: 'getbyrole', role, subaction, name, exact };
509
+ if (value)
510
+ cmd.value = value;
511
+ if (inFrame)
512
+ cmd.inFrame = inFrame;
513
+ return cmd;
514
+ }
515
+ case 'text': {
516
+ const text = findRest[1];
517
+ if (!text)
518
+ error('Missing text', 'agent-browser find text <text> [action] [--exact] [--in-frame <path>]');
519
+ const subaction = findRest[2] || 'click';
520
+ const cmd = { id, action: 'getbytext', text, subaction, exact };
521
+ if (inFrame)
522
+ cmd.inFrame = inFrame;
523
+ return cmd;
524
+ }
525
+ case 'label': {
526
+ const label = findRest[1];
527
+ if (!label)
528
+ error('Missing label', 'agent-browser find label <label> [action] [text] [--exact] [--in-frame <path>]');
529
+ const subaction = findRest[2] || 'click';
530
+ const value = findRest
531
+ .slice(3)
532
+ .filter((a) => !a.startsWith('--'))
533
+ .join(' ');
534
+ const cmd = { id, action: 'getbylabel', label, subaction, exact };
535
+ if (value)
536
+ cmd.value = value;
537
+ if (inFrame)
538
+ cmd.inFrame = inFrame;
539
+ return cmd;
540
+ }
541
+ case 'placeholder': {
542
+ const placeholder = findRest[1];
543
+ if (!placeholder)
544
+ error('Missing placeholder', 'agent-browser find placeholder <text> [action] [text] [--exact] [--in-frame <path>]');
545
+ const subaction = findRest[2] || 'click';
546
+ const value = findRest
547
+ .slice(3)
548
+ .filter((a) => !a.startsWith('--'))
549
+ .join(' ');
550
+ const cmd = { id, action: 'getbyplaceholder', placeholder, subaction, exact };
551
+ if (value)
552
+ cmd.value = value;
553
+ if (inFrame)
554
+ cmd.inFrame = inFrame;
555
+ return cmd;
556
+ }
557
+ case 'alt': {
558
+ const text = findRest[1];
559
+ if (!text)
560
+ error('Missing alt text', 'agent-browser find alt <text> [action] [--exact] [--in-frame <path>]');
561
+ const subaction = findRest[2] || 'click';
562
+ const cmd = { id, action: 'getbyalttext', text, subaction, exact };
563
+ if (inFrame)
564
+ cmd.inFrame = inFrame;
565
+ return cmd;
566
+ }
567
+ case 'title': {
568
+ const text = findRest[1];
569
+ if (!text)
570
+ error('Missing title text', 'agent-browser find title <text> [action] [--exact] [--in-frame <path>]');
571
+ const subaction = findRest[2] || 'click';
572
+ const cmd = { id, action: 'getbytitle', text, subaction, exact };
573
+ if (inFrame)
574
+ cmd.inFrame = inFrame;
575
+ return cmd;
576
+ }
577
+ case 'testid': {
578
+ const testId = findRest[1];
579
+ if (!testId)
580
+ error('Missing testid', 'agent-browser find testid <id> [action] [text] [--in-frame <path>]');
581
+ const subaction = findRest[2] || 'click';
582
+ const value = findRest.slice(3).join(' ');
583
+ const cmd = { id, action: 'getbytestid', testId, subaction };
584
+ if (value)
585
+ cmd.value = value;
586
+ if (inFrame)
587
+ cmd.inFrame = inFrame;
588
+ return cmd;
589
+ }
590
+ case 'first': {
591
+ const selector = findRest[1];
592
+ if (!selector)
593
+ error('Missing selector', 'agent-browser find first <selector> [action] [text] [--in-frame <path>]');
594
+ const subaction = findRest[2] || 'click';
595
+ const value = findRest.slice(3).join(' ');
596
+ const cmd = { id, action: 'nth', selector, index: 0, subaction };
597
+ if (value)
598
+ cmd.value = value;
599
+ if (inFrame)
600
+ cmd.inFrame = inFrame;
601
+ return cmd;
602
+ }
603
+ case 'last': {
604
+ const selector = findRest[1];
605
+ if (!selector)
606
+ error('Missing selector', 'agent-browser find last <selector> [action] [text] [--in-frame <path>]');
607
+ const subaction = findRest[2] || 'click';
608
+ const value = findRest.slice(3).join(' ');
609
+ const cmd = { id, action: 'nth', selector, index: -1, subaction };
610
+ if (value)
611
+ cmd.value = value;
612
+ if (inFrame)
613
+ cmd.inFrame = inFrame;
614
+ return cmd;
615
+ }
616
+ case 'nth': {
617
+ const idxStr = findRest[1];
618
+ if (!idxStr)
619
+ error('Missing index', 'agent-browser find nth <index> <selector> [action] [text] [--in-frame <path>]');
620
+ const idx = parseInt(idxStr, 10);
621
+ if (isNaN(idx))
622
+ error('Invalid index', 'agent-browser find nth <index> <selector> [action] [text] [--in-frame <path>]');
623
+ const selector = findRest[2];
624
+ if (!selector)
625
+ error('Missing selector', 'agent-browser find nth <index> <selector> [action] [text] [--in-frame <path>]');
626
+ const subaction = findRest[3] || 'click';
627
+ const value = findRest.slice(4).join(' ');
628
+ const cmd = { id, action: 'nth', selector, index: idx, subaction };
629
+ if (value)
630
+ cmd.value = value;
631
+ if (inFrame)
632
+ cmd.inFrame = inFrame;
633
+ return cmd;
634
+ }
635
+ default:
636
+ error(`Unknown find locator: ${locator}`, 'agent-browser find <role|text|label|placeholder|alt|title|testid|first|last|nth> ...');
637
+ }
638
+ }
639
+ case 'mouse': {
640
+ const subcmd = rest[0];
641
+ if (!subcmd)
642
+ error('Missing subcommand', 'agent-browser mouse <move|down|up|wheel|wander|trajectory> [args...]');
643
+ switch (subcmd) {
644
+ case 'move': {
645
+ const x = rest[1] ? parseInt(rest[1], 10) : NaN;
646
+ const y = rest[2] ? parseInt(rest[2], 10) : NaN;
647
+ if (isNaN(x) || isNaN(y))
648
+ error('Missing or invalid coordinates', 'agent-browser mouse move <x> <y>');
649
+ return { id, action: 'mousemove', x, y };
650
+ }
651
+ case 'down':
652
+ return { id, action: 'mousedown', button: rest[1] || 'left' };
653
+ case 'up':
654
+ return { id, action: 'mouseup', button: rest[1] || 'left' };
655
+ case 'wheel': {
656
+ const deltaY = rest[1] ? parseInt(rest[1], 10) : 100;
657
+ const deltaX = rest[2] ? parseInt(rest[2], 10) : 0;
658
+ return { id, action: 'wheel', deltaX, deltaY };
659
+ }
660
+ case 'wander': {
661
+ const wRest = rest.slice(1);
662
+ const duration = wRest[0] ? parseInt(wRest[0], 10) : 2000;
663
+ const cmd = { id, action: 'wander', duration };
664
+ if (flags.human.enabled)
665
+ cmd.human = flags.human;
666
+ return cmd;
667
+ }
668
+ case 'trajectory': {
669
+ // agent-browser mouse trajectory "x:y:d;x:y:d;..."
670
+ const data = rest.slice(1).join(' ');
671
+ if (!data)
672
+ error('Missing trajectory data', 'agent-browser mouse trajectory "x:y:d;x:y:d;..."');
673
+ const cmd = { id, action: 'mousetrajectory', data };
674
+ if (flags.human.enabled)
675
+ cmd.human = flags.human;
676
+ return cmd;
677
+ }
678
+ default:
679
+ error(`Unknown mouse subcommand: ${subcmd}`, 'agent-browser mouse <move|down|up|wheel|wander|trajectory> [args...]');
680
+ }
681
+ }
682
+ case 'set': {
683
+ const subcmd = rest[0];
684
+ if (!subcmd)
685
+ error('Missing subcommand', 'agent-browser set <viewport|device|geo|offline|headers|credentials|media> ...');
686
+ switch (subcmd) {
687
+ case 'viewport': {
688
+ const width = rest[1] ? parseInt(rest[1], 10) : NaN;
689
+ const height = rest[2] ? parseInt(rest[2], 10) : NaN;
690
+ if (isNaN(width) || isNaN(height))
691
+ error('Missing or invalid dimensions', 'agent-browser set viewport <width> <height>');
692
+ return { id, action: 'viewport', width, height };
693
+ }
694
+ case 'device': {
695
+ const device = rest[1];
696
+ if (!device)
697
+ error('Missing device name', 'agent-browser set device <name>');
698
+ return { id, action: 'device', device };
699
+ }
700
+ case 'geo':
701
+ case 'geolocation': {
702
+ const latitude = rest[1] ? parseFloat(rest[1]) : NaN;
703
+ const longitude = rest[2] ? parseFloat(rest[2]) : NaN;
704
+ if (isNaN(latitude) || isNaN(longitude))
705
+ error('Missing or invalid coordinates', 'agent-browser set geo <latitude> <longitude>');
706
+ return { id, action: 'geolocation', latitude, longitude };
707
+ }
708
+ case 'offline': {
709
+ const off = rest[1] !== 'off' && rest[1] !== 'false';
710
+ return { id, action: 'offline', offline: off };
711
+ }
712
+ case 'headers': {
713
+ const json = rest[1];
714
+ if (!json)
715
+ error('Missing headers JSON', 'agent-browser set headers <json>');
716
+ try {
717
+ const headers = JSON.parse(json);
718
+ return { id, action: 'headers', headers };
719
+ }
720
+ catch {
721
+ error('Invalid JSON', 'agent-browser set headers <json>');
722
+ }
723
+ }
724
+ case 'credentials':
725
+ case 'auth': {
726
+ const username = rest[1];
727
+ const password = rest[2];
728
+ if (!username || !password)
729
+ error('Missing credentials', 'agent-browser set credentials <username> <password>');
730
+ return { id, action: 'credentials', username, password };
731
+ }
732
+ case 'media': {
733
+ const color = rest.includes('dark')
734
+ ? 'dark'
735
+ : rest.includes('light')
736
+ ? 'light'
737
+ : 'no-preference';
738
+ const reduced = rest.includes('reduced-motion') ? 'reduce' : 'no-preference';
739
+ return { id, action: 'emulatemedia', colorScheme: color, reducedMotion: reduced };
740
+ }
741
+ default:
742
+ error(`Unknown set subcommand: ${subcmd}`, 'agent-browser set <viewport|device|geo|offline|headers|credentials|media> ...');
743
+ }
744
+ }
745
+ case 'network': {
746
+ const subcmd = rest[0];
747
+ if (!subcmd)
748
+ error('Missing subcommand', 'agent-browser network <route|unroute|requests> ...');
749
+ switch (subcmd) {
750
+ case 'route': {
751
+ const url = rest[1];
752
+ if (!url)
753
+ error('Missing URL pattern', 'agent-browser network route <url> [--abort] [--body <json>]');
754
+ const abort = rest.includes('--abort');
755
+ const bodyIdx = rest.indexOf('--body');
756
+ const body = bodyIdx !== -1 ? rest[bodyIdx + 1] : undefined;
757
+ return { id, action: 'route', url, abort, body };
758
+ }
759
+ case 'unroute':
760
+ return { id, action: 'unroute', url: rest[1] };
761
+ case 'requests': {
762
+ const clear = rest.includes('--clear');
763
+ const filterIdx = rest.indexOf('--filter');
764
+ const filter = filterIdx !== -1 ? rest[filterIdx + 1] : undefined;
765
+ return { id, action: 'requests', clear, filter };
766
+ }
767
+ default:
768
+ error(`Unknown network subcommand: ${subcmd}`, 'agent-browser network <route|unroute|requests> ...');
769
+ }
770
+ }
771
+ case 'storage': {
772
+ const type = rest[0];
773
+ if (!type || (type !== 'local' && type !== 'session'))
774
+ error('Missing storage type', 'agent-browser storage <local|session> [key] [value]');
775
+ const subcmd = rest[1];
776
+ if (!subcmd)
777
+ return { id, action: 'storage_get', type };
778
+ if (subcmd === 'set') {
779
+ const key = rest[2];
780
+ const value = rest[3];
781
+ if (!key || !value)
782
+ error('Missing key or value', 'agent-browser storage <local|session> set <key> <value>');
783
+ return { id, action: 'storage_set', type, key, value };
784
+ }
785
+ if (subcmd === 'clear')
786
+ return { id, action: 'storage_clear', type };
787
+ return { id, action: 'storage_get', type, key: subcmd };
788
+ }
789
+ case 'cookies': {
790
+ const subcmd = rest[0] || 'get';
791
+ switch (subcmd) {
792
+ case 'set': {
793
+ const name = rest[1];
794
+ const value = rest[2];
795
+ if (!name || !value)
796
+ error('Missing name or value', 'agent-browser cookies set <name> <value> [options]');
797
+ const cookie = { name, value };
798
+ for (let i = 3; i < rest.length; i++) {
799
+ switch (rest[i]) {
800
+ case '--url':
801
+ cookie.url = rest[++i];
802
+ break;
803
+ case '--domain':
804
+ cookie.domain = rest[++i];
805
+ break;
806
+ case '--path':
807
+ cookie.path = rest[++i];
808
+ break;
809
+ case '--httpOnly':
810
+ cookie.httpOnly = true;
811
+ break;
812
+ case '--secure':
813
+ cookie.secure = true;
814
+ break;
815
+ case '--sameSite':
816
+ cookie.sameSite = rest[++i];
817
+ break;
818
+ case '--expires':
819
+ cookie.expires = parseInt(rest[++i], 10);
820
+ break;
821
+ }
822
+ }
823
+ return { id, action: 'cookies_set', cookies: [cookie] };
824
+ }
825
+ case 'clear':
826
+ return { id, action: 'cookies_clear' };
827
+ default:
828
+ return {
829
+ id,
830
+ action: 'cookies_get',
831
+ urls: subcmd !== 'get' ? [subcmd, ...rest.slice(1)] : undefined,
832
+ };
833
+ }
834
+ }
835
+ case 'tab': {
836
+ const subcmd = rest[0];
837
+ if (!subcmd || subcmd === 'list')
838
+ return { id, action: 'tab_list' };
839
+ if (subcmd === 'new') {
840
+ const cmd = { id, action: 'tab_new' };
841
+ if (rest[1])
842
+ cmd.url = rest[1];
843
+ return cmd;
844
+ }
845
+ if (subcmd === 'close') {
846
+ const cmd = { id, action: 'tab_close' };
847
+ if (rest[1])
848
+ cmd.index = parseInt(rest[1], 10);
849
+ return cmd;
850
+ }
851
+ const index = parseInt(subcmd, 10);
852
+ if (!isNaN(index))
853
+ return { id, action: 'tab_switch', index };
854
+ error('Unknown tab command', 'agent-browser tab <list|new|close|index>');
855
+ }
856
+ case 'window': {
857
+ if (rest[0] === 'new')
858
+ return { id, action: 'window_new' };
859
+ error('Unknown window command', 'agent-browser window new');
860
+ }
861
+ case 'frame': {
862
+ if (rest[0] === 'main')
863
+ return { id, action: 'mainframe' };
864
+ const urlIdx = rest.indexOf('--url');
865
+ const nameIdx = rest.indexOf('--name');
866
+ if (urlIdx !== -1) {
867
+ return { id, action: 'frame', url: rest[urlIdx + 1] };
868
+ }
869
+ if (nameIdx !== -1) {
870
+ return { id, action: 'frame', name: rest[nameIdx + 1] };
871
+ }
872
+ const selector = rest.find((r) => !r.startsWith('--'));
873
+ if (selector)
874
+ return { id, action: 'frame', selector };
875
+ error('Missing frame selector', 'agent-browser frame <selector|main> [--url <url>] [--name <name>]');
876
+ }
877
+ case 'dialog': {
878
+ const subcmd = rest[0];
879
+ if (!subcmd)
880
+ error('Missing subcommand', 'agent-browser dialog <accept|dismiss> [text]');
881
+ if (subcmd === 'accept') {
882
+ const cmd = { id, action: 'dialog', response: 'accept' };
883
+ if (rest[1])
884
+ cmd.promptText = rest[1];
885
+ return cmd;
886
+ }
887
+ if (subcmd === 'dismiss')
888
+ return { id, action: 'dialog', response: 'dismiss' };
889
+ error('Unknown dialog command', 'agent-browser dialog <accept|dismiss> [text]');
890
+ }
891
+ case 'trace': {
892
+ const subcmd = rest[0];
893
+ if (!subcmd)
894
+ error('Missing subcommand', 'agent-browser trace <start|stop> [path]');
895
+ if (subcmd === 'start')
896
+ return { id, action: 'trace_start' };
897
+ if (subcmd === 'stop') {
898
+ const path = rest[1];
899
+ if (!path)
900
+ error('Missing path', 'agent-browser trace stop <path>');
901
+ return { id, action: 'trace_stop', path };
902
+ }
903
+ error('Unknown trace command', 'agent-browser trace <start|stop> [path]');
904
+ }
905
+ case 'record': {
906
+ const subcmd = rest[0];
907
+ if (!subcmd)
908
+ error('Missing subcommand', 'agent-browser record <start|stop|restart> [path] [url]');
909
+ if (subcmd === 'start') {
910
+ const path = rest[1];
911
+ if (!path)
912
+ error('Missing path', 'agent-browser record start <output.webm> [url]');
913
+ const cmd = { id, action: 'recording_start', path };
914
+ if (rest[2])
915
+ cmd.url = rest[2].startsWith('http') ? rest[2] : `https://${rest[2]}`;
916
+ return cmd;
917
+ }
918
+ if (subcmd === 'stop')
919
+ return { id, action: 'recording_stop' };
920
+ if (subcmd === 'restart') {
921
+ const path = rest[1];
922
+ if (!path)
923
+ error('Missing path', 'agent-browser record restart <output.webm> [url]');
924
+ const cmd = { id, action: 'recording_restart', path };
925
+ if (rest[2])
926
+ cmd.url = rest[2].startsWith('http') ? rest[2] : `https://${rest[2]}`;
927
+ return cmd;
928
+ }
929
+ error('Unknown record command', 'agent-browser record <start|stop|restart> [path] [url]');
930
+ }
931
+ case 'recorder': {
932
+ const subcmd = rest[0];
933
+ if (!subcmd)
934
+ error('Missing subcommand', 'agent-browser recorder <start|stop|status> [options]');
935
+ if (subcmd === 'start') {
936
+ const cmd = { id, action: 'recorder_start' };
937
+ const url = rest[1];
938
+ if (url &&
939
+ (url.startsWith('http://') || url.startsWith('https://') || url.startsWith('about:'))) {
940
+ cmd.url = url;
941
+ }
942
+ else if (url && !url.startsWith('-')) {
943
+ cmd.url = `https://${url}`;
944
+ }
945
+ return cmd;
946
+ }
947
+ if (subcmd === 'stop') {
948
+ const outputIdx = rest.indexOf('--output');
949
+ const output = outputIdx !== -1 ? rest[outputIdx + 1] : undefined;
950
+ return { id, action: 'recorder_stop', output };
951
+ }
952
+ if (subcmd === 'status') {
953
+ return { id, action: 'recorder_status' };
954
+ }
955
+ if (subcmd === 'replay') {
956
+ const path = rest[1];
957
+ return { id, action: 'recorder_replay', path };
958
+ }
959
+ error('Unknown recorder command', 'agent-browser recorder <start [url]|stop [--output file.yaml]|status|replay [file.yaml]>');
960
+ }
961
+ case 'console':
962
+ return { id, action: 'console', clear: rest.includes('--clear') };
963
+ case 'errors':
964
+ return { id, action: 'errors', clear: rest.includes('--clear') };
965
+ case 'highlight': {
966
+ const selector = rest[0];
967
+ if (!selector)
968
+ error('Missing selector', 'agent-browser highlight <selector>');
969
+ return { id, action: 'highlight', selector };
970
+ }
971
+ case 'state': {
972
+ const subcmd = rest[0];
973
+ if (!subcmd)
974
+ error('Missing subcommand', 'agent-browser state <save|load> <path>');
975
+ const path = rest[1];
976
+ if (!path)
977
+ error('Missing path', `agent-browser state ${subcmd} <path>`);
978
+ if (subcmd === 'save')
979
+ return { id, action: 'state_save', path };
980
+ if (subcmd === 'load')
981
+ return { id, action: 'state_load', path };
982
+ error('Unknown state command', 'agent-browser state <save|load> <path>');
983
+ }
984
+ case 'connect': {
985
+ const endpoint = rest[0];
986
+ if (!endpoint)
987
+ error('Missing endpoint', 'agent-browser connect <port|url>');
988
+ if (endpoint.startsWith('ws://') ||
989
+ endpoint.startsWith('wss://') ||
990
+ endpoint.startsWith('http://') ||
991
+ endpoint.startsWith('https://')) {
992
+ return { id, action: 'launch', cdpUrl: endpoint };
993
+ }
994
+ const port = parseInt(endpoint, 10);
995
+ if (isNaN(port) || port <= 0 || port > 65535)
996
+ error('Invalid port', 'agent-browser connect <port|url>');
997
+ return { id, action: 'launch', cdpPort: port };
998
+ }
999
+ case 'tap': {
1000
+ const selector = rest[0];
1001
+ if (!selector)
1002
+ error('Missing selector', 'agent-browser tap <selector>');
1003
+ return { id, action: 'tap', selector };
1004
+ }
1005
+ case 'swipe': {
1006
+ const direction = rest[0];
1007
+ if (!direction || !['up', 'down', 'left', 'right'].includes(direction))
1008
+ error('Invalid direction', 'agent-browser swipe <up|down|left|right> [distance]');
1009
+ const cmd = { id, action: 'swipe', direction };
1010
+ if (rest[1])
1011
+ cmd.distance = parseInt(rest[1], 10);
1012
+ return cmd;
1013
+ }
1014
+ case 'device': {
1015
+ const subcmd = rest[0];
1016
+ if (!subcmd || subcmd === 'list')
1017
+ return { id, action: 'device_list' };
1018
+ error('Unknown device command', 'agent-browser device [list]');
1019
+ }
1020
+ case 'viewer':
1021
+ case 'preview': {
1022
+ return { id, action: 'viewer' };
1023
+ }
1024
+ case 'ask': {
1025
+ const question = rest.join(' ');
1026
+ if (!question)
1027
+ error('Missing question', 'agent-browser ask <question>');
1028
+ return { id, action: 'ask', question };
1029
+ }
1030
+ case 'config': {
1031
+ const json = rest.includes('--json');
1032
+ return { id, action: 'config', json };
1033
+ }
1034
+ default:
1035
+ error(`Unknown command: ${cmd}`);
1036
+ }
1037
+ }
1038
+ //# sourceMappingURL=commands.js.map