bb-browser 0.1.0 → 0.1.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.
@@ -17,4 +17,4 @@ export {
17
17
  SSE_HEARTBEAT_INTERVAL,
18
18
  COMMAND_TIMEOUT
19
19
  };
20
- //# sourceMappingURL=chunk-KATHFDYJ.js.map
20
+ //# sourceMappingURL=chunk-YAVLEXUJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../packages/shared/src/protocol.ts","../packages/shared/src/constants.ts"],"sourcesContent":["/**\n * CLI 与 Chrome Extension 之间的通信协议类型定义\n */\n\n/** 支持的操作类型 */\nexport type ActionType =\n | \"open\"\n | \"snapshot\"\n | \"click\"\n | \"hover\"\n | \"fill\"\n | \"type\"\n | \"check\"\n | \"uncheck\"\n | \"select\"\n | \"get\"\n | \"screenshot\"\n | \"close\"\n | \"wait\"\n | \"press\"\n | \"scroll\"\n | \"back\"\n | \"forward\"\n | \"refresh\"\n | \"eval\"\n | \"tab_list\"\n | \"tab_new\"\n | \"tab_select\"\n | \"tab_close\"\n | \"frame\"\n | \"frame_main\"\n | \"dialog\"\n | \"network\"\n | \"console\"\n | \"errors\"\n | \"trace\";\n\n/** 请求类型 */\nexport interface Request {\n /** 请求唯一标识 */\n id: string;\n /** 操作类型 */\n action: ActionType;\n /** 目标 URL(open 操作时必填) */\n url?: string;\n /** 元素引用(click, fill, get 操作时使用) */\n ref?: string;\n /** 输入文本(fill 操作时使用) */\n text?: string;\n /** 获取属性类型(get 操作时使用) */\n attribute?: string;\n /** 截图保存路径(screenshot 操作时使用) */\n path?: string;\n /** 是否只输出可交互元素(snapshot 命令使用) */\n interactive?: boolean;\n /** JavaScript 代码(eval 命令使用) */\n script?: string;\n /** 选项值(select 命令使用) */\n value?: string;\n /** 标签页索引(tab_select, tab_close 命令使用) */\n index?: number;\n /** 标签页 ID(tab_select, tab_close 命令使用,优先于 index) */\n tabId?: number | string;\n /** CSS 选择器(frame 命令使用,定位 iframe) */\n selector?: string;\n /** dialog 响应类型(dialog 命令使用) */\n dialogResponse?: \"accept\" | \"dismiss\";\n /** prompt 对话框的输入文本(dialog accept 时可选) */\n promptText?: string;\n /** network 子命令:requests, route, unroute, clear */\n networkCommand?: \"requests\" | \"route\" | \"unroute\" | \"clear\";\n /** network route 选项 */\n routeOptions?: {\n abort?: boolean;\n body?: string;\n status?: number;\n headers?: Record<string, string>;\n };\n /** 过滤字符串(network requests, console 使用) */\n filter?: string;\n /** console 子命令:get, clear */\n consoleCommand?: \"get\" | \"clear\";\n /** errors 子命令:get, clear */\n errorsCommand?: \"get\" | \"clear\";\n /** trace 子命令:start, stop, status */\n traceCommand?: \"start\" | \"stop\" | \"status\";\n}\n\n/** 元素引用信息 */\nexport interface RefInfo {\n /** 元素的 XPath */\n xpath: string;\n /** 可访问性角色 */\n role: string;\n /** 可访问名称 */\n name?: string;\n /** 标签名 */\n tagName: string;\n}\n\n/** 标签页信息 */\nexport interface TabInfo {\n /** 标签页在窗口中的索引(0-based) */\n index: number;\n /** 标签页 URL */\n url: string;\n /** 标签页标题 */\n title: string;\n /** 是否是当前活动标签页 */\n active: boolean;\n /** 标签页 ID */\n tabId: number;\n}\n\n/** Snapshot 命令返回的数据 */\nexport interface SnapshotData {\n /** 文本格式的可访问性树 */\n snapshot: string;\n /** 元素引用映射,key 为 ref ID */\n refs: Record<string, RefInfo>;\n}\n\n/** 网络请求信息 */\nexport interface NetworkRequestInfo {\n requestId: string;\n url: string;\n method: string;\n type: string;\n timestamp: number;\n status?: number;\n statusText?: string;\n failed?: boolean;\n failureReason?: string;\n}\n\n/** 控制台消息 */\nexport interface ConsoleMessageInfo {\n type: 'log' | 'info' | 'warn' | 'error' | 'debug';\n text: string;\n timestamp: number;\n url?: string;\n lineNumber?: number;\n}\n\n/** JS 错误信息 */\nexport interface JSErrorInfo {\n message: string;\n url?: string;\n lineNumber?: number;\n columnNumber?: number;\n stackTrace?: string;\n timestamp: number;\n}\n\n/** Trace 事件类型 - 录制用户操作 */\nexport interface TraceEvent {\n /** 事件类型 */\n type: 'click' | 'fill' | 'select' | 'check' | 'press' | 'scroll' | 'navigation';\n /** 时间戳 */\n timestamp: number;\n /** 事件发生时的页面 URL */\n url: string;\n \n /** 元素引用 - highlightIndex,可直接用于 @ref */\n ref?: number;\n /** 备用定位 - XPath */\n xpath?: string;\n /** CSS 选择器 */\n cssSelector?: string;\n \n /** 操作参数 - fill/select 的值 */\n value?: string;\n /** 操作参数 - press 的按键 */\n key?: string;\n /** 操作参数 - scroll 方向 */\n direction?: 'up' | 'down' | 'left' | 'right';\n /** 操作参数 - scroll 距离 */\n pixels?: number;\n /** 操作参数 - check/uncheck 状态 */\n checked?: boolean;\n \n /** 语义信息 - 元素角色 */\n elementRole?: string;\n /** 语义信息 - 元素名称 */\n elementName?: string;\n /** 语义信息 - 元素标签 */\n elementTag?: string;\n}\n\n/** Trace 录制状态 */\nexport interface TraceStatus {\n /** 是否正在录制 */\n recording: boolean;\n /** 已录制事件数量 */\n eventCount: number;\n /** 录制的标签页 ID */\n tabId?: number;\n}\n\n/** 响应数据 */\nexport interface ResponseData {\n /** 页面标题 */\n title?: string;\n /** 当前 URL */\n url?: string;\n /** Tab ID */\n tabId?: number;\n /** Snapshot 数据(snapshot 操作返回) */\n snapshotData?: SnapshotData;\n /** 获取的文本或属性值(get 操作返回) */\n value?: string;\n /** 截图路径(screenshot 操作返回) */\n screenshotPath?: string;\n /** eval 执行结果 */\n result?: unknown;\n /** 标签页列表(tab_list 命令返回) */\n tabs?: TabInfo[];\n /** 当前活动标签页索引(tab_list 命令返回) */\n activeIndex?: number;\n /** Frame 信息(frame 命令返回) */\n frameInfo?: {\n /** iframe 的 CSS 选择器 */\n selector?: string;\n /** iframe 的 name 属性 */\n name?: string;\n /** iframe 的 URL */\n url?: string;\n /** frame ID */\n frameId?: number;\n };\n /** dialog 信息(dialog 命令返回) */\n dialogInfo?: {\n /** 对话框类型:alert, confirm, prompt, beforeunload */\n type: string;\n /** 对话框消息 */\n message: string;\n /** 是否成功处理 */\n handled: boolean;\n };\n /** 网络请求列表(network requests 命令返回) */\n networkRequests?: NetworkRequestInfo[];\n /** 网络路由规则数量(network route/unroute 命令返回) */\n routeCount?: number;\n /** 控制台消息列表(console 命令返回) */\n consoleMessages?: ConsoleMessageInfo[];\n /** JS 错误列表(errors 命令返回) */\n jsErrors?: JSErrorInfo[];\n /** Trace 事件列表(trace stop 命令返回) */\n traceEvents?: TraceEvent[];\n /** Trace 录制状态(trace status 命令返回) */\n traceStatus?: TraceStatus;\n}\n\n/** 响应类型 */\nexport interface Response {\n /** 对应请求的 ID */\n id: string;\n /** 操作是否成功 */\n success: boolean;\n /** 成功时返回的数据 */\n data?: ResponseData;\n /** 失败时的错误信息 */\n error?: string;\n}\n\n/** SSE 事件类型 */\nexport type SSEEventType = \"connected\" | \"heartbeat\" | \"command\";\n\n/** SSE 事件数据 */\nexport interface SSEEvent {\n type: SSEEventType;\n data: unknown;\n}\n\n/** Daemon 状态 */\nexport interface DaemonStatus {\n running: boolean;\n extensionConnected: boolean;\n pendingRequests: number;\n uptime: number;\n}\n\n/**\n * 生成唯一请求 ID\n * @returns UUID v4 格式的字符串\n */\nexport function generateId(): string {\n return crypto.randomUUID();\n}\n","/**\n * bb-browser 共享常量\n */\n\n/** Daemon HTTP 服务端口 */\nexport const DAEMON_PORT = 19824;\n\n/** Daemon 主机地址 */\nexport const DAEMON_HOST = \"localhost\";\n\n/** Daemon 基础 URL */\nexport const DAEMON_BASE_URL = `http://${DAEMON_HOST}:${DAEMON_PORT}`;\n\n/** SSE 心跳间隔(毫秒) - 15秒确保 MV3 Service Worker 不休眠 */\nexport const SSE_HEARTBEAT_INTERVAL = 15000; // 15 秒\n\n/** 命令执行超时时间(毫秒) */\nexport const COMMAND_TIMEOUT = 30000; // 30 秒\n\n/** SSE 重连延迟(毫秒) */\nexport const SSE_RECONNECT_DELAY = 3000; // 3 秒\n\n/** SSE 最大重连尝试次数 */\nexport const SSE_MAX_RECONNECT_ATTEMPTS = 5;\n"],"mappings":";;;AA8RO,SAAS,aAAqB;AACnC,SAAO,OAAO,WAAW;AAC3B;AC3RO,IAAM,cAAc;AAGpB,IAAM,cAAc;AAGpB,IAAM,kBAAkB,UAAU,WAAW,IAAI,WAAW;AAG5D,IAAM,yBAAyB;AAG/B,IAAM,kBAAkB;","names":[]}
package/dist/cli.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  COMMAND_TIMEOUT,
4
4
  DAEMON_BASE_URL,
