@mearl/native-host 2.19.1 → 2.19.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 (2) hide show
  1. package/dist/index.js +6 -6
  2. package/package.json +7 -7
package/dist/index.js CHANGED
@@ -29,7 +29,7 @@ Expecting one of '${allowedValues.join("', '")}'`);return this._lifeCycleHooks[e
29
29
  `),this.outputHelp({error:!0}));let config2=errorOptions||{},exitCode=config2.exitCode||1,code=config2.code||"commander.error";this._exit(exitCode,code,message)}_parseOptionsEnv(){this.options.forEach(option=>{if(option.envVar&&option.envVar in process2.env){let optionKey=option.attributeName();(this.getOptionValue(optionKey)===void 0||["default","config","env"].includes(this.getOptionValueSource(optionKey)))&&(option.required||option.optional?this.emit(`optionEnv:${option.name()}`,process2.env[option.envVar]):this.emit(`optionEnv:${option.name()}`))}})}_parseOptionsImplied(){let dualHelper=new DualOptions(this.options),hasCustomOptionValue=optionKey=>this.getOptionValue(optionKey)!==void 0&&!["default","implied"].includes(this.getOptionValueSource(optionKey));this.options.filter(option=>option.implied!==void 0&&hasCustomOptionValue(option.attributeName())&&dualHelper.valueFromOption(this.getOptionValue(option.attributeName()),option)).forEach(option=>{Object.keys(option.implied).filter(impliedKey=>!hasCustomOptionValue(impliedKey)).forEach(impliedKey=>{this.setOptionValueWithSource(impliedKey,option.implied[impliedKey],"implied")})})}missingArgument(name){let message=`error: missing required argument '${name}'`;this.error(message,{code:"commander.missingArgument"})}optionMissingArgument(option){let message=`error: option '${option.flags}' argument missing`;this.error(message,{code:"commander.optionMissingArgument"})}missingMandatoryOptionValue(option){let message=`error: required option '${option.flags}' not specified`;this.error(message,{code:"commander.missingMandatoryOptionValue"})}_conflictingOption(option,conflictingOption){let findBestOptionFromValue=option2=>{let optionKey=option2.attributeName(),optionValue=this.getOptionValue(optionKey),negativeOption=this.options.find(target=>target.negate&&optionKey===target.attributeName()),positiveOption=this.options.find(target=>!target.negate&&optionKey===target.attributeName());return negativeOption&&(negativeOption.presetArg===void 0&&optionValue===!1||negativeOption.presetArg!==void 0&&optionValue===negativeOption.presetArg)?negativeOption:positiveOption||option2},getErrorMessage=option2=>{let bestOption=findBestOptionFromValue(option2),optionKey=bestOption.attributeName();return this.getOptionValueSource(optionKey)==="env"?`environment variable '${bestOption.envVar}'`:`option '${bestOption.flags}'`},message=`error: ${getErrorMessage(option)} cannot be used with ${getErrorMessage(conflictingOption)}`;this.error(message,{code:"commander.conflictingOption"})}unknownOption(flag){if(this._allowUnknownOption)return;let suggestion="";if(flag.startsWith("--")&&this._showSuggestionAfterError){let candidateFlags=[],command=this;do{let moreFlags=command.createHelp().visibleOptions(command).filter(option=>option.long).map(option=>option.long);candidateFlags=candidateFlags.concat(moreFlags),command=command.parent}while(command&&!command._enablePositionalOptions);suggestion=suggestSimilar(flag,candidateFlags)}let message=`error: unknown option '${flag}'${suggestion}`;this.error(message,{code:"commander.unknownOption"})}_excessArguments(receivedArgs){if(this._allowExcessArguments)return;let expected=this.registeredArguments.length,s=expected===1?"":"s",received=receivedArgs.length,forSubcommand=this.parent?` for '${this.name()}'`:"",details=receivedArgs.join(", "),message=`error: too many arguments${forSubcommand}. Expected ${expected} argument${s} but got ${received}: ${details}.`;this.error(message,{code:"commander.excessArguments"})}unknownCommand(){let unknownName=this.args[0],suggestion="";if(this._showSuggestionAfterError){let candidateNames=[];this.createHelp().visibleCommands(this).forEach(command=>{candidateNames.push(command.name()),command.alias()&&candidateNames.push(command.alias())}),suggestion=suggestSimilar(unknownName,candidateNames)}let message=`error: unknown command '${unknownName}'${suggestion}`;this.error(message,{code:"commander.unknownCommand"})}version(str,flags,description){if(str===void 0)return this._version;this._version=str,flags=flags||"-V, --version",description=description||"output the version number";let versionOption=this.createOption(flags,description);return this._versionOptionName=versionOption.attributeName(),this._registerOption(versionOption),this.on("option:"+versionOption.name(),()=>{this._outputConfiguration.writeOut(`${str}
30
30
  `),this._exit(0,"commander.version",str)}),this}description(str,argsDescription){return str===void 0&&argsDescription===void 0?this._description:(this._description=str,argsDescription&&(this._argsDescription=argsDescription),this)}summary(str){return str===void 0?this._summary:(this._summary=str,this)}alias(alias){if(alias===void 0)return this._aliases[0];let command=this;if(this.commands.length!==0&&this.commands[this.commands.length-1]._executableHandler&&(command=this.commands[this.commands.length-1]),alias===command._name)throw new Error("Command alias can't be the same as its name");let matchingCommand=this.parent?._findCommand(alias);if(matchingCommand){let existingCmd=[matchingCommand.name()].concat(matchingCommand.aliases()).join("|");throw new Error(`cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`)}return command._aliases.push(alias),this}aliases(aliases){return aliases===void 0?this._aliases:(aliases.forEach(alias=>this.alias(alias)),this)}usage(str){if(str===void 0){if(this._usage)return this._usage;let args=this.registeredArguments.map(arg=>humanReadableArgName(arg));return[].concat(this.options.length||this._helpOption!==null?"[options]":[],this.commands.length?"[command]":[],this.registeredArguments.length?args:[]).join(" ")}return this._usage=str,this}name(str){return str===void 0?this._name:(this._name=str,this)}helpGroup(heading){return heading===void 0?this._helpGroupHeading??"":(this._helpGroupHeading=heading,this)}commandsGroup(heading){return heading===void 0?this._defaultCommandGroup??"":(this._defaultCommandGroup=heading,this)}optionsGroup(heading){return heading===void 0?this._defaultOptionGroup??"":(this._defaultOptionGroup=heading,this)}_initOptionGroup(option){this._defaultOptionGroup&&!option.helpGroupHeading&&option.helpGroup(this._defaultOptionGroup)}_initCommandGroup(cmd){this._defaultCommandGroup&&!cmd.helpGroup()&&cmd.helpGroup(this._defaultCommandGroup)}nameFromFilename(filename){return this._name=path7.basename(filename,path7.extname(filename)),this}executableDir(path22){return path22===void 0?this._executableDir:(this._executableDir=path22,this)}helpInformation(contextOptions){let helper=this.createHelp(),context=this._getOutputContext(contextOptions);helper.prepareContext({error:context.error,helpWidth:context.helpWidth,outputHasColors:context.hasColors});let text=helper.formatHelp(this,helper);return context.hasColors?text:this._outputConfiguration.stripColor(text)}_getOutputContext(contextOptions){contextOptions=contextOptions||{};let error48=!!contextOptions.error,baseWrite,hasColors,helpWidth;return error48?(baseWrite=str=>this._outputConfiguration.writeErr(str),hasColors=this._outputConfiguration.getErrHasColors(),helpWidth=this._outputConfiguration.getErrHelpWidth()):(baseWrite=str=>this._outputConfiguration.writeOut(str),hasColors=this._outputConfiguration.getOutHasColors(),helpWidth=this._outputConfiguration.getOutHelpWidth()),{error:error48,write:str=>(hasColors||(str=this._outputConfiguration.stripColor(str)),baseWrite(str)),hasColors,helpWidth}}outputHelp(contextOptions){let deprecatedCallback;typeof contextOptions=="function"&&(deprecatedCallback=contextOptions,contextOptions=void 0);let outputContext=this._getOutputContext(contextOptions),eventContext={error:outputContext.error,write:outputContext.write,command:this};this._getCommandAndAncestors().reverse().forEach(command=>command.emit("beforeAllHelp",eventContext)),this.emit("beforeHelp",eventContext);let helpInformation=this.helpInformation({error:outputContext.error});if(deprecatedCallback&&(helpInformation=deprecatedCallback(helpInformation),typeof helpInformation!="string"&&!Buffer.isBuffer(helpInformation)))throw new Error("outputHelp callback must return a string or a Buffer");outputContext.write(helpInformation),this._getHelpOption()?.long&&this.emit(this._getHelpOption().long),this.emit("afterHelp",eventContext),this._getCommandAndAncestors().forEach(command=>command.emit("afterAllHelp",eventContext))}helpOption(flags,description){return typeof flags=="boolean"?(flags?(this._helpOption===null&&(this._helpOption=void 0),this._defaultOptionGroup&&this._initOptionGroup(this._getHelpOption())):this._helpOption=null,this):(this._helpOption=this.createOption(flags??"-h, --help",description??"display help for command"),(flags||description)&&this._initOptionGroup(this._helpOption),this)}_getHelpOption(){return this._helpOption===void 0&&this.helpOption(void 0,void 0),this._helpOption}addHelpOption(option){return this._helpOption=option,this._initOptionGroup(option),this}help(contextOptions){this.outputHelp(contextOptions);let exitCode=Number(process2.exitCode??0);exitCode===0&&contextOptions&&typeof contextOptions!="function"&&contextOptions.error&&(exitCode=1),this._exit(exitCode,"commander.help","(outputHelp)")}addHelpText(position,text){let allowedValues=["beforeAll","before","after","afterAll"];if(!allowedValues.includes(position))throw new Error(`Unexpected value for position to addHelpText.
31
31
  Expecting one of '${allowedValues.join("', '")}'`);let helpEvent=`${position}Help`;return this.on(helpEvent,context=>{let helpStr;typeof text=="function"?helpStr=text({error:context.error,command:context.command}):helpStr=text,helpStr&&context.write(`${helpStr}
32
- `)}),this}_outputHelpIfRequested(args){let helpOption=this._getHelpOption();helpOption&&args.find(arg=>helpOption.is(arg))&&(this.outputHelp(),this._exit(0,"commander.helpDisplayed","(outputHelp)"))}}}});var program,init_commander=__esm({"../../node_modules/.pnpm/commander@15.0.0/node_modules/commander/index.js"(){init_argument();init_command();init_error();init_help();init_option();program=new Command}});var APP_PROFILE_NAME_LIST,DEVICE_PRESET_TYPE,PAGE_DIAGNOSTICS_PARAM,PAGE_OBSERVE_PARAM,COMMANDS,COMMAND_MAP,init_commands=__esm({"../client/dist/commands.js"(){"use strict";init_generated_browser_action_protocol();APP_PROFILE_NAME_LIST=APP_PROFILE_NAMES.join("/"),DEVICE_PRESET_TYPE=BROWSER_DEVICE_PRESET_NAMES.map(name=>JSON.stringify(name)).join(" | "),PAGE_DIAGNOSTICS_PARAM={name:"diagnostics",type:"object | boolean",description:"默认关闭;传 true 返回动作期间新增的 error logs/业务 requests,或传对象自定义通道与过滤"},PAGE_OBSERVE_PARAM={name:"observe",type:"object | false",description:"默认开启 DOM/导航观察;传 false 关闭,不影响显式请求的 diagnostics"},COMMANDS=[{name:"tab_checkpoint",description:"为目标标签页建立日志、请求和埋点增量边界",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_open 获取"}],examples:[`tab_checkpoint --payload '{"tabId":12345}'`]},{name:"get_requests",description:"获取最近的网络请求(mtop 或普通 xhr/fetch)",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"count",type:"number",description:"返回条数,默认 10"},{name:"source",type:'"mtop" | "requests" | "all"',description:"数据来源,不填时默认 mtop;all 返回全部业务请求"},{name:"filter",type:"string",description:"按 URL 或 API 名称过滤,支持正则"},{name:"since",type:"number",description:"只返回最近 N 秒内的请求"},{name:"after",type:"string",description:"只返回指定 tab checkpoint 或同类查询 cursor 之后的请求"},{name:"includeBody",type:"boolean",description:"是否包含请求/响应体,默认 true"},{name:"includeHeaders",type:"boolean",description:"是否包含请求/响应头,默认 false"},{name:"maxBodySize",type:"number",description:"单个请求/响应体最大字符数,默认 50000"},{name:"fields",type:"string[]",description:"从响应体提取指定字段路径,最多 100 个"},{name:"keysOnly",type:"boolean",description:"只返回数据结构,不返回叶子值"}],examples:[`get_requests --payload '{"tabId":12345,"count":5}'`,`get_requests --payload '{"tabId":12345,"source":"mtop","filter":"cart"}'`]},{name:"get_logs",description:"获取浏览器控制台日志",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"limit",type:"number",description:"返回最新 N 条,默认 100"},{name:"level",type:"string",description:"按日志级别过滤:log/info/warn/error/all"},{name:"filter",type:"string",description:"按内容过滤,支持正则"},{name:"since",type:"number",description:"只返回最近 N 秒内的日志"},{name:"after",type:"string",description:"只返回指定 tab checkpoint 或同类查询 cursor 之后的日志"}],examples:[`get_logs --payload '{"tabId":12345,"limit":10,"level":"error"}'`]},{name:"get_events",description:"获取 RUM/aplus/ARMS 埋点事件",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"source",type:'"rum" | "aplus" | "arms" | "all"',description:"数据来源,默认 all"},{name:"event_type",type:"string",description:"按事件类型过滤,支持正则,如 CLK/PV"},{name:"filter",type:"string",description:"按 name 或 url 过滤,支持正则"},{name:"since",type:"number",description:"只返回最近 N 秒内的事件"},{name:"after",type:"string",description:"只返回指定 tab checkpoint 之后的事件"},{name:"limit",type:"number",description:"返回条数,默认 20"},{name:"includeRaw",type:"boolean",description:"返回完整 URL、_raw 和 _context;默认 false"}],examples:[`get_events --payload '{"tabId":12345,"source":"aplus","event_type":"CLK","limit":10}'`,`get_events --payload '{"tabId":12345,"filter":"order","includeRaw":true,"limit":1}'`,`get_events --payload '{"tabId":12345,"source":"all","limit":20}'`]},{name:"set_mock",description:"设置 API mock 数据",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"apiName",type:"string",required:!0,description:"API 名称或正则表达式"},{name:"mockData",type:"object",description:"完整 mock 响应数据(与 fields 二选一)"},{name:"fields",type:"array",description:"按字段路径修改真实响应(与 mockData 二选一)"},{name:"enabled",type:"boolean",description:"是否启用,默认 true。false 时恢复真实数据"},{name:"duration",type:"number",description:"完整响应时长(毫秒):mock 的总耗时,绕过真实服务器精确控制"},{name:"conditions",type:"object",description:"请求 query/body 字段子集匹配;$index 从 0 开始指定调用顺序"}],examples:[`set_mock --payload '{"tabId":12345,"apiName":"mtop.cart.query","mockData":{"ret":["SUCCESS::调用成功"]}}'`,"set_mock --payload-file ./mock-data.json"]},{name:"get_mocks",description:"查看当前生效的 mock 列表",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"apiName",type:"string",description:"按 API 名称或正则表达式过滤"}],examples:[`get_mocks --payload '{"tabId":12345}'`]},{name:"set_rule",description:"添加 Chrome declarativeNetRequest 规则(重定向/修改请求头/拦截请求)",params:[{name:"actionType",type:'"redirect" | "block" | "allow" | "upgradeScheme" | "modifyHeaders"',required:!0,description:"规则动作"},{name:"filter",type:"string",required:!0,description:"URL 过滤表达式"},{name:"redirectUrl",type:"string",description:"redirect 动作的目标 URL"},{name:"requestHeaders",type:"array",description:"modifyHeaders 动作的请求头修改列表"},{name:"responseHeaders",type:"array",description:"modifyHeaders 动作的响应头修改列表"},{name:"initiatorDomains",type:"string",description:"发起方域名过滤"},{name:"resourceTypes",type:"string[]",description:"资源类型过滤"},{name:"priority",type:"number",description:"规则优先级"},{name:"description",type:"string",description:"规则说明"}],examples:[`set_rule --payload '{"actionType":"block","filter":"^https://example\\\\.com/ads/.*"}'`]},{name:"get_rules",description:"查看当前存储的全部请求规则(含 Options 面板配置的)",examples:["get_rules"]},{name:"send_request",description:"发送 HTTP 请求,自动携带浏览器 Cookie,支持 multipart 文件上传",params:[{name:"url",type:"string",required:!0,description:"完整目标 URL"},{name:"method",type:"string",description:"HTTP 方法,默认 GET"},{name:"headers",type:"object",description:"自定义请求头"},{name:"params",type:"object",description:"URL 查询参数"},{name:"body",type:"any",description:"请求体(传对象时自动 JSON 序列化)"},{name:"formData",type:"object",description:"multipart 文本字段(值支持 string/number/boolean)"},{name:"files",type:"SendRequestFile[]",description:"multipart 文件,最多 20 个、总计不超过 40 MiB;Base64 文件总计不超过 7 MiB。每项传 fieldName 和绝对 filePath,或传 base64 + filename"},{name:"withCookies",type:"boolean",description:"是否附加浏览器 Cookie,默认 true"},{name:"responseType",type:'"json" | "text" | "auto"',description:"响应解析方式,默认 auto"},{name:"timeout",type:"number",description:"超时毫秒数,默认 30000"}],examples:[`send_request --payload '{"url":"https://api.example.com/data","method":"GET"}'`,`send_request --payload '{"url":"https://api.example.com/upload","method":"POST","formData":{"folder":"assets"},"files":[{"fieldName":"file","filePath":"/absolute/path/image.png"}]}'`]},{name:"send_mtop_request",description:"使用目标浏览器 Cookie 发起 mtop 请求,自动处理签名和 token",params:[{name:"api",type:"string",required:!0,description:"mtop API 名称"},{name:"data",type:"object",description:"请求数据"},{name:"version",type:"string",description:"API 版本,默认 1.0"},{name:"method",type:"string",description:"HTTP 方法,默认 GET"},{name:"appKey",type:"string",description:"签名使用的 appKey,默认 12574478"},{name:"env",type:'"prod" | "pre"',description:"请求环境,默认 prod"},{name:"timeout",type:"number",description:"超时毫秒数,默认 10000"}],examples:[`send_mtop_request --payload '{"api":"mtop.trade.order.detail","data":{"orderId":"123"}}'`]},{name:"browser_list",description:"列出所有浏览器及其连接状态、类型和 Provider 托管实例信息",summary:"列出本地及远端浏览器与连接状态",examples:["browser_list"]},{name:"browser_release",description:"释放当前浏览器的调试控制和会话级临时效果(含设备/时区模拟);不用于普通任务收尾,Provider 实例的行为以 mearl <providerId> 为准",summary:"释放浏览器调试控制和会话级临时效果",examples:["browser_release","browser_release --browser chrome-a"]},{name:"browser_launch",description:"启动本地 Chrome,或通过已注册 Provider 创建浏览器实例",params:[{name:"name",type:"string",description:"本地实例名称;使用 local Provider 时必填"},{name:"provider",type:"string",description:"运行环境,默认 local;可传 mearl --help 中展示的已注册 Provider ID"},{name:"providerOptions",type:"Record<string, JSON value>",description:"所选 Provider 声明的结构化启动参数;不能与顶层启动字段混用"},{name:"headless",type:"boolean",description:"本地 Provider 是否无头运行,默认 true"},{name:"userAgentMode",type:'"default" | "desktop"',description:"本地 UA 模式:default 使用默认 UA;desktop 使用匹配本机版本的 UA"},{name:"persistent",type:"boolean",description:"本地实例关闭后是否保留 Profile,默认 false"},{name:"url",type:"string",description:"登录完成后打开的初始页面"},{name:"executablePath",type:"string",description:"自定义 Chrome 可执行文件路径"},{name:"copyCookieDomains",type:'string[] | "mearl-services" | { presets?: ["mearl-services"]; domains?: string[] }',description:"从控制浏览器复制 Cookie:可传域名数组、Mearl 登录态预设,或组合预设与额外域名"}],examples:[`browser_launch --payload '{"provider":"brow","providerOptions":{}}'`,`browser_launch --payload '{"name":"figma","userAgentMode":"desktop","copyCookieDomains":["figma.com"]}'`,`browser_launch --payload '{"name":"with-cookies","copyCookieDomains":["example.com","sub.example.org"]}'`]},{name:"browser_close",description:"关闭指定托管浏览器,并按 Provider 策略保留或清理持久化数据",params:[{name:"browser",type:"string",required:!0,description:"托管浏览器的 browserId 或名称"},{name:"deleteProfile",type:"boolean",description:"强制删除持久化数据,默认 false"}],examples:[`browser_close --payload '{"browser":"managed:account-a"}'`,`browser_close --payload '{"browser":"account-b","deleteProfile":true}'`]},{name:"tab_open",description:"打开或按 URL 规则复用 Tab,并等待新页面加载完成",aliases:["tab_new","new_tab","tab_create","create_tab"],params:[{name:"url",type:"string",required:!0,description:"要打开的 URL"},{name:"active",type:"boolean",description:"是否激活目标 Tab 并恢复最小化窗口,默认 false;响应返回 activation 验证结果"},{name:"openerTabId",type:"number",description:"来源 Tab ID;用于把目标 Tab 关联到来源侧边栏对话"},{name:"closeExisting",type:"boolean",description:"打开前先关闭 Agent 受控的已有标签页,默认 false"},{name:"group",type:"string",description:"把新 Tab 加入指定标题的标签页分组(同名分组存在则加入,否则新建)。仅扩展模式支持"},{name:"reuse",type:'"never" | "prefer" | "require"',description:"never 始终新开;prefer 优先复用;require 只允许复用。默认 never"},{name:"match",type:"object",description:"复用匹配规则:urlPattern(支持 *)、ignoreSearch、ignoreHash、onMultiple(error/first)"},{name:"restoreFocusOnClose",type:"boolean",description:"关闭本次新开的 active Tab 后恢复原活动标签页,默认 false"},{name:"emulation",type:"object",description:"开 tab 即进入移动端模拟态(首屏即移动态、无需 reload)。字段同 set_device_emulation 去掉 enabled/reload;与 appProfile、deviceShell=true、orientation=landscape、splitScreen=true 组合可首屏进入左右分屏"},{name:"appProfile",type:"string",description:'开 tab 即注入 App 客户端环境与 JSBridge;档案名同 set_app_profile,如 "fliggy"。需要 iframe WebView 和系统栏时同时传 emulation.deviceShell=true'},{name:"os",type:'"ios" | "android"',description:"与 appProfile 配合;容器系统,默认 ios"},{name:"bridgeConfig",type:"object",description:"与 appProfile 配合;声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}}"}],examples:[`tab_open --payload '{"url":"https://example.com"}'`,`tab_open --payload '{"url":"https://example.com/page","reuse":"prefer","match":{"ignoreSearch":true}}'`,`tab_open --payload '{"url":"https://m.example.com","emulation":{"preset":"iphone-17-pro"}}'`,`tab_open --payload '{"url":"https://market.m.taobao.com/app/trip/rx-home/pages/home","appProfile":"fliggy"}'`,`tab_open --payload '{"url":"https://market.m.taobao.com/app/trip/rx-home/pages/home","appProfile":"fliggy","emulation":{"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}}'`,`tab_open --payload '{"url":"https://example.com","appProfile":"fliggy","os":"android"}'`,`tab_open --payload '{"url":"https://example.com","group":"验证任务"}'`]},{name:"tab_close",description:"关闭指定标签页",aliases:["tab_remove","remove_tab","tab_delete","delete_tab"],params:[{name:"tabId",type:"number",required:!0,description:"要关闭的标签页 ID"}],examples:[`tab_close --payload '{"tabId":123}'`]},{name:"tab_list",description:"列出目标浏览器所有窗口中的标签页",aliases:["tabs","list_tabs","show_tabs"],examples:["tab_list"]},{name:"tab_group",description:"把同一窗口中的标签页加入分组,或通过 ungroup 取消分组并保留标签页;仅扩展模式支持",params:[{name:"tabIds",type:"number[]",required:!0,description:"标签页 ID,分组最多 100 个,取消分组最多 1000 个"},{name:"title",type:"string",required:!1,description:"分组标题;取消分组时省略"},{name:"ungroup",type:"boolean",required:!1,description:"为 true 时取消分组并保留标签页"}],examples:[`tab_group --payload '{"tabIds":[123,124],"title":"项目文档"}'`,`tab_group --payload '{"tabIds":[123,124],"ungroup":true}'`]},{name:"page_click",description:"点击页面元素,支持 CSS/@ref、可见文本或视口坐标定位",params:[{name:"selector",type:"string",description:"原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀)。不支持 :has-text/:visible 等 Playwright 私有伪类"},{name:"text",type:"string",description:"按可见文本(accessibility name)定位。需要时配合 role/exact 消歧;多匹配会报错并列出候选"},{name:"point",type:"{ x: number; y: number }",description:'按视口坐标点击(CSS 像素)。默认使用 outer-viewport;容器或 iframe 内坐标配合 coordinateSpace: "active-frame"'},{name:"frameId",type:"string",description:"浏览器扩展后端:显式指定 CSS/text 查询或 active-frame 坐标所属的 frame;省略时容器模式自动使用当前业务 frame"},{name:"coordinateSpace",type:'"outer-viewport" | "active-frame"',description:"仅配合 point 使用;默认 outer-viewport;浏览器扩展后端的 active-frame 会换算 iframe 偏移与缩放后派发可信输入"},{name:"role",type:"string",description:"配合 text 使用,按 AX role 过滤(如 button、link、heading)"},{name:"exact",type:"boolean",description:"配合 text 使用,默认 true 精确匹配;false 时按子串匹配"},{name:"scope",type:"string",description:"配合 text 使用,把文本匹配限制在指定 CSS 元素或 @eN ref 子树内,适合消除重复文案歧义"},{name:"clickMode",type:'"auto" | "dom" | "mouse" | "touch"',description:"默认 auto:可见页使用匹配设备的可信输入,隐藏页使用 DOM;dom/mouse/touch 可强制指定派发方式"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_click --payload '{"tabId":12345,"text":"提交"}'`,`page_click --payload '{"tabId":12345,"text":"退款明细","role":"button"}'`,`page_click --payload '{"tabId":12345,"text":"确定","scope":"@e12"}'`,`page_click --payload '{"tabId":12345,"selector":"@e3"}'`,`page_click --payload '{"tabId":12345,"selector":".submit-btn"}'`,`page_click --payload '{"tabId":12345,"selector":".gesture-btn","clickMode":"touch"}'`,`page_click --payload '{"tabId":12345,"point":{"x":336,"y":117}}'`,`page_click --payload '{"tabId":12345,"point":{"x":196,"y":240},"coordinateSpace":"active-frame"}'`]},{name:"page_drag",description:"拖动页面元素或视口坐标,适用于轮播图、滑块和拖放",params:[{name:"from",type:"string | { x: number; y: number }",required:!0,description:"起点:原生 CSS、@eN ref,或 { x, y } 视口坐标(CSS 像素)"},{name:"to",type:"string | { x: number; y: number }",required:!0,description:"终点:原生 CSS、@eN ref,或 { x, y } 视口坐标(CSS 像素)"},{name:"dragMode",type:'"auto" | "dom" | "mouse" | "touch"',description:"默认 auto:可见页使用匹配设备的可信输入,隐藏页使用 DOM;dom/mouse/touch 可强制指定派发方式"},{name:"durationMs",type:"number",description:"拖动持续时间,0–5000ms,默认 400ms;内部自动分段移动"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_drag --payload '{"tabId":12345,"from":{"x":350,"y":80},"to":{"x":80,"y":80}}'`,`page_drag --payload '{"tabId":12345,"from":"@e3","to":"#drop-zone","dragMode":"mouse"}'`]},{name:"page_type",description:"向输入框填写文本,兼容 React 受控组件",params:[{name:"selector",type:"string",required:!0,description:"原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀)"},{name:"text",type:"string",required:!0,description:"要填写的文本"},{name:"clearFirst",type:"boolean",description:"是否先清空原有内容,默认 true"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_type --payload '{"tabId":12345,"selector":"@e6","text":"搜索关键词"}'`]},{name:"page_hover",description:"将鼠标悬停在页面元素上",params:[{name:"selector",type:"string",required:!0,description:"原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀)"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_hover --payload '{"tabId":12345,"selector":".nav-menu"}'`]},{name:"page_scroll",description:"滚动页面或指定容器;页面根不可滚动时自动发现活动滚动区",params:[{name:"direction",type:'"up" | "down" | "top" | "bottom"',required:!0,description:"滚动方向"},{name:"distance",type:"number",description:"滚动距离(px),默认 600"},{name:"selector",type:"string",description:"目标滚动容器的原生 CSS 选择器,或 page_snapshot 返回的 @eN ref;不传时滚动页面"},{name:"containerPolicy",type:'"self" | "nearest"',description:"默认 self,要求 selector 本身可滚动;nearest 会在其不可滚动时使用最近的可滚动祖先"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_scroll --payload '{"tabId":12345,"direction":"down"}'`,`page_scroll --payload '{"tabId":12345,"direction":"bottom"}'`,`page_scroll --payload '{"tabId":12345,"selector":".virtual-list","direction":"down","distance":800}'`,`page_scroll --payload '{"tabId":12345,"selector":"@e8","containerPolicy":"nearest","direction":"bottom"}'`]},{name:"page_eval",description:"在页面上下文中执行任意 JavaScript 表达式",params:[{name:"expression",type:"string",required:!0,description:"要执行的 JS 表达式"},{name:"awaitPromise",type:"boolean",description:"表达式返回 Promise 时等待完成,默认 true"},{name:"observe",type:"object",description:"仅在表达式会修改页面且需要观察结果时显式传入;不传保持轻量裸执行"},PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_eval --payload '{"tabId":12345,"expression":"document.title"}'`]},{name:"page_inspect",description:"查询 DOM 元素的数量、边框盒、计算样式、遮挡、溢出和最近滚动容器",params:[{name:"selector",type:"string",description:"原生 CSS、page_snapshot 返回的 @eN ref,或 DevTools Elements 当前选区 $0;做全页溢出诊断时可省略"},{name:"filter",type:'"all" | "overflowing" | "horizontal-overflow" | "vertical-overflow" | "scrollable"',description:"结果过滤;省略 selector 时必须指定非 all 的过滤条件"},{name:"styles",type:"string[]",description:"要返回的计算样式属性,默认 display/position/box-sizing/overflow-x/overflow-y"},{name:"maxResults",type:"number",description:"最多返回的明细数,默认 20,最大 100;未触发 scanTruncated 时 count 为完整命中数"},{name:"includeOuterHTML",type:"boolean",description:"是否返回 outerHTML(最多 3000 字符);$0 默认 true,其他目标默认 false"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_inspect --payload '{"tabId":12345,"selector":".form-field","styles":["display","width"]}'`,`page_inspect --payload '{"tabId":12345,"selector":"@e8"}'`,`page_inspect --payload '{"tabId":12345,"selector":"$0"}'`,`page_inspect --payload '{"tabId":12345,"filter":"horizontal-overflow"}'`,`page_inspect --payload '{"tabId":12345,"filter":"scrollable"}'`]},{name:"page_press",description:"在页面中按下键盘按键或组合键",params:[{name:"key",type:"string",required:!0,description:"按键名称:Enter/Tab/Escape/Backspace 等"},{name:"modifiers",type:"string[]",description:"修饰键数组:ctrl/alt/shift/meta/cmd"},{name:"pressMode",type:'"auto" | "dom" | "keyboard"',description:"派发模式;auto 默认在隐藏页降级为 DOM 键盘事件"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_press --payload '{"tabId":12345,"key":"Enter"}'`]},{name:"page_wait",description:"等待指定时间、元素状态、可见文本或页面条件成立",params:[{name:"time",type:"number",description:"等待毫秒数(与 selector/text/condition 四选一)"},{name:"selector",type:"string",description:"目标 CSS 选择器(与 time/text/condition 四选一)"},{name:"state",type:'"attached" | "detached" | "visible" | "hidden"',description:"selector 的目标状态,默认 attached"},{name:"text",type:"string",description:"等待页面出现的可见文本"},{name:"exact",type:"boolean",description:"text 是否精确匹配,默认 false"},{name:"condition",type:"string",description:"在页面主上下文轮询的 JS 表达式,返回 truthy 时结束"},{name:"timeout",type:"number",description:"等待超时毫秒数,默认 10000"},{name:"interval",type:"number",description:"轮询间隔毫秒数,默认 200"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_wait --payload '{"tabId":12345,"time":1000}'`,`page_wait --payload '{"tabId":12345,"selector":".dialog","state":"visible"}'`,`page_wait --payload '{"tabId":12345,"selector":".loading","state":"hidden"}'`,`page_wait --payload '{"tabId":12345,"text":"提交成功"}'`,`page_wait --payload '{"tabId":12345,"condition":"window.appReady === true","timeout":30000}'`]},{name:"page_navigate",description:"在当前标签页内导航到 URL、刷新页面,或沿浏览历史后退/前进",params:[{name:"url",type:"string",description:"要导航到的 URL;与 refresh/history 互斥"},{name:"refresh",type:"boolean",description:"为 true 时直接重新加载当前页面;与 url/history 互斥"},{name:"history",type:'"back" | "forward"',description:"沿当前标签页浏览历史后退或前进;与 url/refresh 互斥"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_navigate --payload '{"tabId":12345,"url":"https://example.com/page2"}'`,`page_navigate --payload '{"tabId":12345,"refresh":true}'`,`page_navigate --payload '{"tabId":12345,"history":"back"}'`]},{name:"page_upload",description:'向 <input type="file"> 元素上传一个或多个文件',params:[{name:"selector",type:"string",required:!0,description:"原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀),必须指向 input[type=file]"},{name:"filePaths",type:"string[]",required:!0,description:"本地文件路径数组"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_upload --payload '{"tabId":12345,"selector":"#file-input","filePaths":["/Users/me/photo.jpg"]}'`]},{name:"page_snapshot",description:"获取带 @ref 的页面结构快照,默认使用无障碍树,也可显式读取渲染 DOM",params:[{name:"depth",type:"number",description:"树深度,默认 15,复杂页面可调大"},{name:"mode",type:'"full" | "interactive" | "viewport" | "dom"',description:"默认 full;interactive/viewport 裁剪 AX 树;AX 信息缺失时可显式使用 dom 读取渲染 DOM"},{name:"rootSelector",type:"string",description:"只获取指定 CSS 元素的局部子树,可与 mode 组合;与 rootRef 互斥"},{name:"rootRef",type:"string",description:"以已有 @eN ref 为根获取局部子树;与 rootSelector 互斥"},{name:"ancestorDepth",type:"number",description:"rootRef 向上扩展的 DOM 祖先层数,默认 0,最大 20"},{name:"query",type:"{ text?: string; role?: string; exact?: boolean }",description:"服务端按 name / role 过滤当前模式的树,只保留命中节点及祖先路径"},{name:"maxNodes",type:"number",description:"最多输出节点数,0 表示不限制"},{name:"maxChars",type:"number",description:"快照文本最大字符数,默认 60000,超出保留首尾;传 0 不限制"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_snapshot --payload '{"tabId":12345}'`,`page_snapshot --payload '{"tabId":1,"mode":"viewport"}'`,`page_snapshot --payload '{"tabId":1,"mode":"dom"}'`,`page_snapshot --payload '{"tabId":1,"rootSelector":"[role=dialog]"}'`,`page_snapshot --payload '{"tabId":1,"rootRef":"@e8","ancestorDepth":1}'`,`page_snapshot --payload '{"tabId":1,"query":{"text":"保存","role":"button"}}'`]},{name:"page_screenshot",description:"获取当前视口或指定元素截图",outputFlag:!0,params:[{name:"selector",type:"string",description:"CSS 选择器,提供后只截取该元素区域"},{name:"format",type:'"png" | "jpeg"',description:"图片格式,默认 png"},{name:"quality",type:"number",description:"JPEG 压缩质量(0-100),默认 80"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_screenshot --payload '{"tabId":12345}' --output ./screenshot.png`,`page_screenshot --payload '{"tabId":12345,"selector":".product-card"}' --output ./card.png`]},{name:"set_device_emulation",description:"把目标 tab 切换为移动端模拟(视口/DPR/UA/触摸/视觉比例),等价 DevTools 设备工具栏,作用域 per-tab;需保持调试控制才持续生效",summary:"设置或清除目标标签页的设备模拟",params:[{name:"enabled",type:"boolean",required:!0,description:"true=启用,false=清除"},{name:"preset",type:DEVICE_PRESET_TYPE,description:"内置设备预设,提供 width/height/DPR/UA 默认值;旧机型 ID 继续兼容"},{name:"width",type:"number",description:"视口宽度(覆盖 preset)"},{name:"height",type:"number",description:"视口高度(覆盖 preset)"},{name:"deviceScaleFactor",type:"number",description:"DPR(覆盖 preset)"},{name:"scale",type:"number",description:"画面视觉比例,不改变视口尺寸或 DPR;必须为有限正数,默认 1"},{name:"mobile",type:"boolean",description:"是否走移动渲染模式,默认从 preset 推断"},{name:"userAgent",type:"string",description:"自定义 UA(覆盖 preset)"},{name:"orientation",type:'"portrait" | "landscape"',description:"横竖屏,默认 portrait"},{name:"touch",type:"boolean",description:"是否启用触摸事件,默认从 preset 推断;无 preset 时跟随 mobile"},{name:"deviceShell",type:"boolean",description:"是否使用 iframe WebView 并渲染顶部状态栏与底部操作区,默认 false"},{name:"splitScreen",type:"boolean",description:"是否将首页与业务页分置左右 WebView;仅在已启用 App 档案、deviceShell=true、横屏时生效,默认 false"},{name:"reload",type:"boolean",description:"启用后是否重载页面,默认 true"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`set_device_emulation --payload '{"tabId":12345,"enabled":true,"preset":"iphone-17-pro"}'`,`set_device_emulation --payload '{"tabId":12345,"enabled":true,"preset":"pixel-11","orientation":"landscape"}'`,`set_device_emulation --payload '{"tabId":12345,"enabled":true,"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}'`,`set_device_emulation --payload '{"tabId":12345,"enabled":false}'`]},{name:"set_app_profile",description:"设置 App 客户端环境与 JSBridge;可同时设置 MTop 页面接口环境,传 emulation 时联动设备模拟",summary:"设置或清除目标标签页的 App 容器模拟",params:[{name:"enabled",type:"boolean",required:!0,description:"true=启用,false=清除"},{name:"profile",type:"string",description:`容器档案名(enabled=true 时必填):${APP_PROFILE_NAME_LIST}`},{name:"os",type:'"ios" | "android"',description:"容器系统,默认 ios"},{name:"appVersion",type:"string",description:"覆盖档案默认 App 版本号"},{name:"deviceModel",type:"string",description:"Android 机型名(拼入 UA 与 __DEVICE_MODEL__)"},{name:"bridgeConfig",type:"object",description:"声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}};不执行配置脚本"},{name:"mtopEnv",type:'"default" | "prod" | "pre"',description:"可选 MTop 页面接口环境;default 关闭环境改写,省略时保持当前设置。扩展模式全局生效,CDP 模式仅作用于目标 tab"},{name:"emulation",type:"object",description:"可选设备联动参数,字段同 set_device_emulation 去掉 enabled/reload;字段覆盖档案推荐设备,deviceShell 默认 true,横屏时可传 splitScreen=true。省略时不设置或清除设备"},{name:"reload",type:"boolean",description:"应用/清除后是否重载页面,默认 true"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy"}'`,`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy","mtopEnv":"pre"}'`,`set_app_profile --payload '{"tabId":12345,"enabled":false,"mtopEnv":"prod"}'`,`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy","emulation":{}}'`,`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"alipay","emulation":{"preset":"pixel-11","deviceShell":true}}'`,`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy","emulation":{"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}}'`,`set_app_profile --payload '{"tabId":12345,"enabled":false}'`,`set_app_profile --payload '{"tabId":12345,"enabled":false,"emulation":{}}'`]},{name:"set_timezone",description:"覆盖目标 tab 的时区,传空字符串恢复浏览器默认时区",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"},{name:"timezone",type:"string",required:!0,description:"IANA 时区标识(如 Asia/Shanghai);空字符串表示清除覆盖"}],examples:[`set_timezone --payload '{"tabId":12345,"timezone":"America/New_York"}'`,`set_timezone --payload '{"tabId":12345,"timezone":""}'`]},{name:"get_cookie",description:"从目标浏览器读取一个指定非分区 Cookie;拒绝返回 HttpOnly Cookie",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"},{name:"name",type:"string",required:!0,description:"要读取的 Cookie 名称;不支持列举全部 Cookie"},{name:"url",type:"string",description:"可选 Cookie 查询 URL;省略时使用当前标签页 URL"},{name:"domain",type:"string",description:"可选精确域过滤,只允许 Cookie 查询 URL 的 host 或其父域"},{name:"path",type:"string",description:"可选精确 path 过滤"}],examples:[`get_cookie --payload '{"tabId":12345,"name":"feature_flag"}'`,`get_cookie --payload '{"tabId":12345,"name":"edith_switch_br.rx-vehicle-search_home","domain":"taobao.com"}'`,`get_cookie --payload '{"tabId":12345,"name":"tracknick","url":"https://www.taobao.com/","domain":"taobao.com","path":"/"}'`]},{name:"set_cookie",description:"设置当前标签页域下的一个指定非分区 session Cookie,可选刷新页面",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"},{name:"name",type:"string",required:!0,description:"Cookie 名称"},{name:"value",type:"string",required:!0,description:"Cookie 值,可传空字符串;空字符串不会删除 Cookie"},{name:"domain",type:"string",description:"Cookie 域,默认当前 host;只允许当前 host 或其父域"},{name:"path",type:"string",description:"Cookie path,默认 /"},{name:"reload",type:"boolean",description:"设置后是否刷新页面,默认 false"}],examples:[`set_cookie --payload '{"tabId":12345,"name":"feature_flag","value":"enabled"}'`,`set_cookie --payload '{"tabId":12345,"name":"edith_switch_br.rx-vehicle-search_home","value":"3.6.63","domain":"taobao.com","reload":true}'`]},{name:"page_frames",description:"获取页面主 frame 与所有 iframe 列表",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_frames --payload '{"tabId":12345}'`]},{name:"request_domain_permission",description:"申请访问指定域名的权限(必要时弹窗让用户授权)",params:[{name:"domain",type:"string",required:!0,description:"需要授权的域名,如 example.com"}],examples:[`request_domain_permission --payload '{"domain":"example.com"}'`]},{name:"run_actions",description:"批量顺序执行多个 action,减少往返延迟。遇错即停,返回已完成步骤结果;步骤内的页面动作不带内置观察",summary:"批量顺序执行多个 action,遇错即停",params:[{name:"actions",type:"Array<{action: string, data?: object}>",required:!0,description:"要依次执行的 action 列表"},{name:"tabId",type:"number",required:!0,description:"所有步骤共享的 tabId,步骤自身指定的优先"}],examples:[`run_actions --payload '{"tabId":12345,"actions":[{"action":"page_scroll","data":{"direction":"down"}},{"action":"page_wait","data":{"time":500}},{"action":"page_screenshot"}]}'`]}],COMMAND_MAP=new Map(COMMANDS.map(command=>[command.name,command]))}});function findOfficialPlugin(name){return Object.hasOwn(OFFICIAL_PLUGINS,name)?OFFICIAL_PLUGINS[name]:void 0}function listOfficialPluginNames(setup){return Object.entries(OFFICIAL_PLUGINS).filter(([,definition])=>setup===void 0||"setup"in definition&&definition.setup===setup).map(([name])=>name)}var OFFICIAL_PLUGINS,init_officialPluginCatalog=__esm({"../client/dist/officialPluginCatalog.js"(){"use strict";OFFICIAL_PLUGINS={buc:{description:"使用 BUC 身份请求内部服务",installArgs:["trip/mearl","--skill","buc-request","--yes"],skill:"buc-request"},authx:{description:"使用 AuthX 身份请求内部服务",installArgs:["trip/mearl","--skill","authx-request","--yes"],skill:"authx-request"},tdbank:{description:"查询、借用和切换 TDBank 测试账号",installArgs:["trip/mearl","--skill","tdbank-account","--yes"],setup:"alibaba",skill:"tdbank-account"}}}});import{createHash as createHash3}from"node:crypto";import{readFileSync as readFileSync5,realpathSync}from"node:fs";import{basename as basename2,dirname as dirname3,extname,isAbsolute as isAbsolute3,join as join6,relative as relative2,resolve as resolve2,sep as sep2}from"node:path";function pluginRoot(entry){let entryDirectory=dirname3(entry);return basename2(entryDirectory)==="scripts"?dirname3(entryDirectory):entryDirectory}function attributeValue(tag,name){let match=tag.match(new RegExp(`\\b${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s>]+))`,"i"));return match?.[1]??match?.[2]??match?.[3]}function removeAttribute(tag,name){return tag.replace(new RegExp(`\\s+${name}\\s*=\\s*(?:"[^"]*"|'[^']*'|[^\\s>]+)`,"i"),"")}function isEmbeddedReference(reference){return/^(?:data:|blob:|#)/i.test(reference.trim())}function isRemoteReference(reference){return/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(reference.trim())}function contentType(path22){return MIME_TYPES2[extname(path22).toLowerCase()]??"application/octet-stream"}function escapeStyleText(value){return value.replace(/<\/style/gi,"\\3C /style")}function escapeScriptText(value){return value.replace(/<\/script/gi,"<\\/script")}function buildPluginPageBundle(entry,pageEntry){let root=realpathSync(pluginRoot(entry)),sourceBytes=0,countedFiles=new Set,resolveLocalFile=(reference,fromFile)=>{let cleanReference=reference.trim().split(/[?#]/,1)[0];if(!cleanReference||isEmbeddedReference(cleanReference))return"";if(isRemoteReference(cleanReference)||isAbsolute3(cleanReference))throw new Error(`toolbox.page 不允许远程或绝对资源: ${reference}`);let resolved=realpathSync(resolve2(dirname3(fromFile),cleanReference)),relativePath=relative2(root,resolved);if(relativePath===".."||relativePath.startsWith(`..${sep2}`)||isAbsolute3(relativePath))throw new Error(`toolbox.page 资源超出插件目录: ${reference}`);return resolved},readAsset=path22=>{let content2=readFileSync5(path22);if(!countedFiles.has(path22)&&(countedFiles.add(path22),sourceBytes+=content2.byteLength,sourceBytes>MAX_PAGE_SOURCE_BYTES))throw new Error("toolbox.page 源文件总大小不能超过 16 MiB");return content2},dataUrl=(reference,fromFile)=>{if(isEmbeddedReference(reference))return reference;let path22=resolveLocalFile(reference,fromFile);return`data:${contentType(path22)};base64,${readAsset(path22).toString("base64")}`},inlineCss=(css,cssPath)=>css.replace(/url\(\s*(['"]?)([^'"()]+)\1\s*\)/gi,(_match,_quote,reference)=>{let value=reference.trim();return isEmbeddedReference(value)?`url("${value}")`:`url("${dataUrl(value,cssPath)}")`}),absoluteEntry=resolveLocalFile(pageEntry,join6(root,"__toolbox_entry__"));if(extname(absoluteEntry).toLowerCase()!==".html")throw new Error("toolbox.page.entry 必须指向 HTML 文件");let html=readAsset(absoluteEntry).toString("utf8").replace(/^\uFEFF/,"");if(!/<html\b|<!doctype\b/i.test(html))throw new Error("toolbox.page.entry 必须是完整 HTML 文档");if(/<base\b/i.test(html))throw new Error("toolbox.page 不允许声明 base 标签");if(/<meta\b[^>]*http-equiv\s*=\s*["']?content-security-policy/i.test(html))throw new Error("toolbox.page 的安全策略由 Mearl 管理,请移除 CSP meta 标签");html=html.replace(/<link\b[^>]*>/gi,tag=>{let rel=attributeValue(tag,"rel")?.toLowerCase().split(/\s+/)??[],href=attributeValue(tag,"href");if(rel.includes("stylesheet")){if(!href)throw new Error("toolbox.page stylesheet 缺少 href");let cssPath=resolveLocalFile(href,absoluteEntry),css=inlineCss(readAsset(cssPath).toString("utf8"),cssPath);return`<style data-mearl-source="${href.replaceAll('"',"&quot;")}">${escapeStyleText(css)}</style>`}if(href&&rel.some(value=>["icon","apple-touch-icon"].includes(value)))return tag.replace(href,dataUrl(href,absoluteEntry));if(href&&isRemoteReference(href))throw new Error(`toolbox.page 不允许远程 link 资源: ${href}`);return tag}),html=html.replace(/<script\b[^>]*>[\s\S]*?<\/script\s*>/gi,tag=>{let src=attributeValue(tag,"src");if(!src)return tag;let scriptPath=resolveLocalFile(src,absoluteEntry),script=readAsset(scriptPath).toString("utf8");if(attributeValue(tag,"type")?.toLowerCase()==="module"&&/(?:^|[;\n]\s*)(?:import\s|export\s)|\bimport\s*\(/m.test(script))throw new Error("toolbox.page 的模块脚本必须先打包为无 import 的单文件");return`${removeAttribute(tag.slice(0,tag.indexOf(">")+1),"src")}${escapeScriptText(script)}</script>`}),html=html.replace(/(<(?:img|source|video|audio|track|input)\b[^>]*?\s(?:src|poster)\s*=\s*)(["'])([^"']+)\2/gi,(_match,prefix,quote,reference)=>`${prefix}${quote}${dataUrl(reference,absoluteEntry)}${quote}`);let injection=`<meta name="color-scheme" content="light dark">${PAGE_SECURITY_META}${PAGE_THEME_STYLE}<script data-mearl-bridge>${escapeScriptText(PAGE_BRIDGE_SCRIPT)}</script>`;html=/<head\b[^>]*>/i.test(html)?html.replace(/<head\b[^>]*>/i,tag=>`${tag}${injection}`):html.replace(/<html\b[^>]*>/i,tag=>`${tag}<head>${injection}</head>`);let content=html,buffer=Buffer.from(content,"utf8");if(buffer.byteLength>MAX_PAGE_BUNDLE_BYTES)throw new Error("toolbox.page 打包后不能超过 24 MiB");return{content,hash:createHash3("sha256").update(buffer).digest("hex"),size:buffer.byteLength,chunks:Math.ceil(buffer.byteLength/PLUGIN_PAGE_CHUNK_BYTES)}}var PLUGIN_PAGE_CHUNK_BYTES,MAX_PAGE_SOURCE_BYTES,MAX_PAGE_BUNDLE_BYTES,MIME_TYPES2,PAGE_BRIDGE_SCRIPT,PAGE_SECURITY_META,PAGE_THEME_STYLE,init_pluginPageBundle=__esm({"../client/dist/pluginPageBundle.js"(){"use strict";PLUGIN_PAGE_CHUNK_BYTES=384*1024,MAX_PAGE_SOURCE_BYTES=16*1024*1024,MAX_PAGE_BUNDLE_BYTES=24*1024*1024,MIME_TYPES2={".avif":"image/avif",".gif":"image/gif",".ico":"image/x-icon",".jpeg":"image/jpeg",".jpg":"image/jpeg",".mp3":"audio/mpeg",".mp4":"video/mp4",".ogg":"audio/ogg",".otf":"font/otf",".png":"image/png",".svg":"image/svg+xml",".ttf":"font/ttf",".wav":"audio/wav",".webm":"video/webm",".webp":"image/webp",".woff":"font/woff",".woff2":"font/woff2"},PAGE_BRIDGE_SCRIPT=String.raw`(() => {
32
+ `)}),this}_outputHelpIfRequested(args){let helpOption=this._getHelpOption();helpOption&&args.find(arg=>helpOption.is(arg))&&(this.outputHelp(),this._exit(0,"commander.helpDisplayed","(outputHelp)"))}}}});var program,init_commander=__esm({"../../node_modules/.pnpm/commander@15.0.0/node_modules/commander/index.js"(){init_argument();init_command();init_error();init_help();init_option();program=new Command}});var APP_PROFILE_NAME_LIST,DEVICE_PRESET_TYPE,PAGE_DIAGNOSTICS_PARAM,PAGE_OBSERVE_PARAM,COMMANDS,COMMAND_MAP,init_commands=__esm({"../client/dist/commands.js"(){"use strict";init_generated_browser_action_protocol();APP_PROFILE_NAME_LIST=APP_PROFILE_NAMES.join("/"),DEVICE_PRESET_TYPE=BROWSER_DEVICE_PRESET_NAMES.map(name=>JSON.stringify(name)).join(" | "),PAGE_DIAGNOSTICS_PARAM={name:"diagnostics",type:"object | boolean",description:"默认关闭;传 true 返回动作期间新增的 error logs/业务 requests,或传对象自定义通道与过滤"},PAGE_OBSERVE_PARAM={name:"observe",type:"object | false",description:"默认开启 DOM/导航观察;传 false 关闭,不影响显式请求的 diagnostics"},COMMANDS=[{name:"tab_checkpoint",description:"为目标标签页建立日志、请求和埋点增量边界",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_open 获取"}],examples:[`tab_checkpoint --payload '{"tabId":12345}'`]},{name:"get_requests",description:"获取最近的网络请求(mtop 或普通 xhr/fetch)",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"count",type:"number",description:"返回条数,默认 10"},{name:"source",type:'"mtop" | "requests" | "all"',description:"数据来源,不填时默认 mtop;all 返回全部业务请求"},{name:"filter",type:"string",description:"按 URL 或 API 名称过滤,支持正则"},{name:"since",type:"number",description:"只返回最近 N 秒内的请求"},{name:"after",type:"string",description:"只返回指定 tab checkpoint 或同类查询 cursor 之后的请求"},{name:"includeBody",type:"boolean",description:"是否包含请求/响应体,默认 true"},{name:"includeHeaders",type:"boolean",description:"是否包含请求/响应头,默认 false"},{name:"maxBodySize",type:"number",description:"单个请求/响应体最大字符数,默认 50000"},{name:"fields",type:"string[]",description:"从响应体提取指定字段路径,最多 100 个"},{name:"keysOnly",type:"boolean",description:"只返回数据结构,不返回叶子值"}],examples:[`get_requests --payload '{"tabId":12345,"count":5}'`,`get_requests --payload '{"tabId":12345,"source":"mtop","filter":"cart"}'`]},{name:"get_logs",description:"获取浏览器控制台日志",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"limit",type:"number",description:"返回最新 N 条,默认 100"},{name:"level",type:"string",description:"按日志级别过滤:log/info/warn/error/all"},{name:"filter",type:"string",description:"按内容过滤,支持正则"},{name:"since",type:"number",description:"只返回最近 N 秒内的日志"},{name:"after",type:"string",description:"只返回指定 tab checkpoint 或同类查询 cursor 之后的日志"}],examples:[`get_logs --payload '{"tabId":12345,"limit":10,"level":"error"}'`]},{name:"get_events",description:"获取 RUM/aplus/ARMS 埋点事件",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"source",type:'"rum" | "aplus" | "arms" | "all"',description:"数据来源,默认 all"},{name:"event_type",type:"string",description:"按事件类型过滤,支持正则,如 CLK/PV"},{name:"filter",type:"string",description:"按 name 或 url 过滤,支持正则"},{name:"since",type:"number",description:"只返回最近 N 秒内的事件"},{name:"after",type:"string",description:"只返回指定 tab checkpoint 之后的事件"},{name:"limit",type:"number",description:"返回条数,默认 20"},{name:"includeRaw",type:"boolean",description:"返回完整 URL、_raw 和 _context;默认 false"}],examples:[`get_events --payload '{"tabId":12345,"source":"aplus","event_type":"CLK","limit":10}'`,`get_events --payload '{"tabId":12345,"filter":"order","includeRaw":true,"limit":1}'`,`get_events --payload '{"tabId":12345,"source":"all","limit":20}'`]},{name:"set_mock",description:"设置 API mock 数据",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"apiName",type:"string",required:!0,description:"API 名称或正则表达式"},{name:"mockData",type:"object",description:"完整 mock 响应数据(与 fields 二选一)"},{name:"fields",type:"array",description:"按字段路径修改真实响应(与 mockData 二选一)"},{name:"enabled",type:"boolean",description:"是否启用,默认 true。false 时恢复真实数据"},{name:"duration",type:"number",description:"完整响应时长(毫秒):mock 的总耗时,绕过真实服务器精确控制"},{name:"conditions",type:"object",description:"请求 query/body 字段子集匹配;$index 从 0 开始指定调用顺序"}],examples:[`set_mock --payload '{"tabId":12345,"apiName":"mtop.cart.query","mockData":{"ret":["SUCCESS::调用成功"]}}'`,"set_mock --payload-file ./mock-data.json"]},{name:"get_mocks",description:"查看当前生效的 mock 列表",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID,从 tab_list 获取"},{name:"apiName",type:"string",description:"按 API 名称或正则表达式过滤"}],examples:[`get_mocks --payload '{"tabId":12345}'`]},{name:"set_rule",description:"添加浏览器请求规则;enabled=false 且传 ruleId 时彻底删除规则",params:[{name:"ruleId",type:"number",description:"删除时必填,从 get_rules 获取"},{name:"enabled",type:"boolean",description:"省略时添加;false 时按 ruleId 删除"},{name:"actionType",type:'"redirect" | "block" | "allow" | "upgradeScheme" | "modifyHeaders"',description:"添加时必填,规则动作"},{name:"filter",type:"string",description:"添加时必填,URL 过滤表达式"},{name:"redirectUrl",type:"string",description:"redirect 动作的目标 URL"},{name:"requestHeaders",type:"array",description:"modifyHeaders 动作的请求头修改列表"},{name:"responseHeaders",type:"array",description:"modifyHeaders 动作的响应头修改列表"},{name:"initiatorDomains",type:"string",description:"发起方域名过滤"},{name:"resourceTypes",type:"string[]",description:"资源类型过滤"},{name:"priority",type:"number",description:"规则优先级"},{name:"description",type:"string",description:"规则说明"}],examples:[`set_rule --payload '{"actionType":"block","filter":"^https://example\\\\.com/ads/.*"}'`,`set_rule --payload '{"ruleId":42,"enabled":false}'`]},{name:"get_rules",description:"查看当前模式的请求规则;扩展模式包含 Options 面板配置的规则",examples:["get_rules"]},{name:"send_request",description:"发送 HTTP 请求,自动携带浏览器 Cookie,支持 multipart 文件上传",params:[{name:"url",type:"string",required:!0,description:"完整目标 URL"},{name:"method",type:"string",description:"HTTP 方法,默认 GET"},{name:"headers",type:"object",description:"自定义请求头"},{name:"params",type:"object",description:"URL 查询参数"},{name:"body",type:"any",description:"请求体(传对象时自动 JSON 序列化)"},{name:"formData",type:"object",description:"multipart 文本字段(值支持 string/number/boolean)"},{name:"files",type:"SendRequestFile[]",description:"multipart 文件,最多 20 个、总计不超过 40 MiB;Base64 文件总计不超过 7 MiB。每项传 fieldName 和绝对 filePath,或传 base64 + filename"},{name:"withCookies",type:"boolean",description:"是否附加浏览器 Cookie,默认 true"},{name:"responseType",type:'"json" | "text" | "auto"',description:"响应解析方式,默认 auto"},{name:"timeout",type:"number",description:"超时毫秒数,默认 30000"}],examples:[`send_request --payload '{"url":"https://api.example.com/data","method":"GET"}'`,`send_request --payload '{"url":"https://api.example.com/upload","method":"POST","formData":{"folder":"assets"},"files":[{"fieldName":"file","filePath":"/absolute/path/image.png"}]}'`]},{name:"send_mtop_request",description:"使用目标浏览器 Cookie 发起 mtop 请求,自动处理签名和 token",params:[{name:"api",type:"string",required:!0,description:"mtop API 名称"},{name:"data",type:"object",description:"请求数据"},{name:"version",type:"string",description:"API 版本,默认 1.0"},{name:"method",type:"string",description:"HTTP 方法,默认 GET"},{name:"appKey",type:"string",description:"签名使用的 appKey,默认 12574478"},{name:"env",type:'"prod" | "pre"',description:"请求环境,默认 prod"},{name:"timeout",type:"number",description:"超时毫秒数,默认 10000"}],examples:[`send_mtop_request --payload '{"api":"mtop.trade.order.detail","data":{"orderId":"123"}}'`]},{name:"browser_list",description:"列出所有浏览器及其连接状态、类型和 Provider 托管实例信息",summary:"列出本地及远端浏览器与连接状态",examples:["browser_list"]},{name:"browser_release",description:"释放当前浏览器的调试控制和会话级临时效果(含设备/时区模拟);不用于普通任务收尾,Provider 实例的行为以 mearl <providerId> 为准",summary:"释放浏览器调试控制和会话级临时效果",examples:["browser_release","browser_release --browser chrome-a"]},{name:"browser_launch",description:"启动本地 Chrome,或通过已注册 Provider 创建浏览器实例",params:[{name:"name",type:"string",description:"本地实例名称;使用 local Provider 时必填"},{name:"provider",type:"string",description:"运行环境,默认 local;可传 mearl --help 中展示的已注册 Provider ID"},{name:"providerOptions",type:"Record<string, JSON value>",description:"所选 Provider 声明的结构化启动参数;不能与顶层启动字段混用"},{name:"headless",type:"boolean",description:"本地 Provider 是否无头运行,默认 true"},{name:"userAgentMode",type:'"default" | "desktop"',description:"本地 UA 模式:default 使用默认 UA;desktop 使用匹配本机版本的 UA"},{name:"persistent",type:"boolean",description:"本地实例关闭后是否保留 Profile,默认 false"},{name:"url",type:"string",description:"登录完成后打开的初始页面"},{name:"executablePath",type:"string",description:"自定义 Chrome 可执行文件路径"},{name:"copyCookieDomains",type:'string[] | "mearl-services" | { presets?: ["mearl-services"]; domains?: string[] }',description:"从控制浏览器复制 Cookie:可传域名数组、Mearl 登录态预设,或组合预设与额外域名"}],examples:[`browser_launch --payload '{"provider":"brow","providerOptions":{}}'`,`browser_launch --payload '{"name":"figma","userAgentMode":"desktop","copyCookieDomains":["figma.com"]}'`,`browser_launch --payload '{"name":"with-cookies","copyCookieDomains":["example.com","sub.example.org"]}'`]},{name:"browser_close",description:"关闭指定托管浏览器,并按 Provider 策略保留或清理持久化数据",params:[{name:"browser",type:"string",required:!0,description:"托管浏览器的 browserId 或名称"},{name:"deleteProfile",type:"boolean",description:"强制删除持久化数据,默认 false"}],examples:[`browser_close --payload '{"browser":"managed:account-a"}'`,`browser_close --payload '{"browser":"account-b","deleteProfile":true}'`]},{name:"tab_open",description:"打开或按 URL 规则复用 Tab,并等待新页面加载完成",aliases:["tab_new","new_tab","tab_create","create_tab"],params:[{name:"url",type:"string",required:!0,description:"要打开的 URL"},{name:"active",type:"boolean",description:"是否激活目标 Tab 并恢复最小化窗口,默认 false;响应返回 activation 验证结果"},{name:"openerTabId",type:"number",description:"来源 Tab ID;用于把目标 Tab 关联到来源侧边栏对话"},{name:"closeExisting",type:"boolean",description:"打开前先关闭 Agent 受控的已有标签页,默认 false"},{name:"group",type:"string",description:"把新 Tab 加入指定标题的标签页分组(同名分组存在则加入,否则新建)。仅扩展模式支持"},{name:"reuse",type:'"never" | "prefer" | "require"',description:"never 始终新开;prefer 优先复用;require 只允许复用。默认 never"},{name:"match",type:"object",description:"复用匹配规则:urlPattern(支持 *)、ignoreSearch、ignoreHash、onMultiple(error/first)"},{name:"restoreFocusOnClose",type:"boolean",description:"关闭本次新开的 active Tab 后恢复原活动标签页,默认 false"},{name:"emulation",type:"object",description:"开 tab 即进入移动端模拟态(首屏即移动态、无需 reload)。字段同 set_device_emulation 去掉 enabled/reload;与 appProfile、deviceShell=true、orientation=landscape、splitScreen=true 组合可首屏进入左右分屏"},{name:"appProfile",type:"string",description:'开 tab 即注入 App 客户端环境与 JSBridge;档案名同 set_app_profile,如 "fliggy"。需要 iframe WebView 和系统栏时同时传 emulation.deviceShell=true'},{name:"os",type:'"ios" | "android"',description:"与 appProfile 配合;容器系统,默认 ios"},{name:"bridgeConfig",type:"object",description:"与 appProfile 配合;声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}}"}],examples:[`tab_open --payload '{"url":"https://example.com"}'`,`tab_open --payload '{"url":"https://example.com/page","reuse":"prefer","match":{"ignoreSearch":true}}'`,`tab_open --payload '{"url":"https://m.example.com","emulation":{"preset":"iphone-17-pro"}}'`,`tab_open --payload '{"url":"https://market.m.taobao.com/app/trip/rx-home/pages/home","appProfile":"fliggy"}'`,`tab_open --payload '{"url":"https://market.m.taobao.com/app/trip/rx-home/pages/home","appProfile":"fliggy","emulation":{"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}}'`,`tab_open --payload '{"url":"https://example.com","appProfile":"fliggy","os":"android"}'`,`tab_open --payload '{"url":"https://example.com","group":"验证任务"}'`]},{name:"tab_close",description:"关闭指定标签页",aliases:["tab_remove","remove_tab","tab_delete","delete_tab"],params:[{name:"tabId",type:"number",required:!0,description:"要关闭的标签页 ID"}],examples:[`tab_close --payload '{"tabId":123}'`]},{name:"tab_list",description:"列出目标浏览器所有窗口中的标签页",aliases:["tabs","list_tabs","show_tabs"],examples:["tab_list"]},{name:"tab_group",description:"把同一窗口中的标签页加入分组,或通过 ungroup 取消分组并保留标签页;仅扩展模式支持",params:[{name:"tabIds",type:"number[]",required:!0,description:"标签页 ID,分组最多 100 个,取消分组最多 1000 个"},{name:"title",type:"string",required:!1,description:"分组标题;取消分组时省略"},{name:"ungroup",type:"boolean",required:!1,description:"为 true 时取消分组并保留标签页"}],examples:[`tab_group --payload '{"tabIds":[123,124],"title":"项目文档"}'`,`tab_group --payload '{"tabIds":[123,124],"ungroup":true}'`]},{name:"page_click",description:"点击页面元素,支持 CSS/@ref、可见文本或视口坐标定位",params:[{name:"selector",type:"string",description:"原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀)。不支持 :has-text/:visible 等 Playwright 私有伪类"},{name:"text",type:"string",description:"按可见文本(accessibility name)定位。需要时配合 role/exact 消歧;多匹配会报错并列出候选"},{name:"point",type:"{ x: number; y: number }",description:'按视口坐标点击(CSS 像素)。默认使用 outer-viewport;容器或 iframe 内坐标配合 coordinateSpace: "active-frame"'},{name:"frameId",type:"string",description:"浏览器扩展后端:显式指定 CSS/text 查询或 active-frame 坐标所属的 frame;省略时容器模式自动使用当前业务 frame"},{name:"coordinateSpace",type:'"outer-viewport" | "active-frame"',description:"仅配合 point 使用;默认 outer-viewport;浏览器扩展后端的 active-frame 会换算 iframe 偏移与缩放后派发可信输入"},{name:"role",type:"string",description:"配合 text 使用,按 AX role 过滤(如 button、link、heading)"},{name:"exact",type:"boolean",description:"配合 text 使用,默认 true 精确匹配;false 时按子串匹配"},{name:"scope",type:"string",description:"配合 text 使用,把文本匹配限制在指定 CSS 元素或 @eN ref 子树内,适合消除重复文案歧义"},{name:"clickMode",type:'"auto" | "dom" | "mouse" | "touch"',description:"默认 auto:可见页使用匹配设备的可信输入,隐藏页使用 DOM;dom/mouse/touch 可强制指定派发方式"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_click --payload '{"tabId":12345,"text":"提交"}'`,`page_click --payload '{"tabId":12345,"text":"退款明细","role":"button"}'`,`page_click --payload '{"tabId":12345,"text":"确定","scope":"@e12"}'`,`page_click --payload '{"tabId":12345,"selector":"@e3"}'`,`page_click --payload '{"tabId":12345,"selector":".submit-btn"}'`,`page_click --payload '{"tabId":12345,"selector":".gesture-btn","clickMode":"touch"}'`,`page_click --payload '{"tabId":12345,"point":{"x":336,"y":117}}'`,`page_click --payload '{"tabId":12345,"point":{"x":196,"y":240},"coordinateSpace":"active-frame"}'`]},{name:"page_drag",description:"拖动页面元素或视口坐标,适用于轮播图、滑块和拖放",params:[{name:"from",type:"string | { x: number; y: number }",required:!0,description:"起点:原生 CSS、@eN ref,或 { x, y } 视口坐标(CSS 像素)"},{name:"to",type:"string | { x: number; y: number }",required:!0,description:"终点:原生 CSS、@eN ref,或 { x, y } 视口坐标(CSS 像素)"},{name:"dragMode",type:'"auto" | "dom" | "mouse" | "touch"',description:"默认 auto:可见页使用匹配设备的可信输入,隐藏页使用 DOM;dom/mouse/touch 可强制指定派发方式"},{name:"durationMs",type:"number",description:"拖动持续时间,0–5000ms,默认 400ms;内部自动分段移动"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_drag --payload '{"tabId":12345,"from":{"x":350,"y":80},"to":{"x":80,"y":80}}'`,`page_drag --payload '{"tabId":12345,"from":"@e3","to":"#drop-zone","dragMode":"mouse"}'`]},{name:"page_type",description:"向输入框填写文本,兼容 React 受控组件",params:[{name:"selector",type:"string",required:!0,description:"原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀)"},{name:"text",type:"string",required:!0,description:"要填写的文本"},{name:"clearFirst",type:"boolean",description:"是否先清空原有内容,默认 true"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_type --payload '{"tabId":12345,"selector":"@e6","text":"搜索关键词"}'`]},{name:"page_hover",description:"将鼠标悬停在页面元素上",params:[{name:"selector",type:"string",required:!0,description:"原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀)"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_hover --payload '{"tabId":12345,"selector":".nav-menu"}'`]},{name:"page_scroll",description:"滚动页面或指定容器;页面根不可滚动时自动发现活动滚动区",params:[{name:"direction",type:'"up" | "down" | "top" | "bottom"',required:!0,description:"滚动方向"},{name:"distance",type:"number",description:"滚动距离(px),默认 600"},{name:"selector",type:"string",description:"目标滚动容器的原生 CSS 选择器,或 page_snapshot 返回的 @eN ref;不传时滚动页面"},{name:"containerPolicy",type:'"self" | "nearest"',description:"默认 self,要求 selector 本身可滚动;nearest 会在其不可滚动时使用最近的可滚动祖先"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_scroll --payload '{"tabId":12345,"direction":"down"}'`,`page_scroll --payload '{"tabId":12345,"direction":"bottom"}'`,`page_scroll --payload '{"tabId":12345,"selector":".virtual-list","direction":"down","distance":800}'`,`page_scroll --payload '{"tabId":12345,"selector":"@e8","containerPolicy":"nearest","direction":"bottom"}'`]},{name:"page_eval",description:"在页面上下文中执行任意 JavaScript 表达式",params:[{name:"expression",type:"string",required:!0,description:"要执行的 JS 表达式"},{name:"awaitPromise",type:"boolean",description:"表达式返回 Promise 时等待完成,默认 true"},{name:"observe",type:"object",description:"仅在表达式会修改页面且需要观察结果时显式传入;不传保持轻量裸执行"},PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_eval --payload '{"tabId":12345,"expression":"document.title"}'`]},{name:"page_inspect",description:"查询 DOM 元素的数量、边框盒、计算样式、遮挡、溢出和最近滚动容器",params:[{name:"selector",type:"string",description:"原生 CSS、page_snapshot 返回的 @eN ref,或 DevTools Elements 当前选区 $0;做全页溢出诊断时可省略"},{name:"filter",type:'"all" | "overflowing" | "horizontal-overflow" | "vertical-overflow" | "scrollable"',description:"结果过滤;省略 selector 时必须指定非 all 的过滤条件"},{name:"styles",type:"string[]",description:"要返回的计算样式属性,默认 display/position/box-sizing/overflow-x/overflow-y"},{name:"maxResults",type:"number",description:"最多返回的明细数,默认 20,最大 100;未触发 scanTruncated 时 count 为完整命中数"},{name:"includeOuterHTML",type:"boolean",description:"是否返回 outerHTML(最多 3000 字符);$0 默认 true,其他目标默认 false"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_inspect --payload '{"tabId":12345,"selector":".form-field","styles":["display","width"]}'`,`page_inspect --payload '{"tabId":12345,"selector":"@e8"}'`,`page_inspect --payload '{"tabId":12345,"selector":"$0"}'`,`page_inspect --payload '{"tabId":12345,"filter":"horizontal-overflow"}'`,`page_inspect --payload '{"tabId":12345,"filter":"scrollable"}'`]},{name:"page_press",description:"在页面中按下键盘按键或组合键",params:[{name:"key",type:"string",required:!0,description:"按键名称:Enter/Tab/Escape/Backspace 等"},{name:"modifiers",type:"string[]",description:"修饰键数组:ctrl/alt/shift/meta/cmd"},{name:"pressMode",type:'"auto" | "dom" | "keyboard"',description:"派发模式;auto 默认在隐藏页降级为 DOM 键盘事件"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_press --payload '{"tabId":12345,"key":"Enter"}'`]},{name:"page_wait",description:"等待指定时间、元素状态、可见文本或页面条件成立",params:[{name:"time",type:"number",description:"等待毫秒数(与 selector/text/condition 四选一)"},{name:"selector",type:"string",description:"目标 CSS 选择器(与 time/text/condition 四选一)"},{name:"state",type:'"attached" | "detached" | "visible" | "hidden"',description:"selector 的目标状态,默认 attached"},{name:"text",type:"string",description:"等待页面出现的可见文本"},{name:"exact",type:"boolean",description:"text 是否精确匹配,默认 false"},{name:"condition",type:"string",description:"在页面主上下文轮询的 JS 表达式,返回 truthy 时结束"},{name:"timeout",type:"number",description:"等待超时毫秒数,默认 10000"},{name:"interval",type:"number",description:"轮询间隔毫秒数,默认 200"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_wait --payload '{"tabId":12345,"time":1000}'`,`page_wait --payload '{"tabId":12345,"selector":".dialog","state":"visible"}'`,`page_wait --payload '{"tabId":12345,"selector":".loading","state":"hidden"}'`,`page_wait --payload '{"tabId":12345,"text":"提交成功"}'`,`page_wait --payload '{"tabId":12345,"condition":"window.appReady === true","timeout":30000}'`]},{name:"page_navigate",description:"在当前标签页内导航到 URL、刷新页面,或沿浏览历史后退/前进",params:[{name:"url",type:"string",description:"要导航到的 URL;与 refresh/history 互斥"},{name:"refresh",type:"boolean",description:"为 true 时直接重新加载当前页面;与 url/history 互斥"},{name:"history",type:'"back" | "forward"',description:"沿当前标签页浏览历史后退或前进;与 url/refresh 互斥"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_navigate --payload '{"tabId":12345,"url":"https://example.com/page2"}'`,`page_navigate --payload '{"tabId":12345,"refresh":true}'`,`page_navigate --payload '{"tabId":12345,"history":"back"}'`]},{name:"page_upload",description:'向 <input type="file"> 元素上传一个或多个文件',params:[{name:"selector",type:"string",required:!0,description:"原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀),必须指向 input[type=file]"},{name:"filePaths",type:"string[]",required:!0,description:"本地文件路径数组"},PAGE_OBSERVE_PARAM,PAGE_DIAGNOSTICS_PARAM,{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_upload --payload '{"tabId":12345,"selector":"#file-input","filePaths":["/Users/me/photo.jpg"]}'`]},{name:"page_snapshot",description:"获取带 @ref 的页面结构快照,默认使用无障碍树,也可显式读取渲染 DOM",params:[{name:"depth",type:"number",description:"树深度,默认 15,复杂页面可调大"},{name:"mode",type:'"full" | "interactive" | "viewport" | "dom"',description:"默认 full;interactive/viewport 裁剪 AX 树;AX 信息缺失时可显式使用 dom 读取渲染 DOM"},{name:"rootSelector",type:"string",description:"只获取指定 CSS 元素的局部子树,可与 mode 组合;与 rootRef 互斥"},{name:"rootRef",type:"string",description:"以已有 @eN ref 为根获取局部子树;与 rootSelector 互斥"},{name:"ancestorDepth",type:"number",description:"rootRef 向上扩展的 DOM 祖先层数,默认 0,最大 20"},{name:"query",type:"{ text?: string; role?: string; exact?: boolean }",description:"服务端按 name / role 过滤当前模式的树,只保留命中节点及祖先路径"},{name:"maxNodes",type:"number",description:"最多输出节点数,0 表示不限制"},{name:"maxChars",type:"number",description:"快照文本最大字符数,默认 60000,超出保留首尾;传 0 不限制"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_snapshot --payload '{"tabId":12345}'`,`page_snapshot --payload '{"tabId":1,"mode":"viewport"}'`,`page_snapshot --payload '{"tabId":1,"mode":"dom"}'`,`page_snapshot --payload '{"tabId":1,"rootSelector":"[role=dialog]"}'`,`page_snapshot --payload '{"tabId":1,"rootRef":"@e8","ancestorDepth":1}'`,`page_snapshot --payload '{"tabId":1,"query":{"text":"保存","role":"button"}}'`]},{name:"page_screenshot",description:"获取当前视口或指定元素截图",outputFlag:!0,params:[{name:"selector",type:"string",description:"CSS 选择器,提供后只截取该元素区域"},{name:"format",type:'"png" | "jpeg"',description:"图片格式,默认 png"},{name:"quality",type:"number",description:"JPEG 压缩质量(0-100),默认 80"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_screenshot --payload '{"tabId":12345}' --output ./screenshot.png`,`page_screenshot --payload '{"tabId":12345,"selector":".product-card"}' --output ./card.png`]},{name:"set_device_emulation",description:"把目标 tab 切换为移动端模拟(视口/DPR/UA/触摸/视觉比例),等价 DevTools 设备工具栏,作用域 per-tab;需保持调试控制才持续生效",summary:"设置或清除目标标签页的设备模拟",params:[{name:"enabled",type:"boolean",required:!0,description:"true=启用,false=清除"},{name:"preset",type:DEVICE_PRESET_TYPE,description:"内置设备预设,提供 width/height/DPR/UA 默认值;旧机型 ID 继续兼容"},{name:"width",type:"number",description:"视口宽度(覆盖 preset)"},{name:"height",type:"number",description:"视口高度(覆盖 preset)"},{name:"deviceScaleFactor",type:"number",description:"DPR(覆盖 preset)"},{name:"scale",type:"number",description:"画面视觉比例,不改变视口尺寸或 DPR;必须为有限正数,默认 1"},{name:"mobile",type:"boolean",description:"是否走移动渲染模式,默认从 preset 推断"},{name:"userAgent",type:"string",description:"自定义 UA(覆盖 preset)"},{name:"orientation",type:'"portrait" | "landscape"',description:"横竖屏,默认 portrait"},{name:"touch",type:"boolean",description:"是否启用触摸事件,默认从 preset 推断;无 preset 时跟随 mobile"},{name:"deviceShell",type:"boolean",description:"是否使用 iframe WebView 并渲染顶部状态栏与底部操作区,默认 false"},{name:"splitScreen",type:"boolean",description:"是否将首页与业务页分置左右 WebView;仅在已启用 App 档案、deviceShell=true、横屏时生效,默认 false"},{name:"reload",type:"boolean",description:"启用后是否重载页面,默认 true"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`set_device_emulation --payload '{"tabId":12345,"enabled":true,"preset":"iphone-17-pro"}'`,`set_device_emulation --payload '{"tabId":12345,"enabled":true,"preset":"pixel-11","orientation":"landscape"}'`,`set_device_emulation --payload '{"tabId":12345,"enabled":true,"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}'`,`set_device_emulation --payload '{"tabId":12345,"enabled":false}'`]},{name:"set_app_profile",description:"设置 App 客户端环境与 JSBridge;可同时设置 MTop 页面接口环境,传 emulation 时联动设备模拟",summary:"设置或清除目标标签页的 App 容器模拟",params:[{name:"enabled",type:"boolean",required:!0,description:"true=启用,false=清除"},{name:"profile",type:"string",description:`容器档案名(enabled=true 时必填):${APP_PROFILE_NAME_LIST}`},{name:"os",type:'"ios" | "android"',description:"容器系统,默认 ios"},{name:"appVersion",type:"string",description:"覆盖档案默认 App 版本号"},{name:"deviceModel",type:"string",description:"Android 机型名(拼入 UA 与 __DEVICE_MODEL__)"},{name:"bridgeConfig",type:"object",description:"声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}};不执行配置脚本"},{name:"mtopEnv",type:'"default" | "prod" | "pre"',description:"可选 MTop 页面接口环境;default 关闭环境改写,省略时保持当前设置。扩展模式全局生效,CDP 模式仅作用于目标 tab"},{name:"emulation",type:"object",description:"可选设备联动参数,字段同 set_device_emulation 去掉 enabled/reload;字段覆盖档案推荐设备,deviceShell 默认 true,横屏时可传 splitScreen=true。省略时不设置或清除设备"},{name:"reload",type:"boolean",description:"应用/清除后是否重载页面,默认 true"},{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy"}'`,`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy","mtopEnv":"pre"}'`,`set_app_profile --payload '{"tabId":12345,"enabled":false,"mtopEnv":"prod"}'`,`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy","emulation":{}}'`,`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"alipay","emulation":{"preset":"pixel-11","deviceShell":true}}'`,`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy","emulation":{"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}}'`,`set_app_profile --payload '{"tabId":12345,"enabled":false}'`,`set_app_profile --payload '{"tabId":12345,"enabled":false,"emulation":{}}'`]},{name:"set_timezone",description:"覆盖目标 tab 的时区,传空字符串恢复浏览器默认时区",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"},{name:"timezone",type:"string",required:!0,description:"IANA 时区标识(如 Asia/Shanghai);空字符串表示清除覆盖"}],examples:[`set_timezone --payload '{"tabId":12345,"timezone":"America/New_York"}'`,`set_timezone --payload '{"tabId":12345,"timezone":""}'`]},{name:"get_cookie",description:"从目标浏览器读取一个指定非分区 Cookie;拒绝返回 HttpOnly Cookie",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"},{name:"name",type:"string",required:!0,description:"要读取的 Cookie 名称;不支持列举全部 Cookie"},{name:"url",type:"string",description:"可选 Cookie 查询 URL;省略时使用当前标签页 URL"},{name:"domain",type:"string",description:"可选精确域过滤,只允许 Cookie 查询 URL 的 host 或其父域"},{name:"path",type:"string",description:"可选精确 path 过滤"}],examples:[`get_cookie --payload '{"tabId":12345,"name":"feature_flag"}'`,`get_cookie --payload '{"tabId":12345,"name":"edith_switch_br.rx-vehicle-search_home","domain":"taobao.com"}'`,`get_cookie --payload '{"tabId":12345,"name":"tracknick","url":"https://www.taobao.com/","domain":"taobao.com","path":"/"}'`]},{name:"set_cookie",description:"设置当前标签页域下的一个指定非分区 session Cookie,可选刷新页面",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"},{name:"name",type:"string",required:!0,description:"Cookie 名称"},{name:"value",type:"string",required:!0,description:"Cookie 值,可传空字符串;空字符串不会删除 Cookie"},{name:"domain",type:"string",description:"Cookie 域,默认当前 host;只允许当前 host 或其父域"},{name:"path",type:"string",description:"Cookie path,默认 /"},{name:"reload",type:"boolean",description:"设置后是否刷新页面,默认 false"}],examples:[`set_cookie --payload '{"tabId":12345,"name":"feature_flag","value":"enabled"}'`,`set_cookie --payload '{"tabId":12345,"name":"edith_switch_br.rx-vehicle-search_home","value":"3.6.63","domain":"taobao.com","reload":true}'`]},{name:"page_frames",description:"获取页面主 frame 与所有 iframe 列表",params:[{name:"tabId",type:"number",required:!0,description:"目标标签页 ID"}],examples:[`page_frames --payload '{"tabId":12345}'`]},{name:"request_domain_permission",description:"申请访问指定域名的权限(必要时弹窗让用户授权)",params:[{name:"domain",type:"string",required:!0,description:"需要授权的域名,如 example.com"}],examples:[`request_domain_permission --payload '{"domain":"example.com"}'`]},{name:"run_actions",description:"批量顺序执行多个 action,减少往返延迟。遇错即停,返回已完成步骤结果;步骤内的页面动作不带内置观察",summary:"批量顺序执行多个 action,遇错即停",params:[{name:"actions",type:"Array<{action: string, data?: object}>",required:!0,description:"要依次执行的 action 列表"},{name:"tabId",type:"number",required:!0,description:"所有步骤共享的 tabId,步骤自身指定的优先"}],examples:[`run_actions --payload '{"tabId":12345,"actions":[{"action":"page_scroll","data":{"direction":"down"}},{"action":"page_wait","data":{"time":500}},{"action":"page_screenshot"}]}'`]}],COMMAND_MAP=new Map(COMMANDS.map(command=>[command.name,command]))}});function findOfficialPlugin(name){return Object.hasOwn(OFFICIAL_PLUGINS,name)?OFFICIAL_PLUGINS[name]:void 0}function listOfficialPluginNames(setup){return Object.entries(OFFICIAL_PLUGINS).filter(([,definition])=>setup===void 0||"setup"in definition&&definition.setup===setup).map(([name])=>name)}var OFFICIAL_PLUGINS,init_officialPluginCatalog=__esm({"../client/dist/officialPluginCatalog.js"(){"use strict";OFFICIAL_PLUGINS={buc:{description:"使用 BUC 身份请求内部服务",installArgs:["trip/mearl","--skill","buc-request","--yes"],skill:"buc-request"},authx:{description:"使用 AuthX 身份请求内部服务",installArgs:["trip/mearl","--skill","authx-request","--yes"],skill:"authx-request"},tdbank:{description:"查询、借用和切换 TDBank 测试账号",installArgs:["trip/mearl","--skill","tdbank-account","--yes"],setup:"alibaba",skill:"tdbank-account"}}}});import{createHash as createHash3}from"node:crypto";import{readFileSync as readFileSync5,realpathSync}from"node:fs";import{basename as basename2,dirname as dirname3,extname,isAbsolute as isAbsolute3,join as join6,relative as relative2,resolve as resolve2,sep as sep2}from"node:path";function pluginRoot(entry){let entryDirectory=dirname3(entry);return basename2(entryDirectory)==="scripts"?dirname3(entryDirectory):entryDirectory}function attributeValue(tag,name){let match=tag.match(new RegExp(`\\b${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s>]+))`,"i"));return match?.[1]??match?.[2]??match?.[3]}function removeAttribute(tag,name){return tag.replace(new RegExp(`\\s+${name}\\s*=\\s*(?:"[^"]*"|'[^']*'|[^\\s>]+)`,"i"),"")}function isEmbeddedReference(reference){return/^(?:data:|blob:|#)/i.test(reference.trim())}function isRemoteReference(reference){return/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(reference.trim())}function contentType(path22){return MIME_TYPES2[extname(path22).toLowerCase()]??"application/octet-stream"}function escapeStyleText(value){return value.replace(/<\/style/gi,"\\3C /style")}function escapeScriptText(value){return value.replace(/<\/script/gi,"<\\/script")}function buildPluginPageBundle(entry,pageEntry){let root=realpathSync(pluginRoot(entry)),sourceBytes=0,countedFiles=new Set,resolveLocalFile=(reference,fromFile)=>{let cleanReference=reference.trim().split(/[?#]/,1)[0];if(!cleanReference||isEmbeddedReference(cleanReference))return"";if(isRemoteReference(cleanReference)||isAbsolute3(cleanReference))throw new Error(`toolbox.page 不允许远程或绝对资源: ${reference}`);let resolved=realpathSync(resolve2(dirname3(fromFile),cleanReference)),relativePath=relative2(root,resolved);if(relativePath===".."||relativePath.startsWith(`..${sep2}`)||isAbsolute3(relativePath))throw new Error(`toolbox.page 资源超出插件目录: ${reference}`);return resolved},readAsset=path22=>{let content2=readFileSync5(path22);if(!countedFiles.has(path22)&&(countedFiles.add(path22),sourceBytes+=content2.byteLength,sourceBytes>MAX_PAGE_SOURCE_BYTES))throw new Error("toolbox.page 源文件总大小不能超过 16 MiB");return content2},dataUrl=(reference,fromFile)=>{if(isEmbeddedReference(reference))return reference;let path22=resolveLocalFile(reference,fromFile);return`data:${contentType(path22)};base64,${readAsset(path22).toString("base64")}`},inlineCss=(css,cssPath)=>css.replace(/url\(\s*(['"]?)([^'"()]+)\1\s*\)/gi,(_match,_quote,reference)=>{let value=reference.trim();return isEmbeddedReference(value)?`url("${value}")`:`url("${dataUrl(value,cssPath)}")`}),absoluteEntry=resolveLocalFile(pageEntry,join6(root,"__toolbox_entry__"));if(extname(absoluteEntry).toLowerCase()!==".html")throw new Error("toolbox.page.entry 必须指向 HTML 文件");let html=readAsset(absoluteEntry).toString("utf8").replace(/^\uFEFF/,"");if(!/<html\b|<!doctype\b/i.test(html))throw new Error("toolbox.page.entry 必须是完整 HTML 文档");if(/<base\b/i.test(html))throw new Error("toolbox.page 不允许声明 base 标签");if(/<meta\b[^>]*http-equiv\s*=\s*["']?content-security-policy/i.test(html))throw new Error("toolbox.page 的安全策略由 Mearl 管理,请移除 CSP meta 标签");html=html.replace(/<link\b[^>]*>/gi,tag=>{let rel=attributeValue(tag,"rel")?.toLowerCase().split(/\s+/)??[],href=attributeValue(tag,"href");if(rel.includes("stylesheet")){if(!href)throw new Error("toolbox.page stylesheet 缺少 href");let cssPath=resolveLocalFile(href,absoluteEntry),css=inlineCss(readAsset(cssPath).toString("utf8"),cssPath);return`<style data-mearl-source="${href.replaceAll('"',"&quot;")}">${escapeStyleText(css)}</style>`}if(href&&rel.some(value=>["icon","apple-touch-icon"].includes(value)))return tag.replace(href,dataUrl(href,absoluteEntry));if(href&&isRemoteReference(href))throw new Error(`toolbox.page 不允许远程 link 资源: ${href}`);return tag}),html=html.replace(/<script\b[^>]*>[\s\S]*?<\/script\s*>/gi,tag=>{let src=attributeValue(tag,"src");if(!src)return tag;let scriptPath=resolveLocalFile(src,absoluteEntry),script=readAsset(scriptPath).toString("utf8");if(attributeValue(tag,"type")?.toLowerCase()==="module"&&/(?:^|[;\n]\s*)(?:import\s|export\s)|\bimport\s*\(/m.test(script))throw new Error("toolbox.page 的模块脚本必须先打包为无 import 的单文件");return`${removeAttribute(tag.slice(0,tag.indexOf(">")+1),"src")}${escapeScriptText(script)}</script>`}),html=html.replace(/(<(?:img|source|video|audio|track|input)\b[^>]*?\s(?:src|poster)\s*=\s*)(["'])([^"']+)\2/gi,(_match,prefix,quote,reference)=>`${prefix}${quote}${dataUrl(reference,absoluteEntry)}${quote}`);let injection=`<meta name="color-scheme" content="light dark">${PAGE_SECURITY_META}${PAGE_THEME_STYLE}<script data-mearl-bridge>${escapeScriptText(PAGE_BRIDGE_SCRIPT)}</script>`;html=/<head\b[^>]*>/i.test(html)?html.replace(/<head\b[^>]*>/i,tag=>`${tag}${injection}`):html.replace(/<html\b[^>]*>/i,tag=>`${tag}<head>${injection}</head>`);let content=html,buffer=Buffer.from(content,"utf8");if(buffer.byteLength>MAX_PAGE_BUNDLE_BYTES)throw new Error("toolbox.page 打包后不能超过 24 MiB");return{content,hash:createHash3("sha256").update(buffer).digest("hex"),size:buffer.byteLength,chunks:Math.ceil(buffer.byteLength/PLUGIN_PAGE_CHUNK_BYTES)}}var PLUGIN_PAGE_CHUNK_BYTES,MAX_PAGE_SOURCE_BYTES,MAX_PAGE_BUNDLE_BYTES,MIME_TYPES2,PAGE_BRIDGE_SCRIPT,PAGE_SECURITY_META,PAGE_THEME_STYLE,init_pluginPageBundle=__esm({"../client/dist/pluginPageBundle.js"(){"use strict";PLUGIN_PAGE_CHUNK_BYTES=384*1024,MAX_PAGE_SOURCE_BYTES=16*1024*1024,MAX_PAGE_BUNDLE_BYTES=24*1024*1024,MIME_TYPES2={".avif":"image/avif",".gif":"image/gif",".ico":"image/x-icon",".jpeg":"image/jpeg",".jpg":"image/jpeg",".mp3":"audio/mpeg",".mp4":"video/mp4",".ogg":"audio/ogg",".otf":"font/otf",".png":"image/png",".svg":"image/svg+xml",".ttf":"font/ttf",".wav":"audio/wav",".webm":"video/webm",".webp":"image/webp",".woff":"font/woff",".woff2":"font/woff2"},PAGE_BRIDGE_SCRIPT=String.raw`(() => {
33
33
  let context = null;
34
34
  let port = null;
35
35
  let requestSequence = 0;
@@ -763,7 +763,7 @@ except BaseException as error:
763
763
  sys.exit(1)
764
764
  `}});import{readFileSync as readFileSync7,statSync as statSync6}from"node:fs";import{dirname as dirname4,extname as extname2,resolve as resolve4}from"node:path";import{pathToFileURL}from"node:url";function readPluginVersion(entry){try{return readFileSync7(resolve4(dirname4(entry),"..","SKILL.md"),"utf8").match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1]?.split(/\r?\n/).find(line=>/^version:\s*/.test(line))?.match(/^version:\s*["']?([^"'#\s]+)["']?\s*$/)?.[1]}catch{return}}function isObject2(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}function isPluginInvocation(value){return isObject2(value)&&typeof value.command=="string"&&isObject2(value.input)}function normalizePluginProgress(progress){if(typeof progress=="string"){if(!progress)throw new Error("app.progress 需要非空消息");return progress}if(!isObject2(progress)||typeof progress.message!="string"||!progress.message)throw new Error("app.progress 需要非空消息");if(progress.data!==void 0&&!isObject2(progress.data))throw new Error("app.progress data 必须是对象");let data;if(progress.data)try{let serialized=JSON.stringify(progress.data),parsed=serialized===void 0?void 0:JSON.parse(serialized);if(!isObject2(parsed))throw new Error("invalid object");data=Object.freeze(parsed)}catch{throw new Error("app.progress data 必须是可 JSON 序列化的对象")}return Object.freeze({message:progress.message,...data?{data}:{}})}function missingPluginEntryMessage(entry,pluginName){let name=pluginName??"<name>";return["插件入口已失效","",`插件:${name}`,`入口:${entry}`,"",`卸载命令:npx @mearl/setup plugin uninstall ${name}`].join(`
765
765
  `)}async function loadPlugin(entry,context,pluginName){let entryVersion;try{let stat2=statSync6(entry);if(!stat2.isFile())throw new Error("not a file");entryVersion=`${stat2.mtimeMs}-${stat2.size}`}catch{throw new PluginError("PLUGIN_ENTRY_MISSING",missingPluginEntryMessage(entry,pluginName))}let commands=new Map,executing=!1,registering=!0,name,description,toolbox,app=Object.freeze({options:Object.freeze({...context.options}),command(signature,handler,description2=""){if(!registering)throw new Error("命令只能在入口注册阶段声明");let[name2,...args]=signature.trim().split(/\s+/);if(!/^[a-z][a-z0-9-]*$/.test(name2)||commands.has(name2)||typeof handler!="function")throw new Error(`无效或重复的命令: ${signature}`);let command=new Command(name2).description(description2);for(let argument of args){if(!/^(?:<[a-zA-Z][\w-]*(?:\.\.\.)?>|\[[a-zA-Z][\w-]*(?:\.\.\.)?\])$/.test(argument))throw new Error(`无效的位置参数: ${argument}`);command.argument(argument)}let names=command.registeredArguments.map(argument=>argument.name());if(new Set(names).size!==names.length)throw new Error(`参数名称重复: ${signature}`);commands.set(name2,{command,signature,handler})},invoke(action,payload={},options={}){if(!executing)throw new Error("app.invoke 只能在命令执行期间调用");return context.invoke(action,payload,options)},progress(progress){if(!executing)throw new Error("app.progress 只能在命令执行期间调用");context.progress(normalizePluginProgress(progress))}});try{if(extname2(entry).toLowerCase()===".py"){let descriptor=await describePythonPlugin(entry,app.options);name=descriptor.name,description=descriptor.description,toolbox=normalizePluginToolboxContribution(descriptor.toolbox);for(let command of descriptor.commands){let commandName=command.signature.trim().split(/\s+/)[0];app.command(command.signature,input2=>runPythonPluginCommand(entry,commandName,input2,app),command.description)}}else{let moduleUrl=pathToFileURL(entry);moduleUrl.searchParams.set("mearl-version",entryVersion);let module=await import(moduleUrl.href);if(module.name!==void 0&&typeof module.name!="string")throw new Error("入口的 name 导出必须为字符串");if(name=module.name,module.description!==void 0&&typeof module.description!="string")throw new Error("入口的 description 导出必须为字符串");if(description=module.description,toolbox=normalizePluginToolboxContribution(module.toolbox),typeof module.default!="function")throw new Error("入口必须默认导出 register(app) 函数");await module.default(app)}if(commands.size===0)throw new Error("入口未注册任何命令");let toolboxCommands=toolbox?.page.commands??[];for(let command of toolboxCommands)if(!commands.has(command))throw new Error(`toolbox 命令未注册: ${command}`)}catch(error48){throw new PluginError("PLUGIN_LOAD_FAILED",`${entry}: ${error48 instanceof Error?error48.message:String(error48)}`)}finally{registering=!1}let find=name2=>{let command=commands.get(name2);if(!command)throw new PluginError("PLUGIN_COMMAND_NOT_FOUND",`未知子命令: ${name2}`);return command};return{name,description,toolbox,version:readPluginVersion(entry),commandHelp(namespace){return[...commands.values()].map(({command,signature})=>` ${namespace} ${signature} ${command.description()}`).join(`
766
- `)},help(namespace,name2){let selected=name2?[find(name2)]:[...commands.values()],example=selected[0].command,input2=Object.fromEntries(example.registeredArguments.map(argument=>[argument.name(),argument.variadic?[`<${argument.name()}>`]:`<${argument.name()}>`]));return[...selected.map(({command,signature})=>` ${namespace} ${signature} ${command.description()}`),"",` ${namespace} --payload '${JSON.stringify({command:example.name(),input:input2})}'`,"","常用选项: --browser --timeout --compact --output","连接或传输排障运行 mearl check --help。","插件选项: --name=value 传入字符串业务字段;--verbose; -h, --help; -v, --version","同名宿主选项及非字符串字段使用 --payload;业务字段与校验规则见对应 skill。"].join(`
766
+ `)},help(namespace,name2){let selected=name2?[find(name2)]:[...commands.values()],example=selected[0].command,input2=Object.fromEntries(example.registeredArguments.map(argument=>[argument.name(),argument.variadic?[`<${argument.name()}>`]:`<${argument.name()}>`]));return[...selected.map(({command,signature})=>` ${namespace} ${signature} ${command.description()}`),"",` ${namespace} --payload '${JSON.stringify({command:example.name(),input:input2})}'`,"","常用选项: --browser --timeout --compact --output","连接或传输排障运行 mearl check --help。","插件选项: --name=value 传入字符串业务字段;--all 传入 all=true;--verbose; -h, --help; -v, --version","同名宿主选项及非字符串字段使用 --payload;业务字段与校验规则见对应 skill。"].join(`
767
767
  `)},async run(positionals,payload,namedInput={}){if(payload!==void 0&&positionals.length>0)throw new PluginError("PLUGIN_INVALID_INPUT","位置参数调用与 --payload 调用不能混用");if(payload!==void 0&&Object.keys(namedInput).length>0)throw new PluginError("PLUGIN_INVALID_INPUT","插件业务选项与 --payload 调用不能混用");if(payload!==void 0&&(!isObject2(payload)||typeof payload.command!="string"||!isObject2(payload.input)))throw new PluginError("PLUGIN_INVALID_INPUT",'--payload 必须为 {"command":"...","input":{...}}');let envelope=payload,{command,handler}=find(envelope?.command??positionals[0]??""),positionalInput=envelope?{...envelope.input}:Object.fromEntries(command.registeredArguments.map((argument,index)=>[argument.name(),argument.variadic?positionals.slice(index+1):positionals[index+1]]).filter(([,value])=>value!==void 0));for(let name2 of Object.keys(namedInput))if(Object.hasOwn(positionalInput,name2))throw new PluginError("PLUGIN_INVALID_INPUT",`参数不能重复传入: ${name2}`);let input2={...positionalInput,...namedInput};if(!envelope&&!command.registeredArguments.some(argument=>argument.variadic)&&positionals.length-1>command.registeredArguments.length)throw new PluginError("PLUGIN_INVALID_INPUT","位置参数过多");for(let argument of command.registeredArguments){let value=Object.hasOwn(input2,argument.name())?input2[argument.name()]:void 0;if(argument.required&&(value==null||value===""||Array.isArray(value)&&value.length===0))throw new PluginError("PLUGIN_INVALID_INPUT",`缺少必填参数: ${argument.name()}`);if(argument.variadic&&value!==void 0&&!Array.isArray(value))throw new PluginError("PLUGIN_INVALID_INPUT",`${argument.name()} 必须为数组`)}executing=!0;try{return await handler(input2)}finally{executing=!1}}}}async function loadRegisteredPluginWithState(name,context,options={},state={stack:[]}){if(state.stack.includes(name))throw new PluginError("PLUGIN_INVOCATION_CYCLE",`插件调用形成循环: ${[...state.stack,name].join(" -> ")}`);let registration=findPluginRegistration(name);if(!registration&&findOfficialPlugin(name)&&(await(context.ensurePlugin??ensureOfficialPluginRegistered)(name,options.onProgress?message=>options.onProgress?.(message):void 0),registration=findPluginRegistration(name)),!registration)throw new PluginError("PLUGIN_NOT_REGISTERED",`插件未注册: ${name}`);let{onProgress,...invokeOptions}=options,childState={stack:[...state.stack,name]};return loadPlugin(registration.entry,{options:invokeOptions,progress:onProgress??(()=>{}),async invoke(action,payload,overrides){let nestedOptions={...invokeOptions,...overrides};if(COMMAND_MAP.has(action)||action==="connector_list"){let result2=await context.invoke(action,payload,nestedOptions);if(result2?.action?.success===!1)throw new Error(result2.action.error||`${action} failed`);return result2}let pluginInvocation=isPluginInvocation(payload);if(findPluginRegistration(action)||findOfficialPlugin(action)||pluginInvocation){if(!pluginInvocation)throw new PluginError("PLUGIN_INVALID_INPUT",`调用插件 ${action} 需要 {"command":"...","input":{...}}`);return invokeRegisteredPluginWithState(action,payload,context,{...nestedOptions,...onProgress?{onProgress}:{}},childState)}let result=await context.invoke(action,payload,nestedOptions);if(result?.action?.success===!1)throw new Error(result.action.error||`${action} failed`);return result}},name)}async function invokeRegisteredPluginWithState(name,invocation2,context,options={},state={stack:[]}){return(await loadRegisteredPluginWithState(name,context,options,state)).run([],invocation2)}function invokeRegisteredPlugin(name,invocation2,context,options={}){return invokeRegisteredPluginWithState(name,invocation2,context,options)}var init_plugin=__esm({"../client/dist/plugin.js"(){"use strict";init_commander();init_commands();init_officialPluginCatalog();init_officialPluginInstaller();init_pluginRegistry();init_pythonPlugin();init_pluginRegistry();init_officialPluginCatalog()}});import fs10 from"node:fs";import os6 from"node:os";import path9 from"node:path";import{execFileSync}from"node:child_process";function resolveNativeHostDirectory(options={}){let env=options.env??process.env,home=(options.homedir??os6.homedir)();switch(options.platform??process.platform){case"darwin":return path9.join(home,"Library/Application Support/Google/Chrome/NativeMessagingHosts");case"linux":return path9.join(home,".config/google-chrome/NativeMessagingHosts");case"win32":return path9.join(env.PROGRAMDATA||"C:\\ProgramData","Google\\Chrome\\NativeMessagingHosts");default:throw new Error(`Unsupported platform: ${String(options.platform??process.platform)}`)}}function unregisterWindowsNativeHost(hostName){let registryKey=`HKCU\\SOFTWARE\\Google\\Chrome\\NativeMessagingHosts\\${hostName}`;try{execFileSync("reg",["delete",registryKey,"/f"],{stdio:"pipe"})}catch{}}function uninstallNativeHostArtifacts(options={},dependencies={}){let{mode="both",silent=!1}=options;if(mode==="both")return["skills","mcp"].map(integrationMode=>uninstallNativeHostArtifacts({...options,mode:integrationMode},dependencies)).every(Boolean);let writeLine=dependencies.writeLine??(line=>console.error(line)),log2=line=>{silent||writeLine(line)};try{let existsSync11=dependencies.existsSync??fs10.existsSync,platform=dependencies.platform??process.platform,hostDir=dependencies.hostDir??resolveNativeHostDirectory({env:dependencies.env,homedir:dependencies.homedir,platform}),unlinkSync=dependencies.unlinkSync??fs10.unlinkSync,unregister=dependencies.unregisterWindowsNativeHost??unregisterWindowsNativeHost,hostName=MEARL_NATIVE_HOST_NAMES[mode],launcherExtension=platform==="win32"?"cmd":"sh",artifacts=[path9.join(hostDir,`${hostName}.json`),path9.join(hostDir,`${hostName}-launcher.${launcherExtension}`)];for(let artifact of artifacts)existsSync11(artifact)&&(unlinkSync(artifact),log2(`✅ Removed: ${artifact}`));return platform==="win32"&&unregister(hostName),!0}catch(error48){return log2(`❌ Uninstall failed: ${error48 instanceof Error?error48.message:String(error48)}`),!1}}var MEARL_NATIVE_HOST_NAMES,init_nativeHost=__esm({"../setup/dist/nativeHost.js"(){"use strict";MEARL_NATIVE_HOST_NAMES={skills:"com.alibaba.mearl.skills",mcp:"com.alibaba.mearl.mcp"}}});var install_exports={};__export(install_exports,{installNativeHost:()=>installNativeHost,parseNativeHostInstallArgs:()=>parseNativeHostInstallArgs,resolveHostDir:()=>resolveHostDir,runCli:()=>runCli,uninstallNativeHost:()=>uninstallNativeHost});import fs20 from"node:fs";import path20 from"node:path";import{execFileSync as execFileSync2}from"node:child_process";import{createRequire as createRequire4}from"node:module";import{fileURLToPath as fileURLToPath2}from"node:url";function resolveHostDir(){return resolveNativeHostDirectory()}function resolveNativeHostPath(){let siblingPath=path20.join(__dirname,"index.js");if(fs20.existsSync(siblingPath))return siblingPath;try{return createRequire4(import.meta.url).resolve("@mearl/native-host/runtime")}catch{throw new Error("Cannot locate native-host runtime entry point. Ensure @mearl/native-host is installed correctly.")}}function registerWindowsNativeHost(hostName,manifestPath){let regKey=`HKCU\\SOFTWARE\\Google\\Chrome\\NativeMessagingHosts\\${hostName}`;execFileSync2("reg",["add",regKey,"/ve","/t","REG_SZ","/d",manifestPath,"/f"],{stdio:"pipe"})}function createLauncherScript(hostDir,hostPath,hostName){let nodePath=path20.resolve(process.execPath);if(process.platform==="win32"){let launcherPath2=path20.join(hostDir,`${hostName}-launcher.cmd`),content2=`@echo off\r
768
768
  "${nodePath}" "${hostPath}" %*\r
769
769
  `;return fs20.writeFileSync(launcherPath2,content2,"utf-8"),launcherPath2}let launcherPath=path20.join(hostDir,`${hostName}-launcher.sh`),content=["#!/bin/sh",`NODE_BIN=${JSON.stringify(nodePath)}`,`HOST_SCRIPT=${JSON.stringify(hostPath)}`,'exec "$NODE_BIN" "$HOST_SCRIPT" "$@"',""].join(`
@@ -878,7 +878,7 @@ ${truncated}...`}function extractFields(data,fields){if(fields.length>100)throw
878
878
  ${BASE_ICON}
879
879
  ${SOURCE_BADGES[source]}
880
880
  </svg>`;return`data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`}var JSONP_CALLBACK_RE=/^[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)*$/,JSONP_CONTENT_TYPE="application/javascript; charset=utf-8";function getJsonpCallback(url2){try{let searchParams=new URL(url2).searchParams,callback=searchParams.get("callback")??searchParams.get("jsonp");return callback&&JSONP_CALLBACK_RE.test(callback)?callback:null}catch{return null}}function serializeMockResponse(requestUrl,responseData){let callback=getJsonpCallback(requestUrl);if(!callback)return{body:typeof responseData=="string"?responseData:JSON.stringify(responseData)??"null",isJsonp:!1};let json2=JSON.stringify(responseData)??"null";if(typeof responseData=="string")try{JSON.parse(responseData),json2=responseData}catch{}return{body:`${callback}(${json2});`,isJsonp:!0}}function prepareMockResponseHeaders(headers,isJsonp){let stripped=(headers??[]).filter(header=>!["content-encoding","content-length"].includes(header.name.toLowerCase()));if(!isJsonp)return stripped;let index=stripped.findIndex(header=>header.name.toLowerCase()==="content-type");if(index===-1)return[...stripped,{name:"content-type",value:JSONP_CONTENT_TYPE}];let result=[...stripped];return result[index]={...result[index],value:JSONP_CONTENT_TYPE},result}var enabledDomains=new WeakMap;function ensureCdpDomain(client2,domain2,params={}){let domains=enabledDomains.get(client2);domains||(domains=new Map,enabledDomains.set(client2,domains));let existing=domains.get(domain2);if(existing)return existing;let enabling=client2.sendCommand(`${domain2}.enable`,params).then(()=>{}).catch(error48=>{throw domains?.get(domain2)===enabling&&domains.delete(domain2),error48});return domains.set(domain2,enabling),enabling}var MAX_LOGS=500,MAX_EVENTS=500,COLLECTED_RESOURCE_TYPES=new Set(["xhr","fetch","document","eventsource"]);function createBuffers(tabId=0){return{requests:[],logs:[],events:[],pending:new Map,sseStreams:new Map,requestCounter:0,requestBufferAccounting:createRequestBufferAccounting(),capture:{tabId,generation:createCaptureGeneration(),currentSequence:0,droppedRequestsThroughSequence:0,droppedLogsThroughSequence:0,droppedEventsThroughSequence:0}}}function parseQueryString2(url2){try{let u=new URL(url2),result=[];return u.searchParams.forEach((value,name)=>result.push({name,value})),result}catch{return[]}}function headersObjToArray(obj){return Object.entries(obj).map(([name,value])=>({name,value:String(value)}))}function getHeaderValue(headers,targetName){let target=targetName.toLowerCase(),entry=Object.entries(headers).find(([name])=>name.toLowerCase()===target);return entry?String(entry[1]):""}function extractMtopApiName(url2,postData){try{let u=new URL(url2),pathMatch=u.pathname.match(/\/h5\/([\w.]+)\//);if(pathMatch)return pathMatch[1];let proxyMatch=u.searchParams.get("requestUrl")?.match(/\b(?:mtop|mopen)\.[\w.]+/);if(proxyMatch)return proxyMatch[0]}catch{}let urlMatch=url2.match(/\b(?:mtop|mopen)\.[\w.]+/);if(urlMatch)return urlMatch[0];if(!postData)return null;try{let parsed=JSON.parse(postData),proxyMatch=(typeof parsed?.requestUrl=="string"?parsed.requestUrl:void 0)?.match(/\b(?:mtop|mopen)\.[\w.]+/);if(proxyMatch)return proxyMatch[0]}catch{let proxyMatch=new URLSearchParams(postData).get("requestUrl")?.match(/\b(?:mtop|mopen)\.[\w.]+/);if(proxyMatch)return proxyMatch[0]}return null}function requestDisplayName(url2){try{return new URL(url2).pathname}catch{return url2}}function parsePostData(postData){if(!postData)return null;try{return JSON.parse(postData)}catch{try{let params={};return new URLSearchParams(postData).forEach((v,k)=>params[k]=v),params}catch{return postData}}}function appendTrackingEvents(buffers,url2,postData,batchSequence,captureSequence){let events=parseTrackingRequest(url2,postData,{sequence:batchSequence,now:Date.now()}).map(event=>({...event,captureSequence}));if(events.length===0)return!1;let removed=appendCapturedTrackingBatch(buffers.events,events,MAX_EVENTS);for(let event of removed)event.captureSequence!==void 0&&(buffers.capture.droppedEventsThroughSequence=Math.max(buffers.capture.droppedEventsThroughSequence,event.captureSequence));return!0}function recordDroppedRequests(buffers,removed){for(let request of removed)request.captureSequence!==void 0&&(buffers.capture.droppedRequestsThroughSequence=Math.max(buffers.capture.droppedRequestsThroughSequence,request.captureSequence))}function appendCapturedRequest(buffers,request){recordDroppedRequests(buffers,appendRequestToBuffer(buffers.requests,buffers.requestBufferAccounting,request))}function refreshCapturedRequest(buffers,request){recordDroppedRequests(buffers,refreshRequestInBuffer(buffers.requests,buffers.requestBufferAccounting,request))}function recordCdpMtopStreamStart(buffers,data){let capture=createMtopStreamCapture({...data,id:++buffers.requestCounter,tabId:buffers.capture.tabId,captureSequence:nextCaptureSequence(buffers.capture)});return appendCapturedRequest(buffers,capture.request),capture}function recordCdpMtopStreamResponse(buffers,capture,response){updateMtopStreamCaptureResponse(capture,response),refreshCapturedRequest(buffers,capture.request)}function recordCdpMtopStreamChunk(buffers,capture,data,timestampMs2=Date.now()){appendMtopStreamCaptureChunk(capture,data,timestampMs2)&&refreshCapturedRequest(buffers,capture.request)}function recordCdpMtopStreamEnd(buffers,capture,options={}){finishMtopStreamCapture(capture,options),refreshCapturedRequest(buffers,capture.request)}function requestEventTimestamp(partial2,monotonicTimestamp){return monotonicTimestamp!==void 0&&partial2.startTs!==void 0?Math.round(partial2.timestampMs+(monotonicTimestamp-partial2.startTs)*1e3):Date.now()}function ensurePageSseStream(buffers,partial2,mode){partial2.isSSE=!0,Array.isArray(partial2.responseBody)||(partial2.responseBody=[]);let existing=buffers.sseStreams.get(partial2.requestId);if(existing)return existing;let stream={parser:createSseEventParser(),decoder:new TextDecoder2,mode};return buffers.sseStreams.set(partial2.requestId,stream),stream}function appendPageSseEvents(buffers,partial2,stream,events,timestampMs2){if(Array.isArray(partial2.responseBody)){for(let event of events)partial2.responseBody.push({event:event.event,data:event.data,...event.eventId!==void 0?{eventId:event.eventId}:{},timestamp:timestampMs2,duration:stream.lastMessageTimeMs===void 0?0:timestampMs2-stream.lastMessageTimeMs}),stream.lastMessageTimeMs=timestampMs2;events.length>0&&refreshCapturedRequest(buffers,partial2)}}function consumePageSseBytes(buffers,partial2,stream,bytes,timestampMs2){let text=stream.decoder.decode(bytes,{stream:!0});appendPageSseEvents(buffers,partial2,stream,stream.parser.push(text),timestampMs2)}function finishPageSseStream(buffers,partial2,stream,timestampMs2){let tail=stream.decoder.decode(),events=[...stream.parser.push(tail),...stream.parser.finish()];appendPageSseEvents(buffers,partial2,stream,events,timestampMs2)}function replaceWithParsedSseBody(partial2,body,timestampMs2){let parser=createSseEventParser();partial2.responseBody=[...parser.push(body),...parser.finish()].map(event=>({event:event.event,data:event.data,...event.eventId!==void 0?{eventId:event.eventId}:{},timestamp:timestampMs2,duration:0}))}function appendCapturedLog(buffers,log2){if(buffers.logs.push({...log2,captureSequence:nextCaptureSequence(buffers.capture)}),buffers.logs.length>MAX_LOGS){let removed=buffers.logs.shift();removed&&(buffers.capture.droppedLogsThroughSequence=removed.captureSequence)}}async function setupBufferListeners(client2,buffers){client2.on("Network.requestWillBeSent",params=>{let url2=params.request?.url??"";if(!url2.startsWith("http"))return;if(isTrackingUrl(url2)){let batchSequence=++buffers.requestCounter,captureSequence2=nextCaptureSequence(buffers.capture);!appendTrackingEvents(buffers,url2,params.request?.postData,batchSequence,captureSequence2)&&params.request?.hasPostData&&!params.request?.postData&&client2.sendCommand("Network.getRequestPostData",{requestId:params.requestId},1e4).then(result=>appendTrackingEvents(buffers,url2,result?.postData,batchSequence,captureSequence2)).catch(()=>{});return}let resourceType=String(params.type??"").toLowerCase(),mtopApiName=extractMtopApiName(url2,params.request?.postData),isMtop=mtopApiName!==null;if(!isMtop&&!COLLECTED_RESOURCE_TYPES.has(resourceType))return;let ts=params.timestamp,timestampMs2=params.wallTime!==void 0?Math.floor(params.wallTime*1e3):Date.now(),redirected=buffers.pending.get(params.requestId);redirected&&params.redirectResponse&&(redirected.status=params.redirectResponse.status??0,redirected.statusText=params.redirectResponse.statusText??"",redirected.duration=ts!==void 0&&redirected.startTs!==void 0?Math.round((ts-redirected.startTs)*1e3):void 0,redirected.isPending=!1,refreshCapturedRequest(buffers,redirected),buffers.pending.delete(params.requestId),buffers.sseStreams.delete(params.requestId));let id=++buffers.requestCounter,captureSequence=nextCaptureSequence(buffers.capture),partial2={id,requestId:params.requestId,timestamp:new Date(timestampMs2).toISOString(),timestampMs:timestampMs2,method:params.request?.method??"GET",url:url2,apiName:mtopApiName??requestDisplayName(url2),headers:headersObjToArray(params.request?.headers??{}),postData:parsePostData(params.request?.postData),queryString:parseQueryString2(url2),status:0,statusText:"",responseHeaders:[],responseBody:resourceType==="eventsource"?[]:null,isProxy:!1,proxyRequestUrl:null,proxyData:null,startTs:ts,captureSequence,isPending:!0,isSSE:resourceType==="eventsource",source:isMtop?"mtop":"requests",resourceType};buffers.pending.set(params.requestId,partial2),appendCapturedRequest(buffers,partial2)}),client2.on("Network.responseReceived",params=>{let partial2=buffers.pending.get(params.requestId);if(!partial2)return;partial2.status=params.response?.status??0,partial2.statusText=params.response?.statusText??"",partial2.responseHeaders=headersObjToArray(params.response?.headers??{});let contentType2=getHeaderValue(params.response?.headers??{},"content-type");if(partial2.resourceType==="eventsource"||contentType2.toLowerCase().includes("text/event-stream")){let mode=partial2.resourceType==="eventsource"?"eventsource":"resource",stream=ensurePageSseStream(buffers,partial2,mode);mode==="resource"&&client2.sendCommand("Network.streamResourceContent",{requestId:params.requestId},1e4).then(result=>{buffers.sseStreams.get(params.requestId)===stream&&typeof result?.bufferedData=="string"&&result.bufferedData&&consumePageSseBytes(buffers,partial2,stream,Buffer.from(result.bufferedData,"base64"),requestEventTimestamp(partial2,params.timestamp))}).catch(()=>{buffers.sseStreams.get(params.requestId)===stream&&(stream.mode="fallback")})}refreshCapturedRequest(buffers,partial2)}),client2.on("Network.dataReceived",params=>{let partial2=buffers.pending.get(params.requestId),stream=buffers.sseStreams.get(params.requestId);!partial2||stream?.mode!=="resource"||typeof params.data!="string"||consumePageSseBytes(buffers,partial2,stream,Buffer.from(params.data,"base64"),requestEventTimestamp(partial2,params.timestamp))}),client2.on("Network.eventSourceMessageReceived",params=>{let partial2=buffers.pending.get(params.requestId);if(!partial2)return;let stream=ensurePageSseStream(buffers,partial2,"eventsource");appendPageSseEvents(buffers,partial2,stream,[{event:typeof params.eventName=="string"&&params.eventName?params.eventName:"message",data:parseSseDataValue(String(params.data??"")),...typeof params.eventId=="string"&&params.eventId?{eventId:params.eventId}:{}}],requestEventTimestamp(partial2,params.timestamp))}),client2.on("Network.loadingFinished",params=>{let partial2=buffers.pending.get(params.requestId);if(!partial2)return;buffers.pending.delete(params.requestId);let endTs=params.timestamp,duration3=endTs!==void 0&&partial2.startTs!==void 0?Math.round((endTs-partial2.startTs)*1e3):void 0,stream=buffers.sseStreams.get(params.requestId);stream?.mode==="resource"&&finishPageSseStream(buffers,partial2,stream,requestEventTimestamp(partial2,params.timestamp)),buffers.sseStreams.delete(params.requestId),partial2.duration=duration3,partial2.isPending=!1,refreshCapturedRequest(buffers,partial2),!(partial2.isSSE&&Array.isArray(partial2.responseBody)&&partial2.responseBody.length>0)&&client2.sendCommand("Network.getResponseBody",{requestId:params.requestId},1e4).then(result=>{let responseBody=result.base64Encoded?Buffer.from(result.body,"base64").toString("utf-8"):result.body;if(partial2.isSSE&&typeof responseBody=="string"){replaceWithParsedSseBody(partial2,responseBody,requestEventTimestamp(partial2,params.timestamp)),refreshCapturedRequest(buffers,partial2);return}if(partial2.responseBody=responseBody,typeof partial2.responseBody=="string")try{partial2.responseBody=JSON.parse(partial2.responseBody)}catch{}refreshCapturedRequest(buffers,partial2)}).catch(()=>{})}),client2.on("Network.loadingFailed",params=>{let partial2=buffers.pending.get(params.requestId);partial2&&(buffers.pending.delete(params.requestId),buffers.sseStreams.delete(params.requestId),partial2.status=0,partial2.statusText=params.errorText??"Failed",partial2.duration=params.timestamp!==void 0&&partial2.startTs!==void 0?Math.round((params.timestamp-partial2.startTs)*1e3):void 0,partial2.isPending=!1,partial2.isSSE&&Array.isArray(partial2.responseBody)&&partial2.responseBody.length===0&&(partial2.responseBody={error:partial2.statusText}),refreshCapturedRequest(buffers,partial2))}),client2.on("Runtime.consoleAPICalled",params=>{let level={warning:"warn",debug:"debug",info:"info",error:"error",assert:"error"}[params.type]??"log",args=(params.args??[]).map(arg=>arg.type==="string"?arg.value:arg.value!==void 0?String(arg.value):arg.description!==void 0?arg.description:JSON.stringify(arg));appendCapturedLog(buffers,{level,message:args.join(" "),timestampMs:params.timestamp??Date.now(),source:params.stackTrace?.callFrames?.[0]?.url?`${params.stackTrace.callFrames[0].url.split("/").pop()||params.stackTrace.callFrames[0].url}:${params.stackTrace.callFrames[0].lineNumber+1}`:"console",args,origin:"console"})}),client2.on("Runtime.exceptionThrown",params=>{let details=params.exceptionDetails??{},exception=details.exception,message=exception?.description??(exception?.value!==void 0?String(exception.value):void 0)??details.text??"Uncaught exception",topFrame=details.stackTrace?.callFrames?.[0],url2=topFrame?.url||details.url,lineNumber=topFrame?.lineNumber??details.lineNumber,source=url2?`${url2.split("/").pop()||url2}${lineNumber!==void 0?`:${lineNumber+1}`:""}`:void 0;appendCapturedLog(buffers,{level:"error",message,timestampMs:params.timestamp??Date.now(),...source?{source}:{},args:[message],origin:"exception"})}),client2.on("Log.entryAdded",params=>{let entry=params.entry??{},levelMap={verbose:"log",info:"info",warning:"warn",error:"error"},args=(entry.args??[]).map(arg=>arg.value!==void 0?String(arg.value):arg.description??`[${arg.type||"Object"}]`),message=entry.text||args.join(" ");appendCapturedLog(buffers,{level:levelMap[entry.level]??entry.level??"log",message,timestampMs:entry.timestamp??Date.now(),source:entry.url?`${entry.url.split("/").pop()||entry.url}${entry.lineNumber!==void 0?`:${entry.lineNumber+1}`:""}`:entry.source??"other",args:args.length>0?args:[message],origin:"browser"})}),await Promise.all([ensureCdpDomain(client2,"Network",{maxTotalBufferSize:10*1024*1024,maxPostDataSize:5*1024*1024}),ensureCdpDomain(client2,"Runtime"),ensureCdpDomain(client2,"Log")])}import fs from"node:fs";import http from"node:http";import os from"node:os";import path from"node:path";function chromeUserDataDir(){let platform=process.platform,home=os.homedir();return platform==="darwin"?path.join(home,"Library","Application Support","Google","Chrome"):platform==="win32"?path.join(process.env.LOCALAPPDATA??home,"Google","Chrome","User Data"):path.join(home,".config","google-chrome")}function readDevToolsActivePort(userDataDir=chromeUserDataDir()){try{let filePath=path.join(userDataDir,"DevToolsActivePort"),lines=fs.readFileSync(filePath,"utf8").trim().split(`
881
- `).map(l=>l.trim()),port=parseInt(lines[0],10),browserWsPath=lines[1]??"/devtools/browser";return isNaN(port)?null:{port,browserWsPath}}catch{return null}}async function discoverTargets(port=9222){return new Promise((resolve9,reject)=>{let req=http.get(`http://localhost:${port}/json`,res=>{let data="";res.on("data",chunk=>data+=chunk),res.on("end",()=>{try{resolve9(JSON.parse(data))}catch(e){reject(new Error(`Failed to parse CDP targets: ${e}`))}})});req.on("error",reject),req.setTimeout(3e3,()=>{req.destroy(),reject(new Error("CDP discover timeout"))})})}var initializers=[];function registerPageSessionInitializer(initializer3){initializers.push(initializer3)}async function initializePageSession(session){for(let initializer3 of initializers)await initializer3(session)}function isImplicitlySelectablePageUrl(url2){return!url2.startsWith("chrome-extension://")&&!url2.startsWith("about:")&&!url2.startsWith("chrome://")}var CdpSession=class{port;userDataDir;endpointUrl;endpointResolver;browserClient=null;browserClientPromise=null;pageSessions=new Map;tabIdMap=new Map;nextTabId=1e3;constructor(options=9222){if(typeof options=="number"){this.port=options;return}this.port=options.port??9222,this.userDataDir=options.userDataDir,this.endpointUrl=options.endpointUrl,this.endpointResolver=options.endpointResolver}async getBrowserClient(){if(this.browserClient&&!this.browserClient.closed)return this.browserClient;this.browserClientPromise||(this.browserClientPromise=this.connectBrowserClient());let pending=this.browserClientPromise;try{return await pending}finally{this.browserClientPromise===pending&&(this.browserClientPromise=null)}}async getPageSession(virtualTabId){let targetId;if(virtualTabId!==void 0&&(targetId=this.tabIdMap.get(virtualTabId),!targetId))throw new Error(`Tab ${virtualTabId} not found. Open a tab first with tab_open.`);if(targetId){let existing2=this.pageSessions.get(targetId);if(existing2&&!existing2.client.closed)return existing2}let target=targetId?await this.findTargetById(targetId):await this.findDefaultPageTarget();if(!target)throw new Error(virtualTabId?`CDP target for tab ${virtualTabId} is no longer available`:"No implicitly selectable page target found. about:, chrome:, and extension pages are excluded; pass a tabId returned by tab_open or open a web page.");let existing=this.pageSessions.get(target.id);return existing&&!existing.client.closed?existing:this.createPageSession(target)}async registerTarget(targetId){let virtualId=this.nextTabId++;this.tabIdMap.set(virtualId,targetId);let target=await this.findTargetById(targetId);return target&&await this.createPageSession(target),virtualId}async ensureTargetRegistered(targetId){for(let[virtualId2,registeredTargetId]of this.tabIdMap)if(registeredTargetId===targetId)return virtualId2;let virtualId=this.nextTabId++;return this.tabIdMap.set(virtualId,targetId),virtualId}async connectBrowserClient(){let wsUrl=await this.resolveBrowserWsUrl();if(!wsUrl)throw new Error("No browser-level WebSocket URL available from CDP");let client2=await CdpClient.connect(wsUrl);return this.browserClient=client2,client2.on("Target.targetDestroyed",params=>{for(let[virtualId,targetId]of this.tabIdMap)if(targetId===params.targetId){this.tabIdMap.delete(virtualId);break}this.pageSessions.delete(params.targetId)}),client2}async createPageSession(target){let client2;try{let browser=await this.getBrowserClient(),{sessionId}=await browser.sendCommand("Target.attachToTarget",{targetId:target.id,flatten:!0},5e3);client2=browser.createChildSession(sessionId)}catch(error48){if(this.isRemote())throw new Error(`Failed to attach to remote CDP target ${target.id}: ${error48 instanceof Error?error48.message:String(error48)}`,{cause:error48});client2=await CdpClient.connect(target.webSocketDebuggerUrl)}let tabId;for(let[virtualId,registeredTargetId]of this.tabIdMap)if(registeredTargetId===target.id){tabId=virtualId;break}tabId===void 0&&(tabId=this.nextTabId++,this.tabIdMap.set(tabId,target.id));let buffers=createBuffers(tabId);await setupBufferListeners(client2,buffers);let session={tabId,client:client2,buffers,targetId:target.id,url:target.url};this.pageSessions.set(target.id,session),client2.on("Inspector.detached",()=>{this.pageSessions.delete(target.id)});try{await initializePageSession(session)}catch(error48){throw this.pageSessions.delete(target.id),client2.close(),error48}return session}async findTargetById(targetId){if(this.isRemote())return this.findTargetByIdViaCdp(targetId);try{return(await discoverTargets(this.effectivePort())).find(t=>t.id===targetId&&t.webSocketDebuggerUrl)??null}catch{return this.findTargetByIdViaCdp(targetId)}}async findDefaultPageTarget(){if(this.isRemote())return this.findDefaultPageTargetViaCdp();try{return(await discoverTargets(this.effectivePort())).find(t=>t.type==="page"&&t.webSocketDebuggerUrl&&isImplicitlySelectablePageUrl(t.url))??null}catch{return this.findDefaultPageTargetViaCdp()}}effectivePort(){return readDevToolsActivePort(this.userDataDir)?.port??this.port}async resolveBrowserWsUrl(){let configuredEndpoint=this.endpointResolver?await this.endpointResolver():this.endpointUrl;if(configuredEndpoint){let url2=new URL(configuredEndpoint);if(url2.protocol!=="ws:"&&url2.protocol!=="wss:")throw new Error(`Unsupported CDP endpoint protocol: ${url2.protocol}`);return url2.toString()}let fileInfo=readDevToolsActivePort(this.userDataDir);if(fileInfo)return`ws://localhost:${fileInfo.port}${fileInfo.browserWsPath}`;try{return(await this.fetchVersionInfo()).webSocketDebuggerUrl??null}catch{return null}}pageWsUrl(targetId){return`ws://localhost:${this.effectivePort()}/devtools/page/${targetId}`}isRemote(){return!!(this.endpointUrl||this.endpointResolver)}async findTargetByIdViaCdp(targetId){try{let info=(await(await this.getBrowserClient()).sendCommand("Target.getTargets",{})).targetInfos.find(t=>t.targetId===targetId);return info?{id:info.targetId,title:info.title??"",type:info.type??"page",url:info.url??"",webSocketDebuggerUrl:this.pageWsUrl(info.targetId)}:null}catch{return null}}async findDefaultPageTargetViaCdp(){try{let info=(await(await this.getBrowserClient()).sendCommand("Target.getTargets",{})).targetInfos.find(t=>t.type==="page"&&isImplicitlySelectablePageUrl(t.url));return info?{id:info.targetId,title:info.title??"",type:info.type??"page",url:info.url??"",webSocketDebuggerUrl:this.pageWsUrl(info.targetId)}:null}catch{return null}}fetchVersionInfo(){return new Promise((resolve9,reject)=>{let req=http2.get(`http://localhost:${this.port}/json/version`,res=>{let data="";res.on("data",chunk=>data+=chunk),res.on("end",()=>{try{resolve9(JSON.parse(data))}catch(e){reject(new Error(`Failed to parse CDP version info: ${e}`))}})});req.on("error",reject),req.setTimeout(3e3,()=>{req.destroy(),reject(new Error("CDP version info timeout"))})})}async probeAvailability(){try{return await(await this.getBrowserClient()).sendCommand("Target.getTargets",{},3e3),{available:!0}}catch(error48){return this.browserClient?.close(),this.browserClient=null,{available:!1,error:(error48 instanceof Error?error48.message:String(error48)).trim()||"CDP connection failed"}}}async isAvailable(){return(await this.probeAvailability()).available}hasActiveConnections(){return this.browserClient!==null&&!this.browserClient.closed||Array.from(this.pageSessions.values()).some(session=>!session.client.closed)}listOpenPageSessions(){return Array.from(this.pageSessions.values()).filter(session=>!session.client.closed)}listRegisteredTabIds(targetIds){return Array.from(this.tabIdMap.entries()).filter(([,targetId])=>!targetIds||targetIds.has(targetId)).map(([tabId])=>tabId)}close(){this.browserClient?.close(),this.browserClient=null;for(let session of this.pageSessions.values())session.client.close();this.pageSessions.clear(),this.tabIdMap.clear()}};var injectedSessions=new WeakMap,indicatorQueues=new WeakMap;function enqueueIndicatorOperation(session,operation){let queued=(indicatorQueues.get(session)??Promise.resolve()).catch(()=>{}).then(operation);return indicatorQueues.set(session,queued),queued.finally(()=>{indicatorQueues.get(session)===queued&&indicatorQueues.delete(session)})}function createFaviconScript(controlSource){let iconDataUrl=createControlledFaviconDataUrl(controlSource);return`(() => {
881
+ `).map(l=>l.trim()),port=parseInt(lines[0],10),browserWsPath=lines[1]??"/devtools/browser";return isNaN(port)?null:{port,browserWsPath}}catch{return null}}async function discoverTargets(port=9222){return new Promise((resolve9,reject)=>{let req=http.get(`http://localhost:${port}/json`,res=>{let data="";res.on("data",chunk=>data+=chunk),res.on("end",()=>{try{resolve9(JSON.parse(data))}catch(e){reject(new Error(`Failed to parse CDP targets: ${e}`))}})});req.on("error",reject),req.setTimeout(3e3,()=>{req.destroy(),reject(new Error("CDP discover timeout"))})})}var initializers=[];function registerPageSessionInitializer(initializer3){initializers.push(initializer3)}async function initializePageSession(session){for(let initializer3 of initializers)await initializer3(session)}function isImplicitlySelectablePageUrl(url2){return!url2.startsWith("chrome-extension://")&&!url2.startsWith("about:")&&!url2.startsWith("chrome://")}var CdpSession=class{port;userDataDir;endpointUrl;endpointResolver;browserClient=null;browserClientPromise=null;browserConnectedListeners=new Set;pageSessions=new Map;pageSessionPromises=new Map;pageSessionInitializers=new Set;tabIdMap=new Map;nextTabId=1e3;constructor(options=9222){if(typeof options=="number"){this.port=options;return}this.port=options.port??9222,this.userDataDir=options.userDataDir,this.endpointUrl=options.endpointUrl,this.endpointResolver=options.endpointResolver}async getBrowserClient(){if(this.browserClient&&!this.browserClient.closed)return this.browserClient;this.browserClientPromise||(this.browserClientPromise=this.connectBrowserClient());let pending=this.browserClientPromise;try{return await pending}finally{this.browserClientPromise===pending&&(this.browserClientPromise=null)}}onBrowserConnected(listener){return this.browserConnectedListeners.add(listener),()=>this.browserConnectedListeners.delete(listener)}async getPageSession(virtualTabId){let targetId;if(virtualTabId!==void 0&&(targetId=this.tabIdMap.get(virtualTabId),!targetId))throw new Error(`Tab ${virtualTabId} not found. Open a tab first with tab_open.`);if(targetId){let pending2=this.pageSessionPromises.get(targetId);if(pending2)return pending2;let existing2=this.pageSessions.get(targetId);if(existing2&&!existing2.client.closed)return existing2}let target=targetId?await this.findTargetById(targetId):await this.findDefaultPageTarget();if(!target)throw new Error(virtualTabId?`CDP target for tab ${virtualTabId} is no longer available`:"No implicitly selectable page target found. about:, chrome:, and extension pages are excluded; pass a tabId returned by tab_open or open a web page.");let pending=this.pageSessionPromises.get(target.id);if(pending)return pending;let existing=this.pageSessions.get(target.id);return existing&&!existing.client.closed?existing:this.getOrCreatePageSession(target)}async registerTarget(targetId){let virtualId=await this.ensureTargetRegistered(targetId),target=await this.findTargetById(targetId);return target&&await this.getOrCreatePageSession(target),virtualId}async ensureTargetRegistered(targetId){for(let[virtualId2,registeredTargetId]of this.tabIdMap)if(registeredTargetId===targetId)return virtualId2;let virtualId=this.nextTabId++;return this.tabIdMap.set(virtualId,targetId),virtualId}addPageSessionInitializer(initializer3){return this.pageSessionInitializers.add(initializer3),()=>this.pageSessionInitializers.delete(initializer3)}async attachOpenPageTargets(){let result=await(await this.getBrowserClient()).sendCommand("Target.getTargets",{});for(let target of result.targetInfos??[]){if(target.type!=="page"||/^(?:chrome:|chrome-extension:)/.test(target.url??""))continue;let tabId=await this.ensureTargetRegistered(target.targetId);await this.getPageSession(tabId)}}async connectBrowserClient(){let wsUrl=await this.resolveBrowserWsUrl();if(!wsUrl)throw new Error("No browser-level WebSocket URL available from CDP");let client2=await CdpClient.connect(wsUrl);this.browserClient=client2;for(let listener of this.browserConnectedListeners)listener();return client2.on("Target.targetDestroyed",params=>{for(let[virtualId,targetId]of this.tabIdMap)if(targetId===params.targetId){this.tabIdMap.delete(virtualId);break}this.pageSessions.delete(params.targetId)}),client2}async createPageSession(target){let client2;try{let browser=await this.getBrowserClient(),{sessionId}=await browser.sendCommand("Target.attachToTarget",{targetId:target.id,flatten:!0},5e3);client2=browser.createChildSession(sessionId)}catch(error48){if(this.isRemote())throw new Error(`Failed to attach to remote CDP target ${target.id}: ${error48 instanceof Error?error48.message:String(error48)}`,{cause:error48});client2=await CdpClient.connect(target.webSocketDebuggerUrl)}let tabId;for(let[virtualId,registeredTargetId]of this.tabIdMap)if(registeredTargetId===target.id){tabId=virtualId;break}tabId===void 0&&(tabId=this.nextTabId++,this.tabIdMap.set(tabId,target.id));let buffers=createBuffers(tabId);await setupBufferListeners(client2,buffers);let session={tabId,client:client2,buffers,targetId:target.id,url:target.url};this.pageSessions.set(target.id,session),client2.on("Inspector.detached",()=>{this.pageSessions.delete(target.id)});try{await initializePageSession(session);for(let initializer3 of this.pageSessionInitializers)await initializer3(session)}catch(error48){throw this.pageSessions.delete(target.id),client2.close(),error48}return session}async getOrCreatePageSession(target){let existing=this.pageSessions.get(target.id);if(existing&&!existing.client.closed&&!this.pageSessionPromises.has(target.id))return existing;let pending=this.pageSessionPromises.get(target.id);pending||(pending=this.createPageSession(target),this.pageSessionPromises.set(target.id,pending));try{return await pending}finally{this.pageSessionPromises.get(target.id)===pending&&this.pageSessionPromises.delete(target.id)}}async findTargetById(targetId){if(this.isRemote())return this.findTargetByIdViaCdp(targetId);try{return(await discoverTargets(this.effectivePort())).find(t=>t.id===targetId&&t.webSocketDebuggerUrl)??null}catch{return this.findTargetByIdViaCdp(targetId)}}async findDefaultPageTarget(){if(this.isRemote())return this.findDefaultPageTargetViaCdp();try{return(await discoverTargets(this.effectivePort())).find(t=>t.type==="page"&&t.webSocketDebuggerUrl&&isImplicitlySelectablePageUrl(t.url))??null}catch{return this.findDefaultPageTargetViaCdp()}}effectivePort(){return readDevToolsActivePort(this.userDataDir)?.port??this.port}async resolveBrowserWsUrl(){let configuredEndpoint=this.endpointResolver?await this.endpointResolver():this.endpointUrl;if(configuredEndpoint){let url2=new URL(configuredEndpoint);if(url2.protocol!=="ws:"&&url2.protocol!=="wss:")throw new Error(`Unsupported CDP endpoint protocol: ${url2.protocol}`);return url2.toString()}let fileInfo=readDevToolsActivePort(this.userDataDir);if(fileInfo)return`ws://localhost:${fileInfo.port}${fileInfo.browserWsPath}`;try{return(await this.fetchVersionInfo()).webSocketDebuggerUrl??null}catch{return null}}pageWsUrl(targetId){return`ws://localhost:${this.effectivePort()}/devtools/page/${targetId}`}isRemote(){return!!(this.endpointUrl||this.endpointResolver)}async findTargetByIdViaCdp(targetId){try{let info=(await(await this.getBrowserClient()).sendCommand("Target.getTargets",{})).targetInfos.find(t=>t.targetId===targetId);return info?{id:info.targetId,title:info.title??"",type:info.type??"page",url:info.url??"",webSocketDebuggerUrl:this.pageWsUrl(info.targetId)}:null}catch{return null}}async findDefaultPageTargetViaCdp(){try{let info=(await(await this.getBrowserClient()).sendCommand("Target.getTargets",{})).targetInfos.find(t=>t.type==="page"&&isImplicitlySelectablePageUrl(t.url));return info?{id:info.targetId,title:info.title??"",type:info.type??"page",url:info.url??"",webSocketDebuggerUrl:this.pageWsUrl(info.targetId)}:null}catch{return null}}fetchVersionInfo(){return new Promise((resolve9,reject)=>{let req=http2.get(`http://localhost:${this.port}/json/version`,res=>{let data="";res.on("data",chunk=>data+=chunk),res.on("end",()=>{try{resolve9(JSON.parse(data))}catch(e){reject(new Error(`Failed to parse CDP version info: ${e}`))}})});req.on("error",reject),req.setTimeout(3e3,()=>{req.destroy(),reject(new Error("CDP version info timeout"))})})}async probeAvailability(){try{return await(await this.getBrowserClient()).sendCommand("Target.getTargets",{},3e3),{available:!0}}catch(error48){return this.browserClient?.close(),this.browserClient=null,{available:!1,error:(error48 instanceof Error?error48.message:String(error48)).trim()||"CDP connection failed"}}}async isAvailable(){return(await this.probeAvailability()).available}hasActiveConnections(){return this.browserClient!==null&&!this.browserClient.closed||Array.from(this.pageSessions.values()).some(session=>!session.client.closed)}listOpenPageSessions(){return Array.from(this.pageSessions.values()).filter(session=>!session.client.closed)}listRegisteredTabIds(targetIds){return Array.from(this.tabIdMap.entries()).filter(([,targetId])=>!targetIds||targetIds.has(targetId)).map(([tabId])=>tabId)}close(){this.browserClient?.close(),this.browserClient=null;for(let session of this.pageSessions.values())session.client.close();this.pageSessions.clear(),this.pageSessionPromises.clear(),this.tabIdMap.clear()}};var injectedSessions=new WeakMap,indicatorQueues=new WeakMap;function enqueueIndicatorOperation(session,operation){let queued=(indicatorQueues.get(session)??Promise.resolve()).catch(()=>{}).then(operation);return indicatorQueues.set(session,queued),queued.finally(()=>{indicatorQueues.get(session)===queued&&indicatorQueues.delete(session)})}function createFaviconScript(controlSource){let iconDataUrl=createControlledFaviconDataUrl(controlSource);return`(() => {
882
882
  if (window !== window.top) return;
883
883
  const ICON = ${JSON.stringify(iconDataUrl)};
884
884
  const existing = window.__mearlControlledFavicon__;
@@ -1468,7 +1468,7 @@ Content-Type: ${file2.contentType}\r
1468
1468
  `))}return chunks.push(Buffer.from(`--${boundary}--\r
1469
1469
  `)),{contentType:`multipart/form-data; boundary=${boundary}`,body:Buffer.concat(chunks)}}function hasMultipartPayload(data){return data.formData!==void 0||data.files!==void 0}async function executeNodeSendRequest(data,cookieMap=new Map){let{url:url2,method="GET",headers={},params,body,formData,files,responseType="auto",timeout=3e4}=data;if(!url2||typeof url2!="string"||url2.trim()==="")throw new Error("Invalid url: url must be a non-empty string");let normalizedMethod=method.toUpperCase();if(!ALLOWED_METHODS.has(normalizedMethod))throw new Error(`Invalid method: ${method}. Allowed: ${[...ALLOWED_METHODS].join(", ")}`);if(!Number.isFinite(timeout)||timeout<=0)throw new Error("timeout must be a positive number");let targetUrl=new URL(url2);for(let[key,value]of Object.entries(params??{}))targetUrl.searchParams.set(key,String(value));let requestHeaders={Accept:"application/json, text/plain, */*","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",...headers},resolvedSourceHeaders=getSendRequestSourceHeaders(targetUrl,headers);resolvedSourceHeaders.referer?setHeader(requestHeaders,"Referer",resolvedSourceHeaders.referer):removeHeader(requestHeaders,"Referer"),resolvedSourceHeaders.origin?setHeader(requestHeaders,"Origin",resolvedSourceHeaders.origin):removeHeader(requestHeaders,"Origin");let cookieHeader=[...cookieMap.entries()].map(([key,value])=>`${key}=${value}`).join("; ");cookieHeader&&setHeader(requestHeaders,"Cookie",cookieHeader);let xsrfToken=cookieMap.get("XSRF-TOKEN");xsrfToken&&!findSendRequestHeaderName(requestHeaders,"x-xsrf-token")&&setHeader(requestHeaders,"X-XSRF-TOKEN",xsrfToken);let requestBody;if(hasMultipartPayload(data)){if(body!=null)throw new Error("body cannot be combined with formData or files");if(normalizedMethod==="GET"||normalizedMethod==="HEAD")throw new Error(`${normalizedMethod} requests cannot use formData or files`);if(findSendRequestHeaderName(requestHeaders,"content-type"))throw new Error("Do not set Content-Type when using formData or files; Mearl sets the boundary");let multipart=await buildMultipartBody(formData,files);requestBody=multipart.body,setHeader(requestHeaders,"Content-Type",multipart.contentType),setHeader(requestHeaders,"Content-Length",String(multipart.body.byteLength))}else body!=null&&!["GET","HEAD"].includes(normalizedMethod)&&(typeof body=="string"?(requestBody=body,findSendRequestHeaderName(requestHeaders,"content-type")||setHeader(requestHeaders,"Content-Type","text/plain")):(requestBody=JSON.stringify(body),findSendRequestHeaderName(requestHeaders,"content-type")||setHeader(requestHeaders,"Content-Type","application/json")));let result=await nodeFetch(targetUrl.toString(),{method:normalizedMethod,headers:requestHeaders,body:requestBody,timeoutMs:timeout}),contentType2=(result.headers["content-type"]??"").split(";")[0].trim().toLowerCase(),responseHeaders=Object.fromEntries(Object.entries(result.headers).filter(([name])=>name.toLowerCase()!=="set-cookie"&&name.toLowerCase()!=="set-cookie2")),responseBody,bodyType;if(responseType==="auto"&&isBinarySendRequestContentType(contentType2))responseBody=result.bodyBuffer.toString("base64"),bodyType="base64";else{let trimmed=result.body.trimStart();if(responseType==="json"||responseType==="auto"&&contentType2.includes("application/json")||responseType==="auto"&&(trimmed.startsWith("{")||trimmed.startsWith("[")))try{responseBody=JSON.parse(result.body),bodyType="json"}catch{if(responseType==="json")throw new Error("send_request expected a JSON response");responseBody=result.body,bodyType="text"}else responseBody=result.body,bodyType="text"}return{success:!0,status:result.status,statusText:result.statusText,headers:responseHeaders,body:responseBody,bodyType,attachedCookieCount:cookieMap.size}}async function cdpSendRequest(session,data){if(!data.url||typeof data.url!="string")throw new Error("Invalid url: url must be a non-empty string");let cookieMap=new Map;if(data.withCookies!==!1)try{cookieMap=await getCookiesForUrl(session,new URL(data.url).toString())}catch{}return executeNodeSendRequest(data,cookieMap)}async function prepareCdpMtopRequest(session,data,stream=!1){let resolved=resolveMtopRequest(data),cookieMap=await getCookiesForUrl(session,resolved.gatewayUrl.toString()),prepared=prepareSignedMtopRequest(resolved,cookieMap,stream);return{...prepared,requestHeaders:{...prepared.cookieHeader?{Cookie:prepared.cookieHeader}:{},...prepared.requestHeaders}}}async function cdpSendMtopRequest(session,data){let prepared=await prepareCdpMtopRequest(session,data),result=await nodeFetch(prepared.targetUrl.toString(),{method:prepared.normalizedMethod,headers:prepared.requestHeaders,body:prepared.body,timeoutMs:prepared.timeout});return{success:!0,response:parseMtopResponseText(result.body),requestData:prepared.requestData}}async function cdpSendMtopStreamRequest(session,data,callbacks){let prepared=await prepareCdpMtopRequest(session,data,!0),controller=new AbortController,timeoutId=setTimeout(()=>controller.abort(),prepared.timeout);try{await callbacks.onRequestPrepared?.({method:prepared.normalizedMethod,url:prepared.targetUrl.toString(),requestHeaders:Object.entries(prepared.requestHeaders).map(([name,value])=>({name,value}))});let response=await fetch(prepared.targetUrl,{method:prepared.normalizedMethod,headers:prepared.requestHeaders,body:prepared.body,signal:controller.signal}),responseHeaders=[];return response.headers.forEach((value,name)=>{name.toLowerCase()!=="set-cookie"&&responseHeaders.push({name,value})}),await callbacks.onResponse?.({status:response.status,statusText:response.statusText,responseHeaders}),{success:!0,response:await consumeMtopSseResponse(response,event=>callbacks.onReceive(event.data)),requestData:prepared.requestData}}catch(error48){throw error48 instanceof Error&&error48.name==="AbortError"?new Error(`send_mtop_stream timed out after ${prepared.timeout}ms: ${prepared.api}`,{cause:error48}):new Error(`send_mtop_stream failed: ${error48 instanceof Error?error48.message:String(error48)}`,{cause:error48})}finally{clearTimeout(timeoutId)}}registerActions([{name:"send_request",session:"page",handler:cdpSendRequest},{name:"send_mtop_request",session:"page",handler:cdpSendMtopRequest}]);var registries=new WeakMap;function getPageRefRegistry(session){let registry2=registries.get(session);if(!registry2){registry2=new BackendNodeRefRegistry,registries.set(session,registry2);let activeRegistry=registry2;session.client.on("Page.frameNavigated",params=>{params.frame?.parentId||activeRegistry.clearDocument()})}return registry2}function beginPageSnapshotRefs(session){return getPageRefRegistry(session).beginSnapshot()}function resolvePageRef(session,ref){return registries.get(session)?.resolve(ref)}function deletePageRef(session,ref){registries.get(session)?.delete(ref)}function clearPageRefsForNavigation(session){registries.get(session)?.clearDocument()}async function enrichCdpPageChangeSetWithRefs(session,observation){return enrichPageChangeSetWithRefs(observation,getPageRefRegistry(session),selectors=>resolveUniqueBackendNodeIds((method,params)=>sendCdpDeviceShellPageCommand(session,method,params),selectors),(node,backendNodeId)=>({backendNodeId,role:node.role??"",name:node.name??""}))}var MTOP_GATEWAY_FAMILIES=[{prod:"h5api.m.taobao.com",pre:"h5api.wapa.taobao.com"},{prod:"h5api.m.alibaba-inc.com",pre:"h5api.wapa.alibaba-inc.com"}],environments=new WeakMap;function rewriteMtopGatewayUrl(url2,target){try{let parsed=new URL(url2),family=MTOP_GATEWAY_FAMILIES.find(item=>Object.values(item).includes(parsed.hostname));return!family||parsed.hostname===family[target]?url2:(parsed.hostname=family[target],parsed.toString())}catch{return url2}}function isMtopGatewayUrl(url2){try{let host=new URL(url2).hostname;return MTOP_GATEWAY_FAMILIES.some(family=>Object.values(family).includes(host))}catch{return!1}}function hasOriginHeader(request){return Object.keys(request.headers??{}).some(name=>name.toLowerCase()==="origin")}async function handleMtopEnvironmentRequest({session,params,isResponseStage}){let target=environments.get(session);if(!target)return!1;let request=params.request??{},url2=typeof request.url=="string"?request.url:"";if(!isMtopGatewayUrl(url2))return!1;if(!isResponseStage){let rewrittenUrl=rewriteMtopGatewayUrl(url2,target);return rewrittenUrl===url2?!1:(await session.client.sendCommand("Fetch.continueRequest",{requestId:params.requestId,url:rewrittenUrl}),!0)}if(params.responseStatusCode==null||!hasOriginHeader(request))return!1;let responseHeaders=ensureCorsHeaders([...params.responseHeaders??[]],request);return await session.client.sendCommand("Fetch.continueResponse",{requestId:params.requestId,responseCode:params.responseStatusCode,...typeof params.responseStatusText=="string"&&{responsePhrase:params.responseStatusText},responseHeaders}),!0}async function setCdpMtopEnvironment(session,target){if(target!=="default"&&target!=="prod"&&target!=="pre")throw new Error('set_app_profile: "mtopEnv" must be "default", "prod", or "pre"');if(target==="default"){environments.delete(session),await unregisterCdpFetchPauseHandler(session,"mtop-environment");return}environments.set(session,target);try{await registerCdpFetchPauseHandler(session,"mtop-environment",50,handleMtopEnvironmentRequest)}catch(error48){throw environments.delete(session),error48}}function clearCdpMtopEnvironmentState(sessions){if(!sessions){environments=new WeakMap;return}for(let session of sessions)environments.delete(session)}import{randomUUID as randomUUID7}from"node:crypto";var QrCodeDataType=(QrCodeDataType2=>(QrCodeDataType2[QrCodeDataType2.Border=-1]="Border",QrCodeDataType2[QrCodeDataType2.Data=0]="Data",QrCodeDataType2[QrCodeDataType2.Function=1]="Function",QrCodeDataType2[QrCodeDataType2.Position=2]="Position",QrCodeDataType2[QrCodeDataType2.Timing=3]="Timing",QrCodeDataType2[QrCodeDataType2.Alignment=4]="Alignment",QrCodeDataType2))(QrCodeDataType||{}),__defProp2=Object.defineProperty,__defNormalProp=(obj,key,value)=>key in obj?__defProp2(obj,key,{enumerable:!0,configurable:!0,writable:!0,value}):obj[key]=value,__publicField=(obj,key,value)=>(__defNormalProp(obj,typeof key!="symbol"?key+"":key,value),value),LOW=[0,1],MEDIUM=[1,0],QUARTILE=[2,3],HIGH=[3,2],EccMap={L:LOW,M:MEDIUM,Q:QUARTILE,H:HIGH},NUMERIC_REGEX=/^[0-9]*$/,ALPHANUMERIC_REGEX=/^[A-Z0-9 $%*+.\/:-]*$/,ALPHANUMERIC_CHARSET="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:",MIN_VERSION=1,MAX_VERSION=40,PENALTY_N1=3,PENALTY_N2=3,PENALTY_N3=40,PENALTY_N4=10,ECC_CODEWORDS_PER_BLOCK=[[-1,7,10,15,20,26,18,20,24,30,18,20,24,26,30,22,24,28,30,28,28,28,28,30,30,26,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,10,16,26,18,24,16,18,22,22,26,30,22,22,24,24,28,28,26,26,26,26,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28],[-1,13,22,18,26,18,24,18,22,20,24,28,26,24,20,30,24,28,28,26,30,28,30,30,30,30,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,17,28,22,16,22,28,26,26,24,28,24,28,22,24,24,30,28,28,26,28,30,24,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30]],NUM_ERROR_CORRECTION_BLOCKS=[[-1,1,1,1,1,1,2,2,2,2,4,4,4,4,4,6,6,6,6,7,8,8,9,9,10,12,12,12,13,14,15,16,17,18,19,19,20,21,22,24,25],[-1,1,1,1,2,2,4,4,4,5,5,5,8,9,9,10,10,11,13,14,16,17,17,18,20,21,23,25,26,28,29,31,33,35,37,38,40,43,45,47,49],[-1,1,1,2,2,4,4,6,6,8,8,8,10,12,16,12,17,16,18,21,20,23,23,25,27,29,34,34,35,38,40,43,45,48,51,53,56,59,62,65,68],[-1,1,1,2,4,4,4,5,6,8,8,11,11,16,16,18,16,19,21,25,25,25,34,30,32,35,37,40,42,45,48,51,54,57,60,63,66,70,74,77,81]],QrCode=class{constructor(version2,ecc,dataCodewords,msk){if(this.version=version2,this.ecc=ecc,__publicField(this,"size"),__publicField(this,"mask"),__publicField(this,"modules",[]),__publicField(this,"types",[]),version2<MIN_VERSION||version2>MAX_VERSION)throw new RangeError("Version value out of range");if(msk<-1||msk>7)throw new RangeError("Mask value out of range");this.size=version2*4+17;let row=Array.from({length:this.size},()=>!1);for(let i=0;i<this.size;i++)this.modules.push(row.slice()),this.types.push(row.map(()=>0));this.drawFunctionPatterns();let allCodewords=this.addEccAndInterleave(dataCodewords);if(this.drawCodewords(allCodewords),msk===-1){let minPenalty=1e9;for(let i=0;i<8;i++){this.applyMask(i),this.drawFormatBits(i);let penalty=this.getPenaltyScore();penalty<minPenalty&&(msk=i,minPenalty=penalty),this.applyMask(i)}}this.mask=msk,this.applyMask(msk),this.drawFormatBits(msk)}getModule(x,y){return x>=0&&x<this.size&&y>=0&&y<this.size&&this.modules[y][x]}drawFunctionPatterns(){for(let i=0;i<this.size;i++)this.setFunctionModule(6,i,i%2===0,QrCodeDataType.Timing),this.setFunctionModule(i,6,i%2===0,QrCodeDataType.Timing);this.drawFinderPattern(3,3),this.drawFinderPattern(this.size-4,3),this.drawFinderPattern(3,this.size-4);let alignPatPos=this.getAlignmentPatternPositions(),numAlign=alignPatPos.length;for(let i=0;i<numAlign;i++)for(let j=0;j<numAlign;j++)i===0&&j===0||i===0&&j===numAlign-1||i===numAlign-1&&j===0||this.drawAlignmentPattern(alignPatPos[i],alignPatPos[j]);this.drawFormatBits(0),this.drawVersion()}drawFormatBits(mask){let data=this.ecc[1]<<3|mask,rem=data;for(let i=0;i<10;i++)rem=rem<<1^(rem>>>9)*1335;let bits=(data<<10|rem)^21522;for(let i=0;i<=5;i++)this.setFunctionModule(8,i,getBit(bits,i));this.setFunctionModule(8,7,getBit(bits,6)),this.setFunctionModule(8,8,getBit(bits,7)),this.setFunctionModule(7,8,getBit(bits,8));for(let i=9;i<15;i++)this.setFunctionModule(14-i,8,getBit(bits,i));for(let i=0;i<8;i++)this.setFunctionModule(this.size-1-i,8,getBit(bits,i));for(let i=8;i<15;i++)this.setFunctionModule(8,this.size-15+i,getBit(bits,i));this.setFunctionModule(8,this.size-8,!0)}drawVersion(){if(this.version<7)return;let rem=this.version;for(let i=0;i<12;i++)rem=rem<<1^(rem>>>11)*7973;let bits=this.version<<12|rem;for(let i=0;i<18;i++){let color=getBit(bits,i),a=this.size-11+i%3,b=Math.floor(i/3);this.setFunctionModule(a,b,color),this.setFunctionModule(b,a,color)}}drawFinderPattern(x,y){for(let dy=-4;dy<=4;dy++)for(let dx=-4;dx<=4;dx++){let dist=Math.max(Math.abs(dx),Math.abs(dy)),xx=x+dx,yy=y+dy;xx>=0&&xx<this.size&&yy>=0&&yy<this.size&&this.setFunctionModule(xx,yy,dist!==2&&dist!==4,QrCodeDataType.Position)}}drawAlignmentPattern(x,y){for(let dy=-2;dy<=2;dy++)for(let dx=-2;dx<=2;dx++)this.setFunctionModule(x+dx,y+dy,Math.max(Math.abs(dx),Math.abs(dy))!==1,QrCodeDataType.Alignment)}setFunctionModule(x,y,isDark,type=QrCodeDataType.Function){this.modules[y][x]=isDark,this.types[y][x]=type}addEccAndInterleave(data){let ver=this.version,ecl=this.ecc;if(data.length!==getNumDataCodewords(ver,ecl))throw new RangeError("Invalid argument");let numBlocks=NUM_ERROR_CORRECTION_BLOCKS[ecl[0]][ver],blockEccLen=ECC_CODEWORDS_PER_BLOCK[ecl[0]][ver],rawCodewords=Math.floor(getNumRawDataModules(ver)/8),numShortBlocks=numBlocks-rawCodewords%numBlocks,shortBlockLen=Math.floor(rawCodewords/numBlocks),blocks=[],rsDiv=reedSolomonComputeDivisor(blockEccLen);for(let i=0,k=0;i<numBlocks;i++){let dat=data.slice(k,k+shortBlockLen-blockEccLen+(i<numShortBlocks?0:1));k+=dat.length;let ecc=reedSolomonComputeRemainder(dat,rsDiv);i<numShortBlocks&&dat.push(0),blocks.push(dat.concat(ecc))}let result=[];for(let i=0;i<blocks[0].length;i++)blocks.forEach((block,j)=>{(i!==shortBlockLen-blockEccLen||j>=numShortBlocks)&&result.push(block[i])});return result}drawCodewords(data){if(data.length!==Math.floor(getNumRawDataModules(this.version)/8))throw new RangeError("Invalid argument");let i=0;for(let right=this.size-1;right>=1;right-=2){right===6&&(right=5);for(let vert=0;vert<this.size;vert++)for(let j=0;j<2;j++){let x=right-j,y=(right+1&2)===0?this.size-1-vert:vert;!this.types[y][x]&&i<data.length*8&&(this.modules[y][x]=getBit(data[i>>>3],7-(i&7)),i++)}}}applyMask(mask){if(mask<0||mask>7)throw new RangeError("Mask value out of range");for(let y=0;y<this.size;y++)for(let x=0;x<this.size;x++){let invert;switch(mask){case 0:invert=(x+y)%2===0;break;case 1:invert=y%2===0;break;case 2:invert=x%3===0;break;case 3:invert=(x+y)%3===0;break;case 4:invert=(Math.floor(x/3)+Math.floor(y/2))%2===0;break;case 5:invert=x*y%2+x*y%3===0;break;case 6:invert=(x*y%2+x*y%3)%2===0;break;case 7:invert=((x+y)%2+x*y%3)%2===0;break;default:throw new Error("Unreachable")}!this.types[y][x]&&invert&&(this.modules[y][x]=!this.modules[y][x])}}getPenaltyScore(){let result=0;for(let y=0;y<this.size;y++){let runColor=!1,runX=0,runHistory=[0,0,0,0,0,0,0];for(let x=0;x<this.size;x++)this.modules[y][x]===runColor?(runX++,runX===5?result+=PENALTY_N1:runX>5&&result++):(this.finderPenaltyAddHistory(runX,runHistory),runColor||(result+=this.finderPenaltyCountPatterns(runHistory)*PENALTY_N3),runColor=this.modules[y][x],runX=1);result+=this.finderPenaltyTerminateAndCount(runColor,runX,runHistory)*PENALTY_N3}for(let x=0;x<this.size;x++){let runColor=!1,runY=0,runHistory=[0,0,0,0,0,0,0];for(let y=0;y<this.size;y++)this.modules[y][x]===runColor?(runY++,runY===5?result+=PENALTY_N1:runY>5&&result++):(this.finderPenaltyAddHistory(runY,runHistory),runColor||(result+=this.finderPenaltyCountPatterns(runHistory)*PENALTY_N3),runColor=this.modules[y][x],runY=1);result+=this.finderPenaltyTerminateAndCount(runColor,runY,runHistory)*PENALTY_N3}for(let y=0;y<this.size-1;y++)for(let x=0;x<this.size-1;x++){let color=this.modules[y][x];color===this.modules[y][x+1]&&color===this.modules[y+1][x]&&color===this.modules[y+1][x+1]&&(result+=PENALTY_N2)}let dark=0;for(let row of this.modules)dark=row.reduce((sum,color)=>sum+(color?1:0),dark);let total=this.size*this.size,k=Math.ceil(Math.abs(dark*20-total*10)/total)-1;return result+=k*PENALTY_N4,result}getAlignmentPatternPositions(){if(this.version===1)return[];{let numAlign=Math.floor(this.version/7)+2,step=this.version===32?26:Math.ceil((this.version*4+4)/(numAlign*2-2))*2,result=[6];for(let pos=this.size-7;result.length<numAlign;pos-=step)result.splice(1,0,pos);return result}}finderPenaltyCountPatterns(runHistory){let n=runHistory[1],core=n>0&&runHistory[2]===n&&runHistory[3]===n*3&&runHistory[4]===n&&runHistory[5]===n;return(core&&runHistory[0]>=n*4&&runHistory[6]>=n?1:0)+(core&&runHistory[6]>=n*4&&runHistory[0]>=n?1:0)}finderPenaltyTerminateAndCount(currentRunColor,currentRunLength,runHistory){return currentRunColor&&(this.finderPenaltyAddHistory(currentRunLength,runHistory),currentRunLength=0),currentRunLength+=this.size,this.finderPenaltyAddHistory(currentRunLength,runHistory),this.finderPenaltyCountPatterns(runHistory)}finderPenaltyAddHistory(currentRunLength,runHistory){runHistory[0]===0&&(currentRunLength+=this.size),runHistory.pop(),runHistory.unshift(currentRunLength)}};function appendBits(val,len,bb){if(len<0||len>31||val>>>len)throw new RangeError("Value out of range");for(let i=len-1;i>=0;i--)bb.push(val>>>i&1)}function getBit(x,i){return(x>>>i&1)!==0}var QrSegment=class{constructor(mode,numChars,bitData){if(this.mode=mode,this.numChars=numChars,this.bitData=bitData,numChars<0)throw new RangeError("Invalid argument");this.bitData=bitData.slice()}getData(){return this.bitData.slice()}},MODE_NUMERIC=[1,10,12,14],MODE_ALPHANUMERIC=[2,9,11,13],MODE_BYTE=[4,8,16,16];function numCharCountBits(mode,ver){return mode[Math.floor((ver+7)/17)+1]}function makeBytes(data){let bb=[];for(let b of data)appendBits(b,8,bb);return new QrSegment(MODE_BYTE,data.length,bb)}function makeNumeric(digits){if(!isNumeric(digits))throw new RangeError("String contains non-numeric characters");let bb=[];for(let i=0;i<digits.length;){let n=Math.min(digits.length-i,3);appendBits(Number.parseInt(digits.substring(i,i+n),10),n*3+1,bb),i+=n}return new QrSegment(MODE_NUMERIC,digits.length,bb)}function makeAlphanumeric(text){if(!isAlphanumeric(text))throw new RangeError("String contains unencodable characters in alphanumeric mode");let bb=[],i;for(i=0;i+2<=text.length;i+=2){let temp=ALPHANUMERIC_CHARSET.indexOf(text.charAt(i))*45;temp+=ALPHANUMERIC_CHARSET.indexOf(text.charAt(i+1)),appendBits(temp,11,bb)}return i<text.length&&appendBits(ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)),6,bb),new QrSegment(MODE_ALPHANUMERIC,text.length,bb)}function makeSegments(text){return text===""?[]:isNumeric(text)?[makeNumeric(text)]:isAlphanumeric(text)?[makeAlphanumeric(text)]:[makeBytes(toUtf8ByteArray(text))]}function isNumeric(text){return NUMERIC_REGEX.test(text)}function isAlphanumeric(text){return ALPHANUMERIC_REGEX.test(text)}function getTotalBits(segs,version2){let result=0;for(let seg of segs){let ccbits=numCharCountBits(seg.mode,version2);if(seg.numChars>=1<<ccbits)return Number.POSITIVE_INFINITY;result+=4+ccbits+seg.bitData.length}return result}function toUtf8ByteArray(str){str=encodeURI(str);let result=[];for(let i=0;i<str.length;i++)str.charAt(i)!=="%"?result.push(str.charCodeAt(i)):(result.push(Number.parseInt(str.substring(i+1,i+3),16)),i+=2);return result}function getNumRawDataModules(ver){if(ver<MIN_VERSION||ver>MAX_VERSION)throw new RangeError("Version number out of range");let result=(16*ver+128)*ver+64;if(ver>=2){let numAlign=Math.floor(ver/7)+2;result-=(25*numAlign-10)*numAlign-55,ver>=7&&(result-=36)}return result}function getNumDataCodewords(ver,ecl){return Math.floor(getNumRawDataModules(ver)/8)-ECC_CODEWORDS_PER_BLOCK[ecl[0]][ver]*NUM_ERROR_CORRECTION_BLOCKS[ecl[0]][ver]}function reedSolomonComputeDivisor(degree){if(degree<1||degree>255)throw new RangeError("Degree out of range");let result=[];for(let i=0;i<degree-1;i++)result.push(0);result.push(1);let root=1;for(let i=0;i<degree;i++){for(let j=0;j<result.length;j++)result[j]=reedSolomonMultiply(result[j],root),j+1<result.length&&(result[j]^=result[j+1]);root=reedSolomonMultiply(root,2)}return result}function reedSolomonComputeRemainder(data,divisor){let result=divisor.map(_=>0);for(let b of data){let factor=b^result.shift();result.push(0),divisor.forEach((coef,i)=>result[i]^=reedSolomonMultiply(coef,factor))}return result}function reedSolomonMultiply(x,y){if(x>>>8||y>>>8)throw new RangeError("Byte out of range");let z2=0;for(let i=7;i>=0;i--)z2=z2<<1^(z2>>>7)*285,z2^=(y>>>i&1)*x;return z2}function encodeSegments(segs,ecl,minVersion=1,maxVersion=40,mask=-1,boostEcl=!0){if(!(MIN_VERSION<=minVersion&&minVersion<=maxVersion&&maxVersion<=MAX_VERSION)||mask<-1||mask>7)throw new RangeError("Invalid value");let version2,dataUsedBits;for(version2=minVersion;;version2++){let dataCapacityBits2=getNumDataCodewords(version2,ecl)*8,usedBits=getTotalBits(segs,version2);if(usedBits<=dataCapacityBits2){dataUsedBits=usedBits;break}if(version2>=maxVersion)throw new RangeError("Data too long")}for(let newEcl of[MEDIUM,QUARTILE,HIGH])boostEcl&&dataUsedBits<=getNumDataCodewords(version2,newEcl)*8&&(ecl=newEcl);let bb=[];for(let seg of segs){appendBits(seg.mode[0],4,bb),appendBits(seg.numChars,numCharCountBits(seg.mode,version2),bb);for(let b of seg.getData())bb.push(b)}let dataCapacityBits=getNumDataCodewords(version2,ecl)*8;appendBits(0,Math.min(4,dataCapacityBits-bb.length),bb),appendBits(0,(8-bb.length%8)%8,bb);for(let padByte=236;bb.length<dataCapacityBits;padByte^=253)appendBits(padByte,8,bb);let dataCodewords=Array.from({length:Math.ceil(bb.length/8)},()=>0);return bb.forEach((b,i)=>dataCodewords[i>>>3]|=b<<7-(i&7)),new QrCode(version2,ecl,dataCodewords,mask)}function encode(data,options){let{ecc="L",boostEcc=!1,minVersion=1,maxVersion=40,maskPattern=-1,border=1}=options||{},segment=typeof data=="string"?makeSegments(data):Array.isArray(data)?[makeBytes(data)]:void 0;if(!segment)throw new Error(`uqr only supports encoding string and binary data, but got: ${typeof data}`);let qr=encodeSegments(segment,EccMap[ecc],minVersion,maxVersion,maskPattern,boostEcc),result=addBorder({version:qr.version,maskPattern:qr.mask,size:qr.size,data:qr.modules,types:qr.types},border);return options?.invert&&(result.data=result.data.map(row=>row.map(mod=>!mod))),options?.onEncoded?.(result),result}function addBorder(input2,border=1){if(!border)return input2;let{size}=input2,newSize=size+border*2;input2.size=newSize,input2.data.forEach(row=>{for(let i=0;i<border;i++)row.unshift(!1),row.push(!1)});for(let i=0;i<border;i++)input2.data.unshift(Array.from({length:newSize},_=>!1)),input2.data.push(Array.from({length:newSize},_=>!1));let b=QrCodeDataType.Border;input2.types.forEach(row=>{for(let i=0;i<border;i++)row.unshift(b),row.push(b)});for(let i=0;i<border;i++)input2.types.unshift(Array.from({length:newSize},_=>b)),input2.types.push(Array.from({length:newSize},_=>b));return input2}function renderSVG(data,options={}){let result=encode(data,options),{pixelSize=10,whiteColor="white",blackColor="black"}=options,height=result.size*pixelSize,width=result.size*pixelSize,svg=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}">`,pathes=[];for(let row=0;row<result.size;row++)for(let col=0;col<result.size;col++){let x=col*pixelSize,y=row*pixelSize;result.data[row][col]&&pathes.push(`M${x},${y}h${pixelSize}v${pixelSize}h-${pixelSize}z`)}return svg+=`<rect fill="${whiteColor}" width="${width}" height="${height}"/>`,svg+=`<path fill="${blackColor}" d="${pathes.join("")}"/>`,svg+="</svg>",svg}import fs3 from"node:fs";import path3 from"node:path";import fs2 from"node:fs";import path2 from"node:path";import{spawn as spawn3}from"node:child_process";var MAX_CAPTURE_LENGTH=1e6;function isExecutable(filePath,platform=process.platform){try{return fs2.accessSync(filePath,platform==="win32"?fs2.constants.F_OK:fs2.constants.X_OK),!0}catch{return!1}}function executableNames(name,platform=process.platform){return platform==="win32"?[`${name}.cmd`,`${name}.exe`,name]:[name]}function versionManagerExecutableCandidates(home,names,options={}){let env=options.env??process.env,platform=options.platform??process.platform,readdirSync4=options.readdirSync??fs2.readdirSync,fnmDefaultRoot=env.XDG_DATA_HOME?path2.join(env.XDG_DATA_HOME,"fnm"):platform==="darwin"?path2.join(home,"Library","Application Support","fnm"):platform==="win32"&&env.APPDATA?path2.join(env.APPDATA,"fnm"):path2.join(home,".local","share","fnm");return[path2.join(env.NVM_DIR||path2.join(home,".nvm"),"versions","node"),path2.join(env.FNM_DIR||fnmDefaultRoot,"node-versions"),path2.join(home,".fnm","node-versions")].filter((root,index,all)=>all.indexOf(root)===index).flatMap(root=>{try{return readdirSync4(root,{withFileTypes:!0}).filter(entry=>entry.isDirectory()).sort((left,right)=>right.name.localeCompare(left.name,void 0,{numeric:!0})).flatMap(entry=>names.flatMap(name=>[path2.join(root,entry.name,"bin",name),path2.join(root,entry.name,"installation","bin",name)]))}catch{return[]}})}function resolveSpawnCommand(executable,args,platform=process.platform,commandInterpreter=process.env.ComSpec){return platform==="win32"&&/\.(?:cmd|bat)$/i.test(executable)?{command:commandInterpreter||"cmd.exe",args:["/d","/s","/c",executable,...args]}:{command:executable,args}}function prependCommandPath(command,env=process.env){return path2.isAbsolute(command)?prependPathDirectory(path2.dirname(command),env):env}function prependNodePath(env=process.env,nodeExecutable=process.execPath){return prependPathDirectory(path2.dirname(nodeExecutable),env)}function prependPathDirectory(directory,env=process.env){let pathKey=Object.keys(env).find(key=>key.toLowerCase()==="path")||"PATH",entries=(env[pathKey]||"").split(path2.delimiter).filter(Boolean);return entries.includes(directory)?env:{...env,[pathKey]:[directory,...entries].join(path2.delimiter)}}function findExecutable(name,options={}){let env=options.env??process.env,platform=options.platform??process.platform,existsSync11=options.existsSync??(candidate=>isExecutable(candidate,platform)),pathKey=Object.keys(env).find(key=>key.toLowerCase()==="path")||"PATH",directories=[...options.extraDirectories??[],...(env[pathKey]??"").split(path2.delimiter).filter(Boolean)];for(let directory of directories)for(let executableName of executableNames(name,platform)){let candidate=path2.join(directory,executableName);if(existsSync11(candidate))return candidate}return null}var runCommand=(command,args,options={})=>new Promise((resolve9,reject)=>{let capture=options.capture===!0||options.tee===!0,launch=resolveSpawnCommand(command,args),child=spawn3(launch.command,launch.args,{cwd:options.cwd,env:options.env,stdio:capture?[options.tee?"inherit":"ignore","pipe","pipe"]:"inherit",windowsHide:!0}),stdout="",stderr="",settled=!1,append=(current,chunk)=>options.tee?(current+chunk).slice(-MAX_CAPTURE_LENGTH):current.length>=MAX_CAPTURE_LENGTH?current:(current+chunk).slice(0,MAX_CAPTURE_LENGTH),finish=(error48,code=1)=>{settled||(settled=!0,timer&&clearTimeout(timer),error48?reject(error48):resolve9({code,stdout,stderr}))},timer=options.timeoutMs===void 0?void 0:setTimeout(()=>{child.kill("SIGTERM"),finish(new Error(`Command timed out after ${options.timeoutMs}ms`))},options.timeoutMs);capture&&(child.stdout?.setEncoding("utf8").on("data",chunk=>{stdout=append(stdout,chunk),options.tee&&process.stdout.write(chunk)}),child.stderr?.setEncoding("utf8").on("data",chunk=>{stderr=append(stderr,chunk),options.tee&&process.stderr.write(chunk)})),child.once("error",error48=>finish(error48)),child.once("close",code=>finish(void 0,code??1))});function normalizePath(filePath){return filePath.replaceAll("\\","/").replace(/\/+$/,"")}function firstExisting(candidates,existsSync11){return candidates.find(candidate=>existsSync11(candidate))}function fallbackCommand(name,platform){return platform!=="win32"?name:name==="bun"||name==="volta"?`${name}.exe`:`${name}.cmd`}function resolvePackageManagerInstallation(packageRoot,packageName,options={}){let env=options.env??process.env,platform=options.platform??process.platform,existsSync11=options.existsSync??(candidate=>isExecutable(candidate,platform)),processExecPath=options.processExecPath??process.execPath,normalizedRoot=normalizePath(path3.resolve(packageRoot)),lowerRoot=normalizedRoot.toLowerCase(),lowerPackageName=packageName.toLowerCase(),pnpmGlobalRoot=/\/global\/\d+\/(?:\.pnpm\/.*\/)?node_modules\//.exec(lowerRoot);if(pnpmGlobalRoot&&lowerRoot.endsWith(`/node_modules/${lowerPackageName}`)){let pnpmHome=normalizedRoot.slice(0,pnpmGlobalRoot.index);return{manager:"pnpm",command:firstExisting([...executableNames("pnpm",platform).map(name=>path3.join(pnpmHome,name)),...executableNames("pnpm",platform).map(name=>path3.join(path3.dirname(processExecPath),name))],existsSync11)??fallbackCommand("pnpm",platform),binDirectory:pnpmHome}}let bunMarker=`/.bun/install/global/node_modules/${lowerPackageName}`;if(lowerRoot.endsWith(bunMarker)){let bunHome=normalizedRoot.slice(0,lowerRoot.indexOf("/.bun/"));return{manager:"bun",command:firstExisting(executableNames("bun",platform).map(name=>path3.join(bunHome,".bun","bin",name)),existsSync11)??fallbackCommand("bun",platform),binDirectory:path3.join(bunHome,".bun","bin")}}if((lowerRoot.includes("/.config/yarn/global/node_modules/")||lowerRoot.includes("/.yarn/global/node_modules/")||lowerRoot.includes("/yarn/global/node_modules/")||lowerRoot.includes("/yarn/data/global/node_modules/"))&&lowerRoot.endsWith(`/node_modules/${lowerPackageName}`)){let layout=[{marker:"/.config/yarn/global/",binSegments:[".yarn","bin"]},{marker:"/.yarn/global/",binSegments:[".yarn","bin"]},{marker:"/yarn/data/global/",binSegments:["yarn","bin"]},{marker:"/yarn/global/",binSegments:["yarn","bin"]}].find(candidate=>lowerRoot.includes(candidate.marker)),prefix=normalizedRoot.slice(0,lowerRoot.indexOf(layout.marker)),binDirectory=path3.join(prefix,...layout.binSegments);return{manager:"yarn",command:firstExisting([...executableNames("yarn",platform).map(name=>path3.join(binDirectory,name)),...executableNames("yarn",platform).map(name=>path3.join(path3.dirname(processExecPath),name))],existsSync11)??findExecutable("yarn",{env,existsSync:existsSync11,platform})??fallbackCommand("yarn",platform),binDirectory}}if(lowerRoot.includes("/.volta/tools/image/packages/")&&lowerRoot.endsWith(`/lib/node_modules/${lowerPackageName}`)){let voltaHome=normalizedRoot.slice(0,lowerRoot.indexOf("/.volta/"));return{manager:"volta",command:firstExisting(executableNames("volta",platform).map(name=>path3.join(voltaHome,".volta","bin",name)),existsSync11)??fallbackCommand("volta",platform),binDirectory:path3.join(voltaHome,".volta","bin")}}let npmMarker=`/lib/node_modules/${lowerPackageName}`;if(lowerRoot.endsWith(npmMarker)){let prefix=normalizedRoot.slice(0,lowerRoot.length-npmMarker.length);return{manager:"npm",command:firstExisting([...executableNames("npm",platform).map(name=>path3.join(prefix,"bin",name)),...executableNames("npm",platform).map(name=>path3.join(path3.dirname(processExecPath),name))],existsSync11)??fallbackCommand("npm",platform),binDirectory:path3.join(prefix,"bin")}}if(platform==="win32"&&env.APPDATA){let npmRoot=normalizePath(path3.join(env.APPDATA,"npm","node_modules",packageName));if(lowerRoot===npmRoot.toLowerCase()){let binDirectory=path3.join(env.APPDATA,"npm");return{manager:"npm",command:firstExisting([...executableNames("npm",platform).map(name=>path3.join(binDirectory,name)),...executableNames("npm",platform).map(name=>path3.join(path3.dirname(processExecPath),name))],existsSync11)??fallbackCommand("npm",platform),binDirectory}}}return null}function buildGlobalPackageCommand(installation,operation,packages,targetSelector="latest"){let targets=operation==="uninstall"?packages:packages.map(packageName=>`${packageName}@${targetSelector}`),args;switch(installation.manager){case"npm":args=operation==="uninstall"?["uninstall","-g",...targets]:["install","-g",...targets];break;case"pnpm":args=operation==="uninstall"?["remove","-g",...targets]:["add","-g",...targets];break;case"yarn":args=operation==="uninstall"?["global","remove",...targets]:["global","add",...targets];break;case"bun":args=operation==="uninstall"?["remove","-g",...targets]:["add","-g",...targets];break;case"volta":args=operation==="uninstall"?["uninstall",...targets]:["install",...targets];break}return{manager:installation.manager,command:installation.command,args}}function resolveInvokingPackageManager(options={}){let env=options.env??process.env,existsSync11=options.existsSync??fs3.existsSync,platform=options.platform??process.platform,processExecPath=options.processExecPath??process.execPath,userAgent=(env.npm_config_user_agent??"").toLowerCase(),manager=userAgent.startsWith("pnpm/")?"pnpm":userAgent.startsWith("yarn/")?"yarn":userAgent.startsWith("bun/")?"bun":"npm",sibling=firstExisting(executableNames(manager,platform).map(name=>path3.join(path3.dirname(processExecPath),name)),existsSync11);return{manager,command:sibling??fallbackCommand(manager,platform)}}import fs7 from"node:fs";import os4 from"node:os";import path6 from"node:path";import{createHash as createHash2,randomUUID as randomUUID5}from"node:crypto";import WebSocket2 from"ws";init_generated_browser_action_protocol();var OBSERVED_PAGE_ACTIONS=new Set(PAGE_ACT_ACTIONS2);init_generated_browser_action_protocol();import net from"node:net";import fs6 from"node:fs";import os3 from"node:os";import path5 from"node:path";import{createRequire}from"node:module";import fs4 from"node:fs";import fs5 from"node:fs";import os2 from"node:os";import path4 from"node:path";var BROWSERS_DIR=path4.join(os2.homedir(),".mearl","browsers");var require2=createRequire(import.meta.url),CLIENT_VERSION=require2("../package.json").version,MAX_SOCKET_BUFFER_SIZE=64*1024*1024,SOCKET_PATH=process.platform==="win32"?"\\\\.\\pipe\\mearl-agent":path5.join(os3.tmpdir(),"mearl-agent.sock");import{existsSync as existsSync5,readFileSync as readFileSync4}from"node:fs";import{homedir as homedir2}from"node:os";import{join as join5}from"node:path";var MEARL_CONFIG_DIR=join5(homedir2(),".mearl");var import_extract_zip=__toESM(require_extract_zip(),1);import WebSocket3 from"ws";var RELEASE_VERSION_PATTERN=/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-beta\.(0|[1-9]\d*))?$/,RELEASE_LINE_PATTERN=/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.x$/;function parseComponent(value){let component=Number(value);return Number.isSafeInteger(component)&&component<=65535?component:null}function parseMearlReleaseVersion(value){if(typeof value!="string"||value.length>64)return null;let match=RELEASE_VERSION_PATTERN.exec(value);if(!match)return null;let major=parseComponent(match[1]),minor=parseComponent(match[2]),patch=parseComponent(match[3]),beta=match[4]===void 0?void 0:parseComponent(match[4]);return major===null||minor===null||patch===null||beta===null?null:{raw:value,major,minor,patch,channel:beta===void 0?"stable":"beta",...beta===void 0?{}:{beta}}}function isMearlReleaseVersion(value){return parseMearlReleaseVersion(value)!==null}function parseMearlReleaseLine(value){if(typeof value!="string"||value.length>64)return null;let match=RELEASE_LINE_PATTERN.exec(value);if(!match)return null;let major=parseComponent(match[1]),minor=parseComponent(match[2]);return major===null||minor===null?null:{raw:value,major,minor}}function mearlReleaseLineForVersion(version2){let parsed=parseMearlReleaseVersion(version2);if(!parsed)throw new Error("A valid Mearl release version is required");return`${parsed.major}.${parsed.minor}.x`}function isMearlReleaseVersionInLine(version2,releaseLine){let parsedVersion=parseMearlReleaseVersion(version2),parsedLine=parseMearlReleaseLine(releaseLine);return parsedVersion!==null&&parsedLine!==null&&parsedVersion.major===parsedLine.major&&parsedVersion.minor===parsedLine.minor}function compareMearlReleaseLines(leftVersion,rightVersion){let left=parseMearlReleaseVersion(leftVersion),right=parseMearlReleaseVersion(rightVersion);if(!left||!right)throw new Error("Mearl release-line comparison requires valid release versions");for(let key of["major","minor"]){if(left[key]<right[key])return-1;if(left[key]>right[key])return 1}return 0}function compareMearlReleaseVersions(leftVersion,rightVersion){let left=parseMearlReleaseVersion(leftVersion),right=parseMearlReleaseVersion(rightVersion);if(!left||!right)throw new Error("Mearl release comparison requires valid release versions");for(let key of["major","minor","patch"]){if(left[key]<right[key])return-1;if(left[key]>right[key])return 1}if(left.channel!==right.channel)return left.channel==="stable"?1:-1;let leftBeta=left.beta??0,rightBeta=right.beta??0;return leftBeta<rightBeta?-1:leftBeta>rightBeta?1:0}var MEARL_EXTENSION_DOWNLOAD_PAGE="https://mearl.alibaba-inc.com/",MEARL_EXTENSION_REMOTE_CONFIG_URL=`${MEARL_EXTENSION_DOWNLOAD_PAGE}config.json`;var MEARL_EXTENSION_ID="aoehhjnofngknnjefamjbplchbolghkm",MEARL_EXTENSION_SETUP_MARKER=".mearl-setup.json";var MAX_ARCHIVE_BYTES=64*1024*1024,SHA256_PATTERN=/^[a-f\d]{64}$/i;function extensionArchiveUrl(version2){if(!isMearlReleaseVersion(version2))throw new Error(`Invalid Mearl browser extension version: ${version2}`);return new URL(`mearl-chrome-v${version2}.zip`,MEARL_EXTENSION_DOWNLOAD_PAGE).toString()}function validateExtensionRelease(release){if(!isMearlReleaseVersion(release.version))throw new Error("Remote extension config has an invalid latestVersion");let expectedArchiveUrl=extensionArchiveUrl(release.version),archiveUrl;try{archiveUrl=new URL(release.archiveUrl).toString()}catch{throw new Error("Remote extension config has an invalid downloadUrl")}if(archiveUrl!==expectedArchiveUrl)throw new Error("Remote extension downloadUrl does not match latestVersion");if(release.sha256!==void 0&&!SHA256_PATTERN.test(release.sha256))throw new Error("Remote extension config has an invalid downloadSha256");return{archiveUrl,...release.sha256?{sha256:release.sha256.toLowerCase()}:{},version:release.version}}async function fetchBrowserExtensionRelease(fetchImpl=fetch){let response=await fetchImpl(MEARL_EXTENSION_REMOTE_CONFIG_URL,{cache:"no-store"});if(!response.ok)throw new Error(`Extension config returned HTTP ${response.status}`);let config2=await response.json();return validateExtensionRelease({archiveUrl:typeof config2.downloadUrl=="string"?config2.downloadUrl:"",...typeof config2.downloadSha256=="string"?{sha256:config2.downloadSha256}:{},version:typeof config2.latestVersion=="string"?config2.latestVersion:""})}function sameExtensionPath(left,right){let normalizedLeft=path6.normalize(path6.resolve(left)),normalizedRight=path6.normalize(path6.resolve(right));return process.platform==="win32"?normalizedLeft.toLowerCase()===normalizedRight.toLowerCase():normalizedLeft===normalizedRight}function setupMarkerPath(directory){return path6.join(directory,MEARL_EXTENSION_SETUP_MARKER)}function hasSetupMarker(targetDirectory){try{let marker=JSON.parse(fs7.readFileSync(setupMarkerPath(targetDirectory),"utf8"));return marker.schemaVersion===1&&marker.extensionId===MEARL_EXTENSION_ID&&typeof marker.path=="string"&&sameExtensionPath(marker.path,targetDirectory)}catch{return!1}}async function writeSetupMarker(directory,targetDirectory){let marker={extensionId:MEARL_EXTENSION_ID,path:path6.resolve(targetDirectory),schemaVersion:1};await fs7.promises.writeFile(setupMarkerPath(directory),`${JSON.stringify(marker,null,2)}
1470
1470
  `,{mode:384})}async function replaceDirectory(stagingDirectory,targetDirectory){let backupDirectory=`${targetDirectory}.backup-${randomUUID5()}`,targetExists=fs7.existsSync(targetDirectory);try{targetExists&&await fs7.promises.rename(targetDirectory,backupDirectory),await fs7.promises.rename(stagingDirectory,targetDirectory)}catch(error48){throw!fs7.existsSync(targetDirectory)&&fs7.existsSync(backupDirectory)&&await fs7.promises.rename(backupDirectory,targetDirectory),error48}targetExists&&await fs7.promises.rm(backupDirectory,{force:!0,recursive:!0})}function readExtensionManifest(directory){let manifestPath=path6.join(directory,"manifest.json"),parsed;try{parsed=JSON.parse(fs7.readFileSync(manifestPath,"utf8"))}catch(error48){throw new Error(`Downloaded extension has no valid manifest.json: ${error48 instanceof Error?error48.message:error48}`,{cause:error48})}if(parsed.manifest_version!==3||typeof parsed.name!="string"||typeof parsed.key!="string"||parsed.key.length===0)throw new Error("Downloaded archive is not a valid Manifest V3 extension");if(!isMearlReleaseVersion(parsed.version))throw new Error("Downloaded extension manifest has an invalid version");return parsed}async function downloadAndReplaceExtension(releaseInput,targetDirectory,fetchImpl,extractArchive){let release=validateExtensionRelease(releaseInput),parentDirectory=path6.dirname(targetDirectory),stagingDirectory=`${targetDirectory}.staging-${randomUUID5()}`,archivePath=path6.join(parentDirectory,`.mearl-extension-${randomUUID5()}.zip`);await fs7.promises.mkdir(parentDirectory,{recursive:!0});try{let response=await fetchImpl(release.archiveUrl,{redirect:"follow"});if(!response.ok)throw new Error(`Extension archive returned HTTP ${response.status}: ${release.archiveUrl}`);if(Number(response.headers.get("content-length")??0)>MAX_ARCHIVE_BYTES)throw new Error(`Extension archive exceeds ${MAX_ARCHIVE_BYTES} bytes`);let archive=Buffer.from(await response.arrayBuffer());if(archive.length===0||archive.length>MAX_ARCHIVE_BYTES)throw new Error("Extension archive is empty or too large");if(release.sha256&&createHash2("sha256").update(archive).digest("hex")!==release.sha256)throw new Error("Extension archive SHA256 does not match remote config");await fs7.promises.writeFile(archivePath,archive,{mode:384}),await fs7.promises.mkdir(stagingDirectory,{recursive:!0}),await extractArchive(archivePath,stagingDirectory);let manifest=readExtensionManifest(stagingDirectory);if(manifest.version!==release.version)throw new Error(`Extension archive version ${String(manifest.version)} does not match ${release.version}`);return await writeSetupMarker(stagingDirectory,targetDirectory),await replaceDirectory(stagingDirectory,targetDirectory),release}finally{await fs7.promises.rm(archivePath,{force:!0}),await fs7.promises.rm(stagingDirectory,{force:!0,recursive:!0})}}async function updateSetupManagedBrowserExtensionFiles(options,dependencies={}){let targetDirectory=path6.resolve(options.targetDirectory);if(!hasSetupMarker(targetDirectory))throw new Error("The running extension is not managed by Mearl setup");let fetchImpl=dependencies.fetch??fetch,extractArchive=dependencies.extractArchive??((archivePath,destination)=>(0,import_extract_zip.default)(archivePath,{dir:destination}));return{...await downloadAndReplaceExtension(options.release,targetDirectory,fetchImpl,extractArchive),path:targetDirectory}}init_plugin();import fs11 from"node:fs";import path10 from"node:path";import{createInterface as createInterface2}from"node:readline/promises";import{stdin as input,stdout as output}from"node:process";import fs9 from"node:fs";import os5 from"node:os";import path8 from"node:path";import{spawn as spawn6}from"node:child_process";var COMMAND_TIMEOUT_MS=12e4,MAX_OUTPUT_LENGTH=1e6,ANSI_ESCAPE_PATTERN=new RegExp(String.raw`\u001B\[[0-?]*[ -/]*[@-~]`,"g");function existingExecutable(candidates,existsSync11){return candidates.find(candidate=>candidate&&existsSync11(candidate))??null}function stripAnsi(value){return value.replace(ANSI_ESCAPE_PATTERN,"")}function resolveAliSkillsExecutable(options={}){let env=options.env??process.env,home=(options.homedir??os5.homedir)(),platform=options.platform??process.platform,existsSync11=options.existsSync??(candidate=>isExecutable(candidate,platform)),processExecPath=options.processExecPath??process.execPath,readdirSync4=options.readdirSync??fs9.readdirSync,names=executableNames("ali-skills",platform),pathKey=Object.keys(env).find(key=>key.toLowerCase()==="path")||"PATH",pathCandidates=(env[pathKey]||"").split(path8.delimiter).filter(Boolean).flatMap(directory=>names.map(name=>path8.join(directory,name))),candidates=[env.MEARL_ALI_SKILLS_PATH,...names.map(name=>path8.join(path8.dirname(processExecPath),name)),...names.map(name=>path8.join(home,".local","bin",name)),...names.map(name=>path8.join(home,".npm-global","bin",name)),...names.map(name=>path8.join(home,".volta","bin",name)),...names.map(name=>path8.join(home,".local","share","pnpm",name)),...names.map(name=>path8.join(home,"Library","pnpm",name)),...versionManagerExecutableCandidates(home,names,{env,platform,readdirSync:readdirSync4}),...platform==="win32"?[]:["/opt/homebrew/bin/ali-skills","/usr/local/bin/ali-skills","/usr/bin/ali-skills"],...pathCandidates];return existingExecutable(candidates,existsSync11)}var runAliSkillsCli=(executable,args,cwd)=>new Promise((resolve9,reject)=>{let launch=resolveSpawnCommand(executable,args),child=spawn6(launch.command,launch.args,{cwd,env:prependNodePath(prependCommandPath(executable)),stdio:["ignore","pipe","pipe"],windowsHide:!0}),stdout="",stderr="",settled=!1,append=(current,chunk)=>current.length>=MAX_OUTPUT_LENGTH?current:(current+chunk.toString("utf8")).slice(0,MAX_OUTPUT_LENGTH),finish=error48=>{settled||(settled=!0,clearTimeout(timer),error48?reject(error48):resolve9({stdout,stderr}))},timer=setTimeout(()=>{child.kill("SIGTERM"),finish(new Error(`Ali Skills command timed out after ${COMMAND_TIMEOUT_MS/1e3}s`))},COMMAND_TIMEOUT_MS);child.stdout.on("data",chunk=>stdout=append(stdout,chunk)),child.stderr.on("data",chunk=>stderr=append(stderr,chunk)),child.once("error",error48=>finish(error48)),child.once("exit",code=>{if(code===0){finish();return}let detail=stripAnsi(stderr||stdout).trim();finish(new Error(detail||`Ali Skills command exited with code ${String(code)}`))})});function resolveAliSkillsInvocation(options={}){let env=options.env??process.env,executable=resolveAliSkillsExecutable(options);if(executable)return{command:executable,argsPrefix:[],env:prependNodePath(prependCommandPath(executable,env))};let processExecPath=options.processExecPath??process.execPath,npx=findExecutable("npx",{env,existsSync:options.existsSync,platform:options.platform,extraDirectories:[path8.dirname(processExecPath)]});return npx?{command:npx,argsPrefix:["-y","ali-skills"],env:prependNodePath(prependCommandPath(npx,env),processExecPath)}:null}init_nativeHost();init_plugin();import{dirname as dirname6}from"node:path";var ALIBABA_NPM_REGISTRY="https://registry.anpm.alibaba-inc.com/";function packageRegistryEnvironment(packageName,env){return packageName.startsWith("@ali/")?{...env,npm_config_registry:ALIBABA_NPM_REGISTRY}:env}init_plugin();import{existsSync as existsSync7,mkdirSync as mkdirSync5,readdirSync as readdirSync3,readlinkSync,realpathSync as realpathSync2,rmdirSync,statSync as statSync7}from"node:fs";import{homedir as homedir4}from"node:os";import{basename as basename3,dirname as dirname5,isAbsolute as isAbsolute5,join as join10,relative as relative3,resolve as resolve5,sep as sep3}from"node:path";import{existsSync as existsSync6,readFileSync as readFileSync8}from"node:fs";import{createRequire as createRequire3}from"node:module";import{join as join9}from"node:path";var require4=createRequire3(import.meta.url),PLUGIN_RUNTIME_VERSION=require4("../package.json").version;function globalAliSkill(entry){let globalSkillsDirectory=join10(homedir4(),".agents","skills"),relativeEntry=relative3(globalSkillsDirectory,resolve5(entry));if(!isAbsolute5(relativeEntry)&&relativeEntry!==".."&&!relativeEntry.startsWith(`..${sep3}`)){let[name,...entrySegments]=relativeEntry.split(sep3);if(name&&entrySegments.length>0)return{directory:join10(globalSkillsDirectory,name),name}}let sourceDirectory=dirname5(dirname5(resolve5(entry)));if(basename3(dirname5(entry))==="scripts")try{let source=existsSync7(sourceDirectory)?realpathSync2(sourceDirectory):sourceDirectory;for(let name of readdirSync3(globalSkillsDirectory)){let directory=join10(globalSkillsDirectory,name),target;try{target=resolve5(globalSkillsDirectory,readlinkSync(directory))}catch{continue}if(target===sourceDirectory||existsSync7(target)&&realpathSync2(target)===source)return{directory,name}}}catch{}}function projectAliSkill(entry,managedBy){if(managedBy!=="ali-skills")return;let absolute=resolve5(entry),marker=`${sep3}.agents${sep3}skills${sep3}`,markerIndex=absolute.lastIndexOf(marker);if(markerIndex<=0)return;let cwd=absolute.slice(0,markerIndex);if(resolve5(cwd)===resolve5(homedir4()))return;let[name,scripts,filename,...remaining]=absolute.slice(markerIndex+marker.length).split(sep3);if(!(!name||scripts!=="scripts"||!["main.mjs","main.py"].includes(filename)||remaining.length>0))return{directory:join10(cwd,".agents","skills",name),name,cwd}}async function uninstallPlugin(name,runner=runCommand){assertPluginName(name);let entry=findPluginEntry(name);if(!entry)return{removed:!1,unregisteredNames:[]};let entryMissing=!existsSync7(entry),managedSkill=projectAliSkill(entry,findPluginRegistration(name)?.managedBy)??globalAliSkill(entry);if(!managedSkill)return unregisterPlugin(name),{...entryMissing?{entryMissing:!0}:{},removed:!0,unregisteredNames:[name]};let invocation2=resolveAliSkillsInvocation();if(!invocation2)throw new Error("未找到 ali-skills 或 npx,插件注册已保留。");let{directory:skillDirectory,name:skillName}=managedSkill,unregisteredNames=listPluginNames().filter(pluginName=>{try{let candidate=findPluginEntry(pluginName);return candidate?(projectAliSkill(candidate,"ali-skills")??globalAliSkill(candidate))?.directory===skillDirectory:!1}catch{return!1}}),placeholderCreated=!1;if(!existsSync7(skillDirectory)){mkdirSync5(dirname5(skillDirectory),{recursive:!0,mode:448});try{mkdirSync5(skillDirectory,{mode:448}),placeholderCreated=!0}catch(error48){if(error48.code!=="EEXIST")throw error48}}let removed;try{removed=await runner(invocation2.command,[...invocation2.argsPrefix,"remove",skillName,...managedSkill.cwd?[]:["--global"],"--yes"],{env:invocation2.env,tee:!0,...managedSkill.cwd?{cwd:managedSkill.cwd}:{}})}catch(error48){throw new Error(`ali-skills remove ${skillName} 执行失败:${error48 instanceof Error?error48.message:String(error48)};插件注册已保留。`,{cause:error48})}finally{if(placeholderCreated)try{rmdirSync(skillDirectory)}catch{}}if(removed.code!==0)throw new Error(`ali-skills remove ${skillName} 失败(exit ${removed.code});插件注册已保留。`);for(let pluginName of unregisteredNames)unregisterPlugin(pluginName);return{...entryMissing?{entryMissing:!0}:{},removed:!0,skillName,unregisteredNames}}var ALIBABA_INTERNAL_PLUGIN_NAMES=listOfficialPluginNames("alibaba");import{existsSync as existsSync8}from"node:fs";import{join as join11,resolve as resolve6}from"node:path";function parseProviderPackageSpec(value){let nameMatch=value.trim().match(/^(@[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*|[a-z0-9][a-z0-9._-]*)(?:@(.+))?$/i);if(!nameMatch||!nameMatch[1]||/\s/.test(nameMatch[2]??""))throw new Error(`Provider install requires an npm package name, received: ${value}`);return{packageName:nameMatch[1],target:nameMatch[2]||"latest"}}function providerManager(env,dependencies,resolvedManager){return resolvedManager??(dependencies.resolveInvokingManager??(childEnv=>resolveInvokingPackageManager({env:childEnv})))(env)}function outputPath(output2){return output2.split(/\r?\n/).map(line=>line.trim()).filter(Boolean).at(-1)??null}async function resolveGlobalProviderPackageRoot(installation,packageName,runner,env){let args,toNodeModules;switch(installation.manager){case"npm":case"pnpm":args=["root","-g"],toNodeModules=value=>value;break;case"yarn":args=["global","dir"],toNodeModules=value=>join11(value,"node_modules");break;case"bun":args=["pm","bin","-g"],toNodeModules=value=>resolve6(value,"..","install","global","node_modules");break;case"volta":throw new Error("Volta cannot manage a Provider package without a binary; use npm or pnpm")}let result=await runner(installation.command,args,{capture:!0,env:prependCommandPath(installation.command,env)}),root=outputPath(result.stdout);if(result.code!==0||!root)throw new Error(`${installation.manager} global package root lookup failed`);return join11(toNodeModules(root),...packageName.split("/"))}async function runPackageCommand(installation,operation,packageName,target,runner,env){let command=buildGlobalPackageCommand(installation,operation,[packageName],target),commandEnv=operation==="uninstall"?env:packageRegistryEnvironment(packageName,env),result=await runner(command.command,command.args,{env:prependCommandPath(command.command,commandEnv),tee:!0});if(result.code!==0)throw new Error(`${packageName} ${operation} failed (exit ${result.code})`)}async function installProviderPackage(packageSpec,dependencies={}){let{packageName,target}=parseProviderPackageSpec(packageSpec),env=process.env,runner=dependencies.runCommand??runCommand,installation=providerManager(env,dependencies);await runPackageCommand(installation,"install",packageName,target,runner,env);let packageRoot=await(dependencies.resolvePackageRoot??resolveGlobalProviderPackageRoot)(installation,packageName,runner,env);if(!(dependencies.existsSync??existsSync8)(join11(packageRoot,"package.json")))throw new Error(`${packageName} was installed but its package root was not found: ${packageRoot}`);return{manifest:(dependencies.registerPackage??registerProviderPackage)(packageRoot),manager:installation.manager}}init_nativeHost();import net2 from"node:net";import{chmodSync,rmSync as rmSync5}from"node:fs";import{dirname as dirname7}from"node:path";var MAX_REQUEST_BYTES=16*1024*1024;var BROWSERS_SUBDIR="browsers",STALE_RECORD_TTL_MS=5*6e4,FOCUS_WRITE_THROTTLE_MS=1e3,identity=null,logFn=()=>{};function initBrowserRegistry(deps){logFn=deps.log}function recordFileFor(browserId){return keyedConfigFile(BROWSERS_SUBDIR,browserId)}function ownsRecord(browserId){let existing=readRecord(recordFileFor(browserId));return!existing||existing.pid===process.pid||!isAlive(existing.pid)}function persist(patch){if(!identity)return;let file2=recordFileFor(identity.browserId);if(!ownsRecord(identity.browserId))return;let previous=readRecord(file2),record2={pid:process.pid,browserId:identity.browserId,socketPath:identity.socketPath,browserName:identity.browserName,nativeHostVersion:identity.nativeHostVersion,transport:identity.transport,startedAt:identity.startedAt,lastFocusedAt:previous?.lastFocusedAt,extensionVersion:previous?.extensionVersion,...patch,updatedAt:Date.now()};try{writeRecord(file2,record2)}catch(error48){logFn("browser-registry: failed to write record:",String(error48))}}function registerBrowser(info){let startedAt=identity?.startedAt??new Date().toISOString();identity={browserId:info.browserId,socketPath:info.socketPath,browserName:info.browserName,nativeHostVersion:info.nativeHostVersion,transport:info.transport,startedAt};let previous=readRecord(recordFileFor(info.browserId));persist({lastFocusedAt:previous?.lastFocusedAt??info.lastFocusedAt??Date.now(),extensionVersion:info.extensionVersion}),logFn(`browser-registry: registered ${info.browserName} (${info.browserId})`)}var lastFocusWriteAt=0,focusFlushTimer=null;function writeFocusNow(){lastFocusWriteAt=Date.now(),persist({lastFocusedAt:lastFocusWriteAt})}function touchFocus(){if(!identity)return;let elapsed=Date.now()-lastFocusWriteAt;if(elapsed>=FOCUS_WRITE_THROTTLE_MS){writeFocusNow();return}focusFlushTimer||(focusFlushTimer=setTimeout(()=>{focusFlushTimer=null,writeFocusNow()},FOCUS_WRITE_THROTTLE_MS-elapsed),focusFlushTimer.unref())}function unregisterBrowser(){if(focusFlushTimer&&(clearTimeout(focusFlushTimer),focusFlushTimer=null),!identity)return;let file2=recordFileFor(identity.browserId),existing=readRecord(file2);existing&&existing.pid!==process.pid||removeRecord(file2)}function pruneDeadBrowsers(){let now=Date.now();for(let file2 of listRecordFiles(keyedDir(BROWSERS_SUBDIR))){let rec=readRecord(file2);if(!rec){removeRecord(file2);continue}isAlive(rec.pid)||now-(rec.updatedAt??0)>STALE_RECORD_TTL_MS&&removeRecord(file2)}}function listRegisteredBrowsers(){let records=[];for(let file2 of listRecordFiles(keyedDir(BROWSERS_SUBDIR))){let record2=readRecord(file2);record2&&isAlive(record2.pid)&&records.push(record2)}return records.sort((a,b)=>(b.lastFocusedAt??0)-(a.lastFocusedAt??0)||(b.updatedAt??0)-(a.updatedAt??0))}import net3 from"node:net";var MAX_RESPONSE_BUFFER_SIZE=16*1024*1024;function requestBrowserSocket(socketPath,action,data,version2,timeoutMs=6e4,browserId,host){let id=`browser_manager_${Date.now()}_${Math.random().toString(36).slice(2,10)}`;return new Promise((resolve9,reject)=>{let client2=net3.createConnection(socketPath),lines=new Utf8LineBuffer(MAX_RESPONSE_BUFFER_SIZE),settled=!1,finish=(error48,result)=>{settled||(settled=!0,clearTimeout(timer),client2.removeAllListeners(),client2.destroy(),error48?reject(error48):resolve9(result))},timer=setTimeout(()=>finish(new Error(`Browser request timeout after ${timeoutMs}ms`)),timeoutMs);client2.on("connect",()=>{client2.write(`${JSON.stringify({id,action,data,version:version2,controlSource:"local",...browserId?{browserId}:{},...host?{host}:{}})}
1471
- `)}),client2.on("data",chunk=>{let result=lines.push(chunk);if(result.overflow){finish(new Error("Browser response exceeded the supported size"));return}for(let line of result.lines){let response;try{response=JSON.parse(line)}catch{continue}if(response.id===id){response.success?finish(void 0,response.data):finish(new Error(response.error||"Browser request failed"));return}}}),client2.on("error",error48=>finish(error48)),client2.on("end",()=>finish(new Error("Browser connection closed before responding"))),client2.on("close",()=>finish(new Error("Browser connection closed before responding")))})}var NATIVE_HOST_VERSION="2.19.1";function listExternalBrowserProviders(){return listInstalledProviders().map(provider=>({provider:{id:provider.providerId,name:provider.name,builtin:!1,version:provider.version,protocolVersion:provider.protocolVersion},browserType:provider.browserType}))}async function requireLiveProvider(providerId){let warnings=await ensureInstalledProvidersRunning(),live=readLiveProvider(providerId);if(!live){let warning=warnings.find(item=>item.startsWith(`provider ${providerId}:`));throw new Error(warning??`Provider did not start: ${providerId}`)}return{socketPath:live.socketPath}}async function launchProviderBrowser(input2){let providerId=input2.provider.trim();if(!listInstalledProviders().find(item=>item.providerId===providerId))throw new Error(`Provider is not registered: ${providerId}`);let live=await requireLiveProvider(providerId),result=await(input2.host?requestBrowserSocket(live.socketPath,"browser_launch",input2.providerOptions,NATIVE_HOST_VERSION,6e4,void 0,input2.host):requestBrowserSocket(live.socketPath,"browser_launch",input2.providerOptions,NATIVE_HOST_VERSION));return validateProviderBrowser(result),{...result,browserId:providerBrowserKey(providerId,result.browserId)}}function findProviderBrowser(selector){let normalized=selector.toLowerCase(),exact=listRegisteredBrowsers().filter(browser=>browser.transport==="provider").filter(browser=>browser.browserId.toLowerCase()===normalized||browser.providerBrowserId?.toLowerCase()===normalized||browser.browserName.toLowerCase()===normalized);if(exact.length>1)throw new Error(`Provider browser selector is ambiguous: ${selector}`);return exact[0]??null}function requireProviderBrowser(browser){if(browser.transport!=="provider"||!browser.providerBrowserId)throw new Error(`Browser is not managed by an external Provider: ${browser.browserId}`);return browser.providerBrowserId}function closeProviderBrowser(browser,options={}){return requestBrowserSocket(browser.socketPath,"browser_close",{deleteProfile:options.deleteProfile===!0},NATIVE_HOST_VERSION,6e4,requireProviderBrowser(browser))}function detachProviderBrowser(browser){return requestBrowserSocket(browser.socketPath,"browser_release",{},NATIVE_HOST_VERSION,6e4,requireProviderBrowser(browser))}async function accessProviderBrowser(browser){return(await requestBrowserSocket(browser.socketPath,"get_browser_access_url",{},NATIVE_HOST_VERSION,6e4,requireProviderBrowser(browser))).browserAccess}async function startProviderBrowser(browser){let result=await requestBrowserSocket(browser.socketPath,"browser_manager_start",{},NATIVE_HOST_VERSION,12e4,requireProviderBrowser(browser));return validateProviderBrowser(result),{...result,browserId:browser.browserId}}function syncProviderBrowserCookies(browser,scope,host){let browserId=requireProviderBrowser(browser);return host?requestBrowserSocket(browser.socketPath,"browser_manager_sync_cookies",{scope},NATIVE_HOST_VERSION,12e4,browserId,host):requestBrowserSocket(browser.socketPath,"browser_manager_sync_cookies",{scope},NATIVE_HOST_VERSION,12e4,browserId)}async function configureProvider(providerId,options){if(!listInstalledProviders().find(item=>item.providerId===providerId)?.browserType.configuration)throw new Error(`Provider does not support configuration: ${providerId}`);let live=await requireLiveProvider(providerId);return requestBrowserSocket(live.socketPath,"browser_provider_configure",options,NATIVE_HOST_VERSION)}var AUTH_TIMEOUT_MS=12e4,POLL_INTERVAL_MS=750,BROW_BROWSER_PREFIX="provider:brow:",BROW_PACKAGE="@ali/mearl-provider-brow",browInstallation=null,runInstallerCommand=(command,args,options)=>runCommand(command,args,{...options,capture:!0,tee:!1,timeoutMs:options?.tee?18e4:3e4});async function ensureBrowInstalled(onProgress){listInstalledProviders().some(provider=>provider.providerId==="brow")||(onProgress?.("installing"),browInstallation??=installProviderPackage(BROW_PACKAGE,{runCommand:runInstallerCommand}).then(({manifest})=>{if(manifest.providerId!=="brow")throw new Error("Brow installer registered an unexpected Provider")}).finally(()=>{browInstallation=null}),await browInstallation)}function validateAlipayAuthCodeParams(value){let params=value&&typeof value=="object"?value:{},appId=typeof params.appId=="string"?params.appId.trim():"",scopeNicks=params.scopeNicks;if(!/^\d{10,32}$/.test(appId))throw new Error("getAuthCode requires a valid appId");if(!Array.isArray(scopeNicks)||scopeNicks.length<1||scopeNicks.length>8||!scopeNicks.every(scope=>typeof scope=="string"&&/^[a-zA-Z0-9_]{1,64}$/.test(scope)))throw new Error("getAuthCode requires valid scopeNicks");return{appId,scopeNicks,showErrorTip:params.showErrorTip===!0}}async function startAlipayAuthCode(value,onProgress){validateAlipayAuthCodeParams(value),await ensureBrowInstalled(onProgress);let browser=await launchProviderBrowser({provider:"brow",providerOptions:{}});try{if(browser.pairing?.kind!=="qr"||!browser.pairing.url)throw new Error("Brow did not return a pairing QR URL");return{browserId:browser.browserId,qrSvg:renderSVG(browser.pairing.url,{pixelSize:1,border:2})}}catch(error48){throw await closeAlipayAuthCode(browser.browserId).catch(()=>{}),error48}}async function closeAlipayAuthCode(browserId){let prefix=BROW_BROWSER_PREFIX;if(!browserId.startsWith(prefix))return;let browser=findProviderBrowser(browserId);if(browser)try{await closeProviderBrowser(browser);return}catch{}let live=readLiveProvider("brow");live&&await requestBrowserSocket(live.socketPath,"browser_close",{},NATIVE_HOST_VERSION,15e3,browserId.slice(prefix.length))}async function evaluate(browserId,tabId,expression){let browser=findProviderBrowser(browserId);if(!browser?.providerBrowserId)throw new Error("Brow pairing has ended");return(await requestBrowserSocket(browser.socketPath,"page_eval",{tabId,expression},NATIVE_HOST_VERSION,15e3,browser.providerBrowserId))?.result}async function waitAlipayAuthCode(browserId,value,onProgress){if(!browserId.startsWith(BROW_BROWSER_PREFIX))throw new Error("Invalid Brow pairing");let params=validateAlipayAuthCodeParams(value),deadline=Date.now()+AUTH_TIMEOUT_MS,probeKey=`__mearlAuthCode_${randomUUID7().replaceAll("-","")}`,started=!1,tabId=0,connected=!1;for(;Date.now()<deadline;){let browser=findProviderBrowser(browserId);if(browser?.providerBrowserId)try{if(!tabId){let tabs=(await requestBrowserSocket(browser.socketPath,"tab_list",{},NATIVE_HOST_VERSION,15e3,browser.providerBrowserId))?.tabs;tabId=(tabs?.find(item=>item.active&&typeof item.tabId=="number"&&/^https?:\/\//.test(item.url??""))??tabs?.find(item=>typeof item.tabId=="number"&&/^https?:\/\//.test(item.url??"")))?.tabId??0}if(tabId&&!connected&&(connected=!0,onProgress?.("connected")),tabId&&!started){let expression=`(() => {
1471
+ `)}),client2.on("data",chunk=>{let result=lines.push(chunk);if(result.overflow){finish(new Error("Browser response exceeded the supported size"));return}for(let line of result.lines){let response;try{response=JSON.parse(line)}catch{continue}if(response.id===id){response.success?finish(void 0,response.data):finish(new Error(response.error||"Browser request failed"));return}}}),client2.on("error",error48=>finish(error48)),client2.on("end",()=>finish(new Error("Browser connection closed before responding"))),client2.on("close",()=>finish(new Error("Browser connection closed before responding")))})}var NATIVE_HOST_VERSION="2.19.2";function listExternalBrowserProviders(){return listInstalledProviders().map(provider=>({provider:{id:provider.providerId,name:provider.name,builtin:!1,version:provider.version,protocolVersion:provider.protocolVersion},browserType:provider.browserType}))}async function requireLiveProvider(providerId){let warnings=await ensureInstalledProvidersRunning(),live=readLiveProvider(providerId);if(!live){let warning=warnings.find(item=>item.startsWith(`provider ${providerId}:`));throw new Error(warning??`Provider did not start: ${providerId}`)}return{socketPath:live.socketPath}}async function launchProviderBrowser(input2){let providerId=input2.provider.trim();if(!listInstalledProviders().find(item=>item.providerId===providerId))throw new Error(`Provider is not registered: ${providerId}`);let live=await requireLiveProvider(providerId),result=await(input2.host?requestBrowserSocket(live.socketPath,"browser_launch",input2.providerOptions,NATIVE_HOST_VERSION,6e4,void 0,input2.host):requestBrowserSocket(live.socketPath,"browser_launch",input2.providerOptions,NATIVE_HOST_VERSION));return validateProviderBrowser(result),{...result,browserId:providerBrowserKey(providerId,result.browserId)}}function findProviderBrowser(selector){let normalized=selector.toLowerCase(),exact=listRegisteredBrowsers().filter(browser=>browser.transport==="provider").filter(browser=>browser.browserId.toLowerCase()===normalized||browser.providerBrowserId?.toLowerCase()===normalized||browser.browserName.toLowerCase()===normalized);if(exact.length>1)throw new Error(`Provider browser selector is ambiguous: ${selector}`);return exact[0]??null}function requireProviderBrowser(browser){if(browser.transport!=="provider"||!browser.providerBrowserId)throw new Error(`Browser is not managed by an external Provider: ${browser.browserId}`);return browser.providerBrowserId}function closeProviderBrowser(browser,options={}){return requestBrowserSocket(browser.socketPath,"browser_close",{deleteProfile:options.deleteProfile===!0},NATIVE_HOST_VERSION,6e4,requireProviderBrowser(browser))}function detachProviderBrowser(browser){return requestBrowserSocket(browser.socketPath,"browser_release",{},NATIVE_HOST_VERSION,6e4,requireProviderBrowser(browser))}async function accessProviderBrowser(browser){return(await requestBrowserSocket(browser.socketPath,"get_browser_access_url",{},NATIVE_HOST_VERSION,6e4,requireProviderBrowser(browser))).browserAccess}async function startProviderBrowser(browser){let result=await requestBrowserSocket(browser.socketPath,"browser_manager_start",{},NATIVE_HOST_VERSION,12e4,requireProviderBrowser(browser));return validateProviderBrowser(result),{...result,browserId:browser.browserId}}function syncProviderBrowserCookies(browser,scope,host){let browserId=requireProviderBrowser(browser);return host?requestBrowserSocket(browser.socketPath,"browser_manager_sync_cookies",{scope},NATIVE_HOST_VERSION,12e4,browserId,host):requestBrowserSocket(browser.socketPath,"browser_manager_sync_cookies",{scope},NATIVE_HOST_VERSION,12e4,browserId)}async function configureProvider(providerId,options){if(!listInstalledProviders().find(item=>item.providerId===providerId)?.browserType.configuration)throw new Error(`Provider does not support configuration: ${providerId}`);let live=await requireLiveProvider(providerId);return requestBrowserSocket(live.socketPath,"browser_provider_configure",options,NATIVE_HOST_VERSION)}var AUTH_TIMEOUT_MS=12e4,POLL_INTERVAL_MS=750,BROW_BROWSER_PREFIX="provider:brow:",BROW_PACKAGE="@ali/mearl-provider-brow",browInstallation=null,runInstallerCommand=(command,args,options)=>runCommand(command,args,{...options,capture:!0,tee:!1,timeoutMs:options?.tee?18e4:3e4});async function ensureBrowInstalled(onProgress){listInstalledProviders().some(provider=>provider.providerId==="brow")||(onProgress?.("installing"),browInstallation??=installProviderPackage(BROW_PACKAGE,{runCommand:runInstallerCommand}).then(({manifest})=>{if(manifest.providerId!=="brow")throw new Error("Brow installer registered an unexpected Provider")}).finally(()=>{browInstallation=null}),await browInstallation)}function validateAlipayAuthCodeParams(value){let params=value&&typeof value=="object"?value:{},appId=typeof params.appId=="string"?params.appId.trim():"",scopeNicks=params.scopeNicks;if(!/^\d{10,32}$/.test(appId))throw new Error("getAuthCode requires a valid appId");if(!Array.isArray(scopeNicks)||scopeNicks.length<1||scopeNicks.length>8||!scopeNicks.every(scope=>typeof scope=="string"&&/^[a-zA-Z0-9_]{1,64}$/.test(scope)))throw new Error("getAuthCode requires valid scopeNicks");return{appId,scopeNicks,showErrorTip:params.showErrorTip===!0}}async function startAlipayAuthCode(value,onProgress){validateAlipayAuthCodeParams(value),await ensureBrowInstalled(onProgress);let browser=await launchProviderBrowser({provider:"brow",providerOptions:{}});try{if(browser.pairing?.kind!=="qr"||!browser.pairing.url)throw new Error("Brow did not return a pairing QR URL");return{browserId:browser.browserId,qrSvg:renderSVG(browser.pairing.url,{pixelSize:1,border:2})}}catch(error48){throw await closeAlipayAuthCode(browser.browserId).catch(()=>{}),error48}}async function closeAlipayAuthCode(browserId){let prefix=BROW_BROWSER_PREFIX;if(!browserId.startsWith(prefix))return;let browser=findProviderBrowser(browserId);if(browser)try{await closeProviderBrowser(browser);return}catch{}let live=readLiveProvider("brow");live&&await requestBrowserSocket(live.socketPath,"browser_close",{},NATIVE_HOST_VERSION,15e3,browserId.slice(prefix.length))}async function evaluate(browserId,tabId,expression){let browser=findProviderBrowser(browserId);if(!browser?.providerBrowserId)throw new Error("Brow pairing has ended");return(await requestBrowserSocket(browser.socketPath,"page_eval",{tabId,expression},NATIVE_HOST_VERSION,15e3,browser.providerBrowserId))?.result}async function waitAlipayAuthCode(browserId,value,onProgress){if(!browserId.startsWith(BROW_BROWSER_PREFIX))throw new Error("Invalid Brow pairing");let params=validateAlipayAuthCodeParams(value),deadline=Date.now()+AUTH_TIMEOUT_MS,probeKey=`__mearlAuthCode_${randomUUID7().replaceAll("-","")}`,started=!1,tabId=0,connected=!1;for(;Date.now()<deadline;){let browser=findProviderBrowser(browserId);if(browser?.providerBrowserId)try{if(!tabId){let tabs=(await requestBrowserSocket(browser.socketPath,"tab_list",{},NATIVE_HOST_VERSION,15e3,browser.providerBrowserId))?.tabs;tabId=(tabs?.find(item=>item.active&&typeof item.tabId=="number"&&/^https?:\/\//.test(item.url??""))??tabs?.find(item=>typeof item.tabId=="number"&&/^https?:\/\//.test(item.url??"")))?.tabId??0}if(tabId&&!connected&&(connected=!0,onProgress?.("connected")),tabId&&!started){let expression=`(() => {
1472
1472
  if (!/AliApp\\(AP\\//.test(navigator.userAgent) ||
1473
1473
  typeof window.AlipayJSBridge?.call !== 'function') return 'not-ready';
1474
1474
  const key = ${JSON.stringify(probeKey)};
@@ -1483,7 +1483,7 @@ Content-Type: ${file2.contentType}\r
1483
1483
  if (state?.state !== 'done') return null;
1484
1484
  delete window[key];
1485
1485
  return JSON.stringify(state.response);
1486
- })()`);if(typeof state=="string"){let response=JSON.parse(state);if(typeof(response.authcode??response.authCode)!="string"||!(response.authcode??response.authCode))throw new Error(String(response.errorMessage??response.msg??"Alipay authorization failed"));return response}}}catch(error48){if(started)throw error48;tabId=0}await new Promise(resolve9=>setTimeout(resolve9,POLL_INTERVAL_MS))}throw new Error("Alipay authorization timed out")}var APP_PROFILE_BINDING="__mearlCdpAppProfileRelay",APP_PROFILE_RESTORE_HINT="__mearlCdpAppProfileRestoreHint__",APP_PROFILE_RESTORE_STATE="__mearlCdpAppProfileState__",APP_PROFILE_RESTORE_WORLD="__mearl_cdp_app_profile_state__",APP_PROFILE_RESTORE_VERSION=1,MAX_APP_PROFILE_RESTORE_STATE_LENGTH=7e4,appProfileStates=new WeakMap;function serializeForSource2(value){return JSON.stringify(value).replace(/[\u2028\u2029]/g,character=>character==="\u2028"?"\\u2028":"\\u2029")}function installCdpAppProfileRelay(bindingName){let browser=globalThis,target=globalThis;target.__mearlCdpAppProfileRelayInstalled__||(target.__mearlCdpAppProfileRelayInstalled__=!0,browser.addEventListener("message",event=>{if(event.source!==globalThis)return;let message=event.data;if(!message||message.source!=="mearl-app-bridge")return;let requestId=message.requestId;if(typeof requestId!="number")return;if(message.type==="prepareWebView"){browser.postMessage({source:"mearl-content",type:"APP_BRIDGE_PREPARE_WEBVIEW_RESPONSE",requestId,result:{success:!0}},"*");return}if(message.type!=="mtop"&&message.type!=="mtopStream"&&message.type!=="userInfo"&&message.type!=="authCode"&&message.type!=="authCodeCancel"&&message.type!=="screenshot")return;let replyFailure=reason=>{if(browser.console?.warn("[Mearl] App bridge relay unavailable:",reason),message.type==="mtopStream"){browser.postMessage({source:"mearl-content",type:"APP_BRIDGE_MTOP_STREAM_EVENT",requestId,eventType:"onError",data:{ret:["HY_FAILED"],msg:reason}},"*");return}let responseTypes={mtop:"APP_BRIDGE_MTOP_RESPONSE",userInfo:"APP_BRIDGE_USER_INFO_RESPONSE",authCode:"APP_BRIDGE_AUTH_CODE_RESPONSE",screenshot:"APP_BRIDGE_SCREENSHOT_RESPONSE"};browser.postMessage({source:"mearl-content",type:responseTypes[String(message.type)],requestId,result:{success:!1,error:reason}},"*")},binding=target[bindingName];if(typeof binding!="function"){replyFailure("native relay binding is unavailable");return}try{binding(JSON.stringify({type:message.type,requestId,payload:message.payload}))}catch(error48){replyFailure(error48 instanceof Error?error48.message:"native relay call failed")}}))}function installEarlyAppProfileEnvironment(config2,restoreHintName){let browser=globalThis,target=globalThis;try{Object.defineProperty(target,restoreHintName,{configurable:!0,enumerable:!1,writable:!1,value:!0})}catch{target[restoreHintName]=!0}for(let[key,value]of Object.entries(config2.globals))try{target[key]=value}catch{}let insets=config2.safeAreaInsets??{top:config2.statusBarHeight,right:0,bottom:0,left:0};target.__STATUS_BAR_HEIGHT__=config2.statusBarHeight,target.__SAFE_AREA_INSET_BOTTOM__=insets.bottom;for(let[key,value]of[["userAgent",config2.userAgent],["platform",config2.navigatorPlatform],["vendor","Apple Computer, Inc."],["appVersion",config2.userAgent.replace(/^Mozilla\//,"")],["maxTouchPoints",config2.maxTouchPoints],...config2.profile==="alipay"?[["language",config2.language]]:[]])try{Object.defineProperty(browser.navigator,key,{configurable:!0,get:()=>value})}catch{}if(config2.profile==="alipay")try{Object.defineProperty(browser.navigator,"languages",{configurable:!0,get:()=>[config2.language]})}catch{}}function installWhenDocumentElementExists(install,waitForBody=!1){let browser=globalThis,isReady=()=>!!(browser.document.documentElement&&(!waitForBody||browser.document.body));if(isReady()){install();return}let observer=new browser.MutationObserver(()=>{isReady()&&(observer.disconnect(),install())});observer.observe(browser.document,{childList:!0,subtree:waitForBody})}function buildDocumentSource(config2){return`;(() => {const config=${serializeForSource2(config2)};(${installCdpAppProfileRelay.toString()})(${JSON.stringify(APP_PROFILE_BINDING)});(${installEarlyAppProfileEnvironment.toString()})(config,${JSON.stringify(APP_PROFILE_RESTORE_HINT)});(${installWhenDocumentElementExists.toString()})(() => {${buildAppProfileRuntimeCallSource("config")};},config.rootContainer?.enabled===true&&window===window.top);})();`}function usesAppProfileSplitScreen(emulation){return emulation?.deviceShell===!0&&emulation.splitScreen===!0&&emulation.config?.orientation==="landscape"}function resolveAppProfileRuntimeConfig(baseConfig,emulation){if(!usesAppProfileSplitScreen(emulation)||!emulation?.config){let rootContainer={...baseConfig.rootContainer};return delete rootContainer.splitScreen,{...baseConfig,rootContainer:{...rootContainer,enabled:!1},simulateSystemBars:!1,externalDeviceChrome:!1}}let device=emulation.config,sideBarWidth=getDeviceSideBarWidth(device.presetName,device.orientation);return{...baseConfig,statusBarHeight:sideBarWidth?0:24,safeAreaInsets:device.safeAreaInsets,deviceAppearance:{preset:device.presetName??baseConfig.deviceAppearance?.preset??"iphone-17-pro",orientation:device.orientation,cutout:device.appearance.cutout},rootContainer:{...baseConfig.rootContainer,enabled:!0,splitScreen:!0},simulateSystemBars:!0,externalDeviceChrome:sideBarWidth>0}}function buildRestoreHintSource(){return`;(() => {try{Object.defineProperty(globalThis,${JSON.stringify(APP_PROFILE_RESTORE_HINT)},{configurable:true,enumerable:false,writable:false,value:true});}catch{globalThis[${JSON.stringify(APP_PROFILE_RESTORE_HINT)}]=true;}})();`}function buildRestoreStateSource(restoreState,activeDocument){return`;(() => {const state=${serializeForSource2({...restoreState,activeDocument})};try{Object.defineProperty(globalThis,${JSON.stringify(APP_PROFILE_RESTORE_STATE)},{configurable:true,enumerable:false,writable:false,value:state});}catch{globalThis[${JSON.stringify(APP_PROFILE_RESTORE_STATE)}]=state;}})();`}function snapshotCdpAppProfileEmulation(emulation){let config2=emulation?.config;if(!config2)return;let landscape=config2.orientation==="landscape";return{...config2.presetName?{preset:config2.presetName}:{},width:landscape?config2.height:config2.width,height:landscape?config2.width:config2.height,deviceScaleFactor:config2.deviceScaleFactor,scale:config2.scale??1,mobile:config2.mobile,userAgent:config2.userAgent,orientation:config2.orientation,touch:config2.touch,deviceShell:emulation.deviceShell===!0,splitScreen:emulation.splitScreen===!0}}function resolveCdpAppProfileRestoreEmulation(emulation){return resolveEmulationConfig({enabled:!0,...emulation})}async function getRestoreExecutionContext(session){let frameId=(await session.client.sendCommand("Page.getFrameTree")).frameTree?.frame?.id;if(typeof frameId!="string"||!frameId)throw new Error("Chrome did not return the main frame id");let world=await session.client.sendCommand("Page.createIsolatedWorld",{frameId,worldName:APP_PROFILE_RESTORE_WORLD,grantUniveralAccess:!1});if(typeof world.executionContextId!="number")throw new Error("Chrome did not return the App profile restore execution context");return world.executionContextId}function appProfileEmulationCommands(config2,userAgent){return buildEnableEmulationCommands(config2).map(command=>command.method==="Emulation.setUserAgentOverride"?{...command,params:{userAgent,platform:config2.platform}}:command)}function childAppProfileEnvironment(config2,emulation){if(!emulation||!getDeviceSideBarWidth(emulation.presetName,emulation.orientation))return{profile:config2,emulation};let insets={...config2.safeAreaInsets??emulation.safeAreaInsets,right:0};return{profile:{...config2,safeAreaInsets:insets},emulation:{...emulation,safeAreaInsets:{...emulation.safeAreaInsets,right:0}}}}async function sendCommands(client2,commands){for(let{method,params,optional:optional2}of commands)await client2.sendCommand(method,params).catch(error48=>{if(!optional2)throw error48})}async function postRuntimeMessage(client2,executionContextId,message){await client2.sendCommand("Runtime.evaluate",{expression:`window.postMessage(${serializeForSource2(message)}, '*')`,...typeof executionContextId=="number"?{contextId:executionContextId}:{}})}function listenForBridgeRequests(session,client2,state){let authSessions=new Map,cancelledAuth=new Set,pendingAuth=new Set;return client2.on("Runtime.bindingCalled",params=>{if(params?.name!==APP_PROFILE_BINDING||appProfileStates.get(session)!==state)return;let request;try{request=JSON.parse(params.payload)}catch{return}if(typeof request.requestId!="number")return;let requestId=request.requestId,contextId=typeof params.executionContextId=="number"?params.executionContextId:void 0,authKey=`${contextId??"main"}:${requestId}`,reply=message=>postRuntimeMessage(client2,contextId,{requestId,source:"mearl-content",...message});if(request.type==="authCodeCancel"){if(!pendingAuth.has(authKey))return;cancelledAuth.add(authKey);let browserId=authSessions.get(authKey);browserId&&(authSessions.delete(authKey),closeAlipayAuthCode(browserId).catch(()=>{}));return}(async()=>{if(request.type==="authCode"){if(state.config.profile!=="alipay"||state.config.actions.behaviors?.getAuthCode!=="authCode"||pendingAuth.has(authKey))return;pendingAuth.add(authKey);let browserId="";try{let progressQueue=Promise.resolve(),pairing=await startAlipayAuthCode(request.payload,phase=>{progressQueue=progressQueue.then(async()=>{cancelledAuth.has(authKey)||await reply({type:"APP_BRIDGE_AUTH_CODE_PROGRESS",phase})}).catch(()=>{})});if(await progressQueue,browserId=pairing.browserId,cancelledAuth.has(authKey))return;authSessions.set(authKey,browserId),await reply({type:"APP_BRIDGE_AUTH_CODE_PAIRING",result:{qrSvg:pairing.qrSvg}}),progressQueue=Promise.resolve();let response=await waitAlipayAuthCode(browserId,request.payload,phase=>{progressQueue=progressQueue.then(async()=>{cancelledAuth.has(authKey)||await reply({type:"APP_BRIDGE_AUTH_CODE_PROGRESS",phase})}).catch(()=>{})});await progressQueue,cancelledAuth.has(authKey)||await reply({type:"APP_BRIDGE_AUTH_CODE_RESPONSE",result:{success:!0,response}})}catch(error48){cancelledAuth.has(authKey)||await reply({type:"APP_BRIDGE_AUTH_CODE_RESPONSE",result:{success:!1,error:error48 instanceof Error?error48.message:String(error48)}})}finally{authSessions.delete(authKey),cancelledAuth.delete(authKey),pendingAuth.delete(authKey),browserId&&await closeAlipayAuthCode(browserId).catch(()=>{})}return}if(request.type==="screenshot"){if(client2!==session.client)return;try{let result=await cdpPageScreenshot(session,{tabId:session.tabId,format:"png"});await reply({type:"APP_BRIDGE_SCREENSHOT_RESPONSE",result:{success:!0,...result}})}catch(error48){await reply({type:"APP_BRIDGE_SCREENSHOT_RESPONSE",result:{success:!1,error:error48 instanceof Error?error48.message:String(error48)}})}return}if(request.type==="userInfo"){try{let currentUrl=await readCdpCurrentUrl(session,"user_info"),result=await session.client.sendCommand("Network.getCookies",{urls:[currentUrl]}),response=resolveAppProfileUserInfo(currentUrl,(result.cookies??[]).map(cookie=>({name:cookie.name,value:cookie.value})));await reply({type:"APP_BRIDGE_USER_INFO_RESPONSE",result:{success:!0,response}})}catch(error48){await reply({type:"APP_BRIDGE_USER_INFO_RESPONSE",result:{success:!1,error:error48 instanceof Error?error48.message:String(error48)}})}return}let payload=request.payload??{},mtopPayload={...payload,...typeof payload.v=="string"&&payload.version===void 0?{version:payload.v}:{}},streamCapture;try{if(request.type==="mtopStream"){await cdpSendMtopStreamRequest(session,mtopPayload,{onRequestPrepared:metadata=>{streamCapture=recordCdpMtopStreamStart(session.buffers,{api:String(mtopPayload.api??""),url:metadata.url,method:metadata.method,requestHeaders:metadata.requestHeaders,requestData:mtopPayload.data??null})},onResponse:metadata=>{streamCapture&&recordCdpMtopStreamResponse(session.buffers,streamCapture,metadata)},onReceive:async data=>{streamCapture&&recordCdpMtopStreamChunk(session.buffers,streamCapture,data),await reply({type:"APP_BRIDGE_MTOP_STREAM_EVENT",eventType:"onReceive",data})}}),streamCapture&&recordCdpMtopStreamEnd(session.buffers,streamCapture),await reply({type:"APP_BRIDGE_MTOP_STREAM_EVENT",eventType:"onFinish",data:{}});return}let result=await cdpSendMtopRequest(session,mtopPayload);await reply({type:"APP_BRIDGE_MTOP_RESPONSE",result})}catch(error48){let message=error48 instanceof Error?error48.message:String(error48);request.type==="mtopStream"?(streamCapture&&recordCdpMtopStreamEnd(session.buffers,streamCapture,{error:message}),await reply({type:"APP_BRIDGE_MTOP_STREAM_EVENT",eventType:"onError",data:{ret:["HY_FAILED"],msg:message}})):await reply({type:"APP_BRIDGE_MTOP_RESPONSE",result:{success:!1,error:message}})}})().catch(()=>{})})}async function installChildTarget2(session,state,params){let sessionId=params.sessionId;if(typeof sessionId!="string")return;let child=session.client.createChildSession(sessionId);try{if(params.targetInfo?.type!=="iframe"||appProfileStates.get(session)!==state)return;await child.sendCommand("Runtime.enable");let frameName=(await child.sendCommand("Runtime.evaluate",{expression:"window.name",returnByValue:!0})).result?.value;if(frameName!=="__mearl_root__"&&frameName!=="__mearl_layer__")return;let childEnvironment=childAppProfileEnvironment(state.config,state.emulation),source=buildDocumentSource(childEnvironment.profile);childEnvironment.emulation?await sendCommands(child,appProfileEmulationCommands(childEnvironment.emulation,state.config.userAgent)):await child.sendCommand("Emulation.setUserAgentOverride",{userAgent:state.config.userAgent,platform:state.config.navigatorPlatform}),await child.sendCommand("Runtime.addBinding",{name:APP_PROFILE_BINDING}),state.disposeListeners.push(listenForBridgeRequests(session,child,state)),state.childClients.push(child),await child.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source}).catch(()=>{}),await child.sendCommand("Runtime.evaluate",{expression:source})}finally{await child.sendCommand("Runtime.runIfWaitingForDebugger").catch(()=>{})}}async function disposeState(session,state){appProfileStates.get(session)===state&&appProfileStates.delete(session),setCdpDeviceShellChildEnvironmentManagedByApp(session,!1);for(let dispose of state.disposeListeners.splice(0))dispose();isCdpDeviceShellActive(session)||await session.client.sendCommand("Target.setAutoAttach",{autoAttach:!1,waitForDebuggerOnStart:!1,flatten:!0}).catch(()=>{}),await Promise.allSettled(state.documentScriptIdentifiers.map(identifier=>session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier}))),await Promise.allSettled([session.client,...state.childClients].map(client2=>client2.sendCommand("Runtime.removeBinding",{name:APP_PROFILE_BINDING})));try{let contextId=await getRestoreExecutionContext(session);await session.client.sendCommand("Runtime.evaluate",{contextId,expression:`delete globalThis[${JSON.stringify(APP_PROFILE_RESTORE_STATE)}]`})}catch{}await session.client.sendCommand("Runtime.evaluate",{expression:`delete globalThis[${JSON.stringify(APP_PROFILE_RESTORE_HINT)}]`}).catch(()=>{});let deviceEmulation=session.emulation?.config;if(deviceEmulation){let commands=buildEnableEmulationCommands(deviceEmulation);await sendCommands(session.client,commands),await Promise.allSettled(state.childClients.map(client2=>sendCommands(client2,commands)))}else await Promise.allSettled([session.client,...state.childClients].map(client2=>client2.sendCommand("Emulation.setUserAgentOverride",{userAgent:""})))}async function rollbackAppProfileInstall(session,documentScriptIdentifiers,deviceEmulation){await Promise.allSettled([...documentScriptIdentifiers.map(identifier=>session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier})),session.client.sendCommand("Runtime.removeBinding",{name:APP_PROFILE_BINDING}),session.client.sendCommand("Runtime.evaluate",{expression:`delete globalThis[${JSON.stringify(APP_PROFILE_RESTORE_HINT)}]`})]),deviceEmulation?await sendCommands(session.client,buildEnableEmulationCommands(deviceEmulation)).catch(()=>{}):await session.client.sendCommand("Emulation.setUserAgentOverride",{userAgent:""}).catch(()=>{})}function resolveCdpAppProfile(profile,options={}){let resolved=resolveAppProfile(profile,{os:options.os,appVersion:options.appVersion,language:options.language,deviceModel:options.deviceModel,devicePreset:options.devicePreset,orientation:options.orientation,bridgeConfig:options.bridgeConfig}),restoreOptions={os:resolved.injected.platform==="Android"?"android":"ios",appVersion:resolved.injected.globals.__APP_VERSION__??"",...profile==="alipay"?{language:options.language??"zh-CN"}:{},deviceModel:resolved.injected.globals.__DEVICE_MODEL__??"",...resolved.injected.deviceAppearance?.preset?{devicePreset:resolved.injected.deviceAppearance.preset}:{},...resolved.injected.deviceAppearance?.orientation?{orientation:resolved.injected.deviceAppearance.orientation}:{},...options.bridgeConfig?{bridgeConfig:JSON.parse(JSON.stringify(options.bridgeConfig))}:{}};return{profile:resolved,restoreState:{version:APP_PROFILE_RESTORE_VERSION,profile:resolved.profile,options:restoreOptions}}}function isFiniteNumberInRange(value,minimum,maximum){return typeof value=="number"&&Number.isFinite(value)&&value>=minimum&&value<=maximum}function isCdpAppProfileRestoreEmulation(value){if(!value||typeof value!="object"||Array.isArray(value))return!1;let emulation=value,supportedKeys=new Set(["preset","width","height","deviceScaleFactor","scale","mobile","userAgent","orientation","touch","deviceShell","splitScreen"]);return!Object.keys(emulation).some(key=>!supportedKeys.has(key))&&(emulation.preset===void 0||typeof emulation.preset=="string"&&Object.hasOwn(DEVICE_PRESETS,emulation.preset))&&isFiniteNumberInRange(emulation.width,1,1e5)&&isFiniteNumberInRange(emulation.height,1,1e5)&&isFiniteNumberInRange(emulation.deviceScaleFactor,0,100)&&isFiniteNumberInRange(emulation.scale,Number.MIN_VALUE,100)&&typeof emulation.mobile=="boolean"&&typeof emulation.userAgent=="string"&&emulation.userAgent.length<=4096&&(emulation.orientation==="portrait"||emulation.orientation==="landscape")&&typeof emulation.touch=="boolean"&&typeof emulation.deviceShell=="boolean"&&(emulation.splitScreen===void 0||typeof emulation.splitScreen=="boolean")}function parseCdpAppProfileRestoreState(value){if(!value||typeof value!="object"||Array.isArray(value))return null;try{if(JSON.stringify(value).length>MAX_APP_PROFILE_RESTORE_STATE_LENGTH)return null}catch{return null}let state=value,supportedStateKeys=new Set(["version","profile","options","emulation","activeDocument"]);if(Object.keys(state).some(key=>!supportedStateKeys.has(key))||state.version!==APP_PROFILE_RESTORE_VERSION||typeof state.profile!="string"||typeof state.activeDocument!="boolean"||state.emulation!==void 0&&!isCdpAppProfileRestoreEmulation(state.emulation)||!state.options||typeof state.options!="object"||Array.isArray(state.options))return null;let options=state.options,supportedKeys=new Set(["os","appVersion","deviceModel","devicePreset","orientation","bridgeConfig"]);return Object.keys(options).some(key=>!supportedKeys.has(key))||options.os!=="ios"&&options.os!=="android"||typeof options.appVersion!="string"||options.appVersion.length>100||typeof options.deviceModel!="string"||options.deviceModel.length>200||options.devicePreset!==void 0&&(typeof options.devicePreset!="string"||!Object.hasOwn(DEVICE_PRESETS,options.devicePreset))||options.orientation!==void 0&&options.orientation!=="portrait"&&options.orientation!=="landscape"?null:value}function restoreStateForSession(restoreState,emulation){let result={...restoreState},emulationSnapshot=snapshotCdpAppProfileEmulation(emulation);return emulationSnapshot?result.emulation=emulationSnapshot:delete result.emulation,result}async function writeCurrentRestoreState(session,restoreState){let activeProfile=await session.client.sendCommand("Runtime.evaluate",{expression:`globalThis.__mearlAppProfile__===${JSON.stringify(restoreState.profile)}`,returnByValue:!0}),contextId=await getRestoreExecutionContext(session);await session.client.sendCommand("Runtime.evaluate",{contextId,expression:buildRestoreStateSource(restoreState,activeProfile.result?.value===!0)})}async function replaceRestoreState(session,state,restoreState){let result=await session.client.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source:buildRestoreStateSource(restoreState,!0),worldName:APP_PROFILE_RESTORE_WORLD});if(typeof result.identifier!="string"||!result.identifier)throw new Error("Chrome did not return an app profile restore script identifier");let identifier=result.identifier;try{await writeCurrentRestoreState(session,restoreState)}catch(error48){throw await session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier}).catch(()=>{}),error48}let previousIdentifier=state.restoreScriptIdentifier;state.restoreState=restoreState,state.restoreScriptIdentifier=identifier,state.documentScriptIdentifiers.push(identifier),await session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier:previousIdentifier}).then(()=>!0,()=>!1)&&(state.documentScriptIdentifiers=state.documentScriptIdentifiers.filter(scriptIdentifier=>scriptIdentifier!==previousIdentifier))}async function replaceAppProfileDocumentSource(session,state,config2){let result=await session.client.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source:buildDocumentSource(config2)});if(typeof result.identifier!="string"||!result.identifier)throw new Error("Chrome did not return an App profile bootstrap script identifier");let previousIdentifier=state.profileScriptIdentifier;state.config=config2,state.profileScriptIdentifier=result.identifier,state.documentScriptIdentifiers.push(result.identifier),await session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier:previousIdentifier}).then(()=>!0,()=>!1)&&(state.documentScriptIdentifiers=state.documentScriptIdentifiers.filter(identifier=>identifier!==previousIdentifier))}async function restoreCdpAppProfile(session){if(appProfileStates.has(session))return!0;let pageState=(await session.client.sendCommand("Runtime.evaluate",{expression:`({profile:typeof globalThis.__mearlAppProfile__==='string'?globalThis.__mearlAppProfile__:null,restoreHint:globalThis[${JSON.stringify(APP_PROFILE_RESTORE_HINT)}]===true})`,returnByValue:!0,silent:!0})).result?.value;if(typeof pageState?.profile!="string"&&pageState?.restoreHint!==!0)return!1;let contextId=await getRestoreExecutionContext(session),stateProbe=await session.client.sendCommand("Runtime.evaluate",{contextId,expression:`globalThis[${JSON.stringify(APP_PROFILE_RESTORE_STATE)}]??null`,returnByValue:!0}),restoreState=parseCdpAppProfileRestoreState(stateProbe.result?.value);if(!restoreState||restoreState.activeDocument&&typeof pageState?.profile=="string"&&pageState.profile!==restoreState.profile)return!1;let resolved;try{resolved=resolveCdpAppProfile(restoreState.profile,restoreState.options)}catch{return!1}let restoredEmulation;try{restoredEmulation=restoreState.emulation?resolveCdpAppProfileRestoreEmulation(restoreState.emulation):void 0}catch{return!1}let previousEmulation=session.emulation;restoredEmulation&&restoreState.emulation&&(session.emulation={mobile:restoredEmulation.mobile,touch:restoredEmulation.touch,config:restoredEmulation,deviceShell:restoreState.emulation.deviceShell,splitScreen:restoreState.emulation.splitScreen===!0});try{await applyResolvedCdpAppProfile(session,resolved),restoredEmulation&&restoreState.emulation?.deviceShell&&(await applyCdpDeviceShell(session,restoredEmulation,{rootContainerManagedByApp:usesAppProfileSplitScreen(session.emulation)}),setCdpDeviceShellChildEnvironmentManagedByApp(session,!0)),restoreState.activeDocument&&await session.client.sendCommand("Runtime.evaluate",{expression:buildDocumentSource(resolved.profile.injected)})}catch(error48){await clearCdpDeviceShell(session).catch(()=>{});let state=appProfileStates.get(session);throw state&&await disposeState(session,state),session.emulation=previousEmulation,restoredEmulation&&(previousEmulation?.config?await sendCommands(session.client,buildEnableEmulationCommands(previousEmulation.config)).catch(()=>{}):await sendCommands(session.client,buildDisableEmulationCommands()).catch(()=>{})),new Error(`Failed to restore App profile for target ${session.targetId}: ${error48 instanceof Error?error48.message:String(error48)}`,{cause:error48})}return!0}async function applyResolvedCdpAppProfile(session,resolved){let previous=appProfileStates.get(session);previous&&await disposeState(session,previous);let baseConfig=resolved.profile.injected,config2=resolveAppProfileRuntimeConfig(baseConfig,session.emulation),source=buildDocumentSource(config2),deviceEmulation=session.emulation?.config,restoreState=restoreStateForSession(resolved.restoreState,session.emulation);deviceEmulation?await sendCommands(session.client,appProfileEmulationCommands(deviceEmulation,resolved.profile.ua)):await session.client.sendCommand("Emulation.setUserAgentOverride",{userAgent:resolved.profile.ua,platform:resolved.profile.injected.navigatorPlatform}),await session.client.sendCommand("Runtime.enable"),await session.client.sendCommand("Runtime.addBinding",{name:APP_PROFILE_BINDING});let documentScriptIdentifiers=[],state;try{let script=await session.client.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source});if(typeof script.identifier!="string"||!script.identifier)throw new Error("Chrome did not return an app profile bootstrap script identifier");documentScriptIdentifiers.push(script.identifier);let restoreScript=await session.client.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source:buildRestoreStateSource(restoreState,!0),worldName:APP_PROFILE_RESTORE_WORLD});if(typeof restoreScript.identifier!="string"||!restoreScript.identifier)throw new Error("Chrome did not return an app profile restore script identifier");documentScriptIdentifiers.push(restoreScript.identifier),await writeCurrentRestoreState(session,restoreState),await session.client.sendCommand("Runtime.evaluate",{expression:buildRestoreHintSource()});let installedState={baseConfig,config:config2,documentScriptIdentifiers,profileScriptIdentifier:script.identifier,restoreScriptIdentifier:restoreScript.identifier,restoreState,emulation:deviceEmulation,disposeListeners:[],childClients:[]};state=installedState,appProfileStates.set(session,installedState),setCdpDeviceShellChildEnvironmentManagedByApp(session,!0),installedState.disposeListeners.push(listenForBridgeRequests(session,session.client,installedState)),installedState.disposeListeners.push(session.client.on("Target.attachedToTarget",params=>{installChildTarget2(session,installedState,params).catch(()=>{})})),installedState.disposeListeners.push(session.client.on("Target.detachedFromTarget",params=>{let sessionId=params?.sessionId;typeof sessionId!="string"||appProfileStates.get(session)!==installedState||(installedState.childClients=installedState.childClients.filter(client2=>client2.sessionId!==sessionId))})),await session.client.sendCommand("Target.setAutoAttach",{autoAttach:!0,waitForDebuggerOnStart:!0,flatten:!0,filter:[{type:"iframe"},{exclude:!0}]})}catch(error48){throw state?await disposeState(session,state):await rollbackAppProfileInstall(session,documentScriptIdentifiers,deviceEmulation),error48}}async function updateCdpAppProfileDeviceEmulation(session,emulation,deviceShell=session.emulation?.deviceShell===!0,splitScreen=session.emulation?.splitScreen===!0){let state=appProfileStates.get(session);if(!state)return;let nextSessionEmulation=emulation?{mobile:emulation.mobile,touch:emulation.touch,config:emulation,deviceShell,splitScreen}:void 0,nextConfig=resolveAppProfileRuntimeConfig(state.baseConfig,nextSessionEmulation);return JSON.stringify(nextConfig)!==JSON.stringify(state.config)&&await replaceAppProfileDocumentSource(session,state,nextConfig),await replaceRestoreState(session,state,restoreStateForSession(state.restoreState,nextSessionEmulation)),state.emulation=emulation??void 0,await Promise.allSettled(state.childClients.map(client2=>emulation?sendCommands(client2,appProfileEmulationCommands(childAppProfileEnvironment(state.config,emulation).emulation,state.config.userAgent)):client2.sendCommand("Emulation.setUserAgentOverride",{userAgent:state.config.userAgent,platform:state.config.navigatorPlatform}))),{userAgent:state.config.userAgent,platform:state.config.navigatorPlatform}}function isCdpAppProfileActive(session){return appProfileStates.has(session)}async function waitForCdpAppProfileLoad(session,timeoutMs=3e4){if(isCdpDeviceShellActive(session)){await waitForCdpDeviceShellLoad(session,Math.min(timeoutMs,15e3));return}await waitForPageLoad(session,timeoutMs)}async function clearCdpAppProfile(session,reload=!0){let state=appProfileStates.get(session);if(!state)return{enabled:!1,reloaded:!1};await disposeState(session,state),session.emulation?.deviceShell&&session.emulation.config&&await applyCdpDeviceShell(session,session.emulation.config);let reloaded=!1;return reload&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),await waitForCdpAppProfileLoad(session),reloaded=!0),{enabled:!1,reloaded}}async function cdpSetAppProfile(session,data){if(typeof data?.enabled!="boolean")throw new Error('set_app_profile: "enabled" is required (true to enable, false to clear)');if(!data.enabled){if(data.emulation===void 0){if(data.mtopEnv===void 0)return clearCdpAppProfile(session,data.reload!==!1);let appResult2=await clearCdpAppProfile(session,!1);await setCdpMtopEnvironment(session,data.mtopEnv);let reloaded3=!1;return data.reload!==!1&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),await waitForCdpAppProfileLoad(session),reloaded3=!0),{...appResult2,mtopEnv:data.mtopEnv,reloaded:reloaded3}}let hadDeviceShell=await clearCdpDeviceShell(session),appResult=await clearCdpAppProfile(session,!1);await sendCommands(session.client,buildDisableEmulationCommands()),session.emulation=void 0,data.mtopEnv!==void 0&&await setCdpMtopEnvironment(session,data.mtopEnv);let reloaded2=!1;return(data.reload!==!1||hadDeviceShell)&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),await waitForPageLoad(session,3e4),reloaded2=!0),{...appResult,...data.mtopEnv!==void 0&&{mtopEnv:data.mtopEnv},device:{enabled:!1,deviceShell:!1,splitScreen:!1,reloaded:reloaded2},reloaded:reloaded2}}if(!data.profile||typeof data.profile!="string")throw new Error('set_app_profile: "profile" is required when enabled=true');let resolved=resolveCdpAppProfile(data.profile,{...data,devicePreset:session.emulation?.config?.presetName,orientation:session.emulation?.config?.orientation});if(data.emulation!==void 0){let emulation=resolveEmulationConfig({enabled:!0,preset:resolved.profile.recommendedPreset,...data.emulation}),targetOs=emulation.platform==="Android"||emulation.platform==="OpenHarmony"?"android":"ios",targetDeviceModel=data.deviceModel??(emulation.presetName?DEVICE_PRESETS[emulation.presetName].appProfileModel:resolved.profile.injected.globals.__DEVICE_MODEL__),appResolved=resolveCdpAppProfile(data.profile,{...data,os:targetOs,deviceModel:targetDeviceModel}),deviceShell=data.emulation.deviceShell??!0,splitScreen=deviceShell&&data.emulation.splitScreen===!0&&emulation.orientation==="landscape";session.emulation={mobile:emulation.mobile,touch:emulation.touch,config:emulation,deviceShell,splitScreen},await applyResolvedCdpAppProfile(session,appResolved);let shellChanged2=deviceShell?await applyCdpDeviceShell(session,emulation,{rootContainerManagedByApp:splitScreen}):await clearCdpDeviceShell(session);deviceShell&&setCdpDeviceShellChildEnvironmentManagedByApp(session,!0),data.mtopEnv!==void 0&&await setCdpMtopEnvironment(session,data.mtopEnv);let reloaded2=!1;return(data.reload!==!1||shellChanged2)&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),deviceShell?await waitForCdpDeviceShellLoad(session):await waitForPageLoad(session,3e4),reloaded2=!0),{enabled:!0,profile:appResolved.profile.profile,label:appResolved.profile.label,userAgent:appResolved.profile.ua,os:appResolved.profile.injected.platform==="Android"?"android":"ios",...data.mtopEnv!==void 0&&{mtopEnv:data.mtopEnv},device:{enabled:!0,preset:emulation.presetName,viewport:{width:emulation.width,height:emulation.height,deviceScaleFactor:emulation.deviceScaleFactor,scale:emulation.scale??1},userAgent:emulation.userAgent,mobile:emulation.mobile,touch:emulation.touch,orientation:emulation.orientation,deviceShell,splitScreen,reloaded:reloaded2},reloaded:reloaded2}}await applyResolvedCdpAppProfile(session,resolved);let shellChanged=session.emulation?.deviceShell&&session.emulation.config?await applyCdpDeviceShell(session,session.emulation.config,{rootContainerManagedByApp:usesAppProfileSplitScreen(session.emulation)}):!1;data.mtopEnv!==void 0&&await setCdpMtopEnvironment(session,data.mtopEnv);let reloaded=!1;return(data.reload!==!1||shellChanged)&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),await waitForCdpAppProfileLoad(session),reloaded=!0),{enabled:!0,profile:resolved.profile.profile,label:resolved.profile.label,userAgent:resolved.profile.ua,os:resolved.profile.injected.platform==="Android"?"android":"ios",...data.mtopEnv!==void 0&&{mtopEnv:data.mtopEnv},reloaded}}registerPageSessionInitializer(async session=>{try{await restoreCdpAppProfile(session)}catch(error48){console.warn(`[CDP] Failed to restore App profile for target ${session.targetId}:`,error48 instanceof Error?error48.message:String(error48))}});registerActions([{name:"set_app_profile",session:"page",handler:cdpSetAppProfile}]);async function releaseCdpControl(session){let pageSessions=session.listOpenPageSessions(),targetIds=new Set(pageSessions.map(pageSession=>pageSession.targetId)),affectedTabIds=session.listRegisteredTabIds(targetIds).sort((a,b)=>a-b),hadActiveControl=session.hasActiveConnections();return await Promise.allSettled(pageSessions.map(async pageSession=>{let[,deviceShell]=await Promise.allSettled([clearCdpAppProfile(pageSession,!1),clearCdpDeviceShell(pageSession),releaseControlledIndicator(pageSession)]);deviceShell.status==="fulfilled"&&deviceShell.value&&await pageSession.client.sendCommand("Page.reload",{}).catch(()=>{})})),clearCdpMockState(),clearCdpMtopEnvironmentState(pageSessions),clearCdpFetchInterceptionState(pageSessions),session.close(),{released:!0,hadActiveControl,affectedTabIds}}var SAMPLE_PAGE_READINESS_SRC=samplePageReadinessInPage.toString(),DISPOSE_PAGE_READINESS_SRC=disposePageReadinessObserverInPage.toString();async function startCdpNavigationObserver(cdpSession2,pageSession,urlBefore,options={}){let pageEndpoint=await resolveCdpDeviceShellPageEndpoint(pageSession),pageClient=pageEndpoint.client;await ensureCdpDomain(pageClient,"Page"),await ensureCdpDomain(pageClient,"Runtime"),options.trackNetwork&&await ensureCdpDomain(pageClient,"Network");let browserClient=null,baselineTargetIds=new Set;if(options.trackOpenedTabs)try{browserClient=await cdpSession2.getBrowserClient();let targets=await browserClient.sendCommand("Target.getTargets");for(let target of targets.targetInfos??[])baselineTargetIds.add(target.targetId)}catch{browserClient=null}let frameTree=await pageClient.sendCommand("Page.getFrameTree"),observedFrameId=pageEndpoint.frameId??frameTree.frameTree?.frame?.id,observesParentTargetSubframe=pageClient===pageSession.client&&pageEndpoint.frameId!==void 0,tracker=createNavigationSettlementTracker({urlBefore,trackNetwork:options.trackNetwork,networkAvailable:options.trackNetwork===!0,networkIdleMs:options.networkIdleMs,contentReadyAfterMs:options.contentReadyAfterMs,sampleContent:async()=>(await sendCdpDeviceShellPageCommand(pageSession,"Runtime.evaluate",{expression:`(${SAMPLE_PAGE_READINESS_SRC})(${options.networkIdleMs??500})`,returnByValue:!0})).result?.value}),removeFrameNavigated=pageClient.on("Page.frameNavigated",params=>{observedFrameId&&params.frame?.id!==observedFrameId||tracker.markStarted(params.frame?.url)}),removeWithinDocument=pageClient.on("Page.navigatedWithinDocument",params=>{observedFrameId&&params.frameId!==observedFrameId||(tracker.markStarted(params.url),tracker.markDocumentComplete(params.url))}),removeLoad=pageClient.on("Page.loadEventFired",()=>{observesParentTargetSubframe||tracker.hasStarted()&&tracker.markDocumentComplete()}),removeFrameStoppedLoading=pageClient.on("Page.frameStoppedLoading",params=>{observedFrameId&&params.frameId!==observedFrameId||tracker.hasStarted()&&tracker.markDocumentComplete()}),removeRequestStarted=options.trackNetwork?pageClient.on("Network.requestWillBeSent",params=>{isPotentialNavigationRequest(params.type??"",params.request?.url??"")&&tracker.requestStarted(params.requestId)}):()=>{},onRequestFinished=params=>tracker.requestFinished(params.requestId),removeRequestFinished=options.trackNetwork?pageClient.on("Network.loadingFinished",onRequestFinished):()=>{},removeRequestFailed=options.trackNetwork?pageClient.on("Network.loadingFailed",onRequestFinished):()=>{};return{hasStarted:tracker.hasStarted,hasNetworkActivity:tracker.hasNetworkActivity,waitForStart:tracker.waitForStart,waitForNetworkIdle:tracker.waitForNetworkIdle,waitForResult:async timeoutMs=>{let result=await tracker.waitForResult(timeoutMs);try{let pageState=await sendCdpDeviceShellPageCommand(pageSession,"Runtime.evaluate",{expression:"({ title: document.title, url: location.href })",returnByValue:!0});return{...result,title:pageState.result?.value?.title??result.title,urlAfter:pageState.result?.value?.url??result.urlAfter}}catch{return result}},getOpenedTabs:async timeoutMs=>{if(!browserClient||options.sourceTabId===void 0)return[];let candidates=((await browserClient.sendCommand("Target.getTargets")).targetInfos??[]).filter(target=>target.type==="page"&&target.openerId===pageSession.targetId&&!baselineTargetIds.has(target.targetId));return(await Promise.all(candidates.map(async candidate=>{let tabId=await cdpSession2.ensureTargetRegistered(candidate.targetId),ready=!1;try{let openedPageSession=await cdpSession2.getPageSession(tabId);await ensureCdpDomain(openedPageSession.client,"Page"),await waitForPageLoad(openedPageSession,timeoutMs),ready=!0}catch{}let targetInfo=await browserClient.sendCommand("Target.getTargetInfo",{targetId:candidate.targetId}).then(result=>result.targetInfo).catch(()=>null);return targetInfo?{tabId,openerTabId:options.sourceTabId,url:targetInfo.url??candidate.url??"",title:targetInfo.title??candidate.title??"",ready,settledBy:ready?"load":"timeout"}:null}))).filter(tab=>tab!==null)},dispose:async()=>{removeFrameNavigated(),removeWithinDocument(),removeLoad(),removeFrameStoppedLoading(),removeRequestStarted(),removeRequestFinished(),removeRequestFailed(),tracker.dispose(),await sendCdpDeviceShellPageCommand(pageSession,"Runtime.evaluate",{expression:`(${DISPOSE_PAGE_READINESS_SRC})()`,returnByValue:!1}).catch(()=>{})}}}var INSTALL_PAGE_OBSERVER_SRC=installPageObserverInPage.toString(),DISPOSE_PAGE_OBSERVER_SRC=disposePageObserverInPage.toString(),PAGE_OBSERVER_GLOBAL="__MEARL_PAGE_OBSERVER__",observationTargets=new WeakMap;function evaluationError(result){return result.exceptionDetails?result.exceptionDetails.exception?.description??result.exceptionDetails.text??"Page observation evaluation failed":null}async function startPageObservation(session){let result=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`(${INSTALL_PAGE_OBSERVER_SRC})()`,returnByValue:!0}),error48=evaluationError(result);if(error48)throw new Error(error48);let checkpoint=result.result?.value;if(!checkpoint||typeof checkpoint.version!="number")throw new Error("Page observer did not return a checkpoint");let endpoint=await resolveCdpDeviceShellPageEndpoint(session);return observationTargets.set(checkpoint,{...endpoint,startedAt:Date.now()}),checkpoint}async function finishPageObservation(session,checkpoint,options={}){let startedTarget=observationTargets.get(checkpoint),currentTarget=await resolveCdpDeviceShellPageEndpoint(session);if(startedTarget&&currentTarget.url&&(currentTarget.client!==startedTarget.client||currentTarget.frameId!==startedTarget.frameId||currentTarget.url!==(startedTarget.url??checkpoint.url))){let title=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:"document.title",returnByValue:!0}).then(result2=>typeof result2.result?.value=="string"?result2.result.value:"").catch(()=>"");return{mode:"navigation",urlBefore:checkpoint.url,urlAfter:currentTarget.url,title,elapsed:Date.now()-startedTarget.startedAt,loaded:!0,ready:!0,settledBy:"load",pendingRequests:0,fullSnapshotRecommended:!0,snapshotReasons:["navigation"]}}let{quietMs,firstChangeTimeoutMs,timeoutMs}=resolvePageObservationWaitOptions(options),expression=`(() => {
1486
+ })()`);if(typeof state=="string"){let response=JSON.parse(state);if(typeof(response.authcode??response.authCode)!="string"||!(response.authcode??response.authCode))throw new Error(String(response.errorMessage??response.msg??"Alipay authorization failed"));return response}}}catch(error48){if(started)throw error48;tabId=0}await new Promise(resolve9=>setTimeout(resolve9,POLL_INTERVAL_MS))}throw new Error("Alipay authorization timed out")}var APP_PROFILE_BINDING="__mearlCdpAppProfileRelay",APP_PROFILE_RESTORE_HINT="__mearlCdpAppProfileRestoreHint__",APP_PROFILE_RESTORE_STATE="__mearlCdpAppProfileState__",APP_PROFILE_RESTORE_WORLD="__mearl_cdp_app_profile_state__",APP_PROFILE_RESTORE_VERSION=1,MAX_APP_PROFILE_RESTORE_STATE_LENGTH=7e4,appProfileStates=new WeakMap;function serializeForSource2(value){return JSON.stringify(value).replace(/[\u2028\u2029]/g,character=>character==="\u2028"?"\\u2028":"\\u2029")}function installCdpAppProfileRelay(bindingName){let browser=globalThis,target=globalThis;target.__mearlCdpAppProfileRelayInstalled__||(target.__mearlCdpAppProfileRelayInstalled__=!0,browser.addEventListener("message",event=>{if(event.source!==globalThis)return;let message=event.data;if(!message||message.source!=="mearl-app-bridge")return;let requestId=message.requestId;if(typeof requestId!="number")return;if(message.type==="prepareWebView"){browser.postMessage({source:"mearl-content",type:"APP_BRIDGE_PREPARE_WEBVIEW_RESPONSE",requestId,result:{success:!0}},"*");return}if(message.type!=="mtop"&&message.type!=="mtopStream"&&message.type!=="userInfo"&&message.type!=="authCode"&&message.type!=="authCodeCancel"&&message.type!=="screenshot")return;let replyFailure=reason=>{if(browser.console?.warn("[Mearl] App bridge relay unavailable:",reason),message.type==="mtopStream"){browser.postMessage({source:"mearl-content",type:"APP_BRIDGE_MTOP_STREAM_EVENT",requestId,eventType:"onError",data:{ret:["HY_FAILED"],msg:reason}},"*");return}let responseTypes={mtop:"APP_BRIDGE_MTOP_RESPONSE",userInfo:"APP_BRIDGE_USER_INFO_RESPONSE",authCode:"APP_BRIDGE_AUTH_CODE_RESPONSE",screenshot:"APP_BRIDGE_SCREENSHOT_RESPONSE"};browser.postMessage({source:"mearl-content",type:responseTypes[String(message.type)],requestId,result:{success:!1,error:reason}},"*")},binding=target[bindingName];if(typeof binding!="function"){replyFailure("native relay binding is unavailable");return}try{binding(JSON.stringify({type:message.type,requestId,payload:message.payload}))}catch(error48){replyFailure(error48 instanceof Error?error48.message:"native relay call failed")}}))}function installEarlyAppProfileEnvironment(config2,restoreHintName){let browser=globalThis,target=globalThis;try{Object.defineProperty(target,restoreHintName,{configurable:!0,enumerable:!1,writable:!1,value:!0})}catch{target[restoreHintName]=!0}for(let[key,value]of Object.entries(config2.globals))try{target[key]=value}catch{}let insets=config2.safeAreaInsets??{top:config2.statusBarHeight,right:0,bottom:0,left:0};target.__STATUS_BAR_HEIGHT__=config2.statusBarHeight,target.__SAFE_AREA_INSET_BOTTOM__=insets.bottom;for(let[key,value]of[["userAgent",config2.userAgent],["platform",config2.navigatorPlatform],["vendor","Apple Computer, Inc."],["appVersion",config2.userAgent.replace(/^Mozilla\//,"")],["maxTouchPoints",config2.maxTouchPoints],...config2.profile==="alipay"?[["language",config2.language]]:[]])try{Object.defineProperty(browser.navigator,key,{configurable:!0,get:()=>value})}catch{}if(config2.profile==="alipay")try{Object.defineProperty(browser.navigator,"languages",{configurable:!0,get:()=>[config2.language]})}catch{}}function installWhenDocumentElementExists(install,waitForBody=!1){let browser=globalThis,isReady=()=>!!(browser.document.documentElement&&(!waitForBody||browser.document.body));if(isReady()){install();return}let observer=new browser.MutationObserver(()=>{isReady()&&(observer.disconnect(),install())});observer.observe(browser.document,{childList:!0,subtree:waitForBody})}function buildDocumentSource(config2){return`;(() => {const config=${serializeForSource2(config2)};(${installCdpAppProfileRelay.toString()})(${JSON.stringify(APP_PROFILE_BINDING)});(${installEarlyAppProfileEnvironment.toString()})(config,${JSON.stringify(APP_PROFILE_RESTORE_HINT)});(${installWhenDocumentElementExists.toString()})(() => {${buildAppProfileRuntimeCallSource("config")};},config.rootContainer?.enabled===true&&window===window.top);})();`}function usesAppProfileSplitScreen(emulation){return emulation?.deviceShell===!0&&emulation.splitScreen===!0&&emulation.config?.orientation==="landscape"}function resolveAppProfileRuntimeConfig(baseConfig,emulation){if(!usesAppProfileSplitScreen(emulation)||!emulation?.config){let rootContainer={...baseConfig.rootContainer};return delete rootContainer.splitScreen,{...baseConfig,rootContainer:{...rootContainer,enabled:!1},simulateSystemBars:!1,externalDeviceChrome:!1}}let device=emulation.config,sideBarWidth=getDeviceSideBarWidth(device.presetName,device.orientation);return{...baseConfig,statusBarHeight:sideBarWidth?0:24,safeAreaInsets:device.safeAreaInsets,deviceAppearance:{preset:device.presetName??baseConfig.deviceAppearance?.preset??"iphone-17-pro",orientation:device.orientation,cutout:device.appearance.cutout},rootContainer:{...baseConfig.rootContainer,enabled:!0,splitScreen:!0},simulateSystemBars:!0,externalDeviceChrome:sideBarWidth>0}}function buildRestoreHintSource(){return`;(() => {try{Object.defineProperty(globalThis,${JSON.stringify(APP_PROFILE_RESTORE_HINT)},{configurable:true,enumerable:false,writable:false,value:true});}catch{globalThis[${JSON.stringify(APP_PROFILE_RESTORE_HINT)}]=true;}})();`}function buildRestoreStateSource(restoreState,activeDocument){return`;(() => {const state=${serializeForSource2({...restoreState,activeDocument})};try{Object.defineProperty(globalThis,${JSON.stringify(APP_PROFILE_RESTORE_STATE)},{configurable:true,enumerable:false,writable:false,value:state});}catch{globalThis[${JSON.stringify(APP_PROFILE_RESTORE_STATE)}]=state;}})();`}function snapshotCdpAppProfileEmulation(emulation){let config2=emulation?.config;if(!config2)return;let landscape=config2.orientation==="landscape";return{...config2.presetName?{preset:config2.presetName}:{},width:landscape?config2.height:config2.width,height:landscape?config2.width:config2.height,deviceScaleFactor:config2.deviceScaleFactor,scale:config2.scale??1,mobile:config2.mobile,userAgent:config2.userAgent,orientation:config2.orientation,touch:config2.touch,deviceShell:emulation.deviceShell===!0,splitScreen:emulation.splitScreen===!0}}function resolveCdpAppProfileRestoreEmulation(emulation){return resolveEmulationConfig({enabled:!0,...emulation})}async function getRestoreExecutionContext(session){let frameId=(await session.client.sendCommand("Page.getFrameTree")).frameTree?.frame?.id;if(typeof frameId!="string"||!frameId)throw new Error("Chrome did not return the main frame id");let world=await session.client.sendCommand("Page.createIsolatedWorld",{frameId,worldName:APP_PROFILE_RESTORE_WORLD,grantUniveralAccess:!1});if(typeof world.executionContextId!="number")throw new Error("Chrome did not return the App profile restore execution context");return world.executionContextId}function appProfileEmulationCommands(config2,userAgent){return buildEnableEmulationCommands(config2).map(command=>command.method==="Emulation.setUserAgentOverride"?{...command,params:{userAgent,platform:config2.platform}}:command)}function childAppProfileEnvironment(config2,emulation){if(!emulation||!getDeviceSideBarWidth(emulation.presetName,emulation.orientation))return{profile:config2,emulation};let insets={...config2.safeAreaInsets??emulation.safeAreaInsets,right:0};return{profile:{...config2,safeAreaInsets:insets},emulation:{...emulation,safeAreaInsets:{...emulation.safeAreaInsets,right:0}}}}async function sendCommands(client2,commands){for(let{method,params,optional:optional2}of commands)await client2.sendCommand(method,params).catch(error48=>{if(!optional2)throw error48})}async function postRuntimeMessage(client2,executionContextId,message){await client2.sendCommand("Runtime.evaluate",{expression:`window.postMessage(${serializeForSource2(message)}, '*')`,...typeof executionContextId=="number"?{contextId:executionContextId}:{}})}function listenForBridgeRequests(session,client2,state){let authSessions=new Map,cancelledAuth=new Set,pendingAuth=new Set;return client2.on("Runtime.bindingCalled",params=>{if(params?.name!==APP_PROFILE_BINDING||appProfileStates.get(session)!==state)return;let request;try{request=JSON.parse(params.payload)}catch{return}if(typeof request.requestId!="number")return;let requestId=request.requestId,contextId=typeof params.executionContextId=="number"?params.executionContextId:void 0,authKey=`${contextId??"main"}:${requestId}`,reply=message=>postRuntimeMessage(client2,contextId,{requestId,source:"mearl-content",...message});if(request.type==="authCodeCancel"){if(!pendingAuth.has(authKey))return;cancelledAuth.add(authKey);let browserId=authSessions.get(authKey);browserId&&(authSessions.delete(authKey),closeAlipayAuthCode(browserId).catch(()=>{}));return}(async()=>{if(request.type==="authCode"){if(state.config.profile!=="alipay"||state.config.actions.behaviors?.getAuthCode!=="authCode"||pendingAuth.has(authKey))return;pendingAuth.add(authKey);let browserId="";try{let progressQueue=Promise.resolve(),pairing=await startAlipayAuthCode(request.payload,phase=>{progressQueue=progressQueue.then(async()=>{cancelledAuth.has(authKey)||await reply({type:"APP_BRIDGE_AUTH_CODE_PROGRESS",phase})}).catch(()=>{})});if(await progressQueue,browserId=pairing.browserId,cancelledAuth.has(authKey))return;authSessions.set(authKey,browserId),await reply({type:"APP_BRIDGE_AUTH_CODE_PAIRING",result:{qrSvg:pairing.qrSvg}}),progressQueue=Promise.resolve();let response=await waitAlipayAuthCode(browserId,request.payload,phase=>{progressQueue=progressQueue.then(async()=>{cancelledAuth.has(authKey)||await reply({type:"APP_BRIDGE_AUTH_CODE_PROGRESS",phase})}).catch(()=>{})});await progressQueue,cancelledAuth.has(authKey)||await reply({type:"APP_BRIDGE_AUTH_CODE_RESPONSE",result:{success:!0,response}})}catch(error48){cancelledAuth.has(authKey)||await reply({type:"APP_BRIDGE_AUTH_CODE_RESPONSE",result:{success:!1,error:error48 instanceof Error?error48.message:String(error48)}})}finally{authSessions.delete(authKey),cancelledAuth.delete(authKey),pendingAuth.delete(authKey),browserId&&await closeAlipayAuthCode(browserId).catch(()=>{})}return}if(request.type==="screenshot"){if(client2!==session.client)return;try{let result=await cdpPageScreenshot(session,{tabId:session.tabId,format:"png"});await reply({type:"APP_BRIDGE_SCREENSHOT_RESPONSE",result:{success:!0,...result}})}catch(error48){await reply({type:"APP_BRIDGE_SCREENSHOT_RESPONSE",result:{success:!1,error:error48 instanceof Error?error48.message:String(error48)}})}return}if(request.type==="userInfo"){try{let currentUrl=await readCdpCurrentUrl(session,"user_info"),result=await session.client.sendCommand("Network.getCookies",{urls:[currentUrl]}),response=resolveAppProfileUserInfo(currentUrl,(result.cookies??[]).map(cookie=>({name:cookie.name,value:cookie.value})));await reply({type:"APP_BRIDGE_USER_INFO_RESPONSE",result:{success:!0,response}})}catch(error48){await reply({type:"APP_BRIDGE_USER_INFO_RESPONSE",result:{success:!1,error:error48 instanceof Error?error48.message:String(error48)}})}return}let payload=request.payload??{},mtopPayload={...payload,...typeof payload.v=="string"&&payload.version===void 0?{version:payload.v}:{}},streamCapture;try{if(request.type==="mtopStream"){await cdpSendMtopStreamRequest(session,mtopPayload,{onRequestPrepared:metadata=>{streamCapture=recordCdpMtopStreamStart(session.buffers,{api:String(mtopPayload.api??""),url:metadata.url,method:metadata.method,requestHeaders:metadata.requestHeaders,requestData:mtopPayload.data??null})},onResponse:metadata=>{streamCapture&&recordCdpMtopStreamResponse(session.buffers,streamCapture,metadata)},onReceive:async data=>{streamCapture&&recordCdpMtopStreamChunk(session.buffers,streamCapture,data),await reply({type:"APP_BRIDGE_MTOP_STREAM_EVENT",eventType:"onReceive",data})}}),streamCapture&&recordCdpMtopStreamEnd(session.buffers,streamCapture),await reply({type:"APP_BRIDGE_MTOP_STREAM_EVENT",eventType:"onFinish",data:{}});return}let result=await cdpSendMtopRequest(session,mtopPayload);await reply({type:"APP_BRIDGE_MTOP_RESPONSE",result})}catch(error48){let message=error48 instanceof Error?error48.message:String(error48);request.type==="mtopStream"?(streamCapture&&recordCdpMtopStreamEnd(session.buffers,streamCapture,{error:message}),await reply({type:"APP_BRIDGE_MTOP_STREAM_EVENT",eventType:"onError",data:{ret:["HY_FAILED"],msg:message}})):await reply({type:"APP_BRIDGE_MTOP_RESPONSE",result:{success:!1,error:message}})}})().catch(()=>{})})}async function installChildTarget2(session,state,params){let sessionId=params.sessionId;if(typeof sessionId!="string")return;let child=session.client.createChildSession(sessionId);try{if(params.targetInfo?.type!=="iframe"||appProfileStates.get(session)!==state)return;await child.sendCommand("Runtime.enable");let frameName=(await child.sendCommand("Runtime.evaluate",{expression:"window.name",returnByValue:!0})).result?.value;if(frameName!=="__mearl_root__"&&frameName!=="__mearl_layer__")return;let childEnvironment=childAppProfileEnvironment(state.config,state.emulation),source=buildDocumentSource(childEnvironment.profile);childEnvironment.emulation?await sendCommands(child,appProfileEmulationCommands(childEnvironment.emulation,state.config.userAgent)):await child.sendCommand("Emulation.setUserAgentOverride",{userAgent:state.config.userAgent,platform:state.config.navigatorPlatform}),await child.sendCommand("Runtime.addBinding",{name:APP_PROFILE_BINDING}),state.disposeListeners.push(listenForBridgeRequests(session,child,state)),state.childClients.push(child),await child.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source}).catch(()=>{}),await child.sendCommand("Runtime.evaluate",{expression:source})}finally{await child.sendCommand("Runtime.runIfWaitingForDebugger").catch(()=>{})}}async function disposeState(session,state){appProfileStates.get(session)===state&&appProfileStates.delete(session),setCdpDeviceShellChildEnvironmentManagedByApp(session,!1);for(let dispose of state.disposeListeners.splice(0))dispose();isCdpDeviceShellActive(session)||await session.client.sendCommand("Target.setAutoAttach",{autoAttach:!1,waitForDebuggerOnStart:!1,flatten:!0}).catch(()=>{}),await Promise.allSettled(state.documentScriptIdentifiers.map(identifier=>session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier}))),await Promise.allSettled([session.client,...state.childClients].map(client2=>client2.sendCommand("Runtime.removeBinding",{name:APP_PROFILE_BINDING})));try{let contextId=await getRestoreExecutionContext(session);await session.client.sendCommand("Runtime.evaluate",{contextId,expression:`delete globalThis[${JSON.stringify(APP_PROFILE_RESTORE_STATE)}]`})}catch{}await session.client.sendCommand("Runtime.evaluate",{expression:`delete globalThis[${JSON.stringify(APP_PROFILE_RESTORE_HINT)}]`}).catch(()=>{});let deviceEmulation=session.emulation?.config;if(deviceEmulation){let commands=buildEnableEmulationCommands(deviceEmulation);await sendCommands(session.client,commands),await Promise.allSettled(state.childClients.map(client2=>sendCommands(client2,commands)))}else await Promise.allSettled([session.client,...state.childClients].map(client2=>client2.sendCommand("Emulation.setUserAgentOverride",{userAgent:""})))}async function rollbackAppProfileInstall(session,documentScriptIdentifiers,deviceEmulation){await Promise.allSettled([...documentScriptIdentifiers.map(identifier=>session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier})),session.client.sendCommand("Runtime.removeBinding",{name:APP_PROFILE_BINDING}),session.client.sendCommand("Runtime.evaluate",{expression:`delete globalThis[${JSON.stringify(APP_PROFILE_RESTORE_HINT)}]`})]),deviceEmulation?await sendCommands(session.client,buildEnableEmulationCommands(deviceEmulation)).catch(()=>{}):await session.client.sendCommand("Emulation.setUserAgentOverride",{userAgent:""}).catch(()=>{})}function resolveCdpAppProfile(profile,options={}){let resolved=resolveAppProfile(profile,{os:options.os,appVersion:options.appVersion,language:options.language,deviceModel:options.deviceModel,devicePreset:options.devicePreset,orientation:options.orientation,bridgeConfig:options.bridgeConfig}),restoreOptions={os:resolved.injected.platform==="Android"?"android":"ios",appVersion:resolved.injected.globals.__APP_VERSION__??"",...profile==="alipay"?{language:options.language??"zh-CN"}:{},deviceModel:resolved.injected.globals.__DEVICE_MODEL__??"",...resolved.injected.deviceAppearance?.preset?{devicePreset:resolved.injected.deviceAppearance.preset}:{},...resolved.injected.deviceAppearance?.orientation?{orientation:resolved.injected.deviceAppearance.orientation}:{},...options.bridgeConfig?{bridgeConfig:JSON.parse(JSON.stringify(options.bridgeConfig))}:{}};return{profile:resolved,restoreState:{version:APP_PROFILE_RESTORE_VERSION,profile:resolved.profile,options:restoreOptions}}}function isFiniteNumberInRange(value,minimum,maximum){return typeof value=="number"&&Number.isFinite(value)&&value>=minimum&&value<=maximum}function isCdpAppProfileRestoreEmulation(value){if(!value||typeof value!="object"||Array.isArray(value))return!1;let emulation=value,supportedKeys=new Set(["preset","width","height","deviceScaleFactor","scale","mobile","userAgent","orientation","touch","deviceShell","splitScreen"]);return!Object.keys(emulation).some(key=>!supportedKeys.has(key))&&(emulation.preset===void 0||typeof emulation.preset=="string"&&Object.hasOwn(DEVICE_PRESETS,emulation.preset))&&isFiniteNumberInRange(emulation.width,1,1e5)&&isFiniteNumberInRange(emulation.height,1,1e5)&&isFiniteNumberInRange(emulation.deviceScaleFactor,0,100)&&isFiniteNumberInRange(emulation.scale,Number.MIN_VALUE,100)&&typeof emulation.mobile=="boolean"&&typeof emulation.userAgent=="string"&&emulation.userAgent.length<=4096&&(emulation.orientation==="portrait"||emulation.orientation==="landscape")&&typeof emulation.touch=="boolean"&&typeof emulation.deviceShell=="boolean"&&(emulation.splitScreen===void 0||typeof emulation.splitScreen=="boolean")}function parseCdpAppProfileRestoreState(value){if(!value||typeof value!="object"||Array.isArray(value))return null;try{if(JSON.stringify(value).length>MAX_APP_PROFILE_RESTORE_STATE_LENGTH)return null}catch{return null}let state=value,supportedStateKeys=new Set(["version","profile","options","emulation","activeDocument"]);if(Object.keys(state).some(key=>!supportedStateKeys.has(key))||state.version!==APP_PROFILE_RESTORE_VERSION||typeof state.profile!="string"||typeof state.activeDocument!="boolean"||state.emulation!==void 0&&!isCdpAppProfileRestoreEmulation(state.emulation)||!state.options||typeof state.options!="object"||Array.isArray(state.options))return null;let options=state.options,supportedKeys=new Set(["os","appVersion","deviceModel","devicePreset","orientation","bridgeConfig"]);return Object.keys(options).some(key=>!supportedKeys.has(key))||options.os!=="ios"&&options.os!=="android"||typeof options.appVersion!="string"||options.appVersion.length>100||typeof options.deviceModel!="string"||options.deviceModel.length>200||options.devicePreset!==void 0&&(typeof options.devicePreset!="string"||!Object.hasOwn(DEVICE_PRESETS,options.devicePreset))||options.orientation!==void 0&&options.orientation!=="portrait"&&options.orientation!=="landscape"?null:value}function restoreStateForSession(restoreState,emulation){let result={...restoreState},emulationSnapshot=snapshotCdpAppProfileEmulation(emulation);return emulationSnapshot?result.emulation=emulationSnapshot:delete result.emulation,result}async function writeCurrentRestoreState(session,restoreState){let activeProfile=await session.client.sendCommand("Runtime.evaluate",{expression:`globalThis.__mearlAppProfile__===${JSON.stringify(restoreState.profile)}`,returnByValue:!0}),contextId=await getRestoreExecutionContext(session);await session.client.sendCommand("Runtime.evaluate",{contextId,expression:buildRestoreStateSource(restoreState,activeProfile.result?.value===!0)})}async function replaceRestoreState(session,state,restoreState){let result=await session.client.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source:buildRestoreStateSource(restoreState,!0),worldName:APP_PROFILE_RESTORE_WORLD});if(typeof result.identifier!="string"||!result.identifier)throw new Error("Chrome did not return an app profile restore script identifier");let identifier=result.identifier;try{await writeCurrentRestoreState(session,restoreState)}catch(error48){throw await session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier}).catch(()=>{}),error48}let previousIdentifier=state.restoreScriptIdentifier;state.restoreState=restoreState,state.restoreScriptIdentifier=identifier,state.documentScriptIdentifiers.push(identifier),await session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier:previousIdentifier}).then(()=>!0,()=>!1)&&(state.documentScriptIdentifiers=state.documentScriptIdentifiers.filter(scriptIdentifier=>scriptIdentifier!==previousIdentifier))}async function replaceAppProfileDocumentSource(session,state,config2){let result=await session.client.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source:buildDocumentSource(config2)});if(typeof result.identifier!="string"||!result.identifier)throw new Error("Chrome did not return an App profile bootstrap script identifier");let previousIdentifier=state.profileScriptIdentifier;state.config=config2,state.profileScriptIdentifier=result.identifier,state.documentScriptIdentifiers.push(result.identifier),await session.client.sendCommand("Page.removeScriptToEvaluateOnNewDocument",{identifier:previousIdentifier}).then(()=>!0,()=>!1)&&(state.documentScriptIdentifiers=state.documentScriptIdentifiers.filter(identifier=>identifier!==previousIdentifier))}async function restoreCdpAppProfile(session){if(appProfileStates.has(session))return!0;let pageState=(await session.client.sendCommand("Runtime.evaluate",{expression:`({profile:typeof globalThis.__mearlAppProfile__==='string'?globalThis.__mearlAppProfile__:null,restoreHint:globalThis[${JSON.stringify(APP_PROFILE_RESTORE_HINT)}]===true})`,returnByValue:!0,silent:!0})).result?.value;if(typeof pageState?.profile!="string"&&pageState?.restoreHint!==!0)return!1;let contextId=await getRestoreExecutionContext(session),stateProbe=await session.client.sendCommand("Runtime.evaluate",{contextId,expression:`globalThis[${JSON.stringify(APP_PROFILE_RESTORE_STATE)}]??null`,returnByValue:!0}),restoreState=parseCdpAppProfileRestoreState(stateProbe.result?.value);if(!restoreState||restoreState.activeDocument&&typeof pageState?.profile=="string"&&pageState.profile!==restoreState.profile)return!1;let resolved;try{resolved=resolveCdpAppProfile(restoreState.profile,restoreState.options)}catch{return!1}let restoredEmulation;try{restoredEmulation=restoreState.emulation?resolveCdpAppProfileRestoreEmulation(restoreState.emulation):void 0}catch{return!1}let previousEmulation=session.emulation;restoredEmulation&&restoreState.emulation&&(session.emulation={mobile:restoredEmulation.mobile,touch:restoredEmulation.touch,config:restoredEmulation,deviceShell:restoreState.emulation.deviceShell,splitScreen:restoreState.emulation.splitScreen===!0});try{await applyResolvedCdpAppProfile(session,resolved),restoredEmulation&&restoreState.emulation?.deviceShell&&(await applyCdpDeviceShell(session,restoredEmulation,{rootContainerManagedByApp:usesAppProfileSplitScreen(session.emulation)}),setCdpDeviceShellChildEnvironmentManagedByApp(session,!0)),restoreState.activeDocument&&await session.client.sendCommand("Runtime.evaluate",{expression:buildDocumentSource(resolved.profile.injected)})}catch(error48){await clearCdpDeviceShell(session).catch(()=>{});let state=appProfileStates.get(session);throw state&&await disposeState(session,state),session.emulation=previousEmulation,restoredEmulation&&(previousEmulation?.config?await sendCommands(session.client,buildEnableEmulationCommands(previousEmulation.config)).catch(()=>{}):await sendCommands(session.client,buildDisableEmulationCommands()).catch(()=>{})),new Error(`Failed to restore App profile for target ${session.targetId}: ${error48 instanceof Error?error48.message:String(error48)}`,{cause:error48})}return!0}async function applyResolvedCdpAppProfile(session,resolved){let previous=appProfileStates.get(session);previous&&await disposeState(session,previous);let baseConfig=resolved.profile.injected,config2=resolveAppProfileRuntimeConfig(baseConfig,session.emulation),source=buildDocumentSource(config2),deviceEmulation=session.emulation?.config,restoreState=restoreStateForSession(resolved.restoreState,session.emulation);deviceEmulation?await sendCommands(session.client,appProfileEmulationCommands(deviceEmulation,resolved.profile.ua)):await session.client.sendCommand("Emulation.setUserAgentOverride",{userAgent:resolved.profile.ua,platform:resolved.profile.injected.navigatorPlatform}),await session.client.sendCommand("Runtime.enable"),await session.client.sendCommand("Runtime.addBinding",{name:APP_PROFILE_BINDING});let documentScriptIdentifiers=[],state;try{let script=await session.client.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source});if(typeof script.identifier!="string"||!script.identifier)throw new Error("Chrome did not return an app profile bootstrap script identifier");documentScriptIdentifiers.push(script.identifier);let restoreScript=await session.client.sendCommand("Page.addScriptToEvaluateOnNewDocument",{source:buildRestoreStateSource(restoreState,!0),worldName:APP_PROFILE_RESTORE_WORLD});if(typeof restoreScript.identifier!="string"||!restoreScript.identifier)throw new Error("Chrome did not return an app profile restore script identifier");documentScriptIdentifiers.push(restoreScript.identifier),await writeCurrentRestoreState(session,restoreState),await session.client.sendCommand("Runtime.evaluate",{expression:buildRestoreHintSource()});let installedState={baseConfig,config:config2,documentScriptIdentifiers,profileScriptIdentifier:script.identifier,restoreScriptIdentifier:restoreScript.identifier,restoreState,emulation:deviceEmulation,disposeListeners:[],childClients:[]};state=installedState,appProfileStates.set(session,installedState),setCdpDeviceShellChildEnvironmentManagedByApp(session,!0),installedState.disposeListeners.push(listenForBridgeRequests(session,session.client,installedState)),installedState.disposeListeners.push(session.client.on("Target.attachedToTarget",params=>{installChildTarget2(session,installedState,params).catch(()=>{})})),installedState.disposeListeners.push(session.client.on("Target.detachedFromTarget",params=>{let sessionId=params?.sessionId;typeof sessionId!="string"||appProfileStates.get(session)!==installedState||(installedState.childClients=installedState.childClients.filter(client2=>client2.sessionId!==sessionId))})),await session.client.sendCommand("Target.setAutoAttach",{autoAttach:!0,waitForDebuggerOnStart:!0,flatten:!0,filter:[{type:"iframe"},{exclude:!0}]})}catch(error48){throw state?await disposeState(session,state):await rollbackAppProfileInstall(session,documentScriptIdentifiers,deviceEmulation),error48}}async function updateCdpAppProfileDeviceEmulation(session,emulation,deviceShell=session.emulation?.deviceShell===!0,splitScreen=session.emulation?.splitScreen===!0){let state=appProfileStates.get(session);if(!state)return;let nextSessionEmulation=emulation?{mobile:emulation.mobile,touch:emulation.touch,config:emulation,deviceShell,splitScreen}:void 0,nextConfig=resolveAppProfileRuntimeConfig(state.baseConfig,nextSessionEmulation);return JSON.stringify(nextConfig)!==JSON.stringify(state.config)&&await replaceAppProfileDocumentSource(session,state,nextConfig),await replaceRestoreState(session,state,restoreStateForSession(state.restoreState,nextSessionEmulation)),state.emulation=emulation??void 0,await Promise.allSettled(state.childClients.map(client2=>emulation?sendCommands(client2,appProfileEmulationCommands(childAppProfileEnvironment(state.config,emulation).emulation,state.config.userAgent)):client2.sendCommand("Emulation.setUserAgentOverride",{userAgent:state.config.userAgent,platform:state.config.navigatorPlatform}))),{userAgent:state.config.userAgent,platform:state.config.navigatorPlatform}}function isCdpAppProfileActive(session){return appProfileStates.has(session)}async function waitForCdpAppProfileLoad(session,timeoutMs=3e4){if(isCdpDeviceShellActive(session)){await waitForCdpDeviceShellLoad(session,Math.min(timeoutMs,15e3));return}await waitForPageLoad(session,timeoutMs)}async function clearCdpAppProfile(session,reload=!0){let state=appProfileStates.get(session);if(!state)return{enabled:!1,reloaded:!1};await disposeState(session,state),session.emulation?.deviceShell&&session.emulation.config&&await applyCdpDeviceShell(session,session.emulation.config);let reloaded=!1;return reload&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),await waitForCdpAppProfileLoad(session),reloaded=!0),{enabled:!1,reloaded}}async function cdpSetAppProfile(session,data){if(typeof data?.enabled!="boolean")throw new Error('set_app_profile: "enabled" is required (true to enable, false to clear)');if(!data.enabled){if(data.emulation===void 0){if(data.mtopEnv===void 0)return clearCdpAppProfile(session,data.reload!==!1);let appResult2=await clearCdpAppProfile(session,!1);await setCdpMtopEnvironment(session,data.mtopEnv);let reloaded3=!1;return data.reload!==!1&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),await waitForCdpAppProfileLoad(session),reloaded3=!0),{...appResult2,mtopEnv:data.mtopEnv,reloaded:reloaded3}}let hadDeviceShell=await clearCdpDeviceShell(session),appResult=await clearCdpAppProfile(session,!1);await sendCommands(session.client,buildDisableEmulationCommands()),session.emulation=void 0,data.mtopEnv!==void 0&&await setCdpMtopEnvironment(session,data.mtopEnv);let reloaded2=!1;return(data.reload!==!1||hadDeviceShell)&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),await waitForPageLoad(session,3e4),reloaded2=!0),{...appResult,...data.mtopEnv!==void 0&&{mtopEnv:data.mtopEnv},device:{enabled:!1,deviceShell:!1,splitScreen:!1,reloaded:reloaded2},reloaded:reloaded2}}if(!data.profile||typeof data.profile!="string")throw new Error('set_app_profile: "profile" is required when enabled=true');let resolved=resolveCdpAppProfile(data.profile,{...data,devicePreset:session.emulation?.config?.presetName,orientation:session.emulation?.config?.orientation});if(data.emulation!==void 0){let emulation=resolveEmulationConfig({enabled:!0,preset:resolved.profile.recommendedPreset,...data.emulation}),targetOs=emulation.platform==="Android"||emulation.platform==="OpenHarmony"?"android":"ios",targetDeviceModel=data.deviceModel??(emulation.presetName?DEVICE_PRESETS[emulation.presetName].appProfileModel:resolved.profile.injected.globals.__DEVICE_MODEL__),appResolved=resolveCdpAppProfile(data.profile,{...data,os:targetOs,deviceModel:targetDeviceModel}),deviceShell=data.emulation.deviceShell??!0,splitScreen=deviceShell&&data.emulation.splitScreen===!0&&emulation.orientation==="landscape";session.emulation={mobile:emulation.mobile,touch:emulation.touch,config:emulation,deviceShell,splitScreen},await applyResolvedCdpAppProfile(session,appResolved);let shellChanged2=deviceShell?await applyCdpDeviceShell(session,emulation,{rootContainerManagedByApp:splitScreen}):await clearCdpDeviceShell(session);deviceShell&&setCdpDeviceShellChildEnvironmentManagedByApp(session,!0),data.mtopEnv!==void 0&&await setCdpMtopEnvironment(session,data.mtopEnv);let reloaded2=!1;return(data.reload!==!1||shellChanged2)&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),deviceShell?await waitForCdpDeviceShellLoad(session):await waitForPageLoad(session,3e4),reloaded2=!0),{enabled:!0,profile:appResolved.profile.profile,label:appResolved.profile.label,userAgent:appResolved.profile.ua,os:appResolved.profile.injected.platform==="Android"?"android":"ios",...data.mtopEnv!==void 0&&{mtopEnv:data.mtopEnv},device:{enabled:!0,preset:emulation.presetName,viewport:{width:emulation.width,height:emulation.height,deviceScaleFactor:emulation.deviceScaleFactor,scale:emulation.scale??1},userAgent:emulation.userAgent,mobile:emulation.mobile,touch:emulation.touch,orientation:emulation.orientation,deviceShell,splitScreen,reloaded:reloaded2},reloaded:reloaded2}}await applyResolvedCdpAppProfile(session,resolved);let shellChanged=session.emulation?.deviceShell&&session.emulation.config?await applyCdpDeviceShell(session,session.emulation.config,{rootContainerManagedByApp:usesAppProfileSplitScreen(session.emulation)}):!1;data.mtopEnv!==void 0&&await setCdpMtopEnvironment(session,data.mtopEnv);let reloaded=!1;return(data.reload!==!1||shellChanged)&&(clearPageRefsForNavigation(session),await session.client.sendCommand("Page.reload",{}),await waitForCdpAppProfileLoad(session),reloaded=!0),{enabled:!0,profile:resolved.profile.profile,label:resolved.profile.label,userAgent:resolved.profile.ua,os:resolved.profile.injected.platform==="Android"?"android":"ios",...data.mtopEnv!==void 0&&{mtopEnv:data.mtopEnv},reloaded}}registerPageSessionInitializer(async session=>{try{await restoreCdpAppProfile(session)}catch(error48){console.warn(`[CDP] Failed to restore App profile for target ${session.targetId}:`,error48 instanceof Error?error48.message:String(error48))}});registerActions([{name:"set_app_profile",session:"page",handler:cdpSetAppProfile}]);var RESOURCE_TYPES=new Set(["main_frame","sub_frame","xmlhttprequest"]),HEADER_NAME=/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/,stores=new WeakMap;function validateRule(data){if(data?.actionType!=="modifyHeaders")throw new Error("CDP set_rule supports modifyHeaders request headers only");if(typeof data.filter!="string"||!data.filter.trim()||data.filter.length>2048)throw new Error("CDP set_rule requires a non-empty regex filter (max 2048 characters)");let regex;try{regex=new RegExp(data.filter)}catch{throw new Error("CDP set_rule filter is not a valid regex")}if(data.responseHeaders?.length||data.initiatorDomains)throw new Error("CDP set_rule does not support responseHeaders or initiatorDomains");if(!Array.isArray(data.requestHeaders)||data.requestHeaders.length===0)throw new Error("CDP set_rule requires requestHeaders");let requestHeaders=data.requestHeaders.map(header=>{if(!header||typeof header.header!="string"||!HEADER_NAME.test(header.header)||header.operation!=="set"||typeof header.value!="string"||/[\r\n\0]/.test(header.value))throw new Error("CDP set_rule supports request header set operations with valid names and values");return{header:header.header,operation:"set",value:header.value}}),resourceTypes=data.resourceTypes??["main_frame","sub_frame","xmlhttprequest"];if(!Array.isArray(resourceTypes)||resourceTypes.length===0||resourceTypes.some(type=>!RESOURCE_TYPES.has(type)))throw new Error("CDP set_rule supports main_frame, sub_frame, and xmlhttprequest resource types");let priority=data.priority??1;if(!Number.isInteger(priority)||priority<1)throw new Error("CDP set_rule priority must be a positive integer");return{actionType:"modifyHeaders",filter:data.filter,regex,requestHeaders,resourceTypes:[...resourceTypes],priority,description:data.description??"Rule added via MCP/Skill"}}function matchesResourceType(rule,session,params,state){let type=params.resourceType;if(type==="XHR"||type==="Fetch")return rule.resourceTypes.includes("xmlhttprequest");if(type!=="Document")return!1;let mainFrameId=state.mainFrameIds.get(session),requestType=mainFrameId&&params.frameId?params.frameId===mainFrameId?"main_frame":"sub_frame":void 0;return requestType?rule.resourceTypes.includes(requestType):rule.resourceTypes.includes("main_frame")&&rule.resourceTypes.includes("sub_frame")}function headerHandler(state,context){let{session,params,isResponseStage}=context;if(!state.active||isResponseStage||!params.request?.url)return!1;let matched=state.rules.filter(rule=>rule.regex.test(params.request.url)&&matchesResourceType(rule,session,params,state)).sort((a,b)=>a.priority-b.priority||a.ruleId-b.ruleId);if(!matched.length)return!1;let headers=new Map;for(let[name,value]of Object.entries(params.request.headers??{}))headers.set(name.toLowerCase(),{name,value:String(value)});for(let rule of matched)for(let header of rule.requestHeaders)headers.set(header.header.toLowerCase(),{name:header.header,value:header.value});return session.client.sendCommand("Fetch.continueRequest",{requestId:params.requestId,headers:[...headers.values()]}).then(()=>!0)}async function attachRuleHandler(page,state){if(!state.active||state.attachedPages.has(page))return;state.attachedPages.add(page);try{let frameId=(await page.client.sendCommand("Page.getFrameTree",{})).frameTree?.frame?.id;typeof frameId=="string"&&state.mainFrameIds.set(page,frameId)}catch{}if(!state.active)return;let dispose=page.client.on("Page.frameNavigated",params=>{!params.frame?.parentId&&typeof params.frame?.id=="string"&&state.mainFrameIds.set(page,params.frame.id)});state.frameListeners.set(page,dispose);try{await registerCdpFetchPauseHandler(page,"request-header-rules",75,context=>headerHandler(state,context)),state.active||await unregisterCdpFetchPauseHandler(page,"request-header-rules")}catch(error48){throw state.attachedPages.delete(page),state.frameListeners.delete(page),dispose(),error48}}async function initializeRuleState(session,state){state.disposeInitializer=session.addPageSessionInitializer(page=>attachRuleHandler(page,state));let browser=await session.getBrowserClient();state.disposeConnectionListener=session.onBrowserConnected(()=>clearCdpRuleState(session)),state.disposeTargetListener=browser.on("Target.targetCreated",params=>{let target=params.targetInfo;!state.active||target?.type!=="page"||/^(?:chrome:|chrome-extension:)/.test(target.url??"")||session.ensureTargetRegistered(target.targetId).then(tabId=>state.active?session.getPageSession(tabId):void 0).catch(()=>{})}),state.disposeDestroyedListener=browser.on("Target.targetDestroyed",params=>{for(let[page,dispose]of state.frameListeners)page.targetId===params.targetId&&(dispose(),state.frameListeners.delete(page),state.attachedPages.delete(page))}),await browser.sendCommand("Target.setDiscoverTargets",{discover:!0}),await session.attachOpenPageTargets();for(let page of session.listOpenPageSessions())await attachRuleHandler(page,state)}async function cdpSetRule(session,data){if(data?.enabled===!1){let{ruleId}=data;if(!Number.isSafeInteger(ruleId)||ruleId<1)throw new Error("CDP set_rule requires a positive integer ruleId when enabled is false");await session.getBrowserClient();let state2=stores.get(session),index=state2?.rules.findIndex(rule2=>rule2.ruleId===ruleId)??-1;return!state2||index<0?{success:!0,ruleId,affectedCount:0,message:`Rule #${ruleId} not found.`}:(state2.rules.splice(index,1),state2.rules.length===0&&(clearCdpRuleState(session),await Promise.all(session.listOpenPageSessions().map(page=>unregisterCdpFetchPauseHandler(page,"request-header-rules")))),{success:!0,ruleId,affectedCount:1,message:`Rule #${ruleId} removed.`})}let validated=validateRule(data);await session.getBrowserClient();let state=stores.get(session);state||(state={active:!0,rules:[],nextRuleId:1,mainFrameIds:new WeakMap,attachedPages:new WeakSet,frameListeners:new Map},stores.set(session,state));let rule={...validated,ruleId:state.nextRuleId++,enabled:!0};state.rules.push(rule),state.setupPromise||(state.setupPromise=initializeRuleState(session,state));try{if(await state.setupPromise,!state.active||stores.get(session)!==state)throw new Error("CDP browser connection changed while installing the rule; retry")}catch(error48){let index=state.rules.indexOf(rule);throw index>=0&&state.rules.splice(index,1),state.rules.length===0&&stores.get(session)===state&&(clearCdpRuleState(session),await Promise.all(session.listOpenPageSessions().map(page=>unregisterCdpFetchPauseHandler(page,"request-header-rules")))),error48}return{success:!0,ruleId:rule.ruleId,affectedCount:1,message:`Rule #${rule.ruleId} added for the current CDP browser session.`}}async function cdpGetRules(session){return await session.getBrowserClient(),{enabled:!0,rules:(stores.get(session)?.rules??[]).map(({regex:_regex2,...rule})=>({...rule}))}}function clearCdpRuleState(session){let state=stores.get(session);if(state){state.active=!1,state.disposeInitializer?.(),state.disposeTargetListener?.(),state.disposeDestroyedListener?.(),state.disposeConnectionListener?.();for(let dispose of state.frameListeners.values())dispose();state.frameListeners.clear(),stores.delete(session)}}registerActions([{name:"set_rule",session:"browser",handler:cdpSetRule},{name:"get_rules",session:"browser",handler:cdpGetRules}]);async function releaseCdpControl(session){let pageSessions=session.listOpenPageSessions(),targetIds=new Set(pageSessions.map(pageSession=>pageSession.targetId)),affectedTabIds=session.listRegisteredTabIds(targetIds).sort((a,b)=>a-b),hadActiveControl=session.hasActiveConnections();return await Promise.allSettled(pageSessions.map(async pageSession=>{let[,deviceShell]=await Promise.allSettled([clearCdpAppProfile(pageSession,!1),clearCdpDeviceShell(pageSession),releaseControlledIndicator(pageSession)]);deviceShell.status==="fulfilled"&&deviceShell.value&&await pageSession.client.sendCommand("Page.reload",{}).catch(()=>{})})),clearCdpMockState(),clearCdpMtopEnvironmentState(pageSessions),clearCdpRuleState(session),clearCdpFetchInterceptionState(pageSessions),session.close(),{released:!0,hadActiveControl,affectedTabIds}}var SAMPLE_PAGE_READINESS_SRC=samplePageReadinessInPage.toString(),DISPOSE_PAGE_READINESS_SRC=disposePageReadinessObserverInPage.toString();async function startCdpNavigationObserver(cdpSession2,pageSession,urlBefore,options={}){let pageEndpoint=await resolveCdpDeviceShellPageEndpoint(pageSession),pageClient=pageEndpoint.client;await ensureCdpDomain(pageClient,"Page"),await ensureCdpDomain(pageClient,"Runtime"),options.trackNetwork&&await ensureCdpDomain(pageClient,"Network");let browserClient=null,baselineTargetIds=new Set;if(options.trackOpenedTabs)try{browserClient=await cdpSession2.getBrowserClient();let targets=await browserClient.sendCommand("Target.getTargets");for(let target of targets.targetInfos??[])baselineTargetIds.add(target.targetId)}catch{browserClient=null}let frameTree=await pageClient.sendCommand("Page.getFrameTree"),observedFrameId=pageEndpoint.frameId??frameTree.frameTree?.frame?.id,observesParentTargetSubframe=pageClient===pageSession.client&&pageEndpoint.frameId!==void 0,tracker=createNavigationSettlementTracker({urlBefore,trackNetwork:options.trackNetwork,networkAvailable:options.trackNetwork===!0,networkIdleMs:options.networkIdleMs,contentReadyAfterMs:options.contentReadyAfterMs,sampleContent:async()=>(await sendCdpDeviceShellPageCommand(pageSession,"Runtime.evaluate",{expression:`(${SAMPLE_PAGE_READINESS_SRC})(${options.networkIdleMs??500})`,returnByValue:!0})).result?.value}),removeFrameNavigated=pageClient.on("Page.frameNavigated",params=>{observedFrameId&&params.frame?.id!==observedFrameId||tracker.markStarted(params.frame?.url)}),removeWithinDocument=pageClient.on("Page.navigatedWithinDocument",params=>{observedFrameId&&params.frameId!==observedFrameId||(tracker.markStarted(params.url),tracker.markDocumentComplete(params.url))}),removeLoad=pageClient.on("Page.loadEventFired",()=>{observesParentTargetSubframe||tracker.hasStarted()&&tracker.markDocumentComplete()}),removeFrameStoppedLoading=pageClient.on("Page.frameStoppedLoading",params=>{observedFrameId&&params.frameId!==observedFrameId||tracker.hasStarted()&&tracker.markDocumentComplete()}),removeRequestStarted=options.trackNetwork?pageClient.on("Network.requestWillBeSent",params=>{isPotentialNavigationRequest(params.type??"",params.request?.url??"")&&tracker.requestStarted(params.requestId)}):()=>{},onRequestFinished=params=>tracker.requestFinished(params.requestId),removeRequestFinished=options.trackNetwork?pageClient.on("Network.loadingFinished",onRequestFinished):()=>{},removeRequestFailed=options.trackNetwork?pageClient.on("Network.loadingFailed",onRequestFinished):()=>{};return{hasStarted:tracker.hasStarted,hasNetworkActivity:tracker.hasNetworkActivity,waitForStart:tracker.waitForStart,waitForNetworkIdle:tracker.waitForNetworkIdle,waitForResult:async timeoutMs=>{let result=await tracker.waitForResult(timeoutMs);try{let pageState=await sendCdpDeviceShellPageCommand(pageSession,"Runtime.evaluate",{expression:"({ title: document.title, url: location.href })",returnByValue:!0});return{...result,title:pageState.result?.value?.title??result.title,urlAfter:pageState.result?.value?.url??result.urlAfter}}catch{return result}},getOpenedTabs:async timeoutMs=>{if(!browserClient||options.sourceTabId===void 0)return[];let candidates=((await browserClient.sendCommand("Target.getTargets")).targetInfos??[]).filter(target=>target.type==="page"&&target.openerId===pageSession.targetId&&!baselineTargetIds.has(target.targetId));return(await Promise.all(candidates.map(async candidate=>{let tabId=await cdpSession2.ensureTargetRegistered(candidate.targetId),ready=!1;try{let openedPageSession=await cdpSession2.getPageSession(tabId);await ensureCdpDomain(openedPageSession.client,"Page"),await waitForPageLoad(openedPageSession,timeoutMs),ready=!0}catch{}let targetInfo=await browserClient.sendCommand("Target.getTargetInfo",{targetId:candidate.targetId}).then(result=>result.targetInfo).catch(()=>null);return targetInfo?{tabId,openerTabId:options.sourceTabId,url:targetInfo.url??candidate.url??"",title:targetInfo.title??candidate.title??"",ready,settledBy:ready?"load":"timeout"}:null}))).filter(tab=>tab!==null)},dispose:async()=>{removeFrameNavigated(),removeWithinDocument(),removeLoad(),removeFrameStoppedLoading(),removeRequestStarted(),removeRequestFinished(),removeRequestFailed(),tracker.dispose(),await sendCdpDeviceShellPageCommand(pageSession,"Runtime.evaluate",{expression:`(${DISPOSE_PAGE_READINESS_SRC})()`,returnByValue:!1}).catch(()=>{})}}}var INSTALL_PAGE_OBSERVER_SRC=installPageObserverInPage.toString(),DISPOSE_PAGE_OBSERVER_SRC=disposePageObserverInPage.toString(),PAGE_OBSERVER_GLOBAL="__MEARL_PAGE_OBSERVER__",observationTargets=new WeakMap;function evaluationError(result){return result.exceptionDetails?result.exceptionDetails.exception?.description??result.exceptionDetails.text??"Page observation evaluation failed":null}async function startPageObservation(session){let result=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:`(${INSTALL_PAGE_OBSERVER_SRC})()`,returnByValue:!0}),error48=evaluationError(result);if(error48)throw new Error(error48);let checkpoint=result.result?.value;if(!checkpoint||typeof checkpoint.version!="number")throw new Error("Page observer did not return a checkpoint");let endpoint=await resolveCdpDeviceShellPageEndpoint(session);return observationTargets.set(checkpoint,{...endpoint,startedAt:Date.now()}),checkpoint}async function finishPageObservation(session,checkpoint,options={}){let startedTarget=observationTargets.get(checkpoint),currentTarget=await resolveCdpDeviceShellPageEndpoint(session);if(startedTarget&&currentTarget.url&&(currentTarget.client!==startedTarget.client||currentTarget.frameId!==startedTarget.frameId||currentTarget.url!==(startedTarget.url??checkpoint.url))){let title=await sendCdpDeviceShellPageCommand(session,"Runtime.evaluate",{expression:"document.title",returnByValue:!0}).then(result2=>typeof result2.result?.value=="string"?result2.result.value:"").catch(()=>"");return{mode:"navigation",urlBefore:checkpoint.url,urlAfter:currentTarget.url,title,elapsed:Date.now()-startedTarget.startedAt,loaded:!0,ready:!0,settledBy:"load",pendingRequests:0,fullSnapshotRecommended:!0,snapshotReasons:["navigation"]}}let{quietMs,firstChangeTimeoutMs,timeoutMs}=resolvePageObservationWaitOptions(options),expression=`(() => {
1487
1487
  const state = globalThis[${JSON.stringify(PAGE_OBSERVER_GLOBAL)}];
1488
1488
  if (!state || typeof state.waitSince !== 'function') {
1489
1489
  throw new Error('Page observer is unavailable after the action');
@@ -1697,4 +1697,4 @@ Examples:
1697
1697
  `)}return}if(!isExtensionBrowserAction(action)&&(typeof action!="string"||!action.startsWith("__"))){socket.write(JSON.stringify({id,success:!1,error:`Unsupported action: ${String(action)}`})+`
1698
1698
  `);return}let useExtension=!(request.transport==="cdp")&&extensionVersion!==null,transport=useExtension?"extension":"cdp",startedAt=Date.now();try{validateRequiredActionTabId(action,data);let result;useExtension?action==="send_request"&&hasSendRequestFiles(data)?result=await sendRequestWithTransferredFiles(data,(internalAction,payload,timeoutMs)=>sendRequestToExtension(internalAction,payload,timeoutMs,!0,controlSource)):action==="run_actions"&&hasRunActionsSendRequestFiles(data)?result=await sendRunActionsWithTransferredFiles(data,(internalAction,payload,timeoutMs)=>sendRequestToExtension(internalAction,payload,timeoutMs,!0,controlSource),transformed=>toTimeoutMs("run_actions",transformed)):result=await sendRequestToExtension(action,data,toTimeoutMs(action,data),!1,controlSource):(cdpPermissionNoticeLogged||(cdpPermissionNoticeLogged=!0,log("CDP mode: domain permission checks are not enforced — all actions run without domain authorization")),result=await handleViaCdp(action,data,toTimeoutMs(action,data),controlSource)),trackAction(action,{success:!0,transport,duration_ms:Date.now()-startedAt,extension_version:extensionVersion??"not_connected"});let response={id,success:!0,data:result};if(!versionWarningEmitted){let versionWarning=buildVersionWarning(clientVersion);versionWarning&&(versionWarningEmitted=!0,response.versionWarning=versionWarning)}socket.write(JSON.stringify(response)+`
1699
1699
  `)}catch(error48){let message=error48 instanceof Error?error48.message:String(error48);trackAction(action,{success:!1,transport,duration_ms:Date.now()-startedAt,error_code:classifyAnalyticsError(error48),extension_version:extensionVersion??"not_connected"}),socket.write(JSON.stringify({id,success:!1,error:message})+`
1700
- `)}}async function handleSocketLine(socket,line){await handleSocketRequest(socket,line)}async function handleViaCdp(action,data,_timeoutMs,controlSource){if(action==="set_rule"||action==="get_rules")throw new Error(`${action} requires the Mearl browser extension. Install it from https://chromewebstore.google.com/detail/mearl/aoehhjnofngknnjefamjbplchbolghkm`);if(!getRegisteredActionNames().includes(action))throw new Error(`Action "${action}" is not supported in CDP mode`);if(!await getCdpSession().isAvailable())throw CDP_ENDPOINT_FILE?new Error("The remote CDP endpoint is not available"):new Error(`Chrome DevTools remote debugging is not available on port ${CDP_PORT}. Enable it via chrome://inspect/#remote-debugging (Chrome 145+) or install the Mearl extension.`);return isDaemonMode&&!skipBrowserRegistration&&(publishDaemonBrowser(),shouldReconnectDaemonBrowser()||monitorConnectedDaemonBrowser()),shouldObservePageAction(action,data)?cdpObservedPageAction(getCdpSession(),action,data,controlSource):dispatchCdpAction(getCdpSession(),action,data,controlSource)}function onSocketConnection(socket){let lineBuffer=new Utf8LineBuffer(MAX_SOCKET_BUFFER_SIZE2);socket.on("data",chunk=>{let result=lineBuffer.push(chunk);if(result.overflow){log(`socket request exceeded ${MAX_SOCKET_BUFFER_SIZE2} bytes; closing connection`),socket.destroy();return}for(let line of result.lines)line.trim()&&handleSocketLine(socket,line)}),socket.on("error",error48=>{log("socket error:",String(error48))})}function isPathAlive(socketPath){return new Promise(resolve9=>{if(process.platform!=="win32"&&!fs21.existsSync(socketPath)){resolve9(!1);return}let client2=net4.createConnection(socketPath),done=alive=>{client2.removeAllListeners(),client2.destroy(),resolve9(alive)},timer=setTimeout(()=>done(!1),500);client2.on("connect",()=>{clearTimeout(timer),done(!0)}),client2.on("error",()=>{clearTimeout(timer),done(!1)})})}function listenOn(socketPath){return new Promise((resolve9,reject)=>{if(process.platform!=="win32"&&fs21.existsSync(socketPath))try{fs21.unlinkSync(socketPath)}catch{}let server=net4.createServer(onSocketConnection);server.once("error",reject),server.listen(socketPath,()=>{if(process.platform!=="win32")try{fs21.chmodSync(socketPath,384)}catch(error48){server.close();try{fs21.unlinkSync(socketPath)}catch{}reject(error48);return}server.removeListener("error",reject),server.on("error",error48=>log("socket server error:",String(error48))),log(`listening on ${socketPath}`),resolve9(server)})})}async function tryBindLegacySocket(){if(await isPathAlive(LEGACY_SOCKET_PATH)){log("legacy socket already owned by a live host, skipping");return}try{legacyServer=await listenOn(LEGACY_SOCKET_PATH)}catch(error48){log("legacy socket bind failed (raced):",String(error48)),legacyServer=null}}function releaseLegacySocket(){if(!legacyServer)return;let server=legacyServer;legacyServer=null;try{server.close()}catch{}if(process.platform!=="win32")try{fs21.existsSync(LEGACY_SOCKET_PATH)&&fs21.unlinkSync(LEGACY_SOCKET_PATH)}catch{}}async function startSocketServer(){socketServer=await listenOn(INSTANCE_SOCKET_PATH),skipBrowserRegistration||await tryBindLegacySocket()}function cleanupInstanceSocketFile(){if(process.platform!=="win32")try{fs21.existsSync(INSTANCE_SOCKET_PATH)&&fs21.unlinkSync(INSTANCE_SOCKET_PATH)}catch(error48){log("cleanup socket file failed:",String(error48))}}function cleanupAndExit(code){cancelInventoryExit(),cdpRegistrationTimer&&(clearInterval(cdpRegistrationTimer),cdpRegistrationTimer=null),cdpSession?.close(),agentChatManager?.dispose(),agentChatManager=null,unregisterBrowser(),cdpBrowserPublished=!1,releaseLegacySocket();let finish=()=>{cleanupInstanceSocketFile(),process.exit(code)};if(socketServer){socketServer.close(finish),socketServer=null;return}finish()}function restartAfterUpdate(){setTimeout(()=>process.exit(0),2e3).unref(),cleanupAndExit(0)}function publishDaemonBrowser(){cancelInventoryExit(),!cdpBrowserPublished&&(registerBrowser({browserId:CDP_BROWSER_ID,socketPath:INSTANCE_SOCKET_PATH,browserName:CDP_BROWSER_NAME,nativeHostVersion:NATIVE_HOST_VERSION,transport:"cdp",lastFocusedAt:CDP_BROWSER_ID.startsWith("managed:")?0:void 0}),cdpBrowserPublished=!0)}function unpublishDaemonBrowser(){cdpBrowserPublished&&(unregisterBrowser(),cdpBrowserPublished=!1)}function shouldReconnectDaemonBrowser(){return!!CDP_ENDPOINT_FILE||CDP_BROWSER_ID.startsWith("managed:")}function monitorConnectedDaemonBrowser(){cdpRegistrationTimer||(cdpRegistrationTimer=setInterval(()=>{getCdpSession().hasActiveConnections()||(unpublishDaemonBrowser(),cdpRegistrationTimer&&clearInterval(cdpRegistrationTimer),cdpRegistrationTimer=null)},2e3),cdpRegistrationTimer.unref())}async function monitorReconnectableDaemonBrowser(){let checking=!1,refresh=async()=>{if(!checking&&cdpAutoReconnectEnabled){checking=!0;try{await getCdpSession().isAvailable()?publishDaemonBrowser():unpublishDaemonBrowser()}finally{checking=!1}}};await refresh(),cdpRegistrationTimer=setInterval(()=>{refresh()},2e3),cdpRegistrationTimer.unref()}async function main(){if(initBrowserRegistry({log}),pruneDeadBrowsers(),initCloudConnector({log,isDaemonMode,sendToExtension,version:NATIVE_HOST_VERSION}),isDaemonMode?log(`running in ${skipBrowserRegistration?"browser inventory":discoverCdp?"CDP discovery":"CDP"} daemon mode, pid=${process.pid}, version=${NATIVE_HOST_VERSION}, cdp=${describeCdpEndpoint()}`):setupNativeMessageInput(),await startSocketServer(),shouldExitWithoutLegacySocket(runtimeArgs,!!legacyServer)){cleanupAndExit(0);return}discoverCdp&&scheduleInventoryExit(DISCOVERY_REQUEST_IDLE_EXIT_MS),isDaemonMode&&!skipBrowserRegistration&&shouldReconnectDaemonBrowser()&&await monitorReconnectableDaemonBrowser(),process.on("SIGINT",()=>cleanupAndExit(0)),process.on("SIGTERM",()=>cleanupAndExit(0)),process.on("uncaughtException",error48=>{log("uncaughtException:",String(error48)),cleanupAndExit(1)}),process.on("unhandledRejection",error48=>{log("unhandledRejection:",String(error48)),cleanupAndExit(1)})}main().catch(error48=>{log("main() failed:",String(error48)),process.exit(1)});
1700
+ `)}}async function handleSocketLine(socket,line){await handleSocketRequest(socket,line)}async function handleViaCdp(action,data,_timeoutMs,controlSource){if(!getRegisteredActionNames().includes(action))throw new Error(`Action "${action}" is not supported in CDP mode`);if(!await getCdpSession().isAvailable())throw CDP_ENDPOINT_FILE?new Error("The remote CDP endpoint is not available"):new Error(`Chrome DevTools remote debugging is not available on port ${CDP_PORT}. Enable it via chrome://inspect/#remote-debugging (Chrome 145+) or install the Mearl extension.`);return isDaemonMode&&!skipBrowserRegistration&&(publishDaemonBrowser(),shouldReconnectDaemonBrowser()||monitorConnectedDaemonBrowser()),shouldObservePageAction(action,data)?cdpObservedPageAction(getCdpSession(),action,data,controlSource):dispatchCdpAction(getCdpSession(),action,data,controlSource)}function onSocketConnection(socket){let lineBuffer=new Utf8LineBuffer(MAX_SOCKET_BUFFER_SIZE2);socket.on("data",chunk=>{let result=lineBuffer.push(chunk);if(result.overflow){log(`socket request exceeded ${MAX_SOCKET_BUFFER_SIZE2} bytes; closing connection`),socket.destroy();return}for(let line of result.lines)line.trim()&&handleSocketLine(socket,line)}),socket.on("error",error48=>{log("socket error:",String(error48))})}function isPathAlive(socketPath){return new Promise(resolve9=>{if(process.platform!=="win32"&&!fs21.existsSync(socketPath)){resolve9(!1);return}let client2=net4.createConnection(socketPath),done=alive=>{client2.removeAllListeners(),client2.destroy(),resolve9(alive)},timer=setTimeout(()=>done(!1),500);client2.on("connect",()=>{clearTimeout(timer),done(!0)}),client2.on("error",()=>{clearTimeout(timer),done(!1)})})}function listenOn(socketPath){return new Promise((resolve9,reject)=>{if(process.platform!=="win32"&&fs21.existsSync(socketPath))try{fs21.unlinkSync(socketPath)}catch{}let server=net4.createServer(onSocketConnection);server.once("error",reject),server.listen(socketPath,()=>{if(process.platform!=="win32")try{fs21.chmodSync(socketPath,384)}catch(error48){server.close();try{fs21.unlinkSync(socketPath)}catch{}reject(error48);return}server.removeListener("error",reject),server.on("error",error48=>log("socket server error:",String(error48))),log(`listening on ${socketPath}`),resolve9(server)})})}async function tryBindLegacySocket(){if(await isPathAlive(LEGACY_SOCKET_PATH)){log("legacy socket already owned by a live host, skipping");return}try{legacyServer=await listenOn(LEGACY_SOCKET_PATH)}catch(error48){log("legacy socket bind failed (raced):",String(error48)),legacyServer=null}}function releaseLegacySocket(){if(!legacyServer)return;let server=legacyServer;legacyServer=null;try{server.close()}catch{}if(process.platform!=="win32")try{fs21.existsSync(LEGACY_SOCKET_PATH)&&fs21.unlinkSync(LEGACY_SOCKET_PATH)}catch{}}async function startSocketServer(){socketServer=await listenOn(INSTANCE_SOCKET_PATH),skipBrowserRegistration||await tryBindLegacySocket()}function cleanupInstanceSocketFile(){if(process.platform!=="win32")try{fs21.existsSync(INSTANCE_SOCKET_PATH)&&fs21.unlinkSync(INSTANCE_SOCKET_PATH)}catch(error48){log("cleanup socket file failed:",String(error48))}}function cleanupAndExit(code){cancelInventoryExit(),cdpRegistrationTimer&&(clearInterval(cdpRegistrationTimer),cdpRegistrationTimer=null),cdpSession?.close(),agentChatManager?.dispose(),agentChatManager=null,unregisterBrowser(),cdpBrowserPublished=!1,releaseLegacySocket();let finish=()=>{cleanupInstanceSocketFile(),process.exit(code)};if(socketServer){socketServer.close(finish),socketServer=null;return}finish()}function restartAfterUpdate(){setTimeout(()=>process.exit(0),2e3).unref(),cleanupAndExit(0)}function publishDaemonBrowser(){cancelInventoryExit(),!cdpBrowserPublished&&(registerBrowser({browserId:CDP_BROWSER_ID,socketPath:INSTANCE_SOCKET_PATH,browserName:CDP_BROWSER_NAME,nativeHostVersion:NATIVE_HOST_VERSION,transport:"cdp",lastFocusedAt:CDP_BROWSER_ID.startsWith("managed:")?0:void 0}),cdpBrowserPublished=!0)}function unpublishDaemonBrowser(){cdpBrowserPublished&&(unregisterBrowser(),cdpBrowserPublished=!1)}function shouldReconnectDaemonBrowser(){return!!CDP_ENDPOINT_FILE||CDP_BROWSER_ID.startsWith("managed:")}function monitorConnectedDaemonBrowser(){cdpRegistrationTimer||(cdpRegistrationTimer=setInterval(()=>{getCdpSession().hasActiveConnections()||(unpublishDaemonBrowser(),cdpRegistrationTimer&&clearInterval(cdpRegistrationTimer),cdpRegistrationTimer=null)},2e3),cdpRegistrationTimer.unref())}async function monitorReconnectableDaemonBrowser(){let checking=!1,refresh=async()=>{if(!checking&&cdpAutoReconnectEnabled){checking=!0;try{await getCdpSession().isAvailable()?publishDaemonBrowser():unpublishDaemonBrowser()}finally{checking=!1}}};await refresh(),cdpRegistrationTimer=setInterval(()=>{refresh()},2e3),cdpRegistrationTimer.unref()}async function main(){if(initBrowserRegistry({log}),pruneDeadBrowsers(),initCloudConnector({log,isDaemonMode,sendToExtension,version:NATIVE_HOST_VERSION}),isDaemonMode?log(`running in ${skipBrowserRegistration?"browser inventory":discoverCdp?"CDP discovery":"CDP"} daemon mode, pid=${process.pid}, version=${NATIVE_HOST_VERSION}, cdp=${describeCdpEndpoint()}`):setupNativeMessageInput(),await startSocketServer(),shouldExitWithoutLegacySocket(runtimeArgs,!!legacyServer)){cleanupAndExit(0);return}discoverCdp&&scheduleInventoryExit(DISCOVERY_REQUEST_IDLE_EXIT_MS),isDaemonMode&&!skipBrowserRegistration&&shouldReconnectDaemonBrowser()&&await monitorReconnectableDaemonBrowser(),process.on("SIGINT",()=>cleanupAndExit(0)),process.on("SIGTERM",()=>cleanupAndExit(0)),process.on("uncaughtException",error48=>{log("uncaughtException:",String(error48)),cleanupAndExit(1)}),process.on("unhandledRejection",error48=>{log("unhandledRejection:",String(error48)),cleanupAndExit(1)})}main().catch(error48=>{log("main() failed:",String(error48)),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mearl/native-host",
3
- "version": "2.19.1",
3
+ "version": "2.19.2",
4
4
  "description": "Native Messaging Host for Mearl — bridges Chrome Extension and local socket server",
5
5
  "type": "module",
6
6
  "engines": {
@@ -42,12 +42,12 @@
42
42
  "@types/ws": "^8.18.1",
43
43
  "esbuild": "^0.25.2",
44
44
  "typescript": "^5.8.3",
45
- "@mearl/browser-core": "2.19.1",
46
- "@mearl/client": "2.19.1",
47
- "@mearl/app-profiles": "2.19.1",
48
- "@mearl/daemon-core": "2.19.1",
49
- "@mearl/provider": "2.19.1",
50
- "@mearl/setup": "2.19.1"
45
+ "@mearl/app-profiles": "2.19.2",
46
+ "@mearl/client": "2.19.2",
47
+ "@mearl/browser-core": "2.19.2",
48
+ "@mearl/daemon-core": "2.19.2",
49
+ "@mearl/provider": "2.19.2",
50
+ "@mearl/setup": "2.19.2"
51
51
  },
52
52
  "scripts": {
53
53
  "build": "rm -rf dist/ && node build.mjs",