5
5
  generateId
6
- } from "./chunk-KATHFDYJ.js";
6
+ } from "./chunk-YAVLEXUJ.js";
7
7
 
8
8
  // packages/cli/src/client.ts
9
9
  async function sendCommand(request) {
@@ -186,7 +186,8 @@ async function snapshotCommand(options = {}) {
186
186
  const request = {
187
187
  id: generateId(),
188
188
  action: "snapshot",
189
- interactive: options.interactive
189
+ interactive: options.interactive,
190
+ tabId: options.tabId
190
191
  };
191
192
  const response = await sendCommand(request);
192
193
  if (options.json) {
@@ -219,7 +220,8 @@ async function clickCommand(ref, options = {}) {
219
220
  const request = {
220
221
  id: generateId(),
221
222
  action: "click",
222
- ref: parsedRef
223
+ ref: parsedRef,
224
+ tabId: options.tabId
223
225
  };
224
226
  const response = await sendCommand(request);
225
227
  if (options.json) {
@@ -253,7 +255,8 @@ async function hoverCommand(ref, options = {}) {
253
255
  const request = {
254
256
  id: generateId(),
255
257
  action: "hover",
256
- ref: parsedRef
258
+ ref: parsedRef,
259
+ tabId: options.tabId
257
260
  };
258
261
  const response = await sendCommand(request);
259
262
  if (options.json) {
@@ -291,7 +294,8 @@ async function fillCommand(ref, text, options = {}) {
291
294
  id: generateId(),
292
295
  action: "fill",
293
296
  ref: parsedRef,
294
- text
297
+ text,
298
+ tabId: options.tabId
295
299
  };
296
300
  const response = await sendCommand(request);
297
301
  if (options.json) {
@@ -330,7 +334,8 @@ async function typeCommand(ref, text, options = {}) {
330
334
  id: generateId(),
331
335
  action: "type",
332
336
  ref: parsedRef,
333
- text
337
+ text,
338
+ tabId: options.tabId
334
339
  };
335
340
  const response = await sendCommand(request);
336
341
  if (options.json) {
@@ -357,7 +362,8 @@ async function closeCommand(options = {}) {
357
362
  await ensureDaemonRunning();
358
363
  const request = {
359
364
  id: generateId(),
360
- action: "close"
365
+ action: "close",
366
+ tabId: options.tabId
361
367
  };
362
368
  const response = await sendCommand(request);
363
369
  if (options.json) {
@@ -390,7 +396,8 @@ async function getCommand(attribute, ref, options = {}) {
390
396
  id: generateId(),
391
397
  action: "get",
392
398
  attribute,
393
- ref: ref ? parseRef5(ref) : void 0
399
+ ref: ref ? parseRef5(ref) : void 0,
400
+ tabId: options.tabId
394
401
  };
395
402
  const response = await sendCommand(request);
396
403
  if (options.json) {
@@ -429,7 +436,8 @@ async function screenshotCommand(outputPath, options = {}) {
429
436
  const filePath = outputPath ? path.resolve(outputPath) : getDefaultPath();
430
437
  const request = {
431
438
  id: generateId(),
432
- action: "screenshot"
439
+ action: "screenshot",
440
+ tabId: options.tabId
433
441
  };
434
442
  const response = await sendCommand(request);
435
443
  if (response.success && response.data?.dataUrl) {
@@ -473,7 +481,8 @@ async function waitCommand(target, options = {}) {
473
481
  id: generateId(),
474
482
  action: "wait",
475
483
  waitType: "time",
476
- ms
484
+ ms,
485
+ tabId: options.tabId
477
486
  };
478
487
  } else {
479
488
  const ref = parseRef6(target);
@@ -481,7 +490,8 @@ async function waitCommand(target, options = {}) {
481
490
  id: generateId(),
482
491
  action: "wait",
483
492
  waitType: "element",
484
- ref
493
+ ref,
494
+ tabId: options.tabId
485
495
  };
486
496
  }
487
497
  const response = await sendCommand(request);
@@ -529,7 +539,8 @@ async function pressCommand(keyString, options = {}) {
529
539
  id: generateId(),
530
540
  action: "press",
531
541
  key,
532
- modifiers
542
+ modifiers,
543
+ tabId: options.tabId
533
544
  };
534
545
  const response = await sendCommand(request);
535
546
  if (options.json) {
@@ -569,7 +580,8 @@ async function scrollCommand(direction, pixels, options = {}) {
569
580
  id: generateId(),
570
581
  action: "scroll",
571
582
  direction,
572
- pixels: pixelValue
583
+ pixels: pixelValue,
584
+ tabId: options.tabId
573
585
  };
574
586
  const response = await sendCommand(request);
575
587
  if (options.json) {
@@ -758,7 +770,8 @@ async function backCommand(options = {}) {
758
770
  await ensureDaemonRunning();
759
771
  const request = {
760
772
  id: generateId(),
761
- action: "back"
773
+ action: "back",
774
+ tabId: options.tabId
762
775
  };
763
776
  const response = await sendCommand(request);
764
777
  if (options.json) {
@@ -781,7 +794,8 @@ async function forwardCommand(options = {}) {
781
794
  await ensureDaemonRunning();
782
795
  const request = {
783
796
  id: generateId(),
784
- action: "forward"
797
+ action: "forward",
798
+ tabId: options.tabId
785
799
  };
786
800
  const response = await sendCommand(request);
787
801
  if (options.json) {
@@ -804,7 +818,8 @@ async function refreshCommand(options = {}) {
804
818
  await ensureDaemonRunning();
805
819
  const request = {
806
820
  id: generateId(),
807
- action: "refresh"
821
+ action: "refresh",
822
+ tabId: options.tabId
808
823
  };
809
824
  const response = await sendCommand(request);
810
825
  if (options.json) {
@@ -837,7 +852,8 @@ async function checkCommand(ref, options = {}) {
837
852
  const request = {
838
853
  id: generateId(),
839
854
  action: "check",
840
- ref: parsedRef
855
+ ref: parsedRef,
856
+ tabId: options.tabId
841
857
  };
842
858
  const response = await sendCommand(request);
843
859
  if (options.json) {
@@ -875,7 +891,8 @@ async function uncheckCommand(ref, options = {}) {
875
891
  const request = {
876
892
  id: generateId(),
877
893
  action: "uncheck",
878
- ref: parsedRef
894
+ ref: parsedRef,
895
+ tabId: options.tabId
879
896
  };
880
897
  const response = await sendCommand(request);
881
898
  if (options.json) {
@@ -922,7 +939,8 @@ async function selectCommand(ref, value, options = {}) {
922
939
  id: generateId(),
923
940
  action: "select",
924
941
  ref: parsedRef,
925
- value
942
+ value,
943
+ tabId: options.tabId
926
944
  };
927
945
  const response = await sendCommand(request);
928
946
  if (options.json) {
@@ -959,7 +977,8 @@ async function evalCommand(script, options = {}) {
959
977
  const request = {
960
978
  id: generateId(),
961
979
  action: "eval",
962
- script
980
+ script,
981
+ tabId: options.tabId
963
982
  };
964
983
  const response = await sendCommand(request);
965
984
  if (options.json) {
@@ -984,7 +1003,17 @@ async function evalCommand(script, options = {}) {
984
1003
  }
985
1004
 
986
1005
  // packages/cli/src/commands/tab.ts
987
- function parseTabSubcommand(args) {
1006
+ function parseTabSubcommand(args, rawArgv) {
1007
+ let tabId;
1008
+ if (rawArgv) {
1009
+ const idIdx = rawArgv.indexOf("--id");
1010
+ if (idIdx >= 0 && rawArgv[idIdx + 1]) {
1011
+ tabId = parseInt(rawArgv[idIdx + 1], 10);
1012
+ if (isNaN(tabId)) {
1013
+ throw new Error(`\u65E0\u6548\u7684 tabId: ${rawArgv[idIdx + 1]}`);
1014
+ }
1015
+ }
1016
+ }
988
1017
  if (args.length === 0) {
989
1018
  return { action: "tab_list" };
990
1019
  }
@@ -992,7 +1021,16 @@ function parseTabSubcommand(args) {
992
1021
  if (first === "new") {
993
1022
  return { action: "tab_new", url: args[1] };
994
1023
  }
1024
+ if (first === "select") {
1025
+ if (tabId !== void 0) {
1026
+ return { action: "tab_select", tabId };
1027
+ }
1028
+ throw new Error("tab select \u9700\u8981 --id \u53C2\u6570\uFF0C\u7528\u6CD5\uFF1Abb-browser tab select --id <tabId>");
1029
+ }
995
1030
  if (first === "close") {
1031
+ if (tabId !== void 0) {
1032
+ return { action: "tab_close", tabId };
1033
+ }
996
1034
  const indexArg = args[1];
997
1035
  if (indexArg !== void 0) {
998
1036
  const index2 = parseInt(indexArg, 10);
@@ -1021,12 +1059,13 @@ function formatTabList(tabs, activeIndex) {
1021
1059
  }
1022
1060
  async function tabCommand(args, options = {}) {
1023
1061
  await ensureDaemonRunning();
1024
- const parsed = parseTabSubcommand(args);
1062
+ const parsed = parseTabSubcommand(args, process.argv);
1025
1063
  const request = {
1026
1064
  id: generateId(),
1027
1065
  action: parsed.action,
1028
1066
  url: parsed.url,
1029
- index: parsed.index
1067
+ index: parsed.index,
1068
+ tabId: parsed.tabId
1030
1069
  };
1031
1070
  const response = await sendCommand(request);
1032
1071
  if (options.json) {
@@ -1074,7 +1113,8 @@ async function frameCommand(selector, options = {}) {
1074
1113
  const request = {
1075
1114
  id: generateId(),
1076
1115
  action: "frame",
1077
- selector
1116
+ selector,
1117
+ tabId: options.tabId
1078
1118
  };
1079
1119
  const response = await sendCommand(request);
1080
1120
  if (options.json) {
@@ -1097,7 +1137,8 @@ async function frameMainCommand(options = {}) {
1097
1137
  await ensureDaemonRunning();
1098
1138
  const request = {
1099
1139
  id: generateId(),
1100
- action: "frame_main"
1140
+ action: "frame_main",
1141
+ tabId: options.tabId
1101
1142
  };
1102
1143
  const response = await sendCommand(request);
1103
1144
  if (options.json) {
@@ -1122,7 +1163,8 @@ async function dialogCommand(subCommand, promptText, options = {}) {
1122
1163
  id: generateId(),
1123
1164
  action: "dialog",
1124
1165
  dialogResponse: subCommand,
1125
- promptText: subCommand === "accept" ? promptText : void 0
1166
+ promptText: subCommand === "accept" ? promptText : void 0,
1167
+ tabId: options.tabId
1126
1168
  };
1127
1169
  const response = await sendCommand(request);
1128
1170
  if (options.json) {
@@ -1154,7 +1196,8 @@ async function networkCommand(subCommand, urlOrFilter, options = {}) {
1154
1196
  routeOptions: subCommand === "route" ? {
1155
1197
  abort: options.abort,
1156
1198
  body: options.body
1157
- } : void 0
1199
+ } : void 0,
1200
+ tabId: options.tabId
1158
1201
  });
1159
1202
  if (options.json) {
1160
1203
  console.log(JSON.stringify(response));
@@ -1217,7 +1260,8 @@ async function consoleCommand(options = {}) {
1217
1260
  const response = await sendCommand({
1218
1261
  id: crypto.randomUUID(),
1219
1262
  action: "console",
1220
- consoleCommand: options.clear ? "clear" : "get"
1263
+ consoleCommand: options.clear ? "clear" : "get",
1264
+ tabId: options.tabId
1221
1265
  });
1222
1266
  if (options.json) {
1223
1267
  console.log(JSON.stringify(response));
@@ -1261,7 +1305,8 @@ async function errorsCommand(options = {}) {
1261
1305
  const response = await sendCommand({
1262
1306
  id: crypto.randomUUID(),
1263
1307
  action: "errors",
1264
- errorsCommand: options.clear ? "clear" : "get"
1308
+ errorsCommand: options.clear ? "clear" : "get",
1309
+ tabId: options.tabId
1265
1310
  });
1266
1311
  if (options.json) {
1267
1312
  console.log(JSON.stringify(response));
@@ -1300,7 +1345,8 @@ async function traceCommand(subCommand, options = {}) {
1300
1345
  const response = await sendCommand({
1301
1346
  id: crypto.randomUUID(),
1302
1347
  action: "trace",
1303
- traceCommand: subCommand
1348
+ traceCommand: subCommand,
1349
+ tabId: options.tabId
1304
1350
  });
1305
1351
  if (options.json) {
1306
1352
  console.log(JSON.stringify(response));
@@ -1376,7 +1422,7 @@ async function traceCommand(subCommand, options = {}) {
1376
1422
  }
1377
1423
 
1378
1424
  // packages/cli/src/index.ts
1379
- var VERSION = "0.1.0";
1425
+ var VERSION = "0.1.2";
1380
1426
  var HELP_TEXT = `
1381
1427
  bb-browser - AI Agent \u6D4F\u89C8\u5668\u81EA\u52A8\u5316\u5DE5\u5177
1382
1428
 
@@ -1412,8 +1458,10 @@ bb-browser - AI Agent \u6D4F\u89C8\u5668\u81EA\u52A8\u5316\u5DE5\u5177
1412
1458
  refresh \u5237\u65B0\u9875\u9762
1413
1459
  tab \u5217\u51FA\u6240\u6709\u6807\u7B7E\u9875
1414
1460
  tab new [url] \u65B0\u5EFA\u6807\u7B7E\u9875
1415
- tab <n> \u5207\u6362\u5230\u7B2C n \u4E2A\u6807\u7B7E\u9875
1416
- tab close [n] \u5173\u95ED\u6807\u7B7E\u9875\uFF08\u9ED8\u8BA4\u5F53\u524D\uFF09
1461
+ tab <n> \u5207\u6362\u5230\u7B2C n \u4E2A\u6807\u7B7E\u9875\uFF08\u6309 index\uFF09
1462
+ tab select --id <id> \u5207\u6362\u5230\u6307\u5B9A tabId \u7684\u6807\u7B7E\u9875
1463
+ tab close [n] \u5173\u95ED\u6807\u7B7E\u9875\uFF08\u6309 index\uFF0C\u9ED8\u8BA4\u5F53\u524D\uFF09
1464
+ tab close --id <id> \u5173\u95ED\u6307\u5B9A tabId \u7684\u6807\u7B7E\u9875
1417
1465
  frame <selector> \u5207\u6362\u5230\u6307\u5B9A iframe
1418
1466
  frame main \u8FD4\u56DE\u4E3B frame
1419
1467
  dialog accept [text] \u63A5\u53D7\u5BF9\u8BDD\u6846\uFF08alert/confirm/prompt\uFF09
@@ -1433,6 +1481,7 @@ bb-browser - AI Agent \u6D4F\u89C8\u5668\u81EA\u52A8\u5316\u5DE5\u5177
1433
1481
  \u9009\u9879\uFF1A
1434
1482
  --json \u4EE5 JSON \u683C\u5F0F\u8F93\u51FA
1435
1483
  -i, --interactive \u53EA\u8F93\u51FA\u53EF\u4EA4\u4E92\u5143\u7D20\uFF08snapshot \u547D\u4EE4\uFF09
1484
+ --tab <tabId> \u6307\u5B9A\u64CD\u4F5C\u7684\u6807\u7B7E\u9875 ID
1436
1485
  --help, -h \u663E\u793A\u5E2E\u52A9\u4FE1\u606F
1437
1486
  --version, -v \u663E\u793A\u7248\u672C\u53F7
1438
1487
 
@@ -1461,7 +1510,12 @@ function parseArgs(argv) {
1461
1510
  interactive: false
1462
1511
  }
1463
1512
  };
1513
+ let skipNext = false;
1464
1514
  for (const arg of args) {
1515
+ if (skipNext) {
1516
+ skipNext = false;
1517
+ continue;
1518
+ }
1465
1519
  if (arg === "--json") {
1466
1520
  result.flags.json = true;
1467
1521
  } else if (arg === "--help" || arg === "-h") {
@@ -1470,6 +1524,10 @@ function parseArgs(argv) {
1470
1524
  result.flags.version = true;
1471
1525
  } else if (arg === "--interactive" || arg === "-i") {
1472
1526
  result.flags.interactive = true;
1527
+ } else if (arg === "--id") {
1528
+ skipNext = true;
1529
+ } else if (arg === "--tab" && !result.command) {
1530
+ skipNext = true;
1473
1531
  } else if (arg.startsWith("-")) {
1474
1532
  } else if (result.command === null) {
1475
1533
  result.command = arg;
@@ -1481,6 +1539,8 @@ function parseArgs(argv) {
1481
1539
  }
1482
1540
  async function main() {
1483
1541
  const parsed = parseArgs(process.argv);
1542
+ const tabArgIdx = process.argv.indexOf("--tab");
1543
+ const globalTabId = tabArgIdx >= 0 && process.argv[tabArgIdx + 1] ? parseInt(process.argv[tabArgIdx + 1], 10) : void 0;
1484
1544
  if (parsed.flags.version) {
1485
1545
  console.log(VERSION);
1486
1546
  return;
@@ -1504,7 +1564,7 @@ async function main() {
1504
1564
  break;
1505
1565
  }
1506
1566
  case "snapshot": {
1507
- await snapshotCommand({ json: parsed.flags.json, interactive: parsed.flags.interactive });
1567
+ await snapshotCommand({ json: parsed.flags.json, interactive: parsed.flags.interactive, tabId: globalTabId });
1508
1568
  break;
1509
1569
  }
1510
1570
  case "click": {
@@ -1515,7 +1575,7 @@ async function main() {
1515
1575
  console.error("\u793A\u4F8B\uFF1Abb-browser click @5");
1516
1576
  process.exit(1);
1517
1577
  }
1518
- await clickCommand(ref, { json: parsed.flags.json });
1578
+ await clickCommand(ref, { json: parsed.flags.json, tabId: globalTabId });
1519
1579
  break;
1520
1580
  }
1521
1581
  case "hover": {
@@ -1526,7 +1586,7 @@ async function main() {
1526
1586
  console.error("\u793A\u4F8B\uFF1Abb-browser hover @5");
1527
1587
  process.exit(1);
1528
1588
  }
1529
- await hoverCommand(ref, { json: parsed.flags.json });
1589
+ await hoverCommand(ref, { json: parsed.flags.json, tabId: globalTabId });
1530
1590
  break;
1531
1591
  }
1532
1592
  case "check": {
@@ -1537,7 +1597,7 @@ async function main() {
1537
1597
  console.error("\u793A\u4F8B\uFF1Abb-browser check @5");
1538
1598
  process.exit(1);
1539
1599
  }
1540
- await checkCommand(ref, { json: parsed.flags.json });
1600
+ await checkCommand(ref, { json: parsed.flags.json, tabId: globalTabId });
1541
1601
  break;
1542
1602
  }
1543
1603
  case "uncheck": {
@@ -1548,7 +1608,7 @@ async function main() {
1548
1608
  console.error("\u793A\u4F8B\uFF1Abb-browser uncheck @5");
1549
1609
  process.exit(1);
1550
1610
  }
1551
- await uncheckCommand(ref, { json: parsed.flags.json });
1611
+ await uncheckCommand(ref, { json: parsed.flags.json, tabId: globalTabId });
1552
1612
  break;
1553
1613
  }
1554
1614
  case "fill": {
@@ -1566,7 +1626,7 @@ async function main() {
1566
1626
  console.error('\u793A\u4F8B\uFF1Abb-browser fill @3 "hello world"');
1567
1627
  process.exit(1);
1568
1628
  }
1569
- await fillCommand(ref, text, { json: parsed.flags.json });
1629
+ await fillCommand(ref, text, { json: parsed.flags.json, tabId: globalTabId });
1570
1630
  break;
1571
1631
  }
1572
1632
  case "type": {
@@ -1584,7 +1644,7 @@ async function main() {
1584
1644
  console.error('\u793A\u4F8B\uFF1Abb-browser type @3 "append text"');
1585
1645
  process.exit(1);
1586
1646
  }
1587
- await typeCommand(ref, text, { json: parsed.flags.json });
1647
+ await typeCommand(ref, text, { json: parsed.flags.json, tabId: globalTabId });
1588
1648
  break;
1589
1649
  }
1590
1650
  case "select": {
@@ -1602,7 +1662,7 @@ async function main() {
1602
1662
  console.error('\u793A\u4F8B\uFF1Abb-browser select @4 "option1"');
1603
1663
  process.exit(1);
1604
1664
  }
1605
- await selectCommand(ref, value, { json: parsed.flags.json });
1665
+ await selectCommand(ref, value, { json: parsed.flags.json, tabId: globalTabId });
1606
1666
  break;
1607
1667
  }
1608
1668
  case "eval": {
@@ -1613,7 +1673,7 @@ async function main() {
1613
1673
  console.error('\u793A\u4F8B\uFF1Abb-browser eval "document.title"');
1614
1674
  process.exit(1);
1615
1675
  }
1616
- await evalCommand(script, { json: parsed.flags.json });
1676
+ await evalCommand(script, { json: parsed.flags.json, tabId: globalTabId });
1617
1677
  break;
1618
1678
  }
1619
1679
  case "get": {
@@ -1631,7 +1691,7 @@ async function main() {
1631
1691
  process.exit(1);
1632
1692
  }
1633
1693
  const ref = parsed.args[1];
1634
- await getCommand(attribute, ref, { json: parsed.flags.json });
1694
+ await getCommand(attribute, ref, { json: parsed.flags.json, tabId: globalTabId });
1635
1695
  break;
1636
1696
  }
1637
1697
  case "daemon":
@@ -1652,24 +1712,24 @@ async function main() {
1652
1712
  break;
1653
1713
  }
1654
1714
  case "close": {
1655
- await closeCommand({ json: parsed.flags.json });
1715
+ await closeCommand({ json: parsed.flags.json, tabId: globalTabId });
1656
1716
  break;
1657
1717
  }
1658
1718
  case "back": {
1659
- await backCommand({ json: parsed.flags.json });
1719
+ await backCommand({ json: parsed.flags.json, tabId: globalTabId });
1660
1720
  break;
1661
1721
  }
1662
1722
  case "forward": {
1663
- await forwardCommand({ json: parsed.flags.json });
1723
+ await forwardCommand({ json: parsed.flags.json, tabId: globalTabId });
1664
1724
  break;
1665
1725
  }
1666
1726
  case "refresh": {
1667
- await refreshCommand({ json: parsed.flags.json });
1727
+ await refreshCommand({ json: parsed.flags.json, tabId: globalTabId });
1668
1728
  break;
1669
1729
  }
1670
1730
  case "screenshot": {
1671
1731
  const outputPath = parsed.args[0];
1672
- await screenshotCommand(outputPath, { json: parsed.flags.json });
1732
+ await screenshotCommand(outputPath, { json: parsed.flags.json, tabId: globalTabId });
1673
1733
  break;
1674
1734
  }
1675
1735
  case "wait": {
@@ -1681,7 +1741,7 @@ async function main() {
1681
1741
  console.error(" bb-browser wait @5");
1682
1742
  process.exit(1);
1683
1743
  }
1684
- await waitCommand(target, { json: parsed.flags.json });
1744
+ await waitCommand(target, { json: parsed.flags.json, tabId: globalTabId });
1685
1745
  break;
1686
1746
  }
1687
1747
  case "press": {
@@ -1693,7 +1753,7 @@ async function main() {
1693
1753
  console.error(" bb-browser press Control+a");
1694
1754
  process.exit(1);
1695
1755
  }
1696
- await pressCommand(key, { json: parsed.flags.json });
1756
+ await pressCommand(key, { json: parsed.flags.json, tabId: globalTabId });
1697
1757
  break;
1698
1758
  }
1699
1759
  case "scroll": {
@@ -1706,7 +1766,7 @@ async function main() {
1706
1766
  console.error(" bb-browser scroll up 500");
1707
1767
  process.exit(1);
1708
1768
  }
1709
- await scrollCommand(direction, pixels, { json: parsed.flags.json });
1769
+ await scrollCommand(direction, pixels, { json: parsed.flags.json, tabId: globalTabId });
1710
1770
  break;
1711
1771
  }
1712
1772
  case "tab": {
@@ -1723,9 +1783,9 @@ async function main() {
1723
1783
  process.exit(1);
1724
1784
  }
1725
1785
  if (selectorOrMain === "main") {
1726
- await frameMainCommand({ json: parsed.flags.json });
1786
+ await frameMainCommand({ json: parsed.flags.json, tabId: globalTabId });
1727
1787
  } else {
1728
- await frameCommand(selectorOrMain, { json: parsed.flags.json });
1788
+ await frameCommand(selectorOrMain, { json: parsed.flags.json, tabId: globalTabId });
1729
1789
  }
1730
1790
  break;
1731
1791
  }
@@ -1740,7 +1800,7 @@ async function main() {
1740
1800
  process.exit(1);
1741
1801
  }
1742
1802
  const promptText = parsed.args[1];
1743
- await dialogCommand(subCommand, promptText, { json: parsed.flags.json });
1803
+ await dialogCommand(subCommand, promptText, { json: parsed.flags.json, tabId: globalTabId });
1744
1804
  break;
1745
1805
  }
1746
1806
  case "network": {
@@ -1749,17 +1809,17 @@ async function main() {
1749
1809
  const abort = process.argv.includes("--abort");
1750
1810
  const bodyIndex = process.argv.findIndex((a) => a === "--body");
1751
1811
  const body = bodyIndex >= 0 ? process.argv[bodyIndex + 1] : void 0;
1752
- await networkCommand(subCommand, urlOrFilter, { json: parsed.flags.json, abort, body });
1812
+ await networkCommand(subCommand, urlOrFilter, { json: parsed.flags.json, abort, body, tabId: globalTabId });
1753
1813
  break;
1754
1814
  }
1755
1815
  case "console": {
1756
1816
  const clear = process.argv.includes("--clear");
1757
- await consoleCommand({ json: parsed.flags.json, clear });
1817
+ await consoleCommand({ json: parsed.flags.json, clear, tabId: globalTabId });
1758
1818
  break;
1759
1819
  }
1760
1820
  case "errors": {
1761
1821
  const clear = process.argv.includes("--clear");
1762
- await errorsCommand({ json: parsed.flags.json, clear });
1822
+ await errorsCommand({ json: parsed.flags.json, clear, tabId: globalTabId });
1763
1823
  break;
1764
1824
  }
1765
1825
  case "trace": {
@@ -1772,7 +1832,7 @@ async function main() {
1772
1832
  console.error(" bb-browser trace status");
1773
1833
  process.exit(1);
1774
1834
  }
1775
- await traceCommand(subCmd, { json: parsed.flags.json });
1835
+ await traceCommand(subCmd, { json: parsed.flags.json, tabId: globalTabId });
1776
1836
  break;
1777
1837
  }
1778
1838
  default: